Changeset 1698
- Timestamp:
- 06/30/10 02:30:26 (14 years ago)
- Files:
-
- trunk/docsrc/changelog.dd (modified) (1 diff)
- trunk/phobos/std/algorithm.d (modified) (8 diffs)
- trunk/phobos/std/range.d (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/docsrc/changelog.dd
r1697 r1698 2 2 3 3 $(D_S D Change Log, 4 4 5 5 6 6 $(VERSION 048, Jun 11, 2010, =================================================, 7 7 8 8 $(WHATSNEW 9 9 $(LI std.string: icmp() now works with all built-in string types.) 10 10 ) 11 11 $(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) 13 16 $(LI $(BUGZILLA 978): std.utf's toUTF* functions accept some invalid and reject some valid UTF) 14 17 $(LI $(BUGZILLA 996): Error in doc on implicit conversion between pointer and array) 15 18 $(LI $(BUGZILLA 2275): std.utf.toUTF16z() should return const(wchar)*) 16 19 $(LI $(BUGZILLA 2872): Length, opIndex for Map) 17 20 $(LI $(BUGZILLA 3202): std.math.pow cause dead loop) 18 21 $(LI $(BUGZILLA 3355): std.string.cmp works incorrectly for mixed-type and different-length strings) 19 22 $(LI $(BUGZILLA 3386): to!bool(string) is not implemented) 20 23 $(LI $(BUGZILLA 3436): std.functional.compose with only one function) 21 24 $(LI $(BUGZILLA 3439): std.range.Sequence.opIndex not consistent after calling popFront().) 22 25 $(LI $(BUGZILLA 3447): std.file uses unconventional file permissions) 23 26 $(LI $(BUGZILLA 3874): std.range.stride assumes a bidirectional input range) 24 27 $(LI $(BUGZILLA 3937): os.path.dirname fails on absolute path) 25 28 $(LI $(BUGZILLA 3961): Error with to!(somestruct)) 26 29 $(LI $(BUGZILLA 4109): (reopened) writeln doesn't work with empty static array) 27 30 $(LI $(BUGZILLA 4171): std.random.uniform does not work for a range of characters) 28 31 $(LI $(BUGZILLA 4260): windows & basename) 29 32 $(LI $(BUGZILLA 4305): Take, Chain on top of ranges w/o moveFront() ) 30 33 $(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) 32 35 $(LI $(BUGZILLA 4363): std.algorithm.Until is not a forward range) 33 36 $(LI $(BUGZILLA 4406): Typo (bug) in std.concurrency) 34 37 ) 35 38 ) 36 39 37 40 <div id=version> 38 41 $(UL 39 42 $(NEW 048) 40 43 $(NEW 047) 41 44 $(NEW 046) trunk/phobos/std/algorithm.d
r1688 r1698 46 46 module std.algorithm; 47 47 48 48 import std.c.string; 49 49 import std.array, std.container, std.contracts, std.conv, std.date, 50 50 std.functional, std.math, std.metastrings, std.range, std.string, 51 51 std.traits, std.typecons, std.typetuple; 52 52 53 53 version(unittest) 54 54 { 55 55 import std.random, std.stdio, std.string; 56 57 mixin(dummyRanges); 56 58 } 57 59 58 60 /** 59 61 Implements the homonym function (also known as $(D transform)) present 60 62 in many languages of functional flavor. The call $(D map!(fun)(range)) 61 63 returns a range of which elements are obtained by applying $(D fun(x)) 62 64 left to right for all $(D x) in $(D range). The original ranges are 63 65 not changed. Evaluation is done lazily. The range returned by $(D map) 64 66 caches the last value such that evaluating $(D front) multiple times 65 67 does not result in multiple calls to $(D fun). … … 121 123 // and wasted space when 99% of the time this range will only be iterated 122 124 // over in the forward direction. Use a bool to determine whether cache 123 125 // is front or back instead. 124 126 bool cacheIsBack; 125 127 126 128 private void fillCacheBack() { 127 129 if (!_input.empty) _cache = fun(_input.back); 128 130 cacheIsBack = true; 129 131 } 130 132 131 ElementType back() {133 @property ElementType back() { 132 134 if(!cacheIsBack) { 133 135 fillCacheBack(); 134 136 } 135 137 return _cache; 136 138 } 137 139 138 140 void popBack() { 139 141 _input.popBack; 140 142 fillCacheBack(); 141 143 } … … 161 163 @property bool empty() { 162 164 return _input.empty; 163 165 } 164 166 } 165 167 166 168 void popFront() { 167 169 _input.popFront; 168 170 fillCache; 169 171 } 170 172 171 ElementType front() {173 @property ElementType front() { 172 174 static if(isBidirectionalRange!(Range)) { 173 175 if(cacheIsBack) { 174 176 fillCache(); 175 177 } 176 178 } 177 179 return _cache; 178 180 } 179 181 180 182 static if(isRandomAccessRange!Range) { 181 183 ElementType opIndex(size_t index) { 182 184 return fun(_input[index]); 183 185 } 184 186 } 185 187 186 188 // 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() { 190 192 return _input.length; 191 193 } 192 194 } 193 195 194 196 static if(hasSlicing!(Range)) { 195 197 typeof(this) opSlice(size_t lowerBound, size_t upperBound) { 196 198 return typeof(this)(_input[lowerBound..upperBound]); 197 199 } 198 200 } 199 201 … … 259 261 fibsSquares.popFront; 260 262 assert(fibsSquares.front == 4); 261 263 fibsSquares.popFront; 262 264 assert(fibsSquares.front == 9); 263 265 264 266 auto repeatMap = map!"a"(repeat(1)); 265 267 static assert(isInfinite!(typeof(repeatMap))); 266 268 267 269 auto intRange = map!"a"([1,2,3]); 268 270 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 } 269 277 } 270 278 271 279 // reduce 272 280 /** 273 281 Implements the homonym function (also known as $(D accumulate), $(D 274 282 compress), $(D inject), or $(D foldl)) present in various programming 275 283 languages of functional flavor. The call $(D reduce!(fun)(seed, 276 284 range)) first assigns $(D seed) to an internal variable $(D result), 277 285 also called the accumulator. Then, for each element $(D x) in $(D 278 286 range), $(D result = fun(result, x)) gets evaluated. Finally, $(D … … 600 608 static assert(isForwardRange!(typeof(r))); 601 609 602 610 a = [ 1, 22, 3, 42, 5 ]; 603 611 auto under10 = filter!("a < 10")(a); 604 612 assert(equal(under10, [1, 3, 5][])); 605 613 static assert(isForwardRange!(typeof(under10))); 606 614 607 615 auto infinite = filter!"a > 2"(repeat(3)); 608 616 static assert(isInfinite!(typeof(infinite))); 609 617 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 } 610 624 } 611 625 612 626 // move 613 627 /** 614 628 Moves $(D source) into $(D target) via a destructive 615 629 copy. Specifically: $(UL $(LI If $(D hasAliasing!T) is true (see 616 630 $(XREF traits, hasAliasing)), then the representation of $(D source) 617 631 is bitwise copied into $(D target) and then $(D source = T.init) is 618 632 evaluated.) $(LI Otherwise, $(D target = source) is evaluated.)) See 619 633 also $(XREF contracts, pointsTo). … … 886 900 // foreach (x; splitter(a, 0)) { 887 901 // writeln("[", x, "]"); 888 902 // } 889 903 assert(equal(splitter(a, 0), w)); 890 904 a = null; 891 905 assert(equal(splitter(a, 0), [ (int[]).init ][])); 892 906 a = [ 0 ]; 893 907 assert(equal(splitter(a, 0), [ (int[]).init, (int[]).init ][])); 894 908 a = [ 0, 1 ]; 895 909 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 // } 896 919 } 897 920 898 921 /** 899 922 Splits a range using another range as a separator. This can be used 900 923 with any range type, but is most popular with string types. 901 924 */ 902 925 struct Splitter(Range, Separator) 903 926 if (is(typeof(Range.init.front == Separator.init.front))) 904 927 { 905 928 private: … … 1196 1219 void popFront() 1197 1220 { 1198 1221 auto last = _input.front; 1199 1222 do 1200 1223 { 1201 1224 _input.popFront; 1202 1225 } 1203 1226 while (!_input.empty && binaryFun!(pred)(last, _input.front)); 1204 1227 } 1205 1228 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; } 1214 1241 } 1215 1242 1216 1243 bool empty() { return _input.empty; } 1217 1244 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 } 1219 1251 } 1220 1252 1221 1253 /// Ditto 1222 1254 Uniq!(pred, Range) uniq(alias pred = "a == b", Range)(Range r) 1223 1255 { 1224 1256 return typeof(return)(r); 1225 1257 } 1226 1258 1227 1259 unittest 1228 1260 { 1229 1261 int[] arr = [ 1, 2, 2, 2, 2, 3, 4, 4, 4, 5 ]; 1230 1262 auto r = uniq(arr); 1231 1263 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 } 1232 1277 } 1233 1278 1234 1279 // group 1235 1280 /** 1236 1281 Similarly to $(D uniq), $(D group) iterates unique consecutive 1237 1282 elements of the given range. The element type is $(D 1238 1283 Tuple!(ElementType!R, uint)) because it includes the count of 1239 1284 equivalent elements seen. Equivalence of elements is assessed by using 1240 1285 the predicate $(D pred), by default $(D "a == b"). 1241 1286 … … 1272 1317 _current = tuple(_input.front, 1u); 1273 1318 _input.popFront; 1274 1319 while (!_input.empty && comp(_current.field[0], _input.front)) 1275 1320 { 1276 1321 ++_current.field[1]; 1277 1322 _input.popFront; 1278 1323 } 1279 1324 } 1280 1325 } 1281 1326 1282 bool empty()1327 @property bool empty() 1283 1328 { 1284 1329 return _current.field[1] == 0; 1285 1330 } 1286 1331 1287 ref Tuple!(ElementType!R, uint) front()1332 @property ref Tuple!(ElementType!R, uint) front() 1288 1333 { 1289 1334 assert(!empty); 1290 1335 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 } 1291 1346 } 1292 1347 } 1293 1348 1294 1349 /// Ditto 1295 1350 Group!(pred, Range) group(alias pred = "a == b", Range)(Range r) 1296 1351 { 1297 1352 return typeof(return)(r); 1298 1353 } 1299 1354 1300 1355 unittest 1301 1356 { 1302 1357 int[] arr = [ 1, 2, 2, 2, 2, 3, 4, 4, 4, 5 ]; 1303 1358 assert(equal(group(arr), [ tuple(1, 1u), tuple(2, 4u), tuple(3, 1u), 1304 1359 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 } 1305 1371 } 1306 1372 1307 1373 // overwriteAdjacent 1308 1374 /* 1309 1375 Reduces $(D r) by shifting it to the left until no adjacent elements 1310 1376 $(D a), $(D b) remain in $(D r) such that $(D pred(a, b)). Shifting is 1311 1377 performed by evaluating $(D move(source, target)) as a primitive. The 1312 1378 algorithm is stable and runs in $(BIGOH r.length) time. Returns the 1313 1379 reduced range. 1314 1380 trunk/phobos/std/range.d
r1695 r1698 21 21 module std.range; 22 22 23 23 public import std.array; 24 24 import std.contracts; 25 25 import std.traits; 26 26 import std.typecons; 27 27 import std.typetuple; 28 28 import std.algorithm; 29 29 import std.functional; 30 30 import 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. 35 enum dummyRanges = q{ 35 36 // Used with the dummy ranges for testing higher order ranges. 36 37 enum RangeType { 37 38 Input, 38 39 Forward, 39 40 Bidirectional, 40 41 Random 41 42 } 42 43 43 44 enum Length { 44 45 Yes, … … 139 140 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Input), 140 141 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Forward), 141 142 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Bidirectional), 142 143 DummyRange!(ReturnBy.Value, Length.Yes, RangeType.Random), 143 144 DummyRange!(ReturnBy.Value, Length.No, RangeType.Input), 144 145 DummyRange!(ReturnBy.Value, Length.No, RangeType.Forward), 145 146 DummyRange!(ReturnBy.Value, Length.No, RangeType.Bidirectional) 146 147 ) AllDummyRanges; 147 148 148 149 alias TypeTuple!(1,2,3,4,5,6,7,8,9,0,11,12,13,14,15,16) DummyIndices; 150 }; 151 152 version(unittest) 153 { 154 import std.container, std.conv, std.math, std.stdio; 155 156 mixin(dummyRanges); 149 157 } 150 158 151 159 /** 152 160 Returns $(D true) if $(D R) is an input range. An input range must 153 161 define the primitives $(D empty), $(D popFront), and $(D front). The 154 162 following code should compile for any input range. 155 163 156 164 ---- 157 165 R r; // can define a range object 158 166 if (r.empty) {} // can test for empty
