ソースを参照

feat(libstdc++): add stl set

greatbridf 1 年間 前
コミット
3807ff3e32

+ 634 - 0
gblibstdc++/include/bits/rbtree

@@ -0,0 +1,634 @@
+#ifndef __GBLIBCPP_BITS_RBTREE__
+#define __GBLIBCPP_BITS_RBTREE__
+
+#include <functional>
+#include <utility>
+#include <memory>
+
+namespace std::impl {
+
+template <typename T, typename Compare, typename Allocator>
+struct rbtree {
+    struct node {
+        node* parent;
+        node* left;
+        node* right;
+        T value;
+        enum class node_color : unsigned char { RED, BLACK, } color;
+
+        constexpr node(const T& val)
+            : parent {}, left {}, right {}
+            , value { val } , color {node_color::RED} {}
+
+        constexpr node(T&& val)
+            : parent {}, left {}, right {}
+            , value { std::move(val) } , color {node_color::RED} {}
+
+        constexpr node* grandparent(void) const
+        { return this->parent->parent; }
+
+        constexpr node* uncle(void) const
+        {
+            node* pp = this->grandparent();
+            if (this->parent == pp->left)
+                return pp->right;
+            return pp->left;
+        }
+
+        constexpr node* leftmost(void)
+        {
+            node* nd = this;
+            while (nd->left)
+                nd = nd->left;
+            return nd;
+        }
+
+        constexpr node* rightmost(void)
+        {
+            node* nd = this;
+            while (nd->right)
+                nd = nd->right;
+            return nd;
+        }
+
+        constexpr node* next(void)
+        {
+            if (this->right)
+                return this->right->leftmost();
+            if (this->is_root())
+                return nullptr;
+            if (this->is_left_child())
+                return this->parent;
+            node* ret = this;
+            do {
+                ret = ret->parent;
+            } while (!ret->is_root() && !ret->is_left_child());
+            return ret->parent;
+        }
+
+        constexpr node* prev(void)
+        {
+            if (this->left)
+                return this->left->rightmost();
+            if (this->is_root())
+                return nullptr;
+            if (this->is_right_child())
+                return this->parent;
+            node* ret = this;
+            do {
+                ret = ret->parent;
+            } while (!ret->is_root() && !ret->is_right_child());
+            return ret->parent;
+        }
+
+        static constexpr bool is_red(node* nd)
+        { return nd && nd->color == node_color::RED; }
+        static constexpr bool is_black(node* nd)
+        { return !node::is_red(nd); }
+
+        constexpr bool is_root(void) const
+        { return this->parent == nullptr; }
+        constexpr bool is_full(void) const
+        { return this->left && this->right; }
+        constexpr bool has_child(void) const
+        { return this->left || this->right; }
+        constexpr bool is_leaf(void) const
+        { return !this->has_child(); }
+
+        constexpr bool is_left_child(void) const
+        { return this == this->parent->left; }
+        constexpr bool is_right_child(void) const
+        { return this == this->parent->right; }
+
+        constexpr void tored(void)
+        { this->color = node_color::RED; }
+        constexpr void toblack(void)
+        { this->color = node_color::BLACK; }
+
+        static constexpr void swap(node* first, node* second)
+        {
+            if (node::is_red(first)) {
+                first->color = second->color;
+                second->color = node_color::RED;
+            } else {
+                first->color = second->color;
+                second->color = node_color::BLACK;
+            }
+
+            if (first->parent == second) {
+                node* tmp = first;
+                first = second;
+                second = tmp;
+            }
+
+            bool f_is_left_child = first->parent ? first->is_left_child() : false;
+            bool s_is_left_child = second->parent ? second->is_left_child() : false;
+
+            node* fp = first->parent;
+            node* fl = first->left;
+            node* fr = first->right;
+
+            node* sp = second->parent;
+            node* sl = second->left;
+            node* sr = second->right;
+
+            if (second->parent != first) {
+                first->parent = sp;
+                if (sp) {
+                    if (s_is_left_child)
+                        sp->left = first;
+                    else
+                        sp->right = first;
+                }
+                first->left = sl;
+                if (sl)
+                    sl->parent = first;
+                first->right = sr;
+                if (sr)
+                    sr->parent = first;
+
+                second->parent = fp;
+                if (fp) {
+                    if (f_is_left_child)
+                        fp->left = second;
+                    else
+                        fp->right = second;
+                }
+
+                second->left = fl;
+                if (fl)
+                    fl->parent = second;
+                second->right = fr;
+                if (fr)
+                    fr->parent = second;
+            } else {
+                first->left = sl;
+                if (sl)
+                    sl->parent = first;
+                first->right = sr;
+                if (sr)
+                    sr->parent = first;
+
+                second->parent = fp;
+                if (fp) {
+                    if (f_is_left_child)
+                        fp->left = second;
+                    else
+                        fp->right = second;
+                }
+                first->parent = second;
+
+                if (s_is_left_child) {
+                    second->left = first;
+                    second->right = fr;
+                    if (fr)
+                        fr->parent = second;
+                } else {
+                    second->right = first;
+                    second->left = fl;
+                    if (fl)
+                        fl->parent = second;
+                }
+            }
+        }
+    };
+
+    template <bool Const>
+    class _iterator {
+    public:
+        using node_pointer = node*;
+        using value_type = std::conditional_t<Const, const T, T>;
+        using pointer = std::add_pointer_t<value_type>;
+        using reference = std::add_lvalue_reference_t<value_type>;
+
+        friend rbtree;
+
+    private:
+        node_pointer p;
+
+    public:
+        constexpr _iterator() = default;
+        explicit constexpr _iterator(node_pointer ptr)
+            : p { ptr } {}
+        constexpr _iterator(const _iterator& iter) = default;
+        constexpr _iterator(_iterator&& iter) = default;
+        constexpr ~_iterator() = default;
+        constexpr _iterator& operator=(const _iterator& iter) = default;
+        constexpr _iterator& operator=(_iterator&& iter) = default;
+        constexpr bool operator==(const _iterator& iter) const = default;
+
+        constexpr reference operator*(void) const { return p->value; }
+        constexpr pointer operator&(void) const { return std::addressof(p->value); }
+        constexpr pointer operator->(void) const { return this->operator&(); }
+        constexpr _iterator& operator++(void)
+        { p = p->next(); return *this; }
+        constexpr _iterator operator++(int)
+        { _iterator ret(p); (void)this->operator++(); return ret; }
+        constexpr _iterator& operator--(void)
+        { p = p->prev(); return *this; }
+        constexpr _iterator operator--(int)
+        { _iterator ret(p); (void)this->operator--(); return ret; }
+        explicit constexpr operator bool(void)
+        { return p; }
+        constexpr operator _iterator<true>()
+        { return _iterator<true> { p }; }
+    };
+
+    using iterator = _iterator<false>;
+    using const_iterator = _iterator<true>;
+
+    using node_allocator = typename
+        std::allocator_traits<Allocator>::template rebind_alloc<node>;
+
+    node* root;
+    Compare comp;
+    node_allocator alloc;
+
+private:
+    template <typename UKey>
+    constexpr node* newnode(UKey&& key)
+    {
+        node* ptr = std::allocator_traits<node_allocator>::allocate(alloc, 1);
+        std::allocator_traits<node_allocator>::construct(
+            alloc, ptr, std::forward<UKey>(key));
+        return ptr;
+    }
+
+    constexpr void delnode(node* nd)
+    {
+        std::allocator_traits<node_allocator>::destroy(alloc, nd);
+        std::allocator_traits<node_allocator>::deallocate(alloc, nd, 1);
+    }
+
+public:
+    constexpr iterator end(void) noexcept
+    { return iterator(nullptr); }
+    constexpr const_iterator end(void) const noexcept
+    { return const_iterator(nullptr); }
+    constexpr const_iterator cend(void) const noexcept
+    { return const_iterator(nullptr); }
+
+    constexpr iterator begin(void) noexcept
+    { return root ? iterator(root->leftmost()) : end(); }
+    constexpr const_iterator begin(void) const noexcept
+    { return root ? const_iterator(root->leftmost()) : end(); }
+    constexpr const_iterator cbegin(void) const noexcept
+    { return root ? const_iterator(root->leftmost()) : end(); }
+
+    constexpr void destroy(node* nd)
+    {
+        if (!nd)
+            return;
+        destroy(nd->left);
+        destroy(nd->right);
+        delnode(nd);
+    }
+
+    constexpr void destroy() { destroy(root); root = nullptr; }
+
+    constexpr node* copy(node* nd)
+    {
+        if (!nd)
+            return nullptr;
+
+        node* newnd = newnode(nd->value);
+        newnd->color = nd->color;
+
+        newnd->left = copy(nd->left);
+        if (newnd->left)
+            newnd->left->parent = newnd->left;
+
+        newnd->right = copy(nd->right);
+        if (newnd->right)
+            newnd->right->parent = newnd->right;
+
+        return newnd;
+    }
+
+    explicit constexpr rbtree(const Compare& comp, const node_allocator& alloc)
+        : root(), comp(comp), alloc(alloc) {}
+
+    constexpr rbtree(const rbtree& other)
+        : rbtree(other.comp, other.alloc)
+    {
+        root = copy(other.root);
+        if (root)
+            root->parent = nullptr;
+    }
+
+    constexpr rbtree(const rbtree& other, const node_allocator& alloc)
+        : rbtree(other.comp, alloc)
+    {
+        root = copy(other.root);
+        if (root)
+            root->parent = nullptr;
+    }
+    
+    constexpr rbtree(rbtree&& other) noexcept
+        : root(std::exchange(other.root, nullptr))
+        , comp(std::move(other.comp)), alloc(std::move(other.alloc)) {}
+
+    constexpr rbtree(rbtree&& other, const node_allocator& alloc) noexcept
+        : root(std::exchange(other.root, nullptr))
+        , comp(std::move(other.comp)), alloc(alloc) {}
+    
+    constexpr ~rbtree() { destroy(); }
+
+    constexpr rbtree& operator=(const rbtree& other)
+    {
+        destroy(root);
+
+        comp = other.comp;
+        alloc = other.alloc;
+
+        root = copy(other.root);
+        if (root)
+            root->parent = nullptr;
+    }
+    
+    constexpr rbtree& operator=(rbtree&& other) noexcept
+    {
+        destroy(root);
+        root = std::exchange(other.root, nullptr);
+        comp = std::move(other.comp);
+        alloc = std::move(other.alloc);
+    }
+
+    constexpr void rotateleft(node* rt)
+    {
+        node* nrt = rt->right;
+
+        if (!rt->is_root()) {
+            if (rt->is_left_child())
+                rt->parent->left = nrt;
+            else
+                rt->parent->right = nrt;
+        } else {
+            this->root = nrt;
+        }
+
+        nrt->parent = rt->parent;
+        rt->parent = nrt;
+
+        rt->right = nrt->left;
+        nrt->left = rt;
+    }
+
+    constexpr void rotateright(node* rt)
+    {
+        node* nrt = rt->left;
+
+        if (!rt->is_root()) {
+            if (rt->is_left_child())
+                rt->parent->left = nrt;
+            else
+                rt->parent->right = nrt;
+        } else {
+            this->root = nrt;
+        }
+
+        nrt->parent = rt->parent;
+        rt->parent = nrt;
+
+        rt->left = nrt->right;
+        nrt->right = rt;
+    }
+
+    constexpr void balance(node* nd)
+    {
+        if (nd->is_root()) {
+            nd->toblack();
+            return;
+        }
+
+        if (node::is_black(nd->parent))
+            return;
+
+        node* p = nd->parent;
+        node* pp = nd->grandparent();
+        node* uncle = nd->uncle();
+
+        if (node::is_red(uncle)) {
+            p->toblack();
+            uncle->toblack();
+            pp->tored();
+            this->balance(pp);
+            return;
+        }
+
+        if (p->is_left_child()) {
+            if (nd->is_left_child()) {
+                p->toblack();
+                pp->tored();
+                this->rotateright(pp);
+            } else {
+                this->rotateleft(p);
+                this->balance(p);
+            }
+        } else {
+            if (nd->is_right_child()) {
+                p->toblack();
+                pp->tored();
+                this->rotateleft(pp);
+            } else {
+                this->rotateright(p);
+                this->balance(p);
+            }
+        }
+    }
+
+    constexpr node* _find(const T& key) const
+    {
+        for (node* cur = root; cur; ) {
+            if (comp(key, cur->value))
+                cur = cur->left;
+            else if (comp(cur->value, key))
+                cur = cur->right;
+            else
+                return cur;
+        }
+
+        return nullptr;
+    }
+
+    template <typename U, typename UCompare>
+    constexpr node* _find(const U& key, const UCompare& ucomp) const
+    {
+        for (node* cur = root; cur; ) {
+            if (ucomp(key, cur->value))
+                cur = cur->left;
+            else if (ucomp(cur->value, key))
+                cur = cur->right;
+            else
+                return cur;
+        }
+
+        return nullptr;
+    }
+
+    constexpr iterator find(const T& key)
+    { return iterator { _find(key) }; }
+
+    constexpr const_iterator find(const T& key) const
+    { return const_iterator { _find(key) }; }
+
+    // RBTREE RECURSIVE DELETE
+    // THIS FUNCTION DOES NOT DELLOCATE THE NODE
+    // CALLER IS RESPONSIBLE FOR FREEING THE MEMORY
+    // @param: nd is guaranteed to be a leaf node
+    constexpr void _erase(node* nd)
+    {
+        if (nd->is_root())
+            return;
+
+        if (node::is_black(nd)) {
+            node* p = nd->parent;
+            node* s = nullptr;
+            if (nd->is_left_child())
+                s = p->right;
+            else
+                s = p->left;
+
+            if (node::is_red(s)) {
+                p->tored();
+                s->toblack();
+                if (nd->is_right_child()) {
+                    this->rotateright(p);
+                    s = p->left;
+                } else {
+                    this->rotateleft(p);
+                    s = p->right;
+                }
+            }
+
+            node* r = nullptr;
+            if (node::is_red(s->left)) {
+                r = s->left;
+                if (s->is_left_child()) {
+                    r->toblack();
+                    s->color = p->color;
+                    this->rotateright(p);
+                    p->toblack();
+                } else {
+                    r->color = p->color;
+                    this->rotateright(s);
+                    this->rotateleft(p);
+                    p->toblack();
+                }
+            } else if (node::is_red(s->right)) {
+                r = s->right;
+                if (s->is_left_child()) {
+                    r->color = p->color;
+                    this->rotateleft(s);
+                    this->rotateright(p);
+                    p->toblack();
+                } else {
+                    r->toblack();
+                    s->color = p->color;
+                    this->rotateleft(p);
+                    p->toblack();
+                }
+            } else {
+                s->tored();
+                if (node::is_black(p))
+                    this->_erase(p);
+                else
+                    p->toblack();
+            }
+        }
+    }
+
+    // delete nd from the tree. make nd safe to deallocate
+    // THIS FUNCTION DOES NOT DELLOCATE THE NODE
+    // CALLER IS RESPONSIBLE FOR FREEING THE MEMORY
+    constexpr node* erase(node* nd)
+    {
+        if (nd->is_root() && nd->is_leaf()) {
+            root = nullptr;
+            return nullptr;
+        }
+
+        node* next = nd->next();
+
+        while (!nd->is_leaf()) {
+            node* alt = nd->right ? nd->right->leftmost() : nd->left;
+            if (nd->is_root())
+                this->root = alt;
+            node::swap(nd, alt);
+        }
+
+        this->_erase(nd);
+
+        if (nd->is_left_child())
+            nd->parent->left = nullptr;
+        else
+            nd->parent->right = nullptr;
+
+        return next;
+    }
+
+    constexpr iterator erase(iterator pos) noexcept
+    {
+        node* nextpos = erase(pos.p);
+        delnode(pos.p);
+        return iterator { nextpos };
+    }
+
+    constexpr iterator erase(const_iterator pos) noexcept
+    {
+        node* nextpos = erase(pos.p);
+        delnode(pos.p);
+        return const_iterator { nextpos };
+    }
+
+    // value in nd MUST NOT exist in the rbtree,
+    // that is, if a < b, then a > b
+    constexpr void insert(node* nd)
+    {
+        node* cur = root;
+
+        while (cur) [[likely]] {
+            if (comp(nd->value, cur->value)) {
+                if (!cur->left) {
+                    nd->parent = cur;
+                    cur->left = nd;
+                    this->balance(nd);
+                    return;
+                } else {
+                    cur = cur->left;
+                }
+            } else {
+                if (!cur->right) {
+                    nd->parent = cur;
+                    cur->right = nd;
+                    this->balance(nd);
+                    return;
+                } else {
+                    cur = cur->right;
+                }
+            }
+        }
+
+        root = nd;
+        root->toblack();
+    }
+
+    template <typename U>
+    constexpr std::pair<iterator, bool> insert(U&& value)
+    {
+        auto iter = find(value);
+        if (iter)
+            return { iter, false };
+
+        node* ptr = newnode(std::forward<U>(value));
+        insert(ptr);
+
+        return { iterator { ptr }, true };
+    }
+
+    constexpr bool empty() const noexcept { return !root; }
+};
+
+} // namespace std::impl
+
+#endif

