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

Changeset 1566

Show
Ignore:
Timestamp:
05/29/10 13:43:59 (15 years ago)
Author:
rsinfu
Message:

Fixed bugzilla 3876: std.range.Take back/popBack methods don't work correctly.
Thanks to Philippe Sigaud for the proposed solution. It was helpful.

The former implementation simply used input.back for Take.back. It didn't work if input.length was larger than maxAvailable. For example:

input = [ 1, 2, 3, 4, 5 ]
s = take(input, 3) // [ 1, 2, 3 ]
s.back == input.back == 5 // wrong!

Take must pop all the excess elements from the input ([4,5] in the above example) to provide correct back element. This change makes it to do so if input is purely bidirectional. (random access is used instead if possible.)

- Added Take.opSlice
- Added some enforcement error messages

Files:

Legend:

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

    r1560 r1566  
    1212    ) 
    1313    $(BUGSFIXED 
    1414    $(LI $(BUGZILLA 2738): Rebindable should work for interfaces.) 
    1515    $(LI $(BUGZILLA 2835): std.socket.TcpSocket doesn't actually connect) 
    1616    $(LI $(BUGZILLA 3088): std.xml.check() fails on xml comments) 
    1717    $(LI $(BUGZILLA 3200): std.xml doesn't follow spec for Tag.text) 
    1818    $(LI $(BUGZILLA 3465): isIdeographic can be wrong in std.xml) 
    1919    $(LI $(BUGZILLA 3653): Problem sorting array of Rebindable) 
    2020    $(LI $(BUGZILLA 3786): bug in std.string.removechars) 
    2121    $(LI $(BUGZILLA 3873): std.range.repeat should have popBack defined) 
     22    $(LI $(BUGZILLA 3876): std.range.Take back/popBack methods don't work correctly) 
    2223    $(LI $(BUGZILLA 3880): std.regex functions with const/immutable Regex object) 
    2324    $(LI $(BUGZILLA 4109): writeln doesn't work with empty static array) 
    2425    $(LI $(BUGZILLA 4188): std.file.remove throws Exception on success) 
    2526    $(LI $(BUGZILLA 4202): Changset 1517 doesn't compile) 
    2627    $(LI $(BUGZILLA 4228): std.array.replace contains 2 bugs) 
    2728    $(LI $(BUGZILLA 4219): hasAliasing does not care about immutable) 
    2829    ) 
    2930) 
    3031 
    3132<div id=version> 
  • trunk/phobos/std/range.d

    r1536 r1566  
    11881188assert(s[4] == 5); 
    11891189assert(equal(s, [ 1, 2, 3, 4, 5 ][])); 
    11901190---- 
    11911191 */ 
    11921192 
    11931193struct Take(R) if (isInputRange!(R)) 
    11941194{ 
    11951195private: 
    11961196    R _input; 
    11971197    size_t _maxAvailable; 
    1198     enum bool byRef = is(typeof(&(R.init[0]))); 
     1198    enum bool byRef = is(typeof(&_input.front) == ElementType!(R)*); 
     1199 
     1200    enum bool backByIndex = // Take.back = input[min(n,$) - 1] 
     1201        isRandomAccessRange!(R) && (hasLength!(R) || isInfinite!(R)); 
     1202 
     1203    enum bool backByBack  = // Take.back = input.back 
     1204        !backByIndex && isBidirectionalRange!(R) && hasLength!(R); 
    11991205 
    12001206public: 
    12011207    alias R Source; 
    12021208 
    12031209    static if (byRef) 
    12041210        alias ref .ElementType!(R) ElementType; 
    12051211    else 
    12061212        alias .ElementType!(R) ElementType; 
    12071213 
     1214    this(R input, size_t maxAvailable) 
     1215    { 
     1216        static if (backByBack) 
     1217        { 
     1218            while (input.length > maxAvailable) 
     1219                input.popBack; 
     1220        } 
     1221        _input = input; 
     1222        _maxAvailable = maxAvailable; 
     1223    } 
     1224 
    12081225    bool empty() 
    12091226    { 
    12101227        return _maxAvailable == 0 || _input.empty; 
    12111228    } 
    12121229 
    12131230    void popFront() 
    12141231    { 
    1215         enforce(_maxAvailable > 0); 
     1232        enforce(_maxAvailable > 0, 
     1233            "Attenpting to popFront() past the end of a " 
     1234            ~ Take.stringof); 
    12161235        _input.popFront; 
    12171236        --_maxAvailable; 
    12181237    } 
    12191238 
    12201239    // @@@@@@@@@@@ UGLY @@@@@@@@@@@@@@@ 
    12211240    mixin( 
    12221241        (byRef ? "ref " : "")~ 
    12231242        q{ElementType front() 
    12241243        { 
    1225             enforce(_maxAvailable > 0); 
     1244            enforce(_maxAvailable > 0, 
     1245                "Attempting to fetch the front of an empty " 
     1246                ~ Take.stringof); 
    12261247            return _input.front; 
    12271248        }}); 
    12281249 
    12291250    static if (isInfinite!(R)) 
    12301251    { 
    12311252        @property size_t length() const 
    12321253        { 
    12331254            return _maxAvailable; 
    12341255        } 
    1235  
     1256    } 
     1257    else static if (hasLength!(R)) 
     1258    { 
     1259        @property size_t length() 
     1260        { 
     1261            return min(_maxAvailable, _input.length); 
     1262        } 
     1263    } 
     1264 
     1265    static if (backByIndex) 
     1266    { 
    12361267        void popBack() 
    12371268        { 
    1238             enforce(_maxAvailable); 
     1269            enforce(_maxAvailable > 0, 
     1270                "Attenpting to popBack() past the beginning of a " 
     1271                ~ Take.stringof); 
    12391272            --_maxAvailable; 
    12401273        } 
    1241     } 
    1242     else static if (hasLength!(R)) 
    1243     { 
    1244         @property size_t length() 
    1245         { 
    1246             return min(_maxAvailable, _input.length); 
    1247         } 
    1248  
    1249         static if (isBidirectionalRange!(R)) 
    1250         { 
    1251             void popBack() 
    1252             { 
    1253                 if (_maxAvailable > _input.length) 
    1254                 { 
    1255                     --_maxAvailable; 
    1256                 } 
    1257                 else 
    1258                 { 
    1259                     _input.popBack; 
    1260                 } 
    1261             } 
    1262         } 
    1263     } 
    1264  
    1265     static if (isRandomAccessRange!(R)) 
    1266     { 
     1274 
    12671275        mixin( 
    12681276            (byRef ? "ref " : "")~ 
    1269             q{ElementType opIndex(uint index) 
    1270                 { 
    1271                     enforce(_maxAvailable > index); 
    1272                     return _input[index]; 
    1273                 } 
    1274             }); 
    1275     } 
    1276  
    1277     static if (isBidirectionalRange!(R)) 
    1278     { 
     1277            q{/+auto ref+/ ElementType back() 
     1278            { 
     1279                return _input[this.length - 1]; 
     1280            }}); 
     1281    } 
     1282    else static if (backByBack) 
     1283    { 
     1284        invariant() 
     1285        { 
     1286            assert(_input.length <= _maxAvailable); 
     1287        } 
     1288 
     1289        void popBack() 
     1290        { 
     1291            enforce(_maxAvailable > 0, 
     1292                "Attenpting to popBack() past the beginning of a " 
     1293                ~ Take.stringof); 
     1294            --_maxAvailable; 
     1295            _input.popBack; 
     1296        } 
     1297 
    12791298        mixin( 
    12801299            (byRef ? "ref " : "")~ 
    1281             q{ElementType back() 
    1282                 { 
    1283                     return _input.back; 
    1284                 } 
    1285             }); 
    1286     } 
    1287     else static if (isRandomAccessRange!(R) && isInfinite!(R)) 
    1288     { 
    1289         // Random access but not bidirectional could happen in the 
    1290         // case of e.g. some infinite ranges 
     1300            q{/+auto ref+/ ElementType back() 
     1301            { 
     1302                return _input.back; 
     1303            }}); 
     1304    } 
     1305 
     1306    static if (isRandomAccessRange!(R)) 
     1307    { 
    12911308        mixin( 
    12921309            (byRef ? "ref " : "")~ 
    1293             q{ElementType back() 
    1294                 { 
    1295                     return _input[length - 1]; 
    1296                 } 
    1297             }); 
    1298     } 
     1310            q{/+auto ref+/ ElementType opIndex(size_t index) 
     1311            { 
     1312                enforce(index < this.length, 
     1313                    "Attempting to index out of the bounds of a " 
     1314                    ~ Take.stringof); 
     1315                return _input[index]; 
     1316            }}); 
     1317    } 
     1318 
     1319    Take opSlice() { return this; } 
    12991320} 
    13001321 
    13011322/// Ditto 
    13021323Take!(R) take(R)(R input, size_t n) if (isInputRange!(R)) 
    13031324{ 
    13041325    return Take!(R)(input, n); 
    13051326} 
    13061327 
    13071328unittest 
    13081329{ 
    13091330    int[] arr1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]; 
    13101331    auto s = take(arr1, 5); 
    13111332    assert(s.length == 5); 
    13121333    assert(s[4] == 5); 
    13131334    assert(equal(s, [ 1, 2, 3, 4, 5 ][])); 
     1335    assert(equal(retro(s), [ 5, 4, 3, 2, 1 ][])); 
    13141336} 
    13151337 
    13161338/** 
    13171339Eagerly advances $(D r) itself (not a copy) $(D n) times (by calling 
    13181340$(D r.popFront) $(D n) times). The pass of $(D r) into $(D popFrontN) 
    13191341is by reference, so the original range is affected. Completes in 
    13201342$(BIGOH 1) steps for ranges that support slicing, and in $(BIGOH n) 
    13211343time for all other ranges. 
    13221344 
    13231345Example: