Note: This website is archived. For up-to-date information about D projects and development, please visit wiki.dlang.org.

Changeset 1698

Show
Ignore:
Timestamp:
06/30/10 02:30:26 (14 years ago)
Author:
dsimcha
Message:

Improve unittests for higher order ranges in std.algorithm, fix some unlisted bugs.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/docsrc/changelog.dd

    r1697 r1698  
    22 
    33$(D_S D Change Log, 
    44 
    55 
    66$(VERSION 048, Jun 11, 2010, =================================================, 
    77 
    88    $(WHATSNEW 
    99    $(LI std.string: icmp() now works with all built-in string types.) 
    1010    ) 
    1111    $(BUGSFIXED 
    12     $(L1 $(Unlisted Bug):  std.algorithm.filter not a forward range. 
     12    $(L1 $(Unlisted Bug): std.algorithm.filter not a forward range) 
     13    $(L1 $(Unlisted Bug): std.algorithm.Uniq requires a bidirectional range)  
     14    $(L1 $(Unlisted Bug): std.algorithm.Uniq missing a save() function)  
     15    $(L1 $(Unlisted Bug): std.algorithm.Group missing a save() function)  
    1316    $(LI $(BUGZILLA 978): std.utf's toUTF* functions accept some invalid and reject some valid UTF) 
    1417    $(LI $(BUGZILLA 996): Error in doc on implicit conversion between pointer and array) 
    1518    $(LI $(BUGZILLA 2275): std.utf.toUTF16z() should return const(wchar)*) 
    1619    $(LI $(BUGZILLA 2872): Length, opIndex for Map) 
    1720    $(LI $(BUGZILLA 3202): std.math.pow cause dead loop) 
    1821    $(LI $(BUGZILLA 3355): std.string.cmp works incorrectly for mixed-type and different-length strings) 
    1922    $(LI $(BUGZILLA 3386): to!bool(string) is not implemented) 
    2023    $(LI $(BUGZILLA 3436): std.functional.compose with only one function) 
    2124    $(LI $(BUGZILLA 3439): std.range.Sequence.opIndex not consistent after calling popFront().) 
    2225    $(LI $(BUGZILLA 3447): std.file uses unconventional file permissions) 
    2326    $(LI $(BUGZILLA 3874): std.range.stride assumes a bidirectional input range) 
    2427    $(LI $(BUGZILLA 3937): os.path.dirname fails on absolute path) 
    2528    $(LI $(BUGZILLA 3961): Error with to!(somestruct)) 
    2629    $(LI $(BUGZILLA 4109): (reopened) writeln doesn't work with empty static array) 
    2730    $(LI $(BUGZILLA 4171): std.random.uniform does not work for a range of characters) 
    2831    $(LI $(BUGZILLA 4260): windows & basename) 
    2932    $(LI $(BUGZILLA 4305): Take, Chain on top of ranges w/o moveFront() ) 
    3033    $(LI $(BUGZILLA 4327): std.container.Array.Range.~this() tries to call free(T[])) 
    31     $(LI $(BUGZILLA 4362): std.range.repeat and cycle do not have a .save() method 
     34    $(LI $(BUGZILLA 4362): std.range.repeat and cycle do not have a .save() method) 
    3235    $(LI $(BUGZILLA 4363): std.algorithm.Until is not a forward range) 
    3336    $(LI $(BUGZILLA 4406): Typo (bug) in std.concurrency) 
    3437    ) 
    3538) 
    3639 
    3740<div id=version> 
    3841$(UL 
    3942    $(NEW 048) 
    4043    $(NEW 047) 
    4144    $(NEW 046) 
  • trunk/phobos/std/algorithm.d

    r1688 r1698  
    4646module std.algorithm; 
    4747 
    4848import std.c.string; 
    4949import std.array, std.container, std.contracts, std.conv, std.date, 
    5050    std.functional, std.math, std.metastrings, std.range, std.string, 
    5151    std.traits, std.typecons, std.typetuple; 
    5252 
    5353version(unittest) 
    5454{ 
    5555    import std.random, std.stdio, std.string; 
     56 
     57    mixin(dummyRanges); 
    5658} 
    5759 
    5860/** 
    5961Implements the homonym function (also known as $(D transform)) present 
    6062in many languages of functional flavor. The call $(D map!(fun)(range)) 
    6163returns a range of which elements are obtained by applying $(D fun(x)) 
    6264left to right for all $(D x) in $(D range). The original ranges are 
    6365not changed. Evaluation is done lazily. The range returned by $(D map) 
    6466caches the last value such that evaluating $(D front) multiple times 
    6567does not result in multiple calls to $(D fun). 
     
    121123    // and wasted space when 99% of the time this range will only be iterated 
    122124    // over in the forward direction.  Use a bool to determine whether cache 
    123125    // is front or back instead. 
    124126        bool cacheIsBack; 
    125127 
    126128        private void fillCacheBack() { 
    127129            if (!_input.empty) _cache = fun(_input.back); 
    128130            cacheIsBack = true; 
    129131        } 
    130132 
    131         ElementType back() { 
     133        @property ElementType back() { 
    132134            if(!cacheIsBack) { 
    133135                fillCacheBack(); 
    134136            } 
    135137            return _cache; 
    136138        } 
    137139 
    138140        void popBack() { 
    139141            _input.popBack; 
    140142            fillCacheBack(); 
    141143        } 
     
    161163        @property bool empty() { 
    162164            return _input.empty; 
    163165        } 
    164166    } 
    165167 
    166168    void popFront() { 
    167169        _input.popFront; 
    168170        fillCache; 
    169171    } 
    170172 
    171     ElementType front() { 
     173    @property ElementType front() { 
    172174        static if(isBidirectionalRange!(Range)) { 
    173175            if(cacheIsBack) { 
    174176                fillCache(); 
    175177            } 
    176178        } 
    177179        return _cache; 
    178180    } 
    179181 
    180182    static if(isRandomAccessRange!Range) { 
    181183        ElementType opIndex(size_t index) { 
    182184            return fun(_input[index]); 
    183185        } 
    184186    } 
    185187 
    186188    // hasLength is busted, Bug 2873 
    187     static if(is(typeof(_input.length) : ulong
    188         || is(typeof(_input.length()) : ulong)) { 
    189         size_t length() { 
     189    static if(is(typeof(_input.length) : size_t
     190        || is(typeof(_input.length()) : size_t)) { 
     191        @property size_t length() { 
    190192            return _input.length; 
    191193        } 
    192194    } 
    193195 
    194196    static if(hasSlicing!(Range)) { 
    195197        typeof(this) opSlice(size_t lowerBound, size_t upperBound) { 
    196198            return typeof(this)(_input[lowerBound..upperBound]); 
    197199        } 
    198200    } 
    199201 
     
    259261    fibsSquares.popFront; 
    260262    assert(fibsSquares.front == 4); 
    261263    fibsSquares.popFront; 
    262264    assert(fibsSquares.front == 9); 
    263265 
    264266    auto repeatMap = map!"a"(repeat(1)); 
    265267    static assert(isInfinite!(typeof(repeatMap))); 
    266268 
    267269    auto intRange = map!"a"([1,2,3]); 
    268270    static assert(isRandomAccessRange!(typeof(intRange))); 
     271 
     272    foreach(DummyType; AllDummyRanges) { 
     273        DummyType d; 
     274        auto m = map!"a * a"(d); 
     275        assert(equal(m, [1,4,9,16,25,36,49,64,81,100])); 
     276    } 
    269277} 
    270278 
    271279// reduce 
    272280/** 
    273281Implements the homonym function (also known as $(D accumulate), $(D 
    274282compress), $(D inject), or $(D foldl)) present in various programming 
    275283languages of functional flavor. The call $(D reduce!(fun)(seed, 
    276284range)) first assigns $(D seed) to an internal variable $(D result), 
    277285also called the accumulator. Then, for each element $(D x) in $(D 
    278286range), $(D result = fun(result, x)) gets evaluated. Finally, $(D 
     
    600608    static assert(isForwardRange!(typeof(r))); 
    601609 
    602610    a = [ 1, 22, 3, 42, 5 ]; 
    603611    auto under10 = filter!("a < 10")(a); 
    604612    assert(equal(under10, [1, 3, 5][])); 
    605613    static assert(isForwardRange!(typeof(under10))); 
    606614 
    607615    auto infinite = filter!"a > 2"(repeat(3)); 
    608616    static assert(isInfinite!(typeof(infinite))); 
    609617    static assert(isForwardRange!(typeof(infinite))); 
     618 
     619    foreach(DummyType; AllDummyRanges) { 
     620        DummyType d; 
     621        auto f = filter!"a & 1"(d); 
     622        assert(equal(f, [1,3,5,7,9])); 
     623    } 
    610624} 
    611625 
    612626// move 
    613627/** 
    614628Moves $(D source) into $(D target) via a destructive 
    615629copy. Specifically: $(UL $(LI If $(D hasAliasing!T) is true (see 
    616630$(XREF traits, hasAliasing)), then the representation of $(D source) 
    617631is bitwise copied into $(D target) and then $(D source = T.init) is 
    618632evaluated.)  $(LI Otherwise, $(D target = source) is evaluated.)) See 
    619633also $(XREF contracts, pointsTo). 
     
    886900    // foreach (x; splitter(a, 0)) { 
    887901    //     writeln("[", x, "]"); 
    888902    // } 
    889903    assert(equal(splitter(a, 0), w)); 
    890904    a = null; 
    891905    assert(equal(splitter(a, 0), [ (int[]).init ][])); 
    892906    a = [ 0 ]; 
    893907    assert(equal(splitter(a, 0), [ (int[]).init, (int[]).init ][])); 
    894908    a = [ 0, 1 ]; 
    895909    assert(equal(splitter(a, 0), [ [], [1] ][])); 
     910 
     911//    foreach(DummyType; AllDummyRanges) {  // Bug 4408 
     912//        DummyType d; 
     913//        auto s = splitter(d, 5); 
     914//        assert(equal(s, [[1,2,3,4], [6,7,8,9,10]])); 
     915// 
     916//        auto s2 = splitter(d, [4, 5]); 
     917//        assert(equal(s2, [[1,2,3], [6,7,8,9,10]])); 
     918//    } 
    896919} 
    897920 
    898921/** 
    899922Splits a range using another range as a separator. This can be used 
    900923with any range type, but is most popular with string types. 
    901924 */ 
    902925struct Splitter(Range, Separator) 
    903926    if (is(typeof(Range.init.front == Separator.init.front))) 
    904927{ 
    905928private: 
     
    11961219    void popFront() 
    11971220    { 
    11981221        auto last = _input.front; 
    11991222        do 
    12001223        { 
    12011224            _input.popFront; 
    12021225        } 
    12031226        while (!_input.empty && binaryFun!(pred)(last, _input.front)); 
    12041227    } 
    12051228 
    1206     void popBack() 
    1207     { 
    1208         auto last = _input.back; 
    1209         do 
    1210         { 
    1211             _input.popBack; 
    1212         } 
    1213         while (!_input.empty && binaryFun!(pred)(last, _input.back)); 
     1229    static if(isBidirectionalRange!R) { 
     1230        void popBack() 
     1231        { 
     1232            auto last = _input.back; 
     1233            do 
     1234            { 
     1235                _input.popBack; 
     1236            } 
     1237            while (!_input.empty && binaryFun!(pred)(last, _input.back)); 
     1238        } 
     1239 
     1240        ElementType!(R) back() { return _input.back; } 
    12141241    } 
    12151242 
    12161243    bool empty() { return _input.empty; } 
    12171244    ElementType!(R) front() { return _input.front; } 
    1218     ElementType!(R) back() { return _input.back; } 
     1245 
     1246    static if(isForwardRange!R) { 
     1247        @property typeof(this) save() { 
     1248            return typeof(this)(_input.save); 
     1249        } 
     1250    } 
    12191251} 
    12201252 
    12211253/// Ditto 
    12221254Uniq!(pred, Range) uniq(alias pred = "a == b", Range)(Range r) 
    12231255{ 
    12241256    return typeof(return)(r); 
    12251257} 
    12261258 
    12271259unittest 
    12281260{ 
    12291261    int[] arr = [ 1, 2, 2, 2, 2, 3, 4, 4, 4, 5 ]; 
    12301262    auto r = uniq(arr); 
    12311263    assert(equal(r, [ 1, 2, 3, 4, 5 ][])); 
     1264    assert(equal(retro(r), retro([ 1, 2, 3, 4, 5 ][]))); 
     1265 
     1266    foreach(DummyType; AllDummyRanges) { 
     1267        DummyType d; 
     1268        auto u = uniq(d); 
     1269        assert(equal(u, [1,2,3,4,5,6,7,8,9,10])); 
     1270 
     1271        static assert(d.rt == RangeType.Input || isForwardRange!(typeof(u))); 
     1272 
     1273        static if(d.rt >= RangeType.Bidirectional) { 
     1274            assert(equal(retro(u), [10,9,8,7,6,5,4,3,2,1])); 
     1275        } 
     1276    } 
    12321277} 
    12331278 
    12341279// group 
    12351280/** 
    12361281Similarly to $(D uniq), $(D group) iterates unique consecutive 
    12371282elements of the given range. The element type is $(D 
    12381283Tuple!(ElementType!R, uint)) because it includes the count of 
    12391284equivalent elements seen. Equivalence of elements is assessed by using 
    12401285the predicate $(D pred), by default $(D "a == b"). 
    12411286 
     
    12721317            _current = tuple(_input.front, 1u); 
    12731318            _input.popFront; 
    12741319            while (!_input.empty && comp(_current.field[0], _input.front)) 
    12751320            { 
    12761321                ++_current.field[1]; 
    12771322                _input.popFront; 
    12781323            } 
    12791324        } 
    12801325    } 
    12811326 
    1282     bool empty() 
     1327    @property bool empty() 
    12831328    { 
    12841329        return _current.field[1] == 0; 
    12851330    } 
    12861331 
    1287     ref Tuple!(ElementType!R, uint) front() 
     1332    @property ref Tuple!(ElementType!R, uint) front() 
    12881333    { 
    12891334        assert(!empty); 
    12901335        return _current; 
     1336    } 
     1337 
     1338    static if(isForwardRange!R) { 
     1339        @property typeof(this) save() { 
     1340            typeof(this) ret; 
     1341            ret._input = this._input.save; 
     1342            ret._current = this._current; 
     1343 
     1344            return ret; 
     1345        } 
    12911346    } 
    12921347} 
    12931348 
    12941349/// Ditto 
    12951350Group!(pred, Range) group(alias pred = "a == b", Range)(Range r) 
    12961351{ 
    12971352    return typeof(return)(r); 
    12981353} 
    12991354 
    13001355unittest 
    13011356{ 
    13021357    int[] arr = [ 1, 2, 2, 2, 2, 3, 4, 4, 4, 5 ]; 
    13031358    assert(equal(group(arr), [ tuple(1, 1u), tuple(2, 4u), tuple(3, 1u), 
    13041359                            tuple(4, 3u), tuple(5, 1u) ][])); 
     1360 
     1361    foreach(DummyType; AllDummyRanges) { 
     1362        DummyType d; 
     1363        auto g = group(d); 
     1364 
     1365        static assert(d.rt == RangeType.Input || isForwardRange!(typeof(g))); 
     1366 
     1367        assert(equal(g, [tuple(1, 1u), tuple(2, 1u), tuple(3, 1u), tuple(4, 1u), 
     1368            tuple(5, 1u), tuple(6, 1u), tuple(7, 1u), tuple(8, 1u), 
     1369            tuple(9, 1u), tuple(10, 1u)])); 
     1370    } 
    13051371} 
    13061372 
    13071373// overwriteAdjacent 
    13081374/* 
    13091375Reduces $(D r) by shifting it to the left until no adjacent elements 
    13101376$(D a), $(D b) remain in $(D r) such that $(D pred(a, b)). Shifting is 
    13111377performed by evaluating $(D move(source, target)) as a primitive. The 
    13121378algorithm is stable and runs in $(BIGOH r.length) time. Returns the 
    13131379reduced range. 
    13141380 
  • trunk/phobos/std/range.d

    r1695 r1698  
    2121module std.range; 
    2222 
    2323public import std.array; 
    2424import std.contracts; 
    2525import std.traits; 
    2626import std.typecons; 
    2727import std.typetuple; 
    2828import std.algorithm; 
    2929import std.functional; 
    3030import std.conv; 
    31 version(unittest) 
    32 
    33     import std.container, std.conv, std.math, std.stdio; 
    34  
     31 
     32// For testing only.  This code is included in a string literal to be included 
     33// in whatever module it's needed in, so that each module that uses it can be 
     34// tested individually, without needing to link to std.range. 
     35enum dummyRanges = q{ 
    3536    // Used with the dummy ranges for testing higher order ranges. 
    3637    enum RangeType { 
    3738        Input, 
    3839        Forward, 
    3940        Bidirectional, 
    4041        Random 
    4142    } 
    4243 
    4344    enum Length { 
    4445        Yes, 
     
    139140        DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Input), 
    140141        DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Forward), 
    141142        DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Bidirectional), 
    142143        DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random), 
    143144        DummyRange!(ReturnBy.Value, Length.No, RangeType.Input), 
    144145        DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward), 
    145146        DummyRange!(ReturnBy.Value, Length.No, RangeType.Bidirectional) 
    146147    ) AllDummyRanges; 
    147148 
    148149    alias TypeTuple!(1,2,3,4,5,6,7,8,9,0,11,12,13,14,15,16) DummyIndices; 
     150}; 
     151 
     152version(unittest) 
     153{ 
     154    import std.container, std.conv, std.math, std.stdio; 
     155 
     156    mixin(dummyRanges); 
    149157} 
    150158 
    151159/** 
    152160Returns $(D true) if $(D R) is an input range. An input range must 
    153161define the primitives $(D empty), $(D popFront), and $(D front). The 
    154162following code should compile for any input range. 
    155163 
    156164---- 
    157165R r;             // can define a range object 
    158166if (r.empty) {}  // can test for empty