Skip to content

Commit

Permalink
Constness of opSlice, upperBound, lowerBound and equalRange
Browse files Browse the repository at this point in the history
  • Loading branch information
Groterik committed Aug 9, 2015
1 parent 030595b commit a295525
Showing 1 changed file with 134 additions and 72 deletions.
206 changes: 134 additions & 72 deletions std/container/rbtree.d
Expand Up @@ -610,6 +610,73 @@ unittest
static assert(is(typeof(n.prev)));
}

private struct RBRange(N)
{
alias Node = N;
alias Elem = typeof(Node.value);

private Node _begin;
private Node _end;

private this(Node b, Node e)
{
_begin = b;
_end = e;
}

/**
* Returns $(D true) if the range is _empty
*/
@property bool empty() const
{
return _begin is _end;
}

/**
* Returns the first element in the range
*/
@property Elem front()
{
return _begin.value;
}

/**
* Returns the last element in the range
*/
@property Elem back()
{
return _end.prev.value;
}

/**
* pop the front element from the range
*
* complexity: amortized $(BIGOH 1)
*/
void popFront()
{
_begin = _begin.next;
}

/**
* pop the back element from the range
*
* complexity: amortized $(BIGOH 1)
*/
void popBack()
{
_end = _end.prev;
}

/**
* Trivial _save implementation, needed for $(D isForwardRange).
*/
@property RBRange save()
{
return this;
}
}

/**
* Implementation of a $(LUCKY red-black tree) container.
*
Expand Down Expand Up @@ -701,71 +768,11 @@ final class RedBlackTree(T, alias less = "a < b", bool allowDuplicates = false)
}

/**
* The range type for $(D RedBlackTree)
* The range types for $(D RedBlackTree)
*/
struct Range
{
private Node _begin;
private Node _end;

private this(Node b, Node e)
{
_begin = b;
_end = e;
}

/**
* Returns $(D true) if the range is _empty
*/
@property bool empty() const
{
return _begin is _end;
}

/**
* Returns the first element in the range
*/
@property Elem front()
{
return _begin.value;
}

/**
* Returns the last element in the range
*/
@property Elem back()
{
return _end.prev.value;
}

/**
* pop the front element from the range
*
* complexity: amortized $(BIGOH 1)
*/
void popFront()
{
_begin = _begin.next;
}

/**
* pop the back element from the range
*
* complexity: amortized $(BIGOH 1)
*/
void popBack()
{
_end = _end.prev;
}

/**
* Trivial _save implementation, needed for $(D isForwardRange).
*/
@property Range save()
{
return this;
}
}
alias Range = RBRange!(RBNode*);
alias ConstRange = RBRange!(const(RBNode)*); /// Ditto
alias ImmutableRange = RBRange!(immutable(RBNode)*); /// Ditto

static if(doUnittest) unittest
{
Expand Down Expand Up @@ -965,6 +972,18 @@ final class RedBlackTree(T, alias less = "a < b", bool allowDuplicates = false)
return Range(_begin, _end);
}

/// Ditto
ConstRange opSlice() const
{
return ConstRange(_begin, _end);
}

/// Ditto
ImmutableRange opSlice() immutable
{
return ImmutableRange(_begin, _end);
}

/**
* The front element in the container
*
Expand Down Expand Up @@ -1434,11 +1453,11 @@ assert(equal(rbt[], [5]));
}

// find the first node where the value is > e
private Node _firstGreater(Elem e)
private inout(RBNode)* _firstGreater(Elem e) inout
{
// can't use _find, because we cannot return null
auto cur = _end.left;
auto result = _end;
inout(RBNode)* result = _end;
while(cur)
{
if(_less(e, cur.value))
Expand All @@ -1453,11 +1472,11 @@ assert(equal(rbt[], [5]));
}

// find the first node where the value is >= e
private Node _firstGreaterEqual(Elem e)
private inout(RBNode)* _firstGreaterEqual(Elem e) inout
{
// can't use _find, because we cannot return null.
auto cur = _end.left;
auto result = _end;
inout(RBNode)* result = _end;
while(cur)
{
if(_less(cur.value, e))
Expand All @@ -1483,6 +1502,18 @@ assert(equal(rbt[], [5]));
return Range(_firstGreater(e), _end);
}

/// Ditto
ConstRange upperBound(Elem e) const
{
return ConstRange(_firstGreater(e), _end);
}

/// Ditto
ImmutableRange upperBound(Elem e) immutable
{
return ImmutableRange(_firstGreater(e), _end);
}

/**
* Get a range from the container with all elements that are < e according
* to the less comparator
Expand All @@ -1494,27 +1525,40 @@ assert(equal(rbt[], [5]));
return Range(_begin, _firstGreaterEqual(e));
}

/// Ditto
ConstRange lowerBound(Elem e) const
{
return ConstRange(_begin, _firstGreaterEqual(e));
}

/// Ditto
ImmutableRange lowerBound(Elem e) immutable
{
return ImmutableRange(_begin, _firstGreaterEqual(e));
}

/**
* Get a range from the container with all elements that are == e according
* to the less comparator
*
* Complexity: $(BIGOH log(n))
*/
Range equalRange(Elem e)
auto equalRange(this This)(Elem e)
{
auto beg = _firstGreaterEqual(e);
alias RangeType = RBRange!(typeof(beg));
if(beg is _end || _less(e, beg.value))
// no values are equal
return Range(beg, beg);
return RangeType(beg, beg);
static if(allowDuplicates)
{
return Range(beg, _firstGreater(e));
return RangeType(beg, _firstGreater(e));
}
else
{
// no sense in doing a full search, no duplicates are allowed,
// so we just get the next node.
return Range(beg, beg.next);
return RangeType(beg, beg.next);
}
}

Expand Down Expand Up @@ -1804,4 +1848,22 @@ unittest
const rt1 = redBlackTree(5,4,3,2,1);
static assert(is(typeof(rt1.length)));
static assert(is(typeof(5 in rt1)));

static assert(is(typeof(rt1.upperBound(3).front()) == const(int)));
import std.algorithm : equal;
assert(rt1.upperBound(3).equal([4, 5]));
assert(rt1.lowerBound(3).equal([1, 2]));
assert(rt1.equalRange(3).equal([3]));
assert(rt1[].equal([1, 2, 3, 4, 5]));
}

//immutable checks
unittest
{
immutable rt1 = redBlackTree(5,4,3,2,1);
static assert(is(typeof(rt1.length)));

static assert(is(typeof(rt1.upperBound(3).front()) == immutable(int)));
import std.algorithm : equal;
assert(rt1.upperBound(2).equal([3, 4, 5]));
}

0 comments on commit a295525

Please sign in to comment.