Less crappy skiplist

This commit is contained in:
2024-04-12 13:18:36 +02:00
parent 29fe46159e
commit 728d9f05e9
17 changed files with 772 additions and 408 deletions

View File

@@ -0,0 +1,103 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="BackendCodeEditorSettings">
<option name="/Default/Housekeeping/GlobalSettingsUpgraded/IsUpgraded/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppClangFormat/EnableClangFormatSupport/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/EditorConfig/EnableClangFormatSupport/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_BINARY_EXPRESSIONS_CHAIN/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_CALLS_CHAIN/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXPRESSION/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_FOR_STMT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTIPLE_DECLARATION/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_TERNARY/@EntryValue" value="ALIGN_ALL" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_CLASS_DEFINITION/@EntryValue" value="1" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue" value="2" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_CODE/@EntryValue" value="2" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_USER_LINEBREAKS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CASE_FROM_SWITCH/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_COMMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INT_ALIGN_EQ/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SIMPLE_BLOCK_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_ARGS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_PARAMS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_SEMICOLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_SEMICOLON/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_UNARY_OPERATOR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_ARRAY_ACCESS_BRACKETS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_METHOD_PARENTHESES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPECIAL_ELSE_IF_TREATMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_BINARY_OPSIGN/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_TERNARY_OPSIGNS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TYPE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/OTHER_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CASE_BLOCK_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DECLARATION/@EntryValue" value="1" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DEFINITION/@EntryValue" value="1" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_WHILE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_ELSE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_CATCH_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_INDENTATION/@EntryValue" value="All" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_ARGUMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXTENDS_LIST/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_PARAMETER/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_ARGUMENT/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_PARAMETER/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_DECLARATIONS/@EntryValue" value="0" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_ACCESS_SPECIFIERS_FROM_CLASS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CLASS_MEMBERS_FROM_ACCESS_SPECIFIERS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/LINE_BREAK_AFTER_COLON_IN_MEMBER_INITIALIZER_LISTS/@EntryValue" value="ON_SINGLE_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/MEMBER_INITIALIZER_LIST_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_NAMESPACE_DEFINITIONS_ON_SAME_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_EXTENDS_COLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_EXTENDS_COLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_COLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_COLON/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_DATA_MEMBER/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_DATA_MEMBERS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_METHOD/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_NESTED_DECLARATOR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_DATA_MEMBER/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_DATA_MEMBERS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_METHOD/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_DATA_MEMBER/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_DATA_MEMBERS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_METHOD/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_DATA_MEMBER/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_DATA_MEMBERS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_METHOD/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BETWEEN_CLOSING_ANGLE_BRACKETS_IN_TEMPLATE_ARGS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_DECLARATION_PARENTHESES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_BLOCKS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_INVOCATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_RPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_DECLARATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_RPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_ARGUMENTS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_PARAMETERS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BREAK_TEMPLATE_DECLARATION/@EntryValue" value="LINE_BREAK" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/FREE_BLOCK_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INVOCABLE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ANONYMOUS_METHOD_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INITIALIZER_BRACES/@EntryValue" value="END_OF_LINE_NO_SPACE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_STYLE/@EntryValue" value="Space" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_SIZE/@EntryValue" value="4" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CONTINUOUS_LINE_INDENT/@EntryValue" value="Double" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TAB_WIDTH/@EntryValue" value="4" type="int" />
</component>
</project>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MakefileSettings">
<option name="linkedExternalProjectsSettings">
<MakefileProjectSettings>
<option name="buildDirectory" value="$PROJECT_DIR$/../build" />
<option name="buildSystemName" value="GNU Autotools" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
<option name="version" value="2" />
</MakefileProjectSettings>
</option>
</component>
<component name="MakefileWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
</project>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/../../.." vcs="Git" />
</component>
</project>

View File

@@ -1,3 +1,4 @@
set(CMAKE_CXX_STANDARD 20)
add_executable(kernel.elf) add_executable(kernel.elf)

View File

@@ -107,36 +107,36 @@ uint64_t syscall_lseek(uint64_t fd, uint64_t off, uint64_t whence) {
} }
uint64_t syscall_print_tasks() { uint64_t syscall_print_tasks() {
static SkipList<uint64_t, std::pair<String, uint64_t>> last_times = Scheduler::getTaskTimePerPid(); static SkipListMap<uint64_t, std::pair<String, uint64_t>> last_times = Scheduler::getTaskTimePerPid();
static std::atomic<uint64_t> last_print_time = micros; static std::atomic<uint64_t> last_print_time = micros;
uint64_t prev_print_time = last_print_time; uint64_t prev_print_time = last_print_time;
last_print_time = micros; last_print_time = micros;
SkipList<uint64_t, std::pair<String, uint64_t>> prev_times = std::move(last_times); SkipListMap<uint64_t, std::pair<String, uint64_t>> prev_times = std::move(last_times);
last_times = Scheduler::getTaskTimePerPid(); last_times = Scheduler::getTaskTimePerPid();
uint64_t slice = last_print_time - prev_print_time; uint64_t slice = last_print_time - prev_print_time;
if (slice == 0) return 0; if (slice == 0) return 0;
for (const auto &t: prev_times) { for (const auto &t: prev_times) {
auto f = last_times.find(t.key); auto f = last_times.find(t.first);
if (!f->end && f->key == t.key) { if (f != last_times.end()) {
assert(f->data.second >= t.data.second); assert(f->second.second >= t.second.second);
String buf; String buf;
buf += "PID: "; buf += "PID: ";
buf += t.key; buf += t.first;
buf += " "; buf += " ";
buf += t.data.first; buf += t.second.first;
buf += " usage: "; buf += " usage: ";
buf += (((f->data.second - t.data.second) * 100ULL) / slice); buf += (((f->second.second - t.second.second) * 100ULL) / slice);
buf += "%\n"; buf += "%\n";
GlobalTtyManager.all_tty_putstr(buf.c_str()); GlobalTtyManager.all_tty_putstr(buf.c_str());
} else { } else {
String buf; String buf;
buf += "PID: "; buf += "PID: ";
buf += t.key; buf += t.first;
buf += " "; buf += " ";
buf += t.data.first; buf += t.second.first;
buf += " dead \n"; buf += " dead \n";
GlobalTtyManager.all_tty_putstr(buf.c_str()); GlobalTtyManager.all_tty_putstr(buf.c_str());
} }

View File

@@ -37,14 +37,14 @@ void sanity_check_frame(Arch::TaskFrame *cur_frame) {
assert2((cur_frame->cs == Arch::GDT::gdt_code.selector() || (cur_frame->ss == Arch::GDT::gdt_code_user.selector()) | 0x3), "CS wrong!"); assert2((cur_frame->cs == Arch::GDT::gdt_code.selector() || (cur_frame->ss == Arch::GDT::gdt_code_user.selector()) | 0x3), "CS wrong!");
} }
std::atomic<uint64_t> max_pid = 0; std::atomic<uint64_t> max_pid = 0;
Mutex AllTasks_lock; Mutex AllTasks_lock;
SkipList<uint64_t, UniquePtr<Task>> AllTasks; SkipListMap<uint64_t, UniquePtr<Task>> AllTasks;
static List<Task *>::Node *RunningTask; static List<Task *>::Node *RunningTask;
static Spinlock NextTasks_lock; static Spinlock NextTasks_lock;
static List<Task *> NextTasks; static List<Task *> NextTasks;
// Task freer // Task freer
Mutex TasksToFree_lock; Mutex TasksToFree_lock;
@@ -52,11 +52,11 @@ CV TasksToFree_cv;
List<List<Task *>::Node *> TasksToFree; List<List<Task *>::Node *> TasksToFree;
// Waiting // Waiting
Mutex WaitingTasks_mlock; Mutex WaitingTasks_mlock;
CV WaitingTasks_cv; CV WaitingTasks_cv;
SkipList<uint64_t, List<Task *>::Node *> WaitingTasks; SkipListMultiMap<uint64_t, List<Task *>::Node *> WaitingTasks;
static std::atomic<bool> initialized = false; static std::atomic<bool> initialized = false;
// //
void Scheduler::remove_self() { void Scheduler::remove_self() {
@@ -147,7 +147,7 @@ Task::Task(Task::TaskMode mode, void (*entrypoint)(), const char *name) {
sanity_check_frame(&_frame); sanity_check_frame(&_frame);
{ {
LockGuard l(AllTasks_lock); LockGuard l(AllTasks_lock);
AllTasks.add(_pid, UniquePtr(this)); AllTasks.emplace(_pid, UniquePtr(this));
} }
} }
@@ -155,12 +155,12 @@ Task::~Task() {
assert(_state != TaskState::TS_RUNNING); assert(_state != TaskState::TS_RUNNING);
} }
SkipList<uint64_t, std::pair<String, Task::TaskPID>> Scheduler::getTaskTimePerPid() { SkipListMap<uint64_t, std::pair<String, Task::TaskPID>> Scheduler::getTaskTimePerPid() {
SkipList<uint64_t, std::pair<String, Task::TaskPID>> ret; SkipListMap<uint64_t, std::pair<String, Task::TaskPID>> ret;
{ {
LockGuard l(AllTasks_lock); LockGuard l(AllTasks_lock);
for (const auto &t: AllTasks) { for (const auto &t: AllTasks) {
ret.add(t.data->pid(), std::make_pair(t.data->name(), t.data->used_time())); ret.emplace(t.second->pid(), std::make_pair(t.second->name(), t.second->used_time()));
} }
} }
return ret; return ret;
@@ -216,7 +216,7 @@ void Scheduler::sleep_self(uint64_t diff) {
{ {
WaitingTasks_mlock.lock(); WaitingTasks_mlock.lock();
assert(cur_task() != nullptr); assert(cur_task() != nullptr);
assert(WaitingTasks.add(wake_time, extract_running_task_node()) != nullptr); WaitingTasks.emplace(wake_time, extract_running_task_node());
Scheduler::self_block(WaitingTasks_mlock); Scheduler::self_block(WaitingTasks_mlock);
} }
} }
@@ -233,22 +233,17 @@ static void task_waker() {
{ {
WaitingTasks_mlock.lock(); WaitingTasks_mlock.lock();
while (WaitingTasks.begin() != WaitingTasks.end() && WaitingTasks.begin()->key <= micros && WaitingTasks.begin()->data->val->state() != Task::TaskState::TS_RUNNING) { while (WaitingTasks.begin() != WaitingTasks.end() && WaitingTasks.begin()->first <= micros && WaitingTasks.begin()->second->val->state() != Task::TaskState::TS_RUNNING) {
auto *node = &*WaitingTasks.begin(); auto node = WaitingTasks.begin();
auto task = WaitingTasks.begin()->data; // FIXME:
auto node2 = node;
++node2;
auto task = WaitingTasks.begin()->second;
// TODO this is all ugly WaitingTasks.erase(node, node2);
uint64_t l1 = 0;
for (auto cur = node; !cur->end; cur = cur->next[0]) l1++;
WaitingTasks.erase(node, node->next[0], false);
uint64_t l2 = 0;
for (auto *cur = &*WaitingTasks.begin(); !cur->end; cur = cur->next[0]) l2++;
WaitingTasks_mlock.unlock(); WaitingTasks_mlock.unlock();
assert(l1 - l2 == 1);
task->val->_sleep_until = 0; task->val->_sleep_until = 0;
task->val->_state = Task::TaskState::TS_RUNNING; task->val->_state = Task::TaskState::TS_RUNNING;

View File

@@ -106,7 +106,7 @@ namespace Scheduler {
extern "C" void switch_task(Arch::TaskFrame *cur_frame); extern "C" void switch_task(Arch::TaskFrame *cur_frame);
// TODO: that's quite inefficient! // TODO: that's quite inefficient!
SkipList<uint64_t, std::pair<String, Task::TaskPID>> getTaskTimePerPid(); SkipListMap<uint64_t, std::pair<String, Task::TaskPID>> getTaskTimePerPid();
void yield_self(); void yield_self();
} // namespace Scheduler } // namespace Scheduler

View File

@@ -5,13 +5,13 @@
#include "TestTemplates.hpp" #include "TestTemplates.hpp"
#include "assert.h"
#include "List.hpp" #include "List.hpp"
#include "PointersCollection.hpp" #include "PointersCollection.hpp"
#include "SkipList.hpp" #include "SkipList.hpp"
#include "SkipListSet.hpp" #include "SkipListSet.hpp"
#include "String.hpp" #include "String.hpp"
#include "Vector.hpp" #include "Vector.hpp"
#include "assert.h"
#include "TtyManager.hpp" #include "TtyManager.hpp"
@@ -153,28 +153,28 @@ public:
class SkipListTester { class SkipListTester {
public: public:
bool test() { bool test() {
SkipList<int, String> test1; SkipListMap<int, String> test1;
test1.add(5, "test5", false); test1.emplace(5, "test5");
test1.add(999, "test999", false); test1.emplace(999, "test999");
test1.add(5, "test5", false); test1.emplace(5, "test5");
test1.add(1, "test1", false); test1.emplace(1, "test1");
test1.add(999, "test999", false); test1.emplace(999, "test999");
assert(test1.find(5)->data == "test5"); assert(test1.find(5)->second == "test5");
assert(test1.find(1)->data == "test1"); assert(test1.find(1)->second == "test1");
assert(test1.find(999)->data == "test999"); assert(test1.find(999)->second == "test999");
typename decltype(test1)::iterator tit = test1.begin();
typename decltype(test1)::const_iterator tcit = tit;
test1.erase(1); test1.erase(1);
assert(test1.find(1)->data != "test1"); assert(test1.find(1) == test1.cend());
test1.add(87, "test87", false); test1.emplace(87, "test87");
assert(test1.find(87)->data == "test87"); assert(test1.find(87)->second == "test87");
auto p2 = test1.lower_bound_update(78);
assert(p2->data == "test87");
test1.add(78, "test78", true);
assert(test1.find(78)->data == "test78");
test1.emplace(78, "test78");
assert(test1.find(78)->second == "test78");
// GlobalTtyManager.all_tty_putstr("SkipList tests ok!\n"); // GlobalTtyManager.all_tty_putstr("SkipList tests ok!\n");
return true; return true;
} }

View File

@@ -14,7 +14,7 @@
VMA::VMA(AddressSpace *space) : space(space) { VMA::VMA(AddressSpace *space) : space(space) {
LockGuard l(regions_lock); LockGuard l(regions_lock);
regions.add(0x1000, {0x1000, 0xFFF8000000000000ULL - 0x20000, EntryType::FREE}); regions.emplace(std::make_pair<uintptr_t, ListEntry>(0x1000, {0x1000, 0xFFF8000000000000ULL - 0x20000, EntryType::FREE}));
} }
VMA::ListEntry *VMA::get_entry(uintptr_t v_addr, size_t length) { VMA::ListEntry *VMA::get_entry(uintptr_t v_addr, size_t length) {
@@ -24,7 +24,9 @@ VMA::ListEntry *VMA::get_entry(uintptr_t v_addr, size_t length) {
// Find the region with start before or at v_addr // Find the region with start before or at v_addr
if (v_addr) { if (v_addr) {
found = &regions.find(v_addr)->data; auto ub = regions.upper_bound(v_addr);
--ub;
found = &ub->second;
// Check if it fits // Check if it fits
if (found->length < length || found->type != EntryType::FREE) found = nullptr; if (found->length < length || found->type != EntryType::FREE) found = nullptr;
} }
@@ -32,8 +34,8 @@ VMA::ListEntry *VMA::get_entry(uintptr_t v_addr, size_t length) {
// Otherwise try to find something else // Otherwise try to find something else
if (!found) if (!found)
for (auto &n: regions) { for (auto &n: regions) {
if (n.data.type == EntryType::FREE && n.data.length >= length) { if (n.second.type == EntryType::FREE && n.second.length >= length) {
found = &n.data; found = &n.second;
break; break;
} }
} }
@@ -46,13 +48,13 @@ VMA::ListEntry *VMA::get_entry(uintptr_t v_addr, size_t length) {
// If our region actually starts before what we requested, then cut it up // If our region actually starts before what we requested, then cut it up
if ((tmpFound.begin < v_addr) && (tmpFound.length > ((v_addr - tmpFound.begin) + length))) { if ((tmpFound.begin < v_addr) && (tmpFound.length > ((v_addr - tmpFound.begin) + length))) {
regions.add(tmpFound.begin, {tmpFound.begin, v_addr - tmpFound.begin, EntryType::FREE}); regions.emplace(std::make_pair<uintptr_t, ListEntry>((uintptr_t) tmpFound.begin, {tmpFound.begin, v_addr - tmpFound.begin, EntryType::FREE}));
tmpFound.begin = v_addr; tmpFound.begin = v_addr;
tmpFound.length -= v_addr - tmpFound.begin; tmpFound.length -= v_addr - tmpFound.begin;
} }
regions.add(tmpFound.begin + length, {tmpFound.begin + length, tmpFound.length - length, EntryType::FREE}); regions.emplace(std::make_pair<uintptr_t, ListEntry>(tmpFound.begin + length, {tmpFound.begin + length, tmpFound.length - length, EntryType::FREE}));
found = &regions.add(tmpFound.begin, {tmpFound.begin, length, EntryType::ANON})->data; found = &regions.emplace(std::make_pair<uintptr_t, ListEntry>((uintptr_t) tmpFound.begin, {tmpFound.begin, length, EntryType::ANON})).first->second;
} }
return found; return found;
} }
@@ -106,11 +108,11 @@ int VMA::munmap(void *addr, size_t length) {
} }
VMA::~VMA() { VMA::~VMA() {
for (const auto &e: regions) { for (const auto &e: regions) {
if (e.data.type == EntryType::ANON) { if (e.second.type == EntryType::ANON) {
assert((e.data.length & (PAGE_SIZE - 1)) == 0); assert((e.second.length & (PAGE_SIZE - 1)) == 0);
uint64_t page_len = e.data.length / PAGE_SIZE; uint64_t page_len = e.second.length / PAGE_SIZE;
for (int i = 0; i < page_len; i++) { for (int i = 0; i < page_len; i++) {
free4k((void *) HHDM_P2V(space->virt2real(reinterpret_cast<void *>(e.data.begin + i * PAGE_SIZE)))); free4k((void *) HHDM_P2V(space->virt2real(reinterpret_cast<void *>(e.second.begin + i * PAGE_SIZE))));
} }
} }
} }

View File

@@ -56,7 +56,7 @@ private:
ListEntry *get_entry(uintptr_t v_addr, size_t length); ListEntry *get_entry(uintptr_t v_addr, size_t length);
// //
SkipList<uintptr_t, ListEntry> regions; SkipListMap<uintptr_t, ListEntry> regions;
Mutex regions_lock; Mutex regions_lock;
}; };

View File

@@ -1,8 +1,12 @@
#ifndef SKIPLIST_H #ifndef SKIPLIST_H
#define SKIPLIST_H #define SKIPLIST_H
#include <algorithm>
#include <array>
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <functional>
#include <new>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
@@ -10,21 +14,34 @@
extern "C" int rand(void); extern "C" int rand(void);
template<typename K, typename V> template<typename Data>
class SkipList { class SkipListBase {
protected:
static constexpr size_t maxL{31}; static constexpr size_t maxL{31};
public:
struct Node { struct Node {
Node *next[maxL + 1] = {nullptr}; Node *next[maxL + 1] = {nullptr};
Node *before = nullptr; Node *before = nullptr;
bool end = false; bool end = false;
K key = K();
V data = V(); alignas(Data) std::array<unsigned char, sizeof(Data)> data;
Data &get() {
assert(!end);
return *std::launder(reinterpret_cast<Data *>(&data[0]));
}
const Data &get() const {
assert(!end);
return *std::launder(reinterpret_cast<const Data *>(&data[0]));
}
}; };
private: // static_assert(std::is_trivially_constructible<Node>::value);
// static_assert(std::is_trivially_destructible<Node>::value);
// static_assert(std::is_trivially_copyable<Node>::value);
// static_assert(std::is_trivially_move_assignable<Node>::value);
// static_assert(std::is_trivially_move_constructible<Node>::value);
class NodeAllocator { class NodeAllocator {
static constexpr int size{64}; static constexpr int size{64};
Node *nodes[size]; Node *nodes[size];
@@ -39,6 +56,12 @@ private:
} }
} }
NodeAllocator(const NodeAllocator &) = delete;
// NodeAllocator(NodeAllocator &&) = delete;
NodeAllocator &operator=(const NodeAllocator &) = delete;
// NodeAllocator &operator=(NodeAllocator &&) = delete;
//
void push(Node *&e) { void push(Node *&e) {
if (top >= size - 1) { if (top >= size - 1) {
delete e; delete e;
@@ -58,8 +81,6 @@ private:
node->end = false; node->end = false;
node->before = nullptr; node->before = nullptr;
node->next[0] = nullptr; node->next[0] = nullptr;
node->key = K();
// node->data = V();
return node; return node;
} }
@@ -79,8 +100,7 @@ private:
mutable Node *toUpdate[maxL + 1]; mutable Node *toUpdate[maxL + 1];
size_t curL = 0; size_t curL = 0;
public: SkipListBase() noexcept {
SkipList() noexcept {
root = (Node *) nodeAllocator.get(); root = (Node *) nodeAllocator.get();
root->end = true; root->end = true;
endnode = (Node *) nodeAllocator.get(); endnode = (Node *) nodeAllocator.get();
@@ -92,16 +112,21 @@ public:
} }
}; };
~SkipList() noexcept { // FIXME: Should this be protected?
public:
~SkipListBase() noexcept {
auto cur = root; auto cur = root;
while (cur != nullptr) { while (cur != nullptr) {
if (!cur->end)
std::destroy_at(&cur->get());
auto prev = cur; auto prev = cur;
cur = cur->next[0]; cur = cur->next[0];
nodeAllocator.push(prev); nodeAllocator.push(prev);
} }
} }
SkipList(SkipList const &l) noexcept : SkipList() { SkipListBase(SkipListBase const &l) noexcept : SkipListBase() {
toUpdate[0] = root; toUpdate[0] = root;
for (auto n = l.root->next[0]; n != nullptr && !n->end; n = n->next[0]) { for (auto n = l.root->next[0]; n != nullptr && !n->end; n = n->next[0]) {
@@ -114,7 +139,6 @@ public:
} }
auto newNode = (Node *) nodeAllocator.get(); auto newNode = (Node *) nodeAllocator.get();
newNode->key = n->key;
newNode->data = n->data; newNode->data = n->data;
newNode->before = toUpdate[0]; newNode->before = toUpdate[0];
if (toUpdate[0]->next[0] != nullptr) toUpdate[0]->next[0]->before = newNode; if (toUpdate[0]->next[0] != nullptr) toUpdate[0]->next[0]->before = newNode;
@@ -127,7 +151,7 @@ public:
} }
} }
SkipList(SkipList &&l) noexcept { SkipListBase(SkipListBase &&l) noexcept {
this->root = l.root; this->root = l.root;
l.root = nullptr; l.root = nullptr;
this->endnode = l.endnode; this->endnode = l.endnode;
@@ -136,62 +160,129 @@ public:
l.curL = 0; l.curL = 0;
} }
SkipList &operator=(SkipList l) noexcept { SkipListBase &operator=(SkipListBase l) noexcept {
std::swap(l.root, root); std::swap(l.root, root);
std::swap(l.endnode, endnode); std::swap(l.endnode, endnode);
std::swap(l.curL, curL); std::swap(l.curL, curL);
return *this; return *this;
} }
void add(V *p, size_t n, bool reuseUpdate = false) { protected:
if (!reuseUpdate) { // void add(V *p, size_t n, bool reuseUpdate = false) {
Node *cur = root; // if (!reuseUpdate) {
for (int i = curL; i >= 0; i--) { // Node *cur = root;
while (cur->next[i]->key < p->l && !cur->next[i]->end) // for (int i = curL; i >= 0; i--) {
cur = cur->next[i]; // while (cur->next[i]->key < p->l && !cur->next[i]->end)
toUpdate[i] = cur; // cur = cur->next[i];
} // toUpdate[i] = cur;
// }
// }
//
// for (size_t i = 0; i < n; i++, p++) {
// size_t newLevel = randomL();
//
// if (newLevel > curL) {
// for (size_t j = curL + 1; j <= newLevel; j++)
// toUpdate[j] = root;
//
// curL = newLevel;
// }
//
// auto newNode = (Node *) nodeAllocator.get();
// newNode->key = p->l;
// newNode->data = *p;
//
// newNode->before = toUpdate[0];
// if (toUpdate[0]->next[0] != nullptr) toUpdate[0]->next[0]->before = newNode;
//
// for (size_t j = 0; j <= newLevel; j++) {
// newNode->next[j] = toUpdate[j]->next[j];
// toUpdate[j]->next[j] = newNode;
// toUpdate[j] = newNode;
// }
// }
// }
template<typename value_type_arg>
struct SkipListBaseIteratorBase {
using iterator_category = std::bidirectional_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = value_type_arg;
using pointer = value_type *;
using reference = value_type &;
explicit SkipListBaseIteratorBase(Node *n) : n(std::move(n)){};
reference operator*() const { return n->get(); }
pointer operator->() const { return &n->get(); }
SkipListBaseIteratorBase &operator--() {
if (n->before)
n = n->before;
return *this;
} }
for (size_t i = 0; i < n; i++, p++) { SkipListBaseIteratorBase &operator++() {
size_t newLevel = randomL(); if (n->next[0])
n = n->next[0];
if (newLevel > curL) { return *this;
for (size_t j = curL + 1; j <= newLevel; j++)
toUpdate[j] = root;
curL = newLevel;
}
auto newNode = (Node *) nodeAllocator.get();
newNode->key = p->l;
newNode->data = *p;
newNode->before = toUpdate[0];
if (toUpdate[0]->next[0] != nullptr) toUpdate[0]->next[0]->before = newNode;
for (size_t j = 0; j <= newLevel; j++) {
newNode->next[j] = toUpdate[j]->next[j];
toUpdate[j]->next[j] = newNode;
toUpdate[j] = newNode;
}
} }
}
bool erase(Node *begin, Node *end, bool reuseUpdate = false) { SkipListBaseIteratorBase operator++(int) {
if (begin == end) return false; SkipListBaseIteratorBase tmp = *this;
++(*this);
return tmp;
}
if (!reuseUpdate) { template<typename L, typename R>
Node *cur = root; friend bool operator==(const SkipListBaseIteratorBase<L> &a, const SkipListBaseIteratorBase<R> &b);
for (int i = curL; i >= 0; i--) {
while (cur->next[i]->key < begin->key && !cur->next[i]->end) template<typename L, typename R>
cur = cur->next[i]; friend bool operator!=(const SkipListBaseIteratorBase<L> &a, const SkipListBaseIteratorBase<R> &b);
toUpdate[i] = cur;
} friend SkipListBase;
protected:
Node *n;
};
public:
template<typename L, typename R>
friend bool operator==(const SkipListBaseIteratorBase<L> &a, const SkipListBaseIteratorBase<R> &b) {
if (a.n->end && b.n->end) return true;
return a.n == b.n;
};
template<typename L, typename R>
friend bool operator!=(const SkipListBaseIteratorBase<L> &a, const SkipListBaseIteratorBase<R> &b) {
if (a.n->end && (a.n->end == b.n->end)) return false;
return a.n != b.n;
};
using iterator = SkipListBaseIteratorBase<Data>;
struct const_iterator : public SkipListBaseIteratorBase<const Data> {
using SkipListBaseIteratorBase<const Data>::SkipListBaseIteratorBase;
const_iterator(const iterator &i) : SkipListBaseIteratorBase<const Data>(i.n) {}
};
protected:
// Comparator true if less than, 0 if equal
template<class Comparator>
std::pair<Node *, bool> erase(const_iterator begin, const_iterator end) {
if (begin == end) return {root->next[0], false};
Node *cur = root;
for (int i = curL; i >= 0; i--) {
while (!cur->next[i]->end && Comparator()(cur->next[i]->get(), *begin))
cur = cur->next[i];
toUpdate[i] = cur;
} }
Node *prev = nullptr; Node *prev = nullptr;
for (auto cur = begin; cur != end; cur = cur->next[0]) { for (auto cur = begin.n; cur != end.n; cur = cur->next[0]) {
if (prev) if (prev)
nodeAllocator.push(prev); nodeAllocator.push(prev);
@@ -210,60 +301,24 @@ public:
prev = cur; prev = cur;
} }
auto ret = std::make_pair(prev->next[0], true);
if (prev) if (prev)
nodeAllocator.push(prev); nodeAllocator.push(prev);
return true; return ret;
} }
Node *add(K const &k, V v, bool reuseUpdate = false) { // Comparator true if less than, 0 if equal
if (!reuseUpdate) { std::pair<Node *, bool> erase(const const_iterator &k) {
Node *cur = root;
for (int i = curL; i >= 0; i--) {
while (cur->next[i]->key < k && !cur->next[i]->end)
cur = cur->next[i];
toUpdate[i] = cur;
}
cur = cur->next[0];
// Without this it's a multimap TODO: multiple variants of this and merge it with set
// if (cur->key == k && !cur->end) return nullptr;
}
size_t newLevel = randomL();
if (newLevel > curL) {
for (size_t i = curL + 1; i <= newLevel; i++)
toUpdate[i] = root;
curL = newLevel;
}
auto newNode = (Node *) nodeAllocator.get();
newNode->key = k;
newNode->data = std::move(v);
newNode->before = toUpdate[0];
if (toUpdate[0]->next[0] != nullptr) toUpdate[0]->next[0]->before = newNode;
for (size_t i = 0; i <= newLevel; i++) {
newNode->next[i] = toUpdate[i]->next[i];
toUpdate[i]->next[i] = newNode;
toUpdate[i] = newNode;
}
return newNode;
}
bool erase(K const &k) {
Node *cur = root; Node *cur = root;
for (int i = curL; i >= 0; i--) { for (int i = curL; i >= 0; i--) {
while (cur->next[i]->key < k && !cur->next[i]->end) while (!cur->next[i]->end && cur->next[i] != k.n)
cur = cur->next[i]; cur = cur->next[i];
toUpdate[i] = cur; toUpdate[i] = cur;
} }
cur = cur->next[0]; cur = cur->next[0];
if (cur->end || cur->key != k) return false; if (cur->end || cur != k.n) return {cur, false};
cur->next[0]->before = toUpdate[0]; cur->next[0]->before = toUpdate[0];
@@ -277,71 +332,125 @@ public:
while (curL > 0 && while (curL > 0 &&
root->next[curL] == nullptr) root->next[curL] == nullptr)
curL--; curL--;
cur->data = V();
std::destroy_at(&cur->get());
auto ret = std::make_pair(cur->next[0], true);
nodeAllocator.push(cur); nodeAllocator.push(cur);
return true; return ret;
}; };
// Returns the node PRECEDING the node with a key that is GREATER than k // Comparator true if less than, 0 if equal
Node *find(K const &k) const { template<class Comparator, bool Duplicate>
Node *cur = root; std::pair<Node *, bool> insert(Node *newNode) {
for (int i = curL; i >= 0; i--)
while (cur->next[i]->key <= k && !cur->next[i]->end)
cur = cur->next[i];
return cur;
}
Node *upper_bound(K const &k) const {
Node *cur = root; Node *cur = root;
for (int i = curL; i >= 0; i--) { for (int i = curL; i >= 0; i--) {
while (cur->next[i]->key <= k && !cur->next[i]->end) while (!cur->next[i]->end && Comparator()(cur->next[i]->get(), newNode->get()))
cur = cur->next[i];
}
cur = cur->next[0];
return cur;
}
Node *lower_bound_update(K const &k) const {
Node *cur = root;
for (int i = curL; i >= 0; i--) {
while (cur->next[i]->key < k && !cur->next[i]->end)
cur = cur->next[i]; cur = cur->next[i];
toUpdate[i] = cur; toUpdate[i] = cur;
} }
cur = cur->next[0]; cur = cur->next[0];
if constexpr (!Duplicate)
if (!cur->end && Comparator().eq(cur->get(), newNode->get())) return {cur, false};
return cur; size_t newLevel = randomL();
if (newLevel > curL) {
for (size_t i = curL + 1; i <= newLevel; i++)
toUpdate[i] = root;
curL = newLevel;
}
newNode->before = toUpdate[0];
if (toUpdate[0]->next[0] != nullptr) toUpdate[0]->next[0]->before = newNode;
for (size_t i = 0; i <= newLevel; i++) {
newNode->next[i] = toUpdate[i]->next[i];
toUpdate[i]->next[i] = newNode;
toUpdate[i] = newNode;
}
return {newNode, true};
} }
template<class Comparator, bool Duplicate>
std::pair<Node *, bool> insert(Data d) {
Node *n = nodeAllocator.get();
new (n->data) Data(std::move(d));
return insert<Comparator, Duplicate>(n);
}
Node *lower_bound(K const &k) const { template<class Comparator, bool Duplicate, class... Args>
std::pair<Node *, bool> emplace(Args &&...args) {
Node *n = nodeAllocator.get();
new (&n->get()) Data(std::forward<Args>(args)...);
return insert<Comparator, Duplicate>(n);
}
// Comparator true if less than, 0 if equal
template<class Comparator, typename CmpArg>
std::pair<Node *, bool> erase(const CmpArg &k) {
Node *cur = root; Node *cur = root;
for (int i = curL; i >= 0; i--) { for (int i = curL; i >= 0; i--) {
while (cur->next[i]->key < k && !cur->next[i]->end) while (!cur->next[i]->end && Comparator()(cur->next[i]->get(), k))
cur = cur->next[i]; cur = cur->next[i];
toUpdate[i] = cur;
} }
cur = cur->next[0]; cur = cur->next[0];
if (cur->end || !Comparator().eq(cur->get(), k)) return {cur, false};
cur->next[0]->before = toUpdate[0];
for (size_t i = 0; i <= curL; i++) {
if (toUpdate[i]->next[i] != cur)
break;
toUpdate[i]->next[i] = cur->next[i];
}
while (curL > 0 &&
root->next[curL] == nullptr)
curL--;
std::destroy_at(&cur->get());
auto ret = std::make_pair(cur->next[0], true);
nodeAllocator.push(cur);
return ret;
};
template<class Comparator, typename CmpArg>
Node *upper_bound(const CmpArg &k) const {
Node *cur = root;
for (int i = curL; i >= 0; i--)
while (!cur->next[i]->end && (Comparator()(cur->next[i]->get(), k) || Comparator().eq(cur->next[i]->get(), k)))
cur = cur->next[i];
if (!cur->end && (Comparator()(cur->get(), k) || Comparator().eq(cur->get(), k)))
cur = cur->next[0];
return cur; return cur;
} }
template<class Comparator, typename CmpArg>
Node *lower_bound(const CmpArg &k) const {
Node *cur = root;
bool operator==(SkipList const &r) const { for (int i = curL; i >= 0; i--)
while (!cur->next[i]->end && Comparator()(cur->next[i]->get(), k))
cur = cur->next[i];
return cur->next[0];
}
public:
bool operator==(SkipListBase const &r) const {
auto n = root->next[0]; auto n = root->next[0];
auto n2 = r.root->next[0]; auto n2 = r.root->next[0];
while (!n->end && !n2->end) { while (!n->end && !n2->end) {
if (!(n->data == n2->data)) return false; if (!(n->get() == n2->get())) return false;
n = n->next[0]; n = n->next[0];
n2 = n2->next[0]; n2 = n2->next[0];
} }
@@ -351,54 +460,16 @@ public:
return true; return true;
} }
iterator begin() { return iterator(root->next[0]); }
iterator end() { return iterator(endnode); }
// TODO: pair const_iterator begin() const { return const_iterator(root->next[0]); }
struct SkipListIterator { const_iterator end() const { return const_iterator(endnode); }
// using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = Node;
using pointer = value_type *;
using reference = value_type &;
explicit SkipListIterator(Node *n) : n(std::move(n)){}; const_iterator cbegin() const { return const_iterator(root->next[0]); }
const_iterator cend() const { return const_iterator(endnode); }
reference operator*() const { return *n; }
pointer operator->() const { return n; }
SkipListIterator &operator--() {
if (!n->end)
n = n->before;
return *this;
}
SkipListIterator &operator++() {
if (!n->end)
n = n->next[0];
return *this;
}
SkipListIterator operator++(int) {
SkipListIterator tmp = *this;
++(*this);
return tmp;
}
friend bool operator==(const SkipListIterator &a, const SkipListIterator &b) { return a.n == b.n; };
friend bool operator!=(const SkipListIterator &a, const SkipListIterator &b) { return a.n != b.n; };
private:
Node *n;
};
using iterator = SkipListIterator;
// using const_iterator = SkipListIterator;
iterator begin() const { return SkipListIterator(root->next[0]); }
iterator end() const { return SkipListIterator(endnode); }
protected:
// void print() const { // void print() const {
// std::cout << "LIST STATUS" << std::endl; // std::cout << "LIST STATUS" << std::endl;
// //
@@ -416,4 +487,99 @@ public:
}; };
template<bool Duplicates, typename K, typename V, typename CmpBase = std::less<K>>
class SkipListMapBase : public SkipListBase<std::pair<K, V>> {
using BaseT = SkipListBase<std::pair<K, V>>;
public:
using iterator = typename BaseT::iterator;
using const_iterator = typename BaseT::const_iterator;
using value_type = std::pair<K, V>;
private:
struct Cmp {
constexpr bool operator()(const value_type &lhs, const K &rhs) const {
return CmpBase()(lhs.first, rhs);
}
constexpr bool operator()(const K &lhs, const value_type &rhs) const {
return CmpBase()(lhs, rhs.first);
}
constexpr bool eq(const value_type &lhs, const K &rhs) const {
return lhs.first == rhs;
}
constexpr bool eq(const K &rhs, const value_type &lhs) const {
return lhs.first == rhs;
}
constexpr bool operator()(const value_type &lhs, const value_type &rhs) const {
return CmpBase()(lhs.first, rhs.first);
}
constexpr bool eq(const value_type &lhs, const value_type &rhs) const {
return lhs.first == rhs.first;
}
};
public:
iterator begin() { return BaseT::begin(); }
iterator end() { return BaseT::end(); }
const_iterator begin() const { return BaseT::begin(); }
const_iterator end() const { return BaseT::end(); }
const_iterator cbegin() const { return BaseT::cbegin(); }
const_iterator cend() const { return BaseT::cend(); }
template<class... Args>
std::pair<iterator, bool> emplace(Args &&...args) {
auto r = BaseT::template emplace<Cmp, Duplicates, Args...>(std::forward<Args>(args)...);
return {iterator(r.first), r.second};
}
const_iterator find(const K &k) const {
typename BaseT::Node *n = BaseT::template lower_bound<Cmp>(k);
if (n->end || n->get().first != k) return end();
return const_iterator(n);
}
iterator find(const K &k) {
typename BaseT::Node *n = BaseT::template lower_bound<Cmp>(k);
if (n->end || n->get().first != k) return end();
return iterator(n);
}
const_iterator upper_bound(const K &k) const {
typename BaseT::Node *n = BaseT::template upper_bound<Cmp>(k);
if (n->end) return end();
return const_iterator(n);
}
iterator upper_bound(const K &k) {
typename BaseT::Node *n = BaseT::template upper_bound<Cmp>(k);
if (n->end) return end();
return iterator(n);
}
iterator erase(const K &k) {
std::pair<typename BaseT::Node *, bool> n = BaseT::template erase<Cmp>(k);
if (n.first->end) return end();
return iterator(n.first);
}
iterator erase(const_iterator first, const_iterator last) {
std::pair<typename BaseT::Node *, bool> n = BaseT::template erase<Cmp>(first, last);
if (n.first->end) return end();
return iterator(n.first);
}
iterator erase(const_iterator el) {
std::pair<typename BaseT::Node *, bool> n = BaseT::erase(el);
if (n.first->end) return end();
return iterator(n.first);
}
};
template<typename K, typename V, typename CmpBase = std::less<K>>
using SkipListMap = SkipListMapBase<false, K, V, CmpBase>;
//FIXME: erase is probably janky with this
template<typename K, typename V, typename CmpBase = std::less<K>>
using SkipListMultiMap = SkipListMapBase<true, K, V, CmpBase>;
#endif #endif

View File

@@ -15,7 +15,7 @@
FDT::FD FDT::open(const Path &p, FileOpts opts) { FDT::FD FDT::open(const Path &p, FileOpts opts) {
if (auto n = VFSGlobals::root.traverse(p); n.get() != nullptr) { if (auto n = VFSGlobals::root.traverse(p); n.get() != nullptr) {
LockGuard l(_mtx); LockGuard l(_mtx);
_files.add(_cur_fd++, UniquePtr<File>(new File(n, opts))); _files.emplace(_cur_fd++, UniquePtr<File>(new File(n, opts)));
return _cur_fd - 1; return _cur_fd - 1;
} }
if (opts & FileOpts::O_CREAT) { if (opts & FileOpts::O_CREAT) {
@@ -27,18 +27,13 @@ FDT::FD FDT::open(const Path &p, FileOpts opts) {
void FDT::close(FDT::FD fd) { void FDT::close(FDT::FD fd) {
LockGuard l(_mtx); LockGuard l(_mtx);
if (auto f = _files.find(fd)) if (auto f = _files.find(fd); f != _files.end())
if (!f->end) _files.erase(fd);
if (f->key == fd) {
_files.erase(fd);
}
} }
File *FDT::get(FDT::FD fd) const { File *FDT::get(FDT::FD fd) const {
LockGuard l(_mtx); LockGuard l(_mtx);
if (auto f = _files.find(fd)) if (auto f = _files.find(fd); f != _files.end())
if (!f->end) return f->second.get();
if (f->key == fd)
return f->data.get();
return nullptr; return nullptr;
} }
@@ -46,8 +41,8 @@ FDT *FDT::current() {
return Scheduler::cur_task()->_addressSpace->getFdt(); return Scheduler::cur_task()->_addressSpace->getFdt();
} }
FDT::FDT() { FDT::FDT() {
_files.add(0, UniquePtr(new File(static_ptr_cast<Node>(TtyPipe::create()), O_RDONLY))); _files.emplace(0, UniquePtr(new File(static_ptr_cast<Node>(TtyPipe::create()), O_RDONLY)));
_files.add(1, UniquePtr(new File(static_ptr_cast<Node>(TtyPipe::create()), O_RDWR))); _files.emplace(1, UniquePtr(new File(static_ptr_cast<Node>(TtyPipe::create()), O_RDWR)));
} }
FDHandle::FDHandle(FDT::FD fd) : _fd(fd) { FDHandle::FDHandle(FDT::FD fd) : _fd(fd) {
} }

View File

@@ -24,7 +24,7 @@ public:
static FDT *current(); static FDT *current();
private: private:
SkipList<FD, UniquePtr<File>> _files; SkipListMap<FD, UniquePtr<File>> _files;
int64_t _cur_fd = 10; int64_t _cur_fd = 10;
mutable Mutex _mtx; mutable Mutex _mtx;
}; };

View File

@@ -12,7 +12,7 @@ Vector<SharedPtr<Node>> MemFs::MemFsNodeDir::children() {
Vector<SharedPtr<Node>> out; Vector<SharedPtr<Node>> out;
for (auto c: _children) { for (auto c: _children) {
out.emplace_back(c.data); out.emplace_back(c.second);
} }
return out; return out;
} }
@@ -20,13 +20,13 @@ Vector<SharedPtr<Node>> MemFs::MemFsNodeDir::children() {
SharedPtr<NodeDir> MemFs::MemFsNodeDir::mkdir(const String &name) { SharedPtr<NodeDir> MemFs::MemFsNodeDir::mkdir(const String &name) {
LockGuard l(_lock); LockGuard l(_lock);
auto newnode = MemFsNodeDir::create(name); auto newnode = MemFsNodeDir::create(name);
_children.add(name, static_ptr_cast<Node>(newnode)); _children.emplace(name, static_ptr_cast<Node>(newnode));
return static_ptr_cast<NodeDir>(newnode); return static_ptr_cast<NodeDir>(newnode);
} }
SharedPtr<NodeFile> MemFs::MemFsNodeDir::mkfile(const String &name) { SharedPtr<NodeFile> MemFs::MemFsNodeDir::mkfile(const String &name) {
LockGuard l(_lock); LockGuard l(_lock);
auto newfile = MemFsNodeFile::create(name); auto newfile = MemFsNodeFile::create(name);
_children.add(name, static_ptr_cast<Node>(newfile)); _children.emplace(name, static_ptr_cast<Node>(newfile));
return static_ptr_cast<NodeFile>(newfile); return static_ptr_cast<NodeFile>(newfile);
} }
int64_t MemFs::MemFsNodeFile::read(char *buf, size_t start, size_t num) { int64_t MemFs::MemFsNodeFile::read(char *buf, size_t start, size_t num) {

View File

@@ -26,7 +26,7 @@ class MemFs : public Filesystem {
private: private:
MemFsNodeDir(const String &name) { _name = name; } MemFsNodeDir(const String &name) { _name = name; }
SkipList<String, SharedPtr<Node>> _children; SkipListMap<String, SharedPtr<Node>> _children;
}; };
struct MemFsNodeFile : public NodeFile { struct MemFsNodeFile : public NodeFile {

View File

@@ -38,7 +38,7 @@ public:
friend std::ostream &operator<<(std::ostream &out, const CRange &p) { friend std::ostream &operator<<(std::ostream &out, const CRange &p) {
std::ios::fmtflags f(out.flags()); std::ios::fmtflags f(out.flags());
out << std::dec; out << std::dec << std::resetiosflags(std::ios_base::hex) << std::resetiosflags(std::ios_base::left);
if (p.l == p.r) out << p.l; if (p.l == p.r) out << p.l;
else else
out << "<" << p.l << ".." << p.r << ">"; out << "<" << p.l << ".." << p.r << ">";
@@ -46,7 +46,7 @@ public:
return out; return out;
} }
bool includes(const IntType &p) const { bool includes(const IntType p) const {
return p >= l && p <= r; return p >= l && p <= r;
} }
@@ -57,101 +57,109 @@ public:
bool operator==(const CRange &p) const { bool operator==(const CRange &p) const {
return p.l == l && p.r == r; return p.l == l && p.r == r;
} }
operator std::pair<IntType, IntType>() const { return {l, r}; }
}; };
template<template<class, class, class...> class Storage = std::map>
class CRangeList { class CRangeList {
private: private:
SkipList<IntType, CRange> data; Storage<IntType, std::pair<CRange, bool>> data;
public: public:
// constructor // constructor
CRangeList() = default; CRangeList() {
auto p = std::make_pair(LLONG_MIN, std::make_pair(CRange(LLONG_MIN, LLONG_MAX), false));
data.emplace(p.first, p.second);
}
CRangeList(std::initializer_list<CRange> l) { CRangeList(std::initializer_list<CRange> l) {
for (auto const &r: l) auto p = std::make_pair(LLONG_MIN, std::make_pair(CRange(LLONG_MIN, LLONG_MAX), false));
data.emplace(p.first, p.second);
for (auto const &r: l) {
*this += r; *this += r;
} }
CRangeList(CRangeList &&l) {
data = std::move(l.data);
}
CRangeList(CRangeList const &l) {
data = l.data;
}
CRangeList &operator=(CRangeList l) {
std::swap(l.data, data);
return *this;
} }
// includes long long / range // includes long long / range
bool includes(const IntType l) const { bool includes(const IntType l) const {
auto f = findInData(l); return findInData(l)->second.second;
if (!f->end && f->data.includes(l)) return true;
return false;
} }
bool includes(const CRange &r) const { bool includes(const CRange &r) const {
auto f = findInData(r.l); auto f = findInData(r.l);
if (!f->end && f->data.includes(r)) return true; if (!f->second.second) return false;
return false; return f->second.first.includes(r);
} }
CRangeList operator+(const CRange &rhs) const { CRangeList operator+(const CRange &rhs) const {
return CRangeList(*this) += rhs; auto nl = CRangeList();
nl += *this;
nl += rhs;
return nl;
} }
CRangeList operator-(const CRange &rhs) const { CRangeList operator-(const CRange &rhs) const {
return CRangeList(*this) -= rhs; auto nl = CRangeList();
nl += *this;
nl -= rhs;
return nl;
} }
decltype(data)::Node *findInData(IntType const &l) const { typename decltype(data)::const_iterator findInData(IntType l) const {
return data.find(l); typename decltype(data)::const_iterator ret = data.upper_bound(l);
--ret;
return ret;
} }
void set(CRange r, bool visible) { void set(CRange r, bool visible) {
auto lb = findInData(r.l); auto lb = findInData(r.l);
auto ub = findInData(r.r); if (lb != data.begin() && !lb->second.first.includes(r.l - 1)) {
auto lbm = lb;
bool lbHasPoint = !lb->end && lb->data.includes(r.l); --lbm;
if (visible && !lbHasPoint && !lb->end && r.l != LLONG_MIN && lb->data.includes(r.l - 1)) { if (lbm->second.second == visible) {
r.l--; r.l--;
lbHasPoint = true; lb = lbm;
}
} }
bool ubHasPoint = !ub->end && ub->data.includes(r.r); auto ub = findInData(r.r);
if (visible && !ubHasPoint && r.r != LLONG_MAX && ub->next[0]->data.includes(r.r + 1)) { if (ub != (--data.end()) && !ub->second.first.includes(r.r + 1)) {
ub = ub->next[0]; auto ubp = ub;
r.r++; ++ubp;
ubHasPoint = true; if (ubp->second.second == visible) {
r.r++;
ub = ubp;
}
} }
if (!lbHasPoint) lb = lb->next[0]; if (lb == data.end() || ub == data.end()) throw;
auto lbc = lb->second;
auto ubc = ub->second;
ub++;
CRange toInsert[3]; std::map<IntType, std::pair<CRange, bool>> toInsert;
if (visible) { if (r.l != lbc.first.l) {
if (lbHasPoint) if (lbc.second == visible) {
r.l = std::min(lb->data.l, r.l); r.l = std::min(lbc.first.l, r.l);
if (ubHasPoint) } else {
r.r = std::max(ub->data.r, r.r); toInsert.emplace(lbc.first.l, std::make_pair(CRange(lbc.first.l, r.l - 1), lbc.second));
toInsert[0] = {r};
data.add(toInsert, 1, data.erase(lb, ub->next[0], false));
} else {
int inserted = 0;
if (lbHasPoint && lb->data.l != r.l) {
toInsert[0] = {lb->data.l, r.l - 1};
inserted++;
} }
if (ubHasPoint && ub->data.r != r.r) { }
toInsert[inserted] = {r.r + 1, ub->data.r};
inserted++; if (r.r != ubc.first.r) {
if (ubc.second == visible)
r.r = std::max(ubc.first.r, r.r);
else {
toInsert.emplace(r.r + 1, std::make_pair(CRange(r.r + 1, ubc.first.r), ubc.second));
} }
data.add(toInsert, inserted, data.erase(lb, ub->next[0], false)); }
toInsert.emplace(r.l, std::make_pair(r, visible));
data.erase(lb, ub);
for (auto &r: toInsert) {
data.emplace(std::move(r));
} }
} }
@@ -162,8 +170,10 @@ public:
} }
CRangeList &operator+=(const CRangeList &r) { CRangeList &operator+=(const CRangeList &r) {
for (auto const &l: r) for (auto const &l: r.data) {
*this += l; if (l.second.second)
*this += l.second.first;
}
return *this; return *this;
} }
@@ -174,14 +184,17 @@ public:
} }
CRangeList &operator-=(const CRangeList &r) { CRangeList &operator-=(const CRangeList &r) {
for (auto const &l: r) for (auto const &l: r.data) {
*this -= l; if (l.second.second)
*this -= l.second.first;
}
return *this; return *this;
} }
// = range / range list // = range / range list
CRangeList &operator=(const CRange &r) { CRangeList &operator=(const CRange &r) {
data = decltype(data)(); auto p = std::make_pair(LLONG_MIN, std::make_pair(CRange(LLONG_MIN, LLONG_MAX), false));
data.emplace(p.first, p.second);
*this += (r); *this += (r);
return *this; return *this;
} }
@@ -193,41 +206,47 @@ public:
// operator != // operator !=
bool operator!=(const CRangeList &r) const { bool operator!=(const CRangeList &r) const {
return !(*this == r); return !(this->data == r.data);
} }
// operator << // operator <<
friend std::ostream &operator<<(std::ostream &out, const CRangeList &rl) { friend std::ostream &operator<<(std::ostream &out, const CRangeList &rl) {
out << "{"; out << "{";
bool first = true; bool first = true;
for (const auto &i: rl) { for (const auto &i: rl.data) {
if (!first) out << ","; if (i.second.second) {
out << i; if (!first) out << ",";
first = false; out << i.second.first;
first = false;
}
} }
out << "}"; out << "}";
return out; return out;
} }
struct CRangeListIterator { struct CRangeListIterator {
using iterator_category = std::forward_iterator_tag; using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t; using difference_type = std::ptrdiff_t;
using value_type = const CRange; using value_type = const CRange;
using pointer = value_type *; using pointer = value_type *;
using reference = value_type &; using reference = value_type &;
CRangeListIterator(CRangeListIterator const &it) = default; CRangeListIterator(CRangeListIterator const &it) : it(it.it){};
CRangeListIterator(decltype(data)::Node *n) : n(n){}; CRangeListIterator(decltype(data)::const_iterator it, decltype(data)::const_iterator end) : it(it), end(end) {
if (it != end && !it->second.second)
this->it++;
}
reference operator*() const { return n->data; } reference operator*() const { return (it->second.first); }
pointer operator->() const { return &(n->data); }
pointer operator->() const { return &(it->second.first); }
CRangeListIterator &operator++() { CRangeListIterator &operator++() {
if (n != nullptr && !n->end) ++it;
n = n->next[0]; if (it == end) return *this;
++it;
return *this; return *this;
} }
@@ -237,47 +256,44 @@ public:
return tmp; return tmp;
} }
friend bool operator==(const CRangeListIterator &a, const CRangeListIterator &b) { return a.n == b.n; }; friend bool operator==(const CRangeListIterator &a, const CRangeListIterator &b) { return a.it == b.it; };
friend bool operator!=(const CRangeListIterator &a, const CRangeListIterator &b) { return !(a == b); };
friend bool operator!=(const CRangeListIterator &a, const CRangeListIterator &b) { return !(a.it == b.it); };
private: private:
decltype(data)::Node *n; decltype(data)::const_iterator it;
decltype(data)::const_iterator end;
}; };
using const_iterator = CRangeListIterator; using const_iterator = CRangeListIterator;
const_iterator begin() const { const_iterator begin() const {
return {data.begin()->before->next[0]}; return CRangeListIterator(data.begin(), data.end());
} }
const_iterator end() const { const_iterator end() const {
return {data.end()->before->next[0]}; return CRangeListIterator(data.end(), data.end());
} }
}; };
template<class T>
CRangeList operator+(const CRange &lhs, const CRange &rhs) { std::string toString(const T &x) {
return CRangeList{lhs, rhs};
}
CRangeList operator-(const CRange &lhs, const CRange &rhs) {
return CRangeList{lhs} - rhs;
}
std::string toString(const CRangeList &x) {
std::ostringstream oss; std::ostringstream oss;
oss << x; oss << x;
return oss.str(); return oss.str();
} }
TEST(SkipListDetailedTest, ItWorks) { using sl_detailed_test_list = testing::Types<CRangeList<std::map>, CRangeList<SkipListMap>>;
template<class>
struct SkipListDetailedTestFixture : testing::Test {};
TYPED_TEST_SUITE(SkipListDetailedTestFixture, sl_detailed_test_list);
TYPED_TEST(SkipListDetailedTestFixture, ItWorks) {
assert(std::is_trivially_copyable<CRange>::value); assert(std::is_trivially_copyable<CRange>::value);
CRangeList t; using CRangeListTested = TypeParam;
CRangeListTested t;
t = CRange(10, 20); t = CRange(10, 20);
// t.data.print(); // t.data.print();
@@ -285,7 +301,7 @@ TEST(SkipListDetailedTest, ItWorks) {
// std::cout << ts; // std::cout << ts;
assert(ts == "{<10..20>}"); assert(ts == "{<10..20>}");
// return 0; // return 0;
t = CRangeList{{10, 15}}; t = CRangeListTested{{10, 15}};
assert(toString(t) == "{<10..15>}"); assert(toString(t) == "{<10..15>}");
t = CRange(10, 20); t = CRange(10, 20);
@@ -293,13 +309,16 @@ TEST(SkipListDetailedTest, ItWorks) {
assert(toString(t) == "{<10..20>}"); assert(toString(t) == "{<10..20>}");
t += CRange(LLONG_MIN, LLONG_MAX); t += CRange(LLONG_MIN, LLONG_MAX);
assert(t.includes(CRange(LLONG_MIN, LLONG_MAX))); assert(t.includes(CRange(LLONG_MIN, LLONG_MAX)));
ASSERT_EQ(toString(t), "{<-9223372036854775808..9223372036854775807>}");
assert(t.includes(LLONG_MIN)); assert(t.includes(LLONG_MIN));
assert(t.includes(LLONG_MAX)); assert(t.includes(LLONG_MAX));
t -= CRange(LLONG_MIN, LLONG_MAX); t -= CRange(LLONG_MIN, LLONG_MAX);
ASSERT_EQ(toString(t), "{}");
t += CRange(LLONG_MIN, LLONG_MAX - 1); t += CRange(LLONG_MIN, LLONG_MAX - 1);
ASSERT_EQ(toString(t), "{<-9223372036854775808..9223372036854775806>}");
t += CRange(LLONG_MAX, LLONG_MAX); t += CRange(LLONG_MAX, LLONG_MAX);
assert(toString(t) == "{<-9223372036854775808..9223372036854775807>}"); ASSERT_EQ(toString(t), "{<-9223372036854775808..9223372036854775807>}");
t -= CRange(LLONG_MIN, LLONG_MAX); t -= CRange(LLONG_MIN, LLONG_MAX);
assert(toString(t) == "{}"); assert(toString(t) == "{}");
@@ -358,7 +377,7 @@ TEST(SkipListDetailedTest, ItWorks) {
t += CRange(50, 55); t += CRange(50, 55);
assert(toString(t) == "{<2..4>,<10..80>,<100..150>}"); assert(toString(t) == "{<2..4>,<10..80>,<100..150>}");
auto t2 = CRange(6, 9) + CRange(151, 160); auto t2 = CRangeListTested() + CRange(6, 9) + CRange(151, 160);
assert(toString(t2) == "{<6..9>,<151..160>}"); assert(toString(t2) == "{<6..9>,<151..160>}");
t += t2; t += t2;
s = toString(t); s = toString(t);
@@ -371,9 +390,9 @@ TEST(SkipListDetailedTest, ItWorks) {
t -= CRange(1000, 1100); t -= CRange(1000, 1100);
assert(toString(t) == "{<-100..200>}"); assert(toString(t) == "{<-100..200>}");
t = CRangeList{{10, 15}, t = CRangeListTested{{10, 15},
{20, 25}, {20, 25},
{30, 40}}; {30, 40}};
// t.data.print(); // t.data.print();
assert(toString(t) == "{<10..15>,<20..25>,<30..40>}"); assert(toString(t) == "{<10..15>,<20..25>,<30..40>}");
t -= CRange(40, 9999); t -= CRange(40, 9999);
@@ -389,7 +408,7 @@ TEST(SkipListDetailedTest, ItWorks) {
t -= CRange(22, 22); t -= CRange(22, 22);
assert(toString(t) == "{<14..15>,<20..21>,<23..25>,<30..34>}"); assert(toString(t) == "{<14..15>,<20..21>,<23..25>,<30..34>}");
t = CRangeList(); t = CRangeListTested();
t += CRange(0, 100); t += CRange(0, 100);
assert(toString(t) == "{<0..100>}"); assert(toString(t) == "{<0..100>}");
t += CRange(200, 300); t += CRange(200, 300);
@@ -401,19 +420,19 @@ TEST(SkipListDetailedTest, ItWorks) {
t -= CRange(170, 170); t -= CRange(170, 170);
assert(toString(t) == "{<0..100>,<160..169>,<171..180>,<251..300>}"); assert(toString(t) == "{<0..100>,<160..169>,<171..180>,<251..300>}");
t = CRangeList(); t = CRangeListTested();
t += CRange(10, 90); t += CRange(10, 90);
t -= CRange(20, 30); t -= CRange(20, 30);
t -= CRange(40, 50); t -= CRange(40, 50);
t -= CRange(60, 90); t -= CRange(60, 90);
t += CRange(70, 80); t += CRange(70, 80);
t2 = CRange(10, 90) - CRange(20, 30) - CRange(40, 50) - CRange(60, 90) + CRange(70, 80); t2 = CRangeListTested() + CRange(10, 90) - CRange(20, 30) - CRange(40, 50) - CRange(60, 90) + CRange(70, 80);
ts = toString(t); ts = toString(t);
auto ts2 = toString(t2); auto ts2 = toString(t2);
assert(ts == ts2); assert(ts == ts2);
CRangeList a, b; CRangeListTested a, b;
assert(sizeof(CRange) <= 2 * sizeof(long long)); assert(sizeof(CRange) <= 2 * sizeof(long long));
a = CRange(5, 10); a = CRange(5, 10);
@@ -422,22 +441,22 @@ TEST(SkipListDetailedTest, ItWorks) {
a += CRange(-5, 0); a += CRange(-5, 0);
a += CRange(8, 50); a += CRange(8, 50);
assert(toString(a) == "{<-5..0>,<5..100>}"); assert(toString(a) == "{<-5..0>,<5..100>}");
a += CRange(101, 105) + CRange(120, 150) + CRange(160, 180) + CRange(190, 210); a += CRangeListTested() + CRange(101, 105) + CRange(120, 150) + CRange(160, 180) + CRange(190, 210);
assert(toString(a) == "{<-5..0>,<5..105>,<120..150>,<160..180>,<190..210>}"); assert(toString(a) == "{<-5..0>,<5..105>,<120..150>,<160..180>,<190..210>}");
a += CRange(106, 119) + CRange(152, 158); a += CRangeListTested() + CRange(106, 119) + CRange(152, 158);
assert(toString(a) == "{<-5..0>,<5..150>,<152..158>,<160..180>,<190..210>}"); assert(toString(a) == "{<-5..0>,<5..150>,<152..158>,<160..180>,<190..210>}");
a += CRange(-3, 170); a += CRange(-3, 170);
a += CRange(-30, 1000); a += CRange(-30, 1000);
assert(toString(a) == "{<-30..1000>}"); assert(toString(a) == "{<-30..1000>}");
b = CRange(-500, -300) + CRange(2000, 3000) + CRange(700, 1001); b = CRangeListTested() + CRange(-500, -300) + CRange(2000, 3000) + CRange(700, 1001);
a += b; a += b;
assert(toString(a) == "{<-500..-300>,<-30..1001>,<2000..3000>}"); assert(toString(a) == "{<-500..-300>,<-30..1001>,<2000..3000>}");
a -= CRange(-400, -400); a -= CRange(-400, -400);
assert(toString(a) == "{<-500..-401>,<-399..-300>,<-30..1001>,<2000..3000>}"); assert(toString(a) == "{<-500..-401>,<-399..-300>,<-30..1001>,<2000..3000>}");
a -= CRange(10, 20) + CRange(900, 2500) + CRange(30, 40) + CRange(10000, 20000); a -= CRangeListTested() + CRange(10, 20) + CRange(900, 2500) + CRange(30, 40) + CRange(10000, 20000);
assert(toString(a) == "{<-500..-401>,<-399..-300>,<-30..9>,<21..29>,<41..899>,<2501..3000>}"); assert(toString(a) == "{<-500..-401>,<-399..-300>,<-30..9>,<21..29>,<41..899>,<2501..3000>}");
try { try {
a += CRange(15, 18) + CRange(10, 0) + CRange(35, 38); a += CRangeListTested() + CRange(15, 18) + CRange(10, 0) + CRange(35, 38);
assert("Exception not thrown" == nullptr); assert("Exception not thrown" == nullptr);
} catch (const std::logic_error &e) { } catch (const std::logic_error &e) {
} catch (...) { } catch (...) {
@@ -449,6 +468,7 @@ TEST(SkipListDetailedTest, ItWorks) {
assert(!(a != b)); assert(!(a != b));
b += CRange(2600, 2700); b += CRange(2600, 2700);
assert(toString(b) == "{<-500..-401>,<-399..-300>,<-30..9>,<21..29>,<41..899>,<2501..3000>}"); assert(toString(b) == "{<-500..-401>,<-399..-300>,<-30..9>,<21..29>,<41..899>,<2501..3000>}");
assert(toString(a) == "{<-500..-401>,<-399..-300>,<-30..9>,<21..29>,<41..899>,<2501..3000>}");
assert(a == b); assert(a == b);
assert(!(a != b)); assert(!(a != b));
b += CRange(15, 15); b += CRange(15, 15);
@@ -463,28 +483,28 @@ TEST(SkipListDetailedTest, ItWorks) {
assert(!b.includes(CRange(800, 900))); assert(!b.includes(CRange(800, 900)));
assert(!b.includes(CRange(-1000, -450))); assert(!b.includes(CRange(-1000, -450)));
assert(!b.includes(CRange(0, 500))); assert(!b.includes(CRange(0, 500)));
a += CRange(-10000, 10000) + CRange(10000000, 1000000000); a += CRangeListTested() + CRange(-10000, 10000) + CRange(10000000, 1000000000);
assert(toString(a) == "{<-10000..10000>,<10000000..1000000000>}"); assert(toString(a) == "{<-10000..10000>,<10000000..1000000000>}");
b += a; b += a;
assert(toString(b) == "{<-10000..10000>,<10000000..1000000000>}"); assert(toString(b) == "{<-10000..10000>,<10000000..1000000000>}");
b -= a; b -= a;
assert(toString(b) == "{}"); assert(toString(b) == "{}");
b += CRange(0, 100) + CRange(200, 300) - CRange(150, 250) + CRange(160, 180) - CRange(170, 170); b += CRangeListTested() + CRange(0, 100) + CRange(200, 300) - CRange(150, 250) + CRange(160, 180) - CRange(170, 170);
// b.data.print(); // b.data.print();
assert(toString(b) == "{<0..100>,<160..169>,<171..180>,<251..300>}"); assert(toString(b) == "{<0..100>,<160..169>,<171..180>,<251..300>}");
// b.data.print(); // b.data.print();
b -= b -=
CRange(10, 90) - CRangeListTested() + CRange(10, 90) -
CRange(20, 30) - CRange(20, 30) -
CRange(40, 50) - CRange(40, 50) -
CRange(60, 90) + CRange(60, 90) +
CRange(70, 80); CRange(70, 80);
s = toString(b); s = toString(b);
assert(toString(b) == "{<0..9>,<20..30>,<40..50>,<60..69>,<81..100>,<160..169>,<171..180>,<251..300>}"); assert(toString(b) == "{<0..9>,<20..30>,<40..50>,<60..69>,<81..100>,<160..169>,<171..180>,<251..300>}");
CRangeList x{{5, 20}, CRangeListTested x{{5, 20},
{150, 200}, {150, 200},
{-9, 12}, {-9, 12},
{48, 93}}; {48, 93}};
assert(toString(x) == "{<-9..20>,<48..93>,<150..200>}"); assert(toString(x) == "{<-9..20>,<48..93>,<150..200>}");
std::ostringstream oss; std::ostringstream oss;
oss << std::setfill('=') << std::hex << std::left; oss << std::setfill('=') << std::hex << std::left;
@@ -497,8 +517,8 @@ TEST(SkipListDetailedTest, ItWorks) {
assert(oss.str() == "-100\n<-9..20>\n<48..93>\n<150..200>\n400======="); assert(oss.str() == "-100\n<-9..20>\n<48..93>\n<150..200>\n400=======");
// FIXME: I'll leave it a "stress test" for now // FIXME: I'll leave it a "stress test" for now
for (long long x = 10; x <= 100; x *= 10) { for (long long x = 25; x <= 250; x *= 10) {
CRangeList t; CRangeListTested t;
std::cout << x << "====" << std::endl; std::cout << x << "====" << std::endl;
auto start = std::chrono::high_resolution_clock::now(); auto start = std::chrono::high_resolution_clock::now();
auto stop = std::chrono::high_resolution_clock::now(); auto stop = std::chrono::high_resolution_clock::now();

View File

@@ -10,25 +10,81 @@ struct SkipListTestFixture : testing::Test {};
TYPED_TEST_SUITE(SkipListTestFixture, sl_test_list); TYPED_TEST_SUITE(SkipListTestFixture, sl_test_list);
TYPED_TEST(SkipListTestFixture, PlaceAdd) { TYPED_TEST(SkipListTestFixture, PlaceAdd) {
SkipList<int, TypeParam> test1; SkipListMap<int, TypeParam> test1;
SkipListMap<int, TypeParam> test2;
SkipListMap<long, TypeParam> test3;
SkipListMap<long, TypeParam> test4;
SkipListMap<long, long> test5;
SkipListMap<long, long> test6;
SkipListMap<int, long> test7;
SkipListMap<int, long> test8;
test1.add(5, "test5", false); test1.emplace(5, "test5");
test1.add(999, "test999", false); test1.emplace(999, "test999");
test1.add(5, "test5", false); test1.emplace(5, "test5");
test1.add(1, "test1", false); test1.emplace(1, "test1");
test1.add(999, "test999", false); test1.emplace(999, "test999");
ASSERT_EQ(test1.find(5)->data, "test5"); ASSERT_EQ(test1.find(5)->second, "test5");
ASSERT_EQ(test1.find(1)->data, "test1"); ASSERT_EQ(test1.find(1)->second, "test1");
ASSERT_EQ(test1.find(999)->data, "test999"); ASSERT_EQ(test1.find(999)->second, "test999");
typename decltype(test1)::iterator tit = test1.begin();
typename decltype(test1)::const_iterator tcit = tit;
test1.erase(1); test1.erase(1);
ASSERT_NE(test1.find(1)->data, "test1"); ASSERT_EQ(test1.find(1), test1.cend());
test1.add(87, "test87", false); test1.emplace(87, "test87");
ASSERT_EQ(test1.find(87)->data, "test87"); ASSERT_EQ(test1.find(87)->second, "test87");
auto p2 = test1.lower_bound_update(78); test1.emplace(78, "test78");
ASSERT_EQ(p2->data, "test87"); ASSERT_EQ(test1.find(78)->second, "test78");
test1.add(78, "test78", true); }
ASSERT_EQ(test1.find(78)->data, "test78"); TYPED_TEST(SkipListTestFixture, MultiMapTest) {
SkipListMultiMap<int, TypeParam> test1;
test1.emplace(5, "test5");
test1.emplace(999, "test999");
test1.emplace(5, "test5");
test1.emplace(1, "test1");
test1.emplace(999, "test999");
ASSERT_EQ(test1.find(5)->second, "test5");
ASSERT_EQ(test1.find(1)->second, "test1");
ASSERT_EQ(test1.find(999)->second, "test999");
test1.erase(1);
ASSERT_EQ(test1.find(1), test1.cend());
test1.emplace(87, "test87");
ASSERT_EQ(test1.find(87)->second, "test87");
test1.emplace(78, "test78");
ASSERT_EQ(test1.find(78)->second, "test78");
ASSERT_EQ(test1.find(5)->second, "test5");
ASSERT_EQ(test1.find(999)->second, "test999");
test1.erase(5);
test1.erase(999);
ASSERT_EQ(test1.find(5)->second, "test5");
ASSERT_EQ(test1.find(999)->second, "test999");
test1.erase(5);
test1.erase(999);
ASSERT_EQ(test1.find(5), test1.end());
ASSERT_EQ(test1.find(999), test1.end());
auto r1 = test1.emplace(999, "test9991");
ASSERT_TRUE(r1.second);
ASSERT_EQ(r1.first->second, "test9991");
auto r2 = test1.emplace(999, "test9992");
ASSERT_TRUE(r2.second);
ASSERT_EQ(r2.first->second, "test9992");
auto r3 = test1.emplace(999, "test9993");
ASSERT_TRUE(r3.second);
ASSERT_EQ(r3.first->second, "test9993");
test1.erase(r2.first);
ASSERT_TRUE(r1.second);
ASSERT_EQ(r1.first->second, "test9991");
ASSERT_TRUE(r3.second);
ASSERT_EQ(r3.first->second, "test9993");
} }