| /** | 
 | This module is a submodule of $(MREF std, range). | 
 |  | 
 | The main $(MREF std, range) module provides template-based tools for working with | 
 | ranges, but sometimes an object-based interface for ranges is needed, such as | 
 | when runtime polymorphism is required. For this purpose, this submodule | 
 | provides a number of object and $(D interface) definitions that can be used to | 
 | wrap around _range objects created by the $(MREF std, range) templates. | 
 |  | 
 | $(SCRIPT inhibitQuickIndex = 1;) | 
 | $(BOOKTABLE , | 
 |     $(TR $(TD $(LREF InputRange)) | 
 |         $(TD Wrapper for input ranges. | 
 |     )) | 
 |     $(TR $(TD $(LREF InputAssignable)) | 
 |         $(TD Wrapper for input ranges with assignable elements. | 
 |     )) | 
 |     $(TR $(TD $(LREF ForwardRange)) | 
 |         $(TD Wrapper for forward ranges. | 
 |     )) | 
 |     $(TR $(TD $(LREF ForwardAssignable)) | 
 |         $(TD Wrapper for forward ranges with assignable elements. | 
 |     )) | 
 |     $(TR $(TD $(LREF BidirectionalRange)) | 
 |         $(TD Wrapper for bidirectional ranges. | 
 |     )) | 
 |     $(TR $(TD $(LREF BidirectionalAssignable)) | 
 |         $(TD Wrapper for bidirectional ranges with assignable elements. | 
 |     )) | 
 |     $(TR $(TD $(LREF RandomAccessFinite)) | 
 |         $(TD Wrapper for finite random-access ranges. | 
 |     )) | 
 |     $(TR $(TD $(LREF RandomAccessAssignable)) | 
 |         $(TD Wrapper for finite random-access ranges with assignable elements. | 
 |     )) | 
 |     $(TR $(TD $(LREF RandomAccessInfinite)) | 
 |         $(TD Wrapper for infinite random-access ranges. | 
 |     )) | 
 |     $(TR $(TD $(LREF OutputRange)) | 
 |         $(TD Wrapper for output ranges. | 
 |     )) | 
 |     $(TR $(TD $(LREF OutputRangeObject)) | 
 |         $(TD Class that implements the $(D OutputRange) interface and wraps the | 
 |         $(D put) methods in virtual functions. | 
 |     $(TR $(TD $(LREF outputRangeObject)) | 
 |         Convenience function for creating an $(D OutputRangeObject) with a base | 
 |         range of type R that accepts types E. | 
 |     )) | 
 |     $(TR $(TD $(LREF InputRangeObject)) | 
 |         $(TD Class that implements the $(D InputRange) interface and wraps the | 
 |         input _range methods in virtual functions. | 
 |     )) | 
 |     $(TR $(TD $(LREF inputRangeObject)) | 
 |         $(TD Convenience function for creating an $(D InputRangeObject) | 
 |         of the proper type. | 
 |     )) | 
 |     $(TR $(TD $(LREF MostDerivedInputRange)) | 
 |         $(TD Returns the interface type that best matches the range.) | 
 |     )) | 
 | ) | 
 |  | 
 |  | 
 | Source: $(PHOBOSSRC std/range/_interfaces.d) | 
 |  | 
 | License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). | 
 |  | 
 | Authors: $(HTTP erdani.com, Andrei Alexandrescu), David Simcha, | 
 | and Jonathan M Davis. Credit for some of the ideas in building this module goes | 
 | to $(HTTP fantascienza.net/leonardo/so/, Leonardo Maffi). | 
 | */ | 
 | module std.range.interfaces; | 
 |  | 
 | import std.meta; | 
 | import std.range.primitives; | 
 | import std.traits; | 
 |  | 
 | /**These interfaces are intended to provide virtual function-based wrappers | 
 |  * around input ranges with element type E.  This is useful where a well-defined | 
 |  * binary interface is required, such as when a DLL function or virtual function | 
 |  * needs to accept a generic range as a parameter. Note that | 
 |  * $(REF_ALTTEXT isInputRange, isInputRange, std, range, primitives) | 
 |  * and friends check for conformance to structural interfaces | 
 |  * not for implementation of these $(D interface) types. | 
 |  * | 
 |  * Limitations: | 
 |  * | 
 |  * These interfaces are not capable of forwarding $(D ref) access to elements. | 
 |  * | 
 |  * Infiniteness of the wrapped range is not propagated. | 
 |  * | 
 |  * Length is not propagated in the case of non-random access ranges. | 
 |  * | 
 |  * See_Also: | 
 |  * $(LREF inputRangeObject) | 
 |  */ | 
 | interface InputRange(E) { | 
 |     /// | 
 |     @property E front(); | 
 |  | 
 |     /// | 
 |     E moveFront(); | 
 |  | 
 |     /// | 
 |     void popFront(); | 
 |  | 
 |     /// | 
 |     @property bool empty(); | 
 |  | 
 |     /* Measurements of the benefits of using opApply instead of range primitives | 
 |      * for foreach, using timings for iterating over an iota(100_000_000) range | 
 |      * with an empty loop body, using the same hardware in each case: | 
 |      * | 
 |      * Bare Iota struct, range primitives:  278 milliseconds | 
 |      * InputRangeObject, opApply:           436 milliseconds  (1.57x penalty) | 
 |      * InputRangeObject, range primitives:  877 milliseconds  (3.15x penalty) | 
 |      */ | 
 |  | 
 |     /**$(D foreach) iteration uses opApply, since one delegate call per loop | 
 |      * iteration is faster than three virtual function calls. | 
 |      */ | 
 |     int opApply(scope int delegate(E)); | 
 |  | 
 |     /// Ditto | 
 |     int opApply(scope int delegate(size_t, E)); | 
 |  | 
 | } | 
 |  | 
 | /// | 
 | @safe unittest | 
 | { | 
 |     import std.algorithm.iteration : map; | 
 |     import std.range : iota; | 
 |  | 
 |     void useRange(InputRange!int range) { | 
 |         // Function body. | 
 |     } | 
 |  | 
 |     // Create a range type. | 
 |     auto squares = map!"a * a"(iota(10)); | 
 |  | 
 |     // Wrap it in an interface. | 
 |     auto squaresWrapped = inputRangeObject(squares); | 
 |  | 
 |     // Use it. | 
 |     useRange(squaresWrapped); | 
 | } | 
 |  | 
 | /**Interface for a forward range of type $(D E).*/ | 
 | interface ForwardRange(E) : InputRange!E { | 
 |     /// | 
 |     @property ForwardRange!E save(); | 
 | } | 
 |  | 
 | /**Interface for a bidirectional range of type $(D E).*/ | 
 | interface BidirectionalRange(E) : ForwardRange!(E) { | 
 |     /// | 
 |     @property BidirectionalRange!E save(); | 
 |  | 
 |     /// | 
 |     @property E back(); | 
 |  | 
 |     /// | 
 |     E moveBack(); | 
 |  | 
 |     /// | 
 |     void popBack(); | 
 | } | 
 |  | 
 | /**Interface for a finite random access range of type $(D E).*/ | 
 | interface RandomAccessFinite(E) : BidirectionalRange!(E) { | 
 |     /// | 
 |     @property RandomAccessFinite!E save(); | 
 |  | 
 |     /// | 
 |     E opIndex(size_t); | 
 |  | 
 |     /// | 
 |     E moveAt(size_t); | 
 |  | 
 |     /// | 
 |     @property size_t length(); | 
 |  | 
 |     /// | 
 |     alias opDollar = length; | 
 |  | 
 |     // Can't support slicing until issues with requiring slicing for all | 
 |     // finite random access ranges are fully resolved. | 
 |     version (none) | 
 |     { | 
 |         /// | 
 |         RandomAccessFinite!E opSlice(size_t, size_t); | 
 |     } | 
 | } | 
 |  | 
 | /**Interface for an infinite random access range of type $(D E).*/ | 
 | interface RandomAccessInfinite(E) : ForwardRange!E { | 
 |     /// | 
 |     E moveAt(size_t); | 
 |  | 
 |     /// | 
 |     @property RandomAccessInfinite!E save(); | 
 |  | 
 |     /// | 
 |     E opIndex(size_t); | 
 | } | 
 |  | 
 | /**Adds assignable elements to InputRange.*/ | 
 | interface InputAssignable(E) : InputRange!E { | 
 |     /// | 
 |     @property void front(E newVal); | 
 |  | 
 |     alias front = InputRange!E.front; // overload base interface method | 
 | } | 
 |  | 
 | @safe unittest | 
 | { | 
 |     static assert(isInputRange!(InputAssignable!int)); | 
 | } | 
 |  | 
 | /**Adds assignable elements to ForwardRange.*/ | 
 | interface ForwardAssignable(E) : InputAssignable!E, ForwardRange!E { | 
 |     /// | 
 |     @property ForwardAssignable!E save(); | 
 | } | 
 |  | 
 | /**Adds assignable elements to BidirectionalRange.*/ | 
 | interface BidirectionalAssignable(E) : ForwardAssignable!E, BidirectionalRange!E { | 
 |     /// | 
 |     @property BidirectionalAssignable!E save(); | 
 |  | 
 |     /// | 
 |     @property void back(E newVal); | 
 | } | 
 |  | 
 | /**Adds assignable elements to RandomAccessFinite.*/ | 
 | interface RandomFiniteAssignable(E) : RandomAccessFinite!E, BidirectionalAssignable!E { | 
 |     /// | 
 |     @property RandomFiniteAssignable!E save(); | 
 |  | 
 |     /// | 
 |     void opIndexAssign(E val, size_t index); | 
 | } | 
 |  | 
 | /**Interface for an output range of type $(D E).  Usage is similar to the | 
 |  * $(D InputRange) interface and descendants.*/ | 
 | interface OutputRange(E) { | 
 |     /// | 
 |     void put(E); | 
 | } | 
 |  | 
 | @safe unittest | 
 | { | 
 |     // 6973 | 
 |     static assert(isOutputRange!(OutputRange!int, int)); | 
 | } | 
 |  | 
 |  | 
 | // CTFE function that generates mixin code for one put() method for each | 
 | // type E. | 
 | private string putMethods(E...)() | 
 | { | 
 |     import std.conv : to; | 
 |  | 
 |     string ret; | 
 |  | 
 |     foreach (ti, Unused; E) | 
 |     { | 
 |         ret ~= "void put(E[" ~ to!string(ti) ~ "] e) { .put(_range, e); }"; | 
 |     } | 
 |  | 
 |     return ret; | 
 | } | 
 |  | 
 | /**Implements the $(D OutputRange) interface for all types E and wraps the | 
 |  * $(D put) method for each type $(D E) in a virtual function. | 
 |  */ | 
 | class OutputRangeObject(R, E...) : staticMap!(OutputRange, E) { | 
 |     // @BUG 4689:  There should be constraints on this template class, but | 
 |     // DMD won't let me put them in. | 
 |     private R _range; | 
 |  | 
 |     /// | 
 |     this(R range) { | 
 |         this._range = range; | 
 |     } | 
 |  | 
 |     mixin(putMethods!E()); | 
 | } | 
 |  | 
 |  | 
 | /**Returns the interface type that best matches $(D R).*/ | 
 | template MostDerivedInputRange(R) | 
 | if (isInputRange!(Unqual!R)) | 
 | { | 
 |     private alias E = ElementType!R; | 
 |  | 
 |     static if (isRandomAccessRange!R) | 
 |     { | 
 |         static if (isInfinite!R) | 
 |         { | 
 |             alias MostDerivedInputRange = RandomAccessInfinite!E; | 
 |         } | 
 |         else static if (hasAssignableElements!R) | 
 |         { | 
 |             alias MostDerivedInputRange = RandomFiniteAssignable!E; | 
 |         } | 
 |         else | 
 |         { | 
 |             alias MostDerivedInputRange = RandomAccessFinite!E; | 
 |         } | 
 |     } | 
 |     else static if (isBidirectionalRange!R) | 
 |     { | 
 |         static if (hasAssignableElements!R) | 
 |         { | 
 |             alias MostDerivedInputRange = BidirectionalAssignable!E; | 
 |         } | 
 |         else | 
 |         { | 
 |             alias MostDerivedInputRange = BidirectionalRange!E; | 
 |         } | 
 |     } | 
 |     else static if (isForwardRange!R) | 
 |     { | 
 |         static if (hasAssignableElements!R) | 
 |         { | 
 |             alias MostDerivedInputRange = ForwardAssignable!E; | 
 |         } | 
 |         else | 
 |         { | 
 |             alias MostDerivedInputRange = ForwardRange!E; | 
 |         } | 
 |     } | 
 |     else | 
 |     { | 
 |         static if (hasAssignableElements!R) | 
 |         { | 
 |             alias MostDerivedInputRange = InputAssignable!E; | 
 |         } | 
 |         else | 
 |         { | 
 |             alias MostDerivedInputRange = InputRange!E; | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | /**Implements the most derived interface that $(D R) works with and wraps | 
 |  * all relevant range primitives in virtual functions.  If $(D R) is already | 
 |  * derived from the $(D InputRange) interface, aliases itself away. | 
 |  */ | 
 | template InputRangeObject(R) | 
 | if (isInputRange!(Unqual!R)) | 
 | { | 
 |     static if (is(R : InputRange!(ElementType!R))) | 
 |     { | 
 |         alias InputRangeObject = R; | 
 |     } | 
 |     else static if (!is(Unqual!R == R)) | 
 |     { | 
 |         alias InputRangeObject = InputRangeObject!(Unqual!R); | 
 |     } | 
 |     else | 
 |     { | 
 |  | 
 |         /// | 
 |         class InputRangeObject : MostDerivedInputRange!(R) { | 
 |             private R _range; | 
 |             private alias E = ElementType!R; | 
 |  | 
 |             this(R range) { | 
 |                 this._range = range; | 
 |             } | 
 |  | 
 |             @property E front() { return _range.front; } | 
 |  | 
 |             E moveFront() { | 
 |                 return _range.moveFront(); | 
 |             } | 
 |  | 
 |             void popFront() { _range.popFront(); } | 
 |             @property bool empty() { return _range.empty; } | 
 |  | 
 |             static if (isForwardRange!R) | 
 |             { | 
 |                 @property typeof(this) save() { | 
 |                     return new typeof(this)(_range.save); | 
 |                 } | 
 |             } | 
 |  | 
 |             static if (hasAssignableElements!R) | 
 |             { | 
 |                 @property void front(E newVal) { | 
 |                     _range.front = newVal; | 
 |                 } | 
 |             } | 
 |  | 
 |             static if (isBidirectionalRange!R) | 
 |             { | 
 |                 @property E back() { return _range.back; } | 
 |  | 
 |                 E moveBack() { | 
 |                     return _range.moveBack(); | 
 |                 } | 
 |  | 
 |                 void popBack() { return _range.popBack(); } | 
 |  | 
 |                 static if (hasAssignableElements!R) | 
 |                 { | 
 |                     @property void back(E newVal) { | 
 |                         _range.back = newVal; | 
 |                     } | 
 |                 } | 
 |             } | 
 |  | 
 |             static if (isRandomAccessRange!R) | 
 |             { | 
 |                 E opIndex(size_t index) { | 
 |                     return _range[index]; | 
 |                 } | 
 |  | 
 |                 E moveAt(size_t index) { | 
 |                     return _range.moveAt(index); | 
 |                 } | 
 |  | 
 |                 static if (hasAssignableElements!R) | 
 |                 { | 
 |                     void opIndexAssign(E val, size_t index) { | 
 |                         _range[index] = val; | 
 |                     } | 
 |                 } | 
 |  | 
 |                 static if (!isInfinite!R) | 
 |                 { | 
 |                     @property size_t length() { | 
 |                         return _range.length; | 
 |                     } | 
 |  | 
 |                     alias opDollar = length; | 
 |  | 
 |                     // Can't support slicing until all the issues with | 
 |                     // requiring slicing support for finite random access | 
 |                     // ranges are resolved. | 
 |                     version (none) | 
 |                     { | 
 |                         typeof(this) opSlice(size_t lower, size_t upper) { | 
 |                             return new typeof(this)(_range[lower .. upper]); | 
 |                         } | 
 |                     } | 
 |                 } | 
 |             } | 
 |  | 
 |             // Optimization:  One delegate call is faster than three virtual | 
 |             // function calls.  Use opApply for foreach syntax. | 
 |             int opApply(scope int delegate(E) dg) { | 
 |                 int res; | 
 |  | 
 |                 for (auto r = _range; !r.empty; r.popFront()) | 
 |                 { | 
 |                     res = dg(r.front); | 
 |                     if (res) break; | 
 |                 } | 
 |  | 
 |                 return res; | 
 |             } | 
 |  | 
 |             int opApply(scope int delegate(size_t, E) dg) { | 
 |                 int res; | 
 |  | 
 |                 size_t i = 0; | 
 |                 for (auto r = _range; !r.empty; r.popFront()) | 
 |                 { | 
 |                     res = dg(i, r.front); | 
 |                     if (res) break; | 
 |                     i++; | 
 |                 } | 
 |  | 
 |                 return res; | 
 |             } | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | /**Convenience function for creating an $(D InputRangeObject) of the proper type. | 
 |  * See $(LREF InputRange) for an example. | 
 |  */ | 
 | InputRangeObject!R inputRangeObject(R)(R range) | 
 | if (isInputRange!R) | 
 | { | 
 |     static if (is(R : InputRange!(ElementType!R))) | 
 |     { | 
 |         return range; | 
 |     } | 
 |     else | 
 |     { | 
 |         return new InputRangeObject!R(range); | 
 |     } | 
 | } | 
 |  | 
 | /**Convenience function for creating an $(D OutputRangeObject) with a base range | 
 |  * of type $(D R) that accepts types $(D E). | 
 | */ | 
 | template outputRangeObject(E...) { | 
 |  | 
 |     /// | 
 |     OutputRangeObject!(R, E) outputRangeObject(R)(R range) { | 
 |         return new OutputRangeObject!(R, E)(range); | 
 |     } | 
 | } | 
 |  | 
 | /// | 
 | @safe unittest | 
 | { | 
 |      import std.array; | 
 |      auto app = appender!(uint[])(); | 
 |      auto appWrapped = outputRangeObject!(uint, uint[])(app); | 
 |      static assert(is(typeof(appWrapped) : OutputRange!(uint[]))); | 
 |      static assert(is(typeof(appWrapped) : OutputRange!(uint))); | 
 | } | 
 |  | 
 | @system unittest | 
 | { | 
 |     import std.algorithm.comparison : equal; | 
 |     import std.array; | 
 |     import std.internal.test.dummyrange; | 
 |  | 
 |     static void testEquality(R)(iInputRange r1, R r2) { | 
 |         assert(equal(r1, r2)); | 
 |     } | 
 |  | 
 |     auto arr = [1,2,3,4]; | 
 |     RandomFiniteAssignable!int arrWrapped = inputRangeObject(arr); | 
 |     static assert(isRandomAccessRange!(typeof(arrWrapped))); | 
 |     //    static assert(hasSlicing!(typeof(arrWrapped))); | 
 |     static assert(hasLength!(typeof(arrWrapped))); | 
 |     arrWrapped[0] = 0; | 
 |     assert(arr[0] == 0); | 
 |     assert(arr.moveFront() == 0); | 
 |     assert(arr.moveBack() == 4); | 
 |     assert(arr.moveAt(1) == 2); | 
 |  | 
 |     foreach (elem; arrWrapped) {} | 
 |     foreach (i, elem; arrWrapped) {} | 
 |  | 
 |     assert(inputRangeObject(arrWrapped) is arrWrapped); | 
 |  | 
 |     foreach (DummyType; AllDummyRanges) | 
 |     { | 
 |         auto d = DummyType.init; | 
 |         static assert(propagatesRangeType!(DummyType, | 
 |                         typeof(inputRangeObject(d)))); | 
 |         static assert(propagatesRangeType!(DummyType, | 
 |                         MostDerivedInputRange!DummyType)); | 
 |         InputRange!uint wrapped = inputRangeObject(d); | 
 |         assert(equal(wrapped, d)); | 
 |     } | 
 |  | 
 |     // Test output range stuff. | 
 |     auto app = appender!(uint[])(); | 
 |     auto appWrapped = outputRangeObject!(uint, uint[])(app); | 
 |     static assert(is(typeof(appWrapped) : OutputRange!(uint[]))); | 
 |     static assert(is(typeof(appWrapped) : OutputRange!(uint))); | 
 |  | 
 |     appWrapped.put(1); | 
 |     appWrapped.put([2, 3]); | 
 |     assert(app.data.length == 3); | 
 |     assert(equal(app.data, [1,2,3])); | 
 | } |