Changeset 1749
- Timestamp:
- 07/12/10 00:50:32 (14 years ago)
- Files:
-
- trunk/phobos/std/range.d (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/phobos/std/range.d
r1741 r1749 1 1 // Written in the D programming language. 2 2 3 3 /** 4 This module defines a few useful _range incarnations. Credit for ideas5 in building this module go to $(WEB fantascienza.net/leonardo/so/, 6 Leonardo Maffi).4 This module defines a few useful _range incarnations. Credit for some 5 of the ideas in building this module goes to $(WEB 6 fantascienza.net/leonardo/so/, Leonardo Maffi). 7 7 8 8 Macros: 9 9 10 10 WIKI = Phobos/StdRange 11 11 12 12 Copyright: Copyright Andrei Alexandrescu 2008-. 13 13 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 14 14 Authors: $(WEB erdani.org, Andrei Alexandrescu) 15 15 */ 16 16 module std.range; … … 219 219 bool empty(); 220 220 int front(); 221 221 } 222 222 static assert(isInputRange!(B)); 223 223 static assert(isInputRange!(int[])); 224 224 static assert(isInputRange!(char[])); 225 225 } 226 226 227 227 /** 228 228 Returns $(D true) if $(D R) is an output range. An output range can be 229 defined in two ways. 230 231 $(OL $(LI $(D R) might define the primitive $(D put) that accepts an 232 object convertible to $(D E). The following code should compile for 233 such an output range: 229 defined in three ways. 230 231 $(OL 232 233 $(LI $(D R) might define the primitive $(D put) that accepts an object 234 convertible to $(D E). The following code should compile for such an 235 output range: 234 236 235 237 ---- 236 238 R r; 237 239 E e; 238 240 r.put(e); // can write an element to the range 239 241 ---- 240 242 241 243 The semantics of $(D r.put(e)) an output range (not checkable during 242 244 compilation) are assumed to output $(D e) to $(D r) and advance to the 243 245 next position in $(D r), such that successive calls to $(D r.put) add 244 246 extra elements to $(D r).) 245 247 246 248 $(LI An input range with assignable elements is also an output 247 249 range. In that case, inserting elements into the range is effected 248 250 with two primitive calls: $(D r.front = e, r.popFront()). Such a range 249 functions for output only as long as it is not empty.)) 251 functions for output only as long as it is not empty.) 252 253 ---- 254 R r; 255 E e; 256 r.front = e; // can write an element to the range 257 ---- 258 259 $(LI Any $(D function) or $(D delegate) accepting arrays of $(D E) as 260 input is also a valid output range.)) 250 261 251 262 To write elements to either kind of output range, call the free 252 263 function $(D put(r, e)) defined below. That function takes the 253 264 appropriate cource of action depending on the range's kind. 254 265 */ 255 266 template isOutputRange(R, E) 256 267 { 257 268 enum bool isOutputRange = is(typeof( 258 269 { 259 R r; // can define a range object270 R r; 260 271 E e; 261 r.put(e); // can write element to range 262 }())) || isInputRange!R && is(typeof( 263 { 264 R r; // can define a range object 272 r.put(e); // can write element to range 273 }())) 274 || 275 isInputRange!R && is(typeof( 276 { 277 R r; 265 278 E e; 266 279 r.front = e; // can assign to the front of range 280 }())) 281 || 282 is(typeof( 283 { 284 R r; 285 E[] es; 286 r(es); 267 287 }())); 268 288 } 269 289 270 290 /** 271 291 Outputs $(D e) to $(D r), which must be an output range. Depending on 272 the range's kind, it either evaluates $(D r.put(e)) or $(D (r.front = 273 e, r.popFront())). 292 the range's kind, it evaluates one of the following: 293 294 $(OL 295 296 $(LI If $(D R) defines $(D put), then output is effected by evaluating 297 $(D r.put(e)).) 298 299 $(LI Else if $(D R) is an input range with assignable front, then 300 output is effected by evaluating $(D (r.front = e, r.popFront())).) 301 302 $(LI Else if $(D R) is a function type, a delegate type, or a type 303 defining $(D opCall), then output is effected by evaluating $(D 304 r(e)).) 274 305 */ 275 306 void put(R, E)(ref R r, E e) if (isOutputRange!(R, E)) 276 307 { 277 static if ( is(typeof(&r.put)))308 static if (!isArray!R && is(typeof(r.put(e)))) 278 309 { 279 310 r.put(e); 280 311 } 281 else 312 else static if (isInputRange!R && is(typeof(r.front = e))) 282 313 { 283 314 r.front = e; 284 315 r.popFront(); 316 } 317 else static if (isArray!E && is(typeof(r(e)))) 318 { 319 r(e); 320 } 321 else static if (is(typeof(r(new E[])))) 322 { 323 r((&e)[0 .. 1]); 324 } 325 else 326 { 327 static assert(false); 285 328 } 286 329 } 287 330 288 331 unittest 289 332 { 290 333 struct A {} 291 334 static assert(!isInputRange!(A)); 292 335 struct B 293 336 { 294 337 void put(int); 295 338 } 296 339 static assert(isOutputRange!(B, int)); 297 340 static assert(isOutputRange!(int[], int)); 341 } 342 343 unittest 344 { 345 void myprint(in char[] s) { writeln('[', s, ']'); } 346 static assert(isOutputRange!(typeof(&myprint), char)); 298 347 } 299 348 300 349 /** 301 350 Returns $(D true) if $(D R) is a forward range. A forward range is an 302 351 input range that can save "checkpoints" by simply copying it to 303 352 another value of the same type. Notable examples of input ranges that 304 353 are $(I not) forward ranges are file/socket ranges; copying such a 305 354 range will not save the position in the stream, and they most likely 306 355 reuse an internal buffer as the entire stream does not sit in 307 356 memory. Subsequently, advancing either the original or the copy will
