// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.


#ifndef _RANGETREE_
#define _RANGETREE_

#include "utilcode.h"
#include "memorypool.h"

//
// A RangeTree is a self-balancing binary tree of non-overlapping
// ranges [start-end), which provides log N operation time for
// lookup, insertion, and deletion of nodes.
//
// The tree is always balanced in the sense that the left and right
// sides of a node have the same amount of address space allocated to
// them - (for worst case data, the nodes of the tree might actually
// not be balanced).
//
// This address-space balancing means that if all the ranges cover a
// contiguous range of memory, and if lookup occur uniformly throughout
// the overall range covered, the tree provides optimal lookup
// structure.
//
// Another interesting property is that the same set of
// ranges always produces the same tree layout, regardless of
// the order the nodes are added in.
//
// Each node represents a range of the address space (in binary)
// from m0...0 to m1...1, where m is any number of 31 bits or
// less.
//
// Each node has 3 components:
//  * a range
//  * a 0-child,
//  * a 1-child
//
// The range is the numeric range [start,end),
// represented by the node.  A range is always assigned to the
// widest possible node (i.e. most bits in m) possible.  Thus the
// bits of start and end share the same prefix string m, and
// differ in the next bit after m: the start bound will have a 0
// and the end bound will have a 1 in that position.
//
// Note that any other range which is represented by the same node
// must necessarily intersect the node.  Thus, if no overlaps are
// possible, each node can only contain a single range. (To help
// see why this must be, it helps to realize that the node
// represents the transition from m01...1 to m10...0, which any
// range represented by this node must contain.)
//
// All range nodes represented by the form m0...  are contained in
// the 0-child subtree, and all nodes represented by the form
// m1... are contained in the 1-child subtree.  Either child can
// of course be null.
//

class RangeTree
{
  public:

    //
    // Imbed the RangeTreeNode structure in your data structure
    // in order to place it into a RangeTree.
    //

    struct Node
    {
        friend class RangeTree;

    private:
        // start & end (exclusive) of range
        SIZE_T          start;
        SIZE_T          end;
        // mask of high-order bits which are the same in start & end
        SIZE_T          mask;
        // We could steal a bit from mask or children[] for isIntermediate
        BOOL            isIntermediate;
#ifdef _DEBUG
	// ordinal of when this node was created
        DWORD           ordinal;
#endif

        Node            *children[2];

        void   Init (SIZE_T  rangeStart, SIZE_T  rangeEnd
                     DEBUGARG(DWORD ord));

        Node** Child(SIZE_T address)
        {
            LIMITED_METHOD_CONTRACT;

            return &children[ ! ! (address & ((~mask>>1)+1))];
        }

    public:
        BOOL   IsIntermediate()            { return isIntermediate;  }
        void   IsIntermediate(BOOL value)  { isIntermediate = value; }
        SIZE_T GetStart()                  { return start; }
        SIZE_T GetEnd()                    { return end;   }
    };

    friend struct Node;

    RangeTree();

    Node *Lookup(SIZE_T address) const;
    Node *LookupEndInclusive(SIZE_T nonStartingAddress);
    BOOL Overlaps(SIZE_T start, SIZE_T end);
    HRESULT AddNode(Node *addNode, SIZE_T start, SIZE_T end);
    HRESULT RemoveNode(Node *removeNode);
    void RemoveRange(SIZE_T start, SIZE_T end);

    typedef void (*IterationCallback)(Node *next, void *context);

    void Iterate(IterationCallback pCallback, void *context = NULL);
    void IterateRange(SIZE_T start, SIZE_T end, IterationCallback pCallback, void *context = NULL);

  private:

    Node *     m_root;
    MemoryPool m_pool;
#ifdef _DEBUG
    DWORD      m_nodeCount;
#endif

    Node *AddIntermediateNode(Node *node0, Node *node1);
    Node *AllocateIntermediate();
    void FreeIntermediate(Node *node);

    void IterateNode(Node *node, IterationCallback pCallback, void *context);
    void IterateRangeNode(Node *node, SIZE_T start, SIZE_T end, SIZE_T mask, IterationCallback pCallback, void *context);
    BOOL OverlapsNode(Node *node, SIZE_T start, SIZE_T end, SIZE_T mask);
    void RemoveRangeNode(Node **nodePtr, SIZE_T start, SIZE_T end, SIZE_T mask);

    static SIZE_T GetRangeCommonMask(SIZE_T start, SIZE_T end);
};

#endif // _RANGETREE_
