| /** | |
| This module contains some common utilities used by containers. | |
| This module is a submodule of $(MREF std, container). | |
| Source: $(PHOBOSSRC std/container/util.d) | |
| Copyright: 2010- Andrei Alexandrescu. All rights reserved by the respective holders. | |
| License: Distributed under the Boost Software License, Version 1.0. | |
| (See accompanying file LICENSE_1_0.txt or copy at $(HTTP | |
| boost.org/LICENSE_1_0.txt)). | |
| Authors: $(HTTP erdani.com, Andrei Alexandrescu) | |
| $(SCRIPT inhibitQuickIndex = 1;) | |
| */ | |
| module std.container.util; | |
| /** | |
| Returns an initialized object. This function is mainly for eliminating | |
| construction differences between structs and classes. It allows code to not | |
| worry about whether the type it's constructing is a struct or a class. | |
| */ | |
| template make(T) | |
| if (is(T == struct) || is(T == class)) | |
| { | |
| T make(Args...)(Args arguments) | |
| if (is(T == struct) && __traits(compiles, T(arguments))) | |
| { | |
| // constructing an std.container.Array without arguments, | |
| // does not initialize its payload and is equivalent | |
| // to a null reference. We therefore construct an empty container | |
| // by passing an empty array to its constructor. | |
| // https://issues.dlang.org/show_bug.cgi?id=13872. | |
| static if (arguments.length == 0) | |
| { | |
| import std.range.primitives : ElementType; | |
| alias ET = ElementType!(T.Range); | |
| return T(ET[].init); | |
| } | |
| else | |
| return T(arguments); | |
| } | |
| T make(Args...)(Args arguments) | |
| if (is(T == class) && __traits(compiles, new T(arguments))) | |
| { | |
| return new T(arguments); | |
| } | |
| } | |
| /// | |
| @system unittest | |
| { | |
| import std.algorithm.comparison : equal; | |
| import std.container; | |
| auto arr = make!(Array!int)([4, 2, 3, 1]); | |
| assert(equal(arr[], [4, 2, 3, 1])); | |
| auto rbt = make!(RedBlackTree!(int, "a > b"))([4, 2, 3, 1]); | |
| assert(equal(rbt[], [4, 3, 2, 1])); | |
| alias makeList = make!(SList!int); | |
| auto slist = makeList(1, 2, 3); | |
| assert(equal(slist[], [1, 2, 3])); | |
| } | |
| @system unittest | |
| { | |
| import std.algorithm.comparison : equal; | |
| import std.container; | |
| auto arr1 = make!(Array!dchar)(); | |
| assert(arr1.empty); | |
| auto arr2 = make!(Array!dchar)("hello"d); | |
| assert(equal(arr2[], "hello"d)); | |
| auto rtb1 = make!(RedBlackTree!dchar)(); | |
| assert(rtb1.empty); | |
| auto rtb2 = make!(RedBlackTree!dchar)('h', 'e', 'l', 'l', 'o'); | |
| assert(equal(rtb2[], "ehlo"d)); | |
| } | |
| // https://issues.dlang.org/show_bug.cgi?id=8895 | |
| @safe unittest | |
| { | |
| import std.algorithm.comparison : equal; | |
| import std.container; | |
| auto a = make!(DList!int)(1,2,3,4); | |
| auto b = make!(DList!int)(1,2,3,4); | |
| auto c = make!(DList!int)(1,2,3,5); | |
| auto d = make!(DList!int)(1,2,3,4,5); | |
| assert(a == b); // this better terminate! | |
| assert(a != c); | |
| assert(a != d); | |
| } | |
| /** | |
| * Convenience function for constructing a generic container. | |
| */ | |
| template make(alias Container, Args...) | |
| if (!is(Container)) | |
| { | |
| import std.range : isInputRange, isInfinite; | |
| import std.traits : isDynamicArray; | |
| auto make(Range)(Range range) | |
| if (!isDynamicArray!Range && isInputRange!Range && !isInfinite!Range) | |
| { | |
| import std.range : ElementType; | |
| return .make!(Container!(ElementType!Range, Args))(range); | |
| } | |
| auto make(T)(T[] items...) | |
| if (!isInfinite!T) | |
| { | |
| return .make!(Container!(T, Args))(items); | |
| } | |
| } | |
| /// forbid construction from infinite range | |
| @safe unittest | |
| { | |
| import std.container.array : Array; | |
| import std.range : only, repeat; | |
| import std.range.primitives : isInfinite; | |
| static assert(__traits(compiles, { auto arr = make!Array(only(5)); })); | |
| static assert(!__traits(compiles, { auto arr = make!Array(repeat(5)); })); | |
| } | |
| /// | |
| @system unittest | |
| { | |
| import std.algorithm.comparison : equal; | |
| import std.container.array, std.container.rbtree, std.container.slist; | |
| import std.range : iota; | |
| auto arr = make!Array(iota(5)); | |
| assert(equal(arr[], [0, 1, 2, 3, 4])); | |
| auto rbtmax = make!(RedBlackTree, "a > b")(iota(5)); | |
| assert(equal(rbtmax[], [4, 3, 2, 1, 0])); | |
| auto rbtmin = make!RedBlackTree(4, 1, 3, 2); | |
| assert(equal(rbtmin[], [1, 2, 3, 4])); | |
| alias makeList = make!SList; | |
| auto list = makeList(1, 7, 42); | |
| assert(equal(list[], [1, 7, 42])); | |
| } | |
| @safe unittest | |
| { | |
| import std.algorithm.comparison : equal; | |
| import std.container.rbtree; | |
| auto rbtmin = make!(RedBlackTree, "a < b", false)(3, 2, 2, 1); | |
| assert(equal(rbtmin[], [1, 2, 3])); | |
| } | |
| // https://issues.dlang.org/show_bug.cgi?id=13872 | |
| @system unittest | |
| { | |
| import std.container; | |
| auto tree1 = make!(RedBlackTree!int)(); | |
| auto refToTree1 = tree1; | |
| refToTree1.insert(1); | |
| assert(1 in tree1); | |
| auto array1 = make!(Array!int)(); | |
| auto refToArray1 = array1; | |
| refToArray1.insertBack(1); | |
| assert(!array1.empty); | |
| auto slist = make!(SList!int)(); | |
| auto refToSlist = slist; | |
| refToSlist.insert(1); | |
| assert(!slist.empty); | |
| auto dlist = make!(DList!int)(); | |
| auto refToDList = dlist; | |
| refToDList.insert(1); | |
| assert(!dlist.empty); | |
| } |