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 Jul 27, 2015
1 parent 5d17edc commit edaa65a
Showing 1 changed file with 107 additions and 21 deletions.
128 changes: 107 additions & 21 deletions std/container/rbtree.d
Expand Up @@ -45,6 +45,8 @@ struct RBNode(V)
* Convenience alias
*/
alias Node = RBNode*;
alias ConstNode = const(RBNode)*;
alias ImmutableNode = immutable(RBNode)*;

private Node _left;
private Node _right;
Expand Down Expand Up @@ -677,6 +679,8 @@ final class RedBlackTree(T, alias less = "a < b", bool allowDuplicates = false)
// used for convenience
private alias RBNode = .RBNode!Elem;
private alias Node = RBNode.Node;
private alias ConstNode = RBNode.ConstNode;
private alias ImmutableNode = RBNode.ImmutableNode;

private Node _end;
private Node _begin;
Expand All @@ -700,11 +704,11 @@ final class RedBlackTree(T, alias less = "a < b", bool allowDuplicates = false)
return result;
}

/**
* The range type for $(D RedBlackTree)
*/
struct Range
private struct RangeT(V, N)
{
alias Elem = V;
alias Node = N;

private Node _begin;
private Node _end;

Expand Down Expand Up @@ -761,12 +765,19 @@ final class RedBlackTree(T, alias less = "a < b", bool allowDuplicates = false)
/**
* Trivial _save implementation, needed for $(D isForwardRange).
*/
@property Range save()
@property RangeT save()
{
return this;
}
}

/**
* The range types for $(D RedBlackTree)
*/
alias Range = RangeT!(Elem, Node);
alias ConstRange = RangeT!(const(Elem), ConstNode); /// Ditto
alias ImmutableRange = RangeT!(immutable(Elem), ImmutableNode); /// Ditto

static if(doUnittest) unittest
{
import std.algorithm : equal;
Expand Down Expand Up @@ -965,6 +976,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 +1457,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;
PointerTarget!(typeof(_end))* result = _end;
while(cur)
{
if(_less(e, cur.value))
Expand All @@ -1453,11 +1476,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;
PointerTarget!(typeof(_end))* result = _end;
while(cur)
{
if(_less(cur.value, e))
Expand All @@ -1483,6 +1506,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,30 +1529,63 @@ assert(equal(rbt[], [5]));
return Range(_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)
/// Ditto
ConstRange lowerBound(Elem e) const
{
return ConstRange(_begin, _firstGreaterEqual(e));
}

/// Ditto
ImmutableRange lowerBound(Elem e) immutable
{
auto beg = _firstGreaterEqual(e);
if(beg is _end || _less(e, beg.value))
return ImmutableRange(_begin, _firstGreaterEqual(e));
}

private static auto _equalRange(This)(This t, Elem e)
{
import std.typecons;
auto beg = t._firstGreaterEqual(e);
if(beg is t._end || _less(e, beg.value))
// no values are equal
return Range(beg, beg);
return tuple(beg, beg);
static if(allowDuplicates)
{
return Range(beg, _firstGreater(e));
return tuple(beg, t._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 tuple(beg, beg.next);
}
}

/**
* 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 tp = _equalRange(this, e);
return Range(tp[0], tp[1]);
}

/// Ditto
ConstRange equalRange(Elem e) const
{
auto tp = _equalRange(this, e);
return ConstRange(tp[0], tp[1]);
}

/// Ditto
ImmutableRange equalRange(Elem e) immutable
{
auto tp = _equalRange(this, e);
return ImmutableRange(tp[0], tp[1]);
}

static if(doUnittest) unittest
{
import std.algorithm : equal;
Expand Down Expand Up @@ -1804,4 +1872,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 edaa65a

Please sign in to comment.