+ 3 - 0
gblibstdc++/include/cstddef

@@ -1,6 +1,8 @@
 #ifndef __GBLIBCPP_CSTDDEF__
 #define __GBLIBCPP_CSTDDEF__
 
+#define __GBLIBCPP_CONSTEXPR constexpr
+
 #undef NULL
 #define NULL (nullptr)
 
@@ -9,6 +11,7 @@ namespace std {
 using nullptr_t = decltype(nullptr);
 
 using size_t = __SIZE_TYPE__;
+using ptrdiff_t = __PTRDIFF_TYPE__;
 
 enum class byte : unsigned char {};
 

+ 16 - 0
gblibstdc++/include/functional

@@ -295,6 +295,22 @@ constexpr std::reference_wrapper<const T>
     return t;
 }
 
+// Comparators
+
+template <typename T = void>
+struct less {
+    constexpr bool operator()(const T& lhs, const T& rhs) const
+    { return lhs < rhs; }
+};
+
+template <>
+struct less<void> {
+    template <typename T, typename U>
+    constexpr auto operator()(T&& lhs, U&& rhs) const
+        -> decltype(std::forward<T>(lhs) < std::forward<U>(rhs))
+    { return std::forward<T>(lhs) < std::forward<U>(rhs); }
+};
+
 } // namespace std
 
 #endif

