range.adapter: Add container-range adapters. Fix #67
This commit is contained in:
		| @@ -28,24 +28,67 @@ version (unittest) | ||||
|     } | ||||
| } | ||||
|  | ||||
| package (tanya) auto backInserter(Container)(return ref Container container) | ||||
| private mixin template InserterCtor() | ||||
| { | ||||
|     private Container* container; | ||||
|  | ||||
|     this(ref Container container) @trusted | ||||
|     { | ||||
|         this.container = &container; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * If $(D_PARAM container) is a container with `insertBack`-support, | ||||
|  * $(D_PSYMBOL backInserter) returns an output range that puts the elements | ||||
|  * into the container with `insertBack`. | ||||
|  * | ||||
|  * The resulting output range supports all types `insertBack` supports. | ||||
|  * | ||||
|  * The range keeps a reference to the container passed to it, it doesn't use | ||||
|  * any other storage. So there is no method to get the written data out of the | ||||
|  * range - the container passed to $(D_PSYMBOL backInserter) contains that data | ||||
|  * and can be used directly after all operations on the output range are | ||||
|  * completed. It also means that the result range is not allowed to outlive its | ||||
|  * container. | ||||
|  * | ||||
|  * Params: | ||||
|  *  Container = Container type. | ||||
|  *  container = Container used as an output range. | ||||
|  * | ||||
|  * Returns: `insertBack`-based output range. | ||||
|  */ | ||||
| auto backInserter(Container)(return scope ref Container container) | ||||
| if (hasMember!(Container, "insertBack")) | ||||
| { | ||||
|     static struct BackInserter | ||||
|     static struct Inserter | ||||
|     { | ||||
|         private Container* container; | ||||
|  | ||||
|         this(ref Container container) @trusted | ||||
|         { | ||||
|             this.container = &container; | ||||
|         } | ||||
|  | ||||
|         void opCall(T)(auto ref T data) | ||||
|         { | ||||
|             this.container.insertBack(forward!data); | ||||
|         } | ||||
|  | ||||
|         mixin InserterCtor; | ||||
|     } | ||||
|     return BackInserter(container); | ||||
|     return Inserter(container); | ||||
| } | ||||
|  | ||||
| /// | ||||
| @nogc nothrow pure @safe unittest | ||||
| { | ||||
|     static struct Container | ||||
|     { | ||||
|         int element; | ||||
|  | ||||
|         void insertBack(int element) | ||||
|         { | ||||
|             this.element = element; | ||||
|         } | ||||
|     } | ||||
|     Container container; | ||||
|     backInserter(container)(5); | ||||
|  | ||||
|     assert(container.element == 5); | ||||
| } | ||||
|  | ||||
| @nogc nothrow pure @safe unittest | ||||
| @@ -63,3 +106,56 @@ if (hasMember!(Container, "insertBack")) | ||||
|     Container container; | ||||
|     static assert(isOutputRange!(typeof(backInserter(container)), string)); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * If $(D_PARAM container) is a container with `insertFront`-support, | ||||
|  * $(D_PSYMBOL frontInserter) returns an output range that puts the elements | ||||
|  * into the container with `insertFront`. | ||||
|  * | ||||
|  * The resulting output range supports all types `insertFront` supports. | ||||
|  * | ||||
|  * The range keeps a reference to the container passed to it, it doesn't use | ||||
|  * any other storage. So there is no method to get the written data out of the | ||||
|  * range - the container passed to $(D_PSYMBOL frontInserter) contains that data | ||||
|  * and can be used directly after all operations on the output range are | ||||
|  * completed. It also means that the result range is not allowed to outlive its | ||||
|  * container. | ||||
|  * | ||||
|  * Params: | ||||
|  *  Container = Container type. | ||||
|  *  container = Container used as an output range. | ||||
|  * | ||||
|  * Returns: `insertFront`-based output range. | ||||
|  */ | ||||
| auto frontInserter(Container)(return scope ref Container container) | ||||
| if (hasMember!(Container, "insertFront")) | ||||
| { | ||||
|     static struct Inserter | ||||
|     { | ||||
|         void opCall(T)(auto ref T data) | ||||
|         { | ||||
|             this.container.insertFront(forward!data); | ||||
|         } | ||||
|  | ||||
|         mixin InserterCtor; | ||||
|     } | ||||
|     return Inserter(container); | ||||
| } | ||||
|  | ||||
| /// | ||||
| @nogc nothrow pure @safe unittest | ||||
| { | ||||
|     static struct Container | ||||
|     { | ||||
|         int element; | ||||
|  | ||||
|         void insertFront(int element) | ||||
|         { | ||||
|             this.element = element; | ||||
|         } | ||||
|     } | ||||
|     Container container; | ||||
|     frontInserter(container)(5); | ||||
|  | ||||
|     assert(container.element == 5); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user