redblacktree_node.h

Back to Red-black tree

pastel/sys/redblacktree/

// Description: Red-black tree node

#ifndef PASTELSYS_REDBLACKTREE_NODE_H
#define PASTELSYS_REDBLACKTREE_NODE_H

#include "pastel/sys/redblacktree/redblacktree_fwd.h"
#include "pastel/sys/generic/class.h"
#include "pastel/sys/ensure.h"

namespace Pastel
{

    template <typename, template <typename> class>
    class RedBlackTree;

    namespace RedBlackTree_
    {

        //! Base node
        class Node
        {
        public:
            bool red() const
            {
                return red_;
            }

            bool black() const
            {
                return !red();
            }

            bool isSentinel() const
            {
                // A sentinel is identified by the unique property
                // that its left child points to itself.
                return left() == this;
            }

            bool validPropagation() const
            {
                return size_ >= 0;
            }

            integer size() const
            {
                return size_;
            }

        protected:
            template <typename, template <typename> class>
            friend class Pastel::RedBlackTree;

            template <typename, typename, bool>
            friend class Iterator;

            Node()
                : parent_(nullptr)
                , child_()
                , red_(false)
                , size_(0)
            {
                isolateSelf();

                /*
               These settings correspond to those of sentinel
               nodes. This is so that RedBlackTree's constructor
               does not have to initialize the sentinel nodes
               to refer to themselves.
               */
            }

            Node(const Node& that) = delete;
            Node(Node&& that) = delete;
            Node& operator=(Node that) = delete;

            void isolate()
            {
                parent_ = nullptr;
                child_[0] = nullptr;
                child_[1] = nullptr;
                size_ = 0;
                red_ = true;
            }

            void isolateSelf()
            {
                parent_ = (Node*)this;
                child_[0] = parent_;
                child_[1] = parent_;
                size_ = 0;
            }

            void setRed()
            {
                setRed(true);
            }

            void setBlack()
            {
                setRed(false);
            }

            void setRed(bool red)
            {
                ASSERT(!isSentinel() || !red);
                red_ = red;
            }

            void setSize(integer size)
            {
                ASSERT_OP(size, >=, 0);
                size_ = size;
            }

            Node*& parent() const
            {
                return (Node*&)parent_;
            }

            Node*& child(bool right) const
            {
                return (Node*&)child_[right];
            }

            Node*& left() const
            {
                return (Node*&)child_[0];
            }

            Node*& right() const
            {
                return (Node*&)child_[1];
            }

            void invalidatePropagation()
            {
                size_ = -1;
            }

            //! The parent node.
            Node* parent_;

            //! The child nodes.
            /*
           The child_[0] is the left child, while
           child_[1] is the right child. The array 
           representation is good because it can be indexed 
           with a boolean, and that the boolean can be 
           negated to get to the sibling.

           Visual Studio 2013 has a bug in that it can't
           member-initialize arrays.
           */
            Node* child_[2];

            //! Whether the node is red.
            /*
           A bit-field can not be member-initialized in C++11.
           This is probably a bug in the C++11 standard.
           */
            uint8 red_ : 1;

            //! The number of elements in the subtree.
            /*!
           The subtree refers to the subtree rooted at 
           this node. This number is needed when splitting
           a red-black tree; otherwise the size of the
           resulting trees can not be computed efficiently.
           */
            integer size_;
        };

        //! Propagation node
        template <typename Settings>
        class Propagation_Node
            : public Node
            , public Settings::Propagation_Class
        {
        public:
            using Fwd = Settings;
            PASTEL_FWD(Propagation_Class);

            const Propagation_Class& propagation() const
            {
                return *this;
            }

        protected:
            Propagation_Node()
            : Node()
            , Propagation_Class()
            {
            }

            Propagation_Node(const Propagation_Node& that) = delete;
            Propagation_Node(Propagation_Node&& that) = delete;
            Propagation_Node& operator=(Propagation_Node that) = delete;
        };

        //! Sentinel node
        template <typename Settings>
        class Sentinel_Node
            : public Settings::EndBase
            , public Settings::SentinelData_Class
        {
        public:
            using Fwd = Settings;
            PASTEL_FWD(SentinelData_Class);
            PASTEL_FWD(EndBase);

            Sentinel_Node()
            : EndBase()
            , SentinelData_Class()
            {
            }

            SentinelData_Class& sentinelData()
            {
                return (SentinelData_Class&)*this;
            }

            const SentinelData_Class& sentinelData() const
            {
                return (const SentinelData_Class&)*this;
            }

        protected:
            template <typename, template <typename> class>
            friend class Pastel::RedBlackTree;

            Sentinel_Node(const Sentinel_Node& that) = delete;
            Sentinel_Node(Sentinel_Node&& that) = delete;
            Sentinel_Node& operator=(Sentinel_Node that) = delete;
        };

        //! Data node
        template <typename Settings>
        class Data_Node
            : public Propagation_Node<Settings>
            , public Settings::Data_Class
        {
        public:
            using Fwd = Settings;
            PASTEL_FWD(Data_Class);

            Data_Class& data()
            {
                return (Data_Class&)*this;
            }

            const Data_Class& data() const
            {
                return (const Data_Class&)*this;
            }

        protected:
            using Base = Propagation_Node<Settings>;
            PASTEL_FWD(Propagation_Class);

            Data_Node()
                : Base()
                , Data_Class()
            {
            }

            explicit Data_Node(const Data_Class& data)
                : Base()
                , Data_Class(data)
            {
            }

            Data_Node(const Data_Node& that) = delete;
            Data_Node(Data_Node&& that) = delete;
            Data_Node& operator=(Data_Node that) = delete;
        };

        //! Key node
        template <typename Settings_>
        class Key_Node
            : public Data_Node<Settings_>
            , public Settings_::Key_Class
        {
        public:
            using Fwd = Settings_;

            PASTEL_FWD(Key_Class);

            const Key_Class& key() const
            {
                return (const Key_Class&)*this;
            }

        protected:
            using Base = Data_Node<Settings_>;
            PASTEL_FWD(Data_Class);

            template <typename, template <typename> class>
            friend class Pastel::RedBlackTree;

            Key_Node(
                const Key_Class& key,
                const Data_Class& data)
                : Base(data)
                , Key_Class(key)
            {
            }

            Key_Node() = delete;
            Key_Node(const Key_Node& that) = delete;
            Key_Node(Key_Node&& that) = delete;
            Key_Node& operator=(Key_Node that) = delete;
        };

    }

}

#endif