+ 78 - 0
gblibstdc++/include/memory

@@ -1,6 +1,7 @@
 #ifndef __GBLIBCPP_MEMORY__
 #define __GBLIBCPP_MEMORY__
 
+#include <cstddef>
 #include <type_traits>
 #include <utility>
 
@@ -33,6 +34,83 @@ constexpr T* addressof(T& arg) noexcept
 template <typename T>
 const T* addressof(const T&&) = delete;
 
+template <typename T>
+struct allocator {
+    using value_type = T;
+    using size_type = std::size_t;
+    using difference_type = std::ptrdiff_t;
+
+    constexpr allocator() noexcept = default;
+    constexpr allocator(const allocator& other) noexcept = default;
+
+    template <typename U>
+    constexpr allocator(const allocator<U>&) noexcept {}
+
+    constexpr ~allocator() = default;
+
+    // throws std::bad_alloc
+    [[nodiscard]] constexpr T* allocate(std::size_t n)
+    { return static_cast<T*>(::operator new(n * sizeof(T))); }
+
+    // TODO: check allocated size
+    constexpr void deallocate(T* ptr, std::size_t)
+    { ::operator delete(ptr); }
+};
+
+template <typename T1, typename T2>
+constexpr bool operator==(const allocator<T1>&, const allocator<T2>&) noexcept
+{ return true; }
+
+template <typename T, typename... Args>
+constexpr std::enable_if_t<std::is_same_v<T*,
+    decltype(::new(std::declval<void*>()) T(std::declval<Args>()...))> , T*>
+construct_at(T* p, Args&&... args)
+{
+    return ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...);
+}
+
+template <typename T>
+constexpr void destroy_at(T* p)
+{
+    // TODO: destroy array
+    p->~T();
+}
+
+namespace __helpers {
+
+template <typename Allocator, typename T>
+struct rebind;
+
+template <template <typename, typename...> typename Allocator,
+    typename NewType, typename OldType, typename... Args>
+struct rebind<Allocator<OldType, Args...>, NewType> {
+    using type = Allocator<NewType, Args...>;
+};
+
+} // namespace __helpers
+
+template <typename Allocator>
+struct allocator_traits {
+    using allocator_type = Allocator;
+    using value_type = typename Allocator::value_type;
+    using pointer = value_type*;
+    using size_type = std::size_t;
+
+    template <typename T>
+    using rebind_alloc = typename __helpers::rebind<Allocator, T>::type;
+
+    [[nodiscard]] static constexpr pointer allocate(Allocator& alloc, size_type n)
+    { return alloc.allocate(n); }
+    static constexpr void deallocate(Allocator& alloc, pointer p, size_type n)
+    { return alloc.deallocate(p, n); }
+    template <typename T, typename... Args>
+    static constexpr void construct(Allocator&, T* p, Args&&... args)
+    { std::construct_at(p, std::forward<Args>(args)...); }
+    template <typename T>
+    static constexpr void destroy(Allocator&, T* p)
+    { std::destroy_at(p); }
+};
+
 } // namespace std
 
 #endif

