#pragma once #include #include #include "utils/mark_ref.hpp" namespace lockfree { template class SkipList { public: struct Node { using ref_t = MarkRef; K* key; T* item; const uint8_t height; static Node* create(uint8_t height, K* key, T* item) { auto size = sizeof(Node) + height * sizeof(std::atomic); auto node = static_cast(std::malloc(size)); return new (node) Node(height, key, item); } static void destroy(Node* node) { node->~SkipNode(); free(node); } private: Node(uint8_t height, K* key, T* item) : key(key), item(item), height(height) { for(uint8_t i = 0; i < height; ++i) new (&tower[i]) std::atomic(nullptr); } // this creates an array of the size zero. we can't put any sensible // value here since we don't know what size it will be untill the // node is allocated. we could make it a SkipNode** but then we would // have two memory allocations, one for node and one for the forward // list. this way we avoid expensive malloc/free calls and also cache // thrashing when following a pointer on the heap std::atomic tower[0]; }; //void list_search(const K& key, }; }