From 000c16d447bcab0e4d2193cf75a6ed327f5bc833 Mon Sep 17 00:00:00 2001 From: "gabriel.gheorghe" Date: Sat, 10 Nov 2018 15:49:52 +0200 Subject: [PATCH] Allow containers to be used in safe code entirely (#115) --- src/containers/cyclicbuffer.d | 2 ++ src/containers/dynamicarray.d | 4 +++- src/containers/hashmap.d | 12 +++++++----- src/containers/hashset.d | 8 +++++--- src/containers/immutablehashset.d | 2 ++ src/containers/internal/hash.d | 2 +- src/containers/openhashset.d | 2 ++ src/containers/simdset.d | 4 +++- src/containers/slist.d | 8 +++++--- src/containers/treemap.d | 20 +++++++++++--------- src/containers/ttree.d | 26 ++++++++++++++------------ src/containers/unrolledlist.d | 8 +++++--- 12 files changed, 60 insertions(+), 38 deletions(-) diff --git a/src/containers/cyclicbuffer.d b/src/containers/cyclicbuffer.d index 9c83c9c..c0a5cab 100644 --- a/src/containers/cyclicbuffer.d +++ b/src/containers/cyclicbuffer.d @@ -7,6 +7,8 @@ module containers.cyclicbuffer; +@trusted: + private import core.exception : onRangeError; private import stdx.allocator.mallocator : Mallocator; private import std.range.primitives : empty, front, back, popFront, popBack; diff --git a/src/containers/dynamicarray.d b/src/containers/dynamicarray.d index 87a2ec3..19726d4 100644 --- a/src/containers/dynamicarray.d +++ b/src/containers/dynamicarray.d @@ -7,6 +7,8 @@ module containers.dynamicarray; +@trusted: + private import containers.internal.node : shouldAddGCRange; private import stdx.allocator.mallocator : Mallocator; @@ -563,7 +565,7 @@ version(emsi_containers_unittest) unittest } -version(emsi_containers_unittest) @system unittest +version(emsi_containers_unittest) unittest { DynamicArray!int a; a.reserve(1000); diff --git a/src/containers/hashmap.d b/src/containers/hashmap.d index 2520ebb..45f722a 100644 --- a/src/containers/hashmap.d +++ b/src/containers/hashmap.d @@ -7,6 +7,8 @@ module containers.hashmap; +@trusted: + private import containers.internal.hash; private import containers.internal.node : shouldAddGCRange; private import stdx.allocator.mallocator : Mallocator; @@ -189,7 +191,7 @@ struct HashMap(K, V, Allocator = Mallocator, alias hashFunction = generateHash!K * Returns: pointer to the value corresponding to the given key, * or null if the key is not present in the HashMap. */ - inout(V)* opBinaryRight(string op)(const K key) inout nothrow @trusted if (op == "in") + inout(V)* opBinaryRight(string op)(const K key) inout nothrow if (op == "in") { size_t i; auto n = find(key, i); @@ -237,7 +239,7 @@ struct HashMap(K, V, Allocator = Mallocator, alias hashFunction = generateHash!K /** * Returns: a range of the keys in this map. */ - auto byKey(this This)() inout @trusted + auto byKey(this This)() inout { return MapRange!(This, IterType.key)(cast(Unqual!(This)*) &this); } @@ -266,7 +268,7 @@ struct HashMap(K, V, Allocator = Mallocator, alias hashFunction = generateHash!K /** * Returns: a range of the values in this map. */ - auto byValue(this This)() inout @trusted + auto byValue(this This)() inout { return MapRange!(This, IterType.value)(cast(Unqual!(This)*) &this); } @@ -298,7 +300,7 @@ struct HashMap(K, V, Allocator = Mallocator, alias hashFunction = generateHash!K * Returns: a range of the kev/value pairs in this map. The element type of * this range is a struct with `key` and `value` fields. */ - auto byKeyValue(this This)() inout @trusted + auto byKeyValue(this This)() inout { return MapRange!(This, IterType.both)(cast(Unqual!(This)*) &this); } @@ -512,7 +514,7 @@ private: /** * Rehash the map. */ - void rehash() @trusted + void rehash() { import std.conv : emplace; immutable size_t newLength = buckets.length << 1; diff --git a/src/containers/hashset.d b/src/containers/hashset.d index 431163f..484da8f 100644 --- a/src/containers/hashset.d +++ b/src/containers/hashset.d @@ -7,6 +7,8 @@ module containers.hashset; +@trusted: + private import containers.internal.hash : generateHash, hashToIndex; private import containers.internal.node : shouldAddGCRange; private import stdx.allocator.mallocator : Mallocator; @@ -193,7 +195,7 @@ struct HashSet(T, Allocator = Mallocator, alias hashFunction = generateHash!T, /** * Forward range interface */ - auto opSlice(this This)() nothrow @nogc @trusted + auto opSlice(this This)() nothrow @nogc { return Range!(This)(&this); } @@ -250,7 +252,7 @@ private: return cast(ET) currentNode.items[nodeIndex].value; } - void popFront() nothrow @trusted @nogc + void popFront() nothrow @nogc { if (nodeIndex + 1 < currentNode.l) { @@ -308,7 +310,7 @@ private: return (numberOfNodes / cast(float) buckets.length) > 0.75f; } - void rehash() @trusted + void rehash() { import stdx.allocator : makeArray, dispose; import core.memory : GC; diff --git a/src/containers/immutablehashset.d b/src/containers/immutablehashset.d index d08d804..a1f9895 100644 --- a/src/containers/immutablehashset.d +++ b/src/containers/immutablehashset.d @@ -7,6 +7,8 @@ module containers.immutablehashset; +@trusted: + /** * The immutable hash set is useful for constructing a read-only collection that * supports quickly determining if an element is present. diff --git a/src/containers/internal/hash.d b/src/containers/internal/hash.d index f28fd81..111ed95 100644 --- a/src/containers/internal/hash.d +++ b/src/containers/internal/hash.d @@ -23,7 +23,7 @@ else /** * A variant of the FNV-1a (64) hashing algorithm. */ - hash_t generateHash(T)(T value) pure nothrow @nogc @trusted if (is(T == string)) + hash_t generateHash(T)(T value) pure nothrow @nogc if (is(T == string)) { hash_t h = 0xcbf29ce484222325; foreach (const ubyte c; cast(ubyte[]) value) diff --git a/src/containers/openhashset.d b/src/containers/openhashset.d index 5e30644..4ec6db3 100644 --- a/src/containers/openhashset.d +++ b/src/containers/openhashset.d @@ -6,6 +6,8 @@ */ module containers.openhashset; +@trusted: + private import containers.internal.hash; private import containers.internal.node : shouldAddGCRange; private import stdx.allocator.common : stateSize; diff --git a/src/containers/simdset.d b/src/containers/simdset.d index adb95b6..d61c108 100644 --- a/src/containers/simdset.d +++ b/src/containers/simdset.d @@ -6,6 +6,8 @@ */ module containers.simdset; +@trusted: + private import stdx.allocator.mallocator : Mallocator; /** @@ -66,7 +68,7 @@ version (D_InlineAsm_X86_64) struct SimdSet(T, Allocator = Mallocator) * Returns: * true if the set contains the given item */ - bool contains(T item) const pure nothrow @nogc @trusted + bool contains(T item) const pure nothrow @nogc { if (_length == 0) return false; diff --git a/src/containers/slist.d b/src/containers/slist.d index ff3498f..25a1b35 100644 --- a/src/containers/slist.d +++ b/src/containers/slist.d @@ -7,6 +7,8 @@ module containers.slist; +@trusted: + private import containers.internal.node : shouldAddGCRange; private import stdx.allocator.mallocator : Mallocator; @@ -164,7 +166,7 @@ struct SList(T, Allocator = Mallocator, bool supportGC = shouldAddGCRange!T) * Complexity: O(1) * Params: t = the item to insert into the list */ - void insertFront(T t) @trusted + void insertFront(T t) { _front = make!Node(allocator, _front, t); static if (useGC) @@ -200,7 +202,7 @@ struct SList(T, Allocator = Mallocator, bool supportGC = shouldAddGCRange!T) * Complexity: O(length) * Returns: true if a value was removed. */ - bool remove(V)(V value) @trusted + bool remove(V)(V value) { Node* prev = null; Node* cur = _front; @@ -271,7 +273,7 @@ private: static struct Range(ThisT) { public: - ET front() pure nothrow @property @trusted @nogc + ET front() pure nothrow @property @nogc { return cast(typeof(return)) current.value; } diff --git a/src/containers/treemap.d b/src/containers/treemap.d index c54b3cd..383dc02 100644 --- a/src/containers/treemap.d +++ b/src/containers/treemap.d @@ -7,6 +7,8 @@ module containers.treemap; +@trusted: + private import containers.internal.node : shouldAddGCRange; private import stdx.allocator.mallocator : Mallocator; @@ -54,7 +56,7 @@ struct TreeMap(K, V, Allocator = Mallocator, alias less = "a < b", /** * Inserts or overwrites the given key-value pair. */ - void insert(const K key, V value) @trusted + void insert(const K key, V value) { auto tme = TreeMapElement(cast(ContainerStorageType!K) key, value); auto r = tree.equalRange(tme); @@ -85,7 +87,7 @@ struct TreeMap(K, V, Allocator = Mallocator, alias less = "a < b", /** * Returns: the value associated with the given key, or the given `defaultValue`. */ - auto get(this This)(const K key, lazy V defaultValue) inout @trusted + auto get(this This)(const K key, lazy V defaultValue) inout { alias CET = ContainerElementType!(This, V); auto tme = TreeMapElement(key); @@ -133,7 +135,7 @@ struct TreeMap(K, V, Allocator = Mallocator, alias less = "a < b", /** * Returns: true if the mapping contains the given key */ - bool containsKey(const K key) inout pure nothrow @nogc @trusted + bool containsKey(const K key) inout pure nothrow @nogc { auto tme = TreeMapElement(cast(ContainerStorageType!K) key); return tree.contains(tme); @@ -158,7 +160,7 @@ struct TreeMap(K, V, Allocator = Mallocator, alias less = "a < b", /** * Returns: a GC-allocated array of the keys in the map */ - auto keys(this This)() inout pure @property @trusted + auto keys(this This)() inout pure @property { import std.array : array; @@ -168,7 +170,7 @@ struct TreeMap(K, V, Allocator = Mallocator, alias less = "a < b", /** * Returns: a range of the keys in the map */ - auto byKey(this This)() inout pure @trusted @nogc + auto byKey(this This)() inout pure @nogc { import std.algorithm.iteration : map; alias CETK = ContainerElementType!(This, K); @@ -179,7 +181,7 @@ struct TreeMap(K, V, Allocator = Mallocator, alias less = "a < b", /** * Returns: a GC-allocated array of the values in the map */ - auto values(this This)() inout pure @property @trusted + auto values(this This)() inout pure @property { import std.array : array; @@ -189,7 +191,7 @@ struct TreeMap(K, V, Allocator = Mallocator, alias less = "a < b", /** * Returns: a range of the values in the map */ - auto byValue(this This)() inout pure @trusted @nogc + auto byValue(this This)() inout pure @nogc { import std.algorithm.iteration : map; alias CETV = ContainerElementType!(This, V); @@ -204,7 +206,7 @@ struct TreeMap(K, V, Allocator = Mallocator, alias less = "a < b", * Returns: a range of the kev/value pairs in this map. The element type of * this range is a struct with `key` and `value` fields. */ - auto byKeyValue(this This)() inout pure @trusted + auto byKeyValue(this This)() inout pure { import std.algorithm.iteration : map; alias CETV = ContainerElementType!(This, V); @@ -241,7 +243,7 @@ private: TreeType tree; } -version(emsi_containers_unittest) @system unittest +version(emsi_containers_unittest) unittest { TreeMap!(string, string) tm; tm["test1"] = "hello"; diff --git a/src/containers/ttree.d b/src/containers/ttree.d index 6ecc674..e304cfc 100644 --- a/src/containers/ttree.d +++ b/src/containers/ttree.d @@ -7,6 +7,8 @@ module containers.ttree; +@trusted: + private import containers.internal.node : shouldAddGCRange; private import containers.internal.mixins : AllocatorState; private import stdx.allocator.mallocator : Mallocator; @@ -62,7 +64,7 @@ struct TTree(T, Allocator = Mallocator, bool allowDuplicates = false, else private alias AllocatorType = void*; - ~this() @trusted + ~this() { scope(failure) assert(false); clear(); @@ -221,7 +223,7 @@ struct TTree(T, Allocator = Mallocator, bool allowDuplicates = false, * iterating because you may iterate over the same value multiple times * or skip some values entirely. */ - auto opSlice(this This)() inout @trusted @nogc + auto opSlice(this This)() inout @nogc { return Range!(This)(cast(const(Node)*) root, RangeType.all, T.init); } @@ -229,7 +231,7 @@ struct TTree(T, Allocator = Mallocator, bool allowDuplicates = false, /** * Returns: a range of elements which are less than value. */ - auto lowerBound(this This)(inout T value) inout @trusted + auto lowerBound(this This)(inout T value) inout { return Range!(This)(cast(const(Node)*) root, RangeType.lower, value); } @@ -238,7 +240,7 @@ struct TTree(T, Allocator = Mallocator, bool allowDuplicates = false, * Returns: a range of elements which are equivalent (though not necessarily * equal) to value. */ - auto equalRange(this This)(inout T value) inout @trusted + auto equalRange(this This)(inout T value) inout { return Range!(This)(cast(const(Node)*) root, RangeType.equal, value); } @@ -246,7 +248,7 @@ struct TTree(T, Allocator = Mallocator, bool allowDuplicates = false, /** * Returns: a range of elements which are greater than value. */ - auto upperBound(this This)(inout T value) inout @trusted + auto upperBound(this This)(inout T value) inout { return Range!(This)(cast(const(Node)*) root, RangeType.upper, value); } @@ -254,7 +256,7 @@ struct TTree(T, Allocator = Mallocator, bool allowDuplicates = false, /** * Returns: the first element in the tree. */ - inout(T) front(this This)() inout pure @trusted @property + inout(T) front(this This)() inout pure @property { import std.exception : enforce; @@ -269,7 +271,7 @@ struct TTree(T, Allocator = Mallocator, bool allowDuplicates = false, /** * Returns: the last element in the tree. */ - inout(T) back(this This)() inout pure @trusted @property + inout(T) back(this This)() inout pure @property { import std.exception : enforce; @@ -331,7 +333,7 @@ struct TTree(T, Allocator = Mallocator, bool allowDuplicates = false, // when comparing nodes. Normal users of the containers library cannot // get a reference to the elements because modifying them will violate // the ordering invariant of the tree. - T* _containersFront() const @property @nogc @trusted + T* _containersFront() const @property @nogc { return cast(T*) ¤t.values[index]; } @@ -518,7 +520,7 @@ private: else alias _less = binaryFun!less; - static Node* allocateNode(Value value, Node* parent, AllocatorType allocator) @trusted + static Node* allocateNode(Value value, Node* parent, AllocatorType allocator) out (result) { assert (result.left is null); @@ -601,7 +603,7 @@ private: return (registry & fullBitPattern) == 0; } - bool contains(Value value) const @trusted + bool contains(Value value) const { import std.range : assumeSorted; size_t i = nextAvailableIndex(); @@ -644,7 +646,7 @@ private: return 0; } - bool insert(T value, ref Node* root, AllocatorType allocator, bool overwrite) @trusted + bool insert(T value, ref Node* root, AllocatorType allocator, bool overwrite) in { static if (isPointer!T || is (T == class) || is (T == interface)) @@ -975,7 +977,7 @@ private: newRoot.calcHeight(); } - void fillFromChildren(ref Node* root, AllocatorType allocator) @trusted + void fillFromChildren(ref Node* root, AllocatorType allocator) { while (!isFull()) { diff --git a/src/containers/unrolledlist.d b/src/containers/unrolledlist.d index 28ae3a5..bdce2df 100644 --- a/src/containers/unrolledlist.d +++ b/src/containers/unrolledlist.d @@ -7,6 +7,8 @@ module containers.unrolledlist; +@trusted: + private import containers.internal.node : shouldAddGCRange; private import stdx.allocator.mallocator : Mallocator; @@ -150,7 +152,7 @@ struct UnrolledList(T, Allocator = Mallocator, * * Returns: a pointer to the inserted item. */ - T* insertAnywhere(T item) @trusted + T* insertAnywhere(T item) { Node* n = _front; while (n !is null) @@ -366,7 +368,7 @@ struct UnrolledList(T, Allocator = Mallocator, } /// Returns: a range over the list - auto opSlice(this This)() const nothrow pure @nogc @trusted + auto opSlice(this This)() const nothrow pure @nogc { return Range!(This)(_front); } @@ -390,7 +392,7 @@ struct UnrolledList(T, Allocator = Mallocator, current = null; } - ref ET front() const nothrow @property @trusted @nogc + ref ET front() const nothrow @property @nogc { return *(cast(ET*) ¤t.items[index]); //return cast(T) current.items[index];