+ 155 - 0
gblibstdc++/include/set

@@ -0,0 +1,155 @@
+#ifndef __GBLIBCPP_SET__
+#define __GBLIBCPP_SET__
+
+#include <bits/rbtree>
+#include <functional>
+#include <memory>
+#include <cstddef>
+
+namespace std {
+
+template <typename Key,
+    typename Compare = std::less<Key>,
+    typename Allocator = std::allocator<Key>>
+class set {
+private:
+    using rbtree_type = impl::rbtree<Key, Compare, Allocator>;
+    using node_allocator = typename rbtree_type::node_allocator;
+
+private:
+    rbtree_type tree;
+
+public:
+    using key_type = Key;
+    using value_type = Key;
+    using size_type = std::size_t;
+    using allocator_type = Allocator;
+    using iterator = typename rbtree_type::iterator;
+    using const_iterator = typename rbtree_type::const_iterator;
+
+public:
+    __GBLIBCPP_CONSTEXPR
+    iterator end(void) noexcept { return tree.end(); }
+    __GBLIBCPP_CONSTEXPR
+    const_iterator end(void) const noexcept { return tree.cend(); }
+    __GBLIBCPP_CONSTEXPR
+    const_iterator cend(void) const noexcept { return tree.cend(); }
+
+    __GBLIBCPP_CONSTEXPR
+    iterator begin(void) noexcept { return tree.begin(); }
+    __GBLIBCPP_CONSTEXPR
+    const_iterator begin(void) const noexcept { return tree.cbegin(); }
+    __GBLIBCPP_CONSTEXPR
+    const_iterator cbegin(void) const noexcept { return tree.cbegin(); }
+
+    explicit __GBLIBCPP_CONSTEXPR
+    set(const Compare& comp,
+        const Allocator& alloc = Allocator())
+        : tree(comp, alloc) {}
+    
+    explicit __GBLIBCPP_CONSTEXPR
+    set(const Allocator& alloc)
+        : set(Compare(), alloc) {}
+
+    __GBLIBCPP_CONSTEXPR
+    set() : set(Compare()) {}
+
+    template <typename InputIter>
+    __GBLIBCPP_CONSTEXPR
+    set(InputIter first, InputIter last,
+        const Compare& comp = Compare(),
+        const Allocator& alloc = Allocator())
+        : set(comp, alloc)
+    {
+        insert(first, last);
+    }
+
+    template <typename InputIter>
+    __GBLIBCPP_CONSTEXPR
+    set(InputIter first, InputIter last,
+        const Allocator& alloc = Allocator())
+        : set(first, last, Compare(), alloc) {}
+
+    __GBLIBCPP_CONSTEXPR
+    set(const set& other) : tree(other) {}
+    __GBLIBCPP_CONSTEXPR
+    set(const set& other, const Allocator& alloc)
+        : tree(other, alloc) { }
+
+    __GBLIBCPP_CONSTEXPR
+    set(set&& other) : tree(std::move(other.tree)) {}
+    __GBLIBCPP_CONSTEXPR
+    set(set&& other, const Allocator& alloc)
+        : tree(std::move(other.tree), alloc) {}
+    
+    __GBLIBCPP_CONSTEXPR
+    ~set() { clear(); }
+    
+    __GBLIBCPP_CONSTEXPR
+    set& operator=(const set& other) = default;
+    __GBLIBCPP_CONSTEXPR
+    set& operator=(set&& other) = default;
+
+    // TODO: std::initializer_list
+    // set(std::initializer_list<Key> init,
+    //     const Compare& comp = Compare(),
+    //     const Allocator& alloc = Allocator());
+    //
+    // set(std::initializer_list<Key> init,
+    //     const Allocator& alloc = Allocator())
+    //     : set(init, Compare(), alloc) {}
+    //
+    // set& operator=(std::initializer_list<Key> ilist);
+
+    __GBLIBCPP_CONSTEXPR
+    iterator find(const Key& key) { return tree.find(key); }
+    __GBLIBCPP_CONSTEXPR
+    const_iterator find(const Key& key) const { return tree.find(key); }
+
+    __GBLIBCPP_CONSTEXPR
+    std::pair<iterator, bool> insert(const value_type& value)
+    { return tree.insert(value); }
+    __GBLIBCPP_CONSTEXPR
+    std::pair<iterator, bool> insert(value_type&& value)
+    { return tree.insert(std::move(value)); }
+
+    template <typename InputIter>
+    __GBLIBCPP_CONSTEXPR
+    void insert(InputIter first, InputIter last)
+    {
+        for ( ; first != last; ++first)
+            insert(*first);
+    }
+
+    __GBLIBCPP_CONSTEXPR
+    iterator erase(iterator pos) noexcept { return tree.erase(pos); }
+    __GBLIBCPP_CONSTEXPR
+    iterator erase(const_iterator pos) noexcept { return tree.erase(pos); }
+    __GBLIBCPP_CONSTEXPR
+    iterator erase(const_iterator first, const_iterator last) noexcept
+    {
+        while (first != last)
+            first = erase(first);
+        return first;
+    }
+
+    __GBLIBCPP_CONSTEXPR
+    size_type erase(const Key& key)
+    {
+        auto iter = find(key);
+        if (!iter)
+            return 0;
+        erase(iter);
+        return 1;
+    }
+
+    __GBLIBCPP_CONSTEXPR
+    void clear() noexcept { tree.destroy(); }
+
+    __GBLIBCPP_CONSTEXPR
+    bool empty() const noexcept { return tree.empty(); }
+};
+
+} // namespace std
+
+#endif

+ 19 - 26
include/kernel/process.hpp

@@ -1,5 +1,7 @@
 #pragma once
 
+#include <set>
+#include <tuple>
 #include <utility>
 
 #include <fcntl.h>
@@ -353,6 +355,7 @@ public:
     pid_t sid;
 
     tty* control_tty;
+    std::set<pid_t> children;
 
 public:
     // if waitlist is not empty or mutex in cv_wait
@@ -367,6 +370,8 @@ public:
         , ppid(val.ppid)
         , pgid(val.pgid)
         , sid(val.sid)
+        , control_tty(val.control_tty)
+        , children(std::move(val.children))
     {
         if (current_process == &val)
             current_process = this;
@@ -395,13 +400,11 @@ private:
 class proclist final {
 public:
     using list_type = types::map<pid_t, process>;
-    using child_index_type = types::hash_map<pid_t, types::list<pid_t>>;
     using iterator_type = list_type::iterator_type;
     using const_iterator_type = list_type::const_iterator_type;
 
 private:
     list_type m_procs;
-    child_index_type m_child_idx;
 
 public:
     template <typename... Args>
@@ -412,14 +415,12 @@ public:
         auto ppid = _proc.ppid;
         auto iter = m_procs.insert(std::make_pair(pid, std::move(_proc)));
 
-        auto children = m_child_idx.find(ppid);
-        if (!children) {
-            m_child_idx.emplace(ppid, types::list<pid_t> {});
-            children = m_child_idx.find(ppid);
+        if (ppid) {
+            bool success = false;
+            std::tie(std::ignore, success) = find(ppid).children.insert(pid);
+            assert(success);
         }
 
-        children->second.push_back(pid);
-
         return iter;
     }
 
@@ -428,20 +429,15 @@ public:
         make_children_orphans(pid);
 
         auto proc_iter = m_procs.find(pid);
-        auto ppid = proc_iter->second.ppid;
 
-        auto& [ idx, parent_children ] = *m_child_idx.find(ppid);
-
-        auto i = parent_children.find(pid);
-        parent_children.erase(i);
+        auto ppid = proc_iter->second.ppid;
+        find(ppid).children.erase(pid);
 
         m_procs.erase(proc_iter);
     }
 
     constexpr bool try_find(pid_t pid) const
-    {
-        return !!m_procs.find(pid);
-    }
+    { return !!m_procs.find(pid); }
 
     // if process doesn't exist, the behavior is undefined
     constexpr process& find(pid_t pid)
@@ -453,24 +449,21 @@ public:
 
     constexpr bool has_child(pid_t pid)
     {
-        auto children = m_child_idx.find(pid);
-        return children && !children->second.empty();
+        auto& proc = find(pid);
+        return !proc.children.empty();
     }
 
     constexpr void make_children_orphans(pid_t pid)
     {
-        auto children = m_child_idx.find(pid);
-        auto init_children = m_child_idx.find(1);
-
-        if (!children || !init_children)
-            return;
+        auto& children = find(pid).children;
+        auto& init_children = find(1).children;
 
-        for (auto item : children->second) {
-            init_children->second.push_back(item);
+        for (auto item : children) {
+            init_children.insert(item);
             find(item).ppid = 1;
         }
 
-        m_child_idx.remove(children);
+        children.clear();
     }
 
     // the process MUST exist, or the behavior is undefined

+ 3 - 1
src/kernel/process.cpp

@@ -100,6 +100,7 @@ process::process(const process& parent)
     , pid { process::alloc_pid() }
     , ppid { parent.pid } , pgid { parent.pgid } , sid { parent.sid }
     , control_tty { parent.control_tty }
+    , children {}
 {
     for (auto& area : parent.mms) {
         if (area.is_kernel_space() || area.attr.in.system)
@@ -117,7 +118,8 @@ process::process(pid_t ppid)
     , pwd { "/" }
     , pid { process::alloc_pid() }
     , ppid { ppid }
-    , pgid {} , sid {} , control_tty {} { }
+    , pgid {} , sid {} , control_tty {}
+    , children {} { }
 
 void proclist::kill(pid_t pid, int exit_code)
 {