From 06fd442173bd64ee70279723df2a3ea28a4d5708 Mon Sep 17 00:00:00 2001 From: Ilya Yaroshenko Date: Thu, 8 Nov 2018 20:04:22 +0700 Subject: [PATCH 1/6] rework allFlattened --- source/mir/algorithm/iteration.d | 37 ++++++++++++++++---------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/source/mir/algorithm/iteration.d b/source/mir/algorithm/iteration.d index d83f298e..59873d50 100644 --- a/source/mir/algorithm/iteration.d +++ b/source/mir/algorithm/iteration.d @@ -536,7 +536,7 @@ private void checkShapesMatch( string fun = __FUNCTION__, string pfun = __PRETTY_FUNCTION__, Slices...) - (ref const Slices slices) + (scope ref const Slices slices) if (Slices.length > 1) { enum msg = "all arguments must be slices" ~ tailErrorMessage!(fun, pfun); @@ -569,19 +569,14 @@ template frontOf(size_t N) } } -template allFlattened(args...) +template allFlattened(size_t N) + if (N) { - static if (args.length) - { - alias arg = args[0]; - @optmath @property fwd()(){ - import mir.ndslice.topology: flattened; - return arg.flattened; - } - alias allFlattened = AliasSeq!(fwd, allFlattened!(args[1..$])); - } + enum i = N - 1; + static if (i) + enum allFlattened = .allFlattened!i ~ ("slices[" ~ i.stringof ~ "].flattened, "); else - alias allFlattened = AliasSeq!(); + enum allFlattened = "slices[" ~ i.stringof ~ "].flattened, "; } private template areAllContiguousSlices(Slices...) @@ -713,7 +708,8 @@ template reduce(alias fun) slices.checkShapesMatch; static if (areAllContiguousSlices!Slices) { - return .reduce!fun(seed, allFlattened!slices); + import mir.ndslice.topology: flattened; + return mixin(`.reduce!fun(seed, ` ~ allFlattened!(Slices.length) ~`)`); } else { @@ -735,7 +731,8 @@ template reduce(alias fun) slices.checkShapesMatch; static if (areAllContiguousSlices!Slices) { - return .reduce!fun(seed, allFlattened!slices); + import mir.ndslice.topology: flattened; + return mixin(`.reduce!fun(seed, ` ~ allFlattened!(Slices.length) ~`)`); } else { @@ -957,7 +954,8 @@ template each(alias fun) slices.checkShapesMatch; static if (areAllContiguousSlices!Slices) { - .each!fun(allFlattened!slices); + import mir.ndslice.topology: flattened; + mixin(`.each!fun(` ~ allFlattened!(Slices.length) ~`);`); } else { @@ -1992,7 +1990,8 @@ template any(alias pred = "a") slices.checkShapesMatch; static if (areAllContiguousSlices!Slices) { - return .any!pred(allFlattened!slices); + import mir.ndslice.topology: flattened; + return mixin(`.any!pred(` ~ allFlattened!(Slices.length) ~`)`); } else { @@ -2151,7 +2150,8 @@ template all(alias pred = "a") slices.checkShapesMatch; static if (areAllContiguousSlices!Slices) { - return .all!pred(allFlattened!slices); + import mir.ndslice.topology: flattened; + return mixin(`.all!pred(` ~ allFlattened!(Slices.length) ~`)`); } else { @@ -2285,7 +2285,8 @@ template count(alias fun) else static if (areAllContiguousSlices!Slices) { - return .count!fun(allFlattened!slices); + import mir.ndslice.topology: flattened; + return mixin(`.count!fun(` ~ allFlattened!(Slices.length) ~`)`); } else { From cf01cdb7fa2def950feb8b39257d42dfe6fd4c71 Mon Sep 17 00:00:00 2001 From: Ilya Yaroshenko Date: Thu, 8 Nov 2018 20:20:32 +0700 Subject: [PATCH 2/6] dip1000 ndslice upgade --- source/mir/ndslice/field.d | 20 +++--- source/mir/ndslice/iterator.d | 118 +++++++++++++++++----------------- source/mir/ndslice/ndfield.d | 67 ++++++++++--------- source/mir/ndslice/topology.d | 25 +++---- 4 files changed, 115 insertions(+), 115 deletions(-) diff --git a/source/mir/ndslice/field.d b/source/mir/ndslice/field.d index 27f2b1f9..7868d2fc 100644 --- a/source/mir/ndslice/field.d +++ b/source/mir/ndslice/field.d @@ -722,20 +722,20 @@ struct LinspaceField(T) T _start = cast(T) 0, _stop = cast(T) 0; /// - auto lightConst()() const @property + auto lightConst()() scope const @property { return LinspaceField!T(_length, _start, _stop); } /// - auto lightImmutable()() const @property + auto lightImmutable()() scope const @property { return LinspaceField!T(_length, _start, _stop); } // no fastmath /// - T opIndex()(sizediff_t index) const + T opIndex()(sizediff_t index) scope const { sizediff_t d = _length - 1; auto v = typeof(T.init.re)(d - index); @@ -750,13 +750,13 @@ struct LinspaceField(T) @optmath: /// - size_t length() const @property + size_t length() scope const @property { return _length; } /// - size_t[1] shape(size_t dimension = 0)() const @property @nogc + size_t[1] shape(size_t dimension = 0)() scope const @property @nogc if (dimension == 0) { return [_length]; @@ -776,32 +776,32 @@ struct MagicField() size_t _n; /// - auto lightConst()() const @property + auto lightConst()() scope const @property { return MagicField!()(_n); } /// - auto lightImmutable()() const @property + auto lightImmutable()() scope const @property { return MagicField!()(_n); } /// - size_t length(size_t dimension = 0)() const @property + size_t length(size_t dimension = 0)() scope const @property if(dimension <= 2) { return _n * _n; } /// - size_t[1] shape() const @property @nogc + size_t[1] shape() scope const @property @nogc { return [_n * _n]; } /// - size_t opIndex()(size_t index) const + size_t opIndex()(size_t index) scope const { auto d = index / _n; auto m = index % _n; diff --git a/source/mir/ndslice/iterator.d b/source/mir/ndslice/iterator.d index 347d27b2..eda304d5 100644 --- a/source/mir/ndslice/iterator.d +++ b/source/mir/ndslice/iterator.d @@ -50,11 +50,11 @@ version(D_Exceptions) @optmath: enum std_ops = q{ - void opUnary(string op)() + void opUnary(string op)() scope if (op == "--" || op == "++") { mixin(op ~ "_iterator;"); } - void opOpAssign(string op)(ptrdiff_t index) + void opOpAssign(string op)(ptrdiff_t index) scope if (op == "-" || op == "+") { mixin("_iterator " ~ op ~ "= index;"); } @@ -66,13 +66,13 @@ enum std_ops = q{ return ret; } - ptrdiff_t opBinary(string op : "-")(auto ref const typeof(this) right) const + ptrdiff_t opBinary(string op : "-")(auto scope ref const typeof(this) right) scope const { return this._iterator - right._iterator; } - bool opEquals()(ref const typeof(this) right) const + bool opEquals()(scope ref const typeof(this) right) scope const { return this._iterator == right._iterator; } - ptrdiff_t opCmp()(ref const typeof(this) right) const + ptrdiff_t opCmp()(scope ref const typeof(this) right) scope const { static if (isPointer!Iterator) return this._iterator - right._iterator; @@ -117,14 +117,14 @@ struct IotaIterator(I) I opUnary(string op : "*")() { return _index; } - void opUnary(string op)() + void opUnary(string op)() scope if (op == "--" || op == "++") { mixin(op ~ `_index;`); } - I opIndex()(ptrdiff_t index) const + I opIndex()(ptrdiff_t index) scope const { return cast(I)(_index + index); } - void opOpAssign(string op)(ptrdiff_t index) + void opOpAssign(string op)(ptrdiff_t index) scope if (op == `+` || op == `-`) { mixin(`_index ` ~ op ~ `= index;`); } @@ -136,13 +136,13 @@ struct IotaIterator(I) return ret; } - ptrdiff_t opBinary(string op : "-")(typeof(this) right) const + ptrdiff_t opBinary(string op : "-")(typeof(this) right) scope const { return this._index - right._index; } - bool opEquals()(typeof(this) right) const + bool opEquals()(typeof(this) right) scope const { return this._index == right._index; } - ptrdiff_t opCmp()(typeof(this) right) const + ptrdiff_t opCmp()(typeof(this) right) scope const { return this._index - right._index; } } @@ -252,10 +252,10 @@ struct RetroIterator(Iterator) auto ref opIndex()(ptrdiff_t index) { return *(_iterator - index); } - void opOpAssign(string op : "-")(ptrdiff_t index) + void opOpAssign(string op : "-")(ptrdiff_t index) scope { _iterator += index; } - void opOpAssign(string op : "+")(ptrdiff_t index) + void opOpAssign(string op : "+")(ptrdiff_t index) scope { _iterator -= index; } auto opBinary(string op)(ptrdiff_t index) @@ -266,13 +266,13 @@ struct RetroIterator(Iterator) return ret; } - ptrdiff_t opBinary(string op : "-")(auto ref const typeof(this) right) const + ptrdiff_t opBinary(string op : "-")(auto scope ref const typeof(this) right) scope const { return right._iterator - this._iterator; } - bool opEquals()(ref const typeof(this) right) const + bool opEquals()(scope ref const typeof(this) right) scope const { return right._iterator == this._iterator; } - ptrdiff_t opCmp()(ref const typeof(this) right) const + ptrdiff_t opCmp()(scope ref const typeof(this) right) scope const { static if (isPointer!Iterator) return right._iterator - this._iterator; @@ -316,7 +316,7 @@ struct RetroIterator(Iterator) assert(*retro == *iota); } -auto StrideIterator__map(Iterator, alias fun)(ref StrideIterator!Iterator it) +auto StrideIterator__map(Iterator, alias fun)(StrideIterator!Iterator it) { auto iterator = it._iterator._mapIterator!fun; return StrideIterator!(typeof(iterator))(it._stride, iterator); @@ -362,14 +362,14 @@ struct StrideIterator(Iterator) auto ref opUnary(string op : "*")() { return *_iterator; } - void opUnary(string op)() + void opUnary(string op)() scope if (op == "--" || op == "++") { mixin("_iterator " ~ op[0] ~ "= _stride;"); } auto ref opIndex()(ptrdiff_t index) { return _iterator[index * _stride]; } - void opOpAssign(string op)(ptrdiff_t index) + void opOpAssign(string op)(ptrdiff_t index) scope if (op == "-" || op == "+") { mixin("_iterator " ~ op ~ "= index * _stride;"); } @@ -381,13 +381,13 @@ struct StrideIterator(Iterator) return ret; } - ptrdiff_t opBinary(string op : "-")(auto ref const typeof(this) right) const + ptrdiff_t opBinary(string op : "-")(auto scope ref const typeof(this) right) scope const { return (this._iterator - right._iterator) / _stride; } - bool opEquals()(ref const typeof(this) right) const + bool opEquals()(scope ref const typeof(this) right) scope const { return this._iterator == right._iterator; } - ptrdiff_t opCmp()(ref const typeof(this) right) const + ptrdiff_t opCmp()(scope ref const typeof(this) right) scope const { static if (isPointer!Iterator) ptrdiff_t ret = this._iterator - right._iterator; @@ -518,7 +518,7 @@ struct ZipIterator(Iterators...) auto opUnary(string op : "*")() { return mixin("RefTuple!(_zip_types!Iterators)(" ~ _zip_fronts!Iterators ~ ")"); } - void opUnary(string op)() + void opUnary(string op)() scope if (op == "++" || op == "--") { foreach (ref _iterator; _iterators) @@ -538,7 +538,7 @@ struct ZipIterator(Iterators...) return opIndex(index); } - void opOpAssign(string op)(ptrdiff_t index) + void opOpAssign(string op)(ptrdiff_t index) scope if (op == "+" || op == "-") { foreach (ref _iterator; _iterators) @@ -553,13 +553,13 @@ struct ZipIterator(Iterators...) return ret; } - ptrdiff_t opBinary(string op : "-")(auto ref const typeof(this) right) const + ptrdiff_t opBinary(string op : "-")(auto scope ref const typeof(this) right) scope const { return this._iterators[0] - right._iterators[0]; } - bool opEquals()(ref const typeof(this) right) const + bool opEquals()(scope ref const typeof(this) right) scope const { return this._iterators[0] == right._iterators[0]; } - ptrdiff_t opCmp()(ref const typeof(this) right) const + ptrdiff_t opCmp()(scope ref const typeof(this) right) scope const { static if (isPointer!(Iterators[0])) return this._iterators[0] - right._iterators[0]; @@ -674,7 +674,7 @@ struct CachedIterator(Iterator, CacheIterator, FlagIterator) return _caches[index] = val; } - void opUnary(string op)() + void opUnary(string op)() scope if (op == "--" || op == "++") { mixin(op ~ "_iterator;"); @@ -682,7 +682,7 @@ struct CachedIterator(Iterator, CacheIterator, FlagIterator) mixin(op ~ "_flags;"); } - void opOpAssign(string op)(ptrdiff_t index) + void opOpAssign(string op)(ptrdiff_t index) scope if (op == "-" || op == "+") { mixin("_iterator" ~ op ~ "= index;"); @@ -698,13 +698,13 @@ struct CachedIterator(Iterator, CacheIterator, FlagIterator) return ret; } - ptrdiff_t opBinary(string op : "-")(auto ref const typeof(this) right) const + ptrdiff_t opBinary(string op : "-")(auto scope ref const typeof(this) right) scope const { return (this._iterator - right._iterator) / count; } - bool opEquals()(ref const typeof(this) right) const + bool opEquals()(scope ref const typeof(this) right) scope const { return this._iterator == right._iterator; } - ptrdiff_t opCmp()(ref const typeof(this) right) const + ptrdiff_t opCmp()(scope ref const typeof(this) right) scope const { static if (isPointer!Iterator) return this._iterator - right._iterator; @@ -1022,7 +1022,7 @@ struct BytegroupIterator(Iterator, size_t count, DestinationType) return *(this + index); } - DestinationType opIndexAssign(T)(auto ref T val, ptrdiff_t index) + DestinationType opIndexAssign(T)(T val, ptrdiff_t index) scope { auto it = this + index; U ret = { value: val }; @@ -1031,11 +1031,11 @@ struct BytegroupIterator(Iterator, size_t count, DestinationType) return ret.value; } - void opUnary(string op)() + void opUnary(string op)() scope if (op == "--" || op == "++") { mixin("_iterator " ~ op[0] ~ "= count;"); } - void opOpAssign(string op)(ptrdiff_t index) + void opOpAssign(string op)(ptrdiff_t index) scope if (op == "-" || op == "+") { mixin("_iterator " ~ op ~ "= index * count;"); } @@ -1047,13 +1047,13 @@ struct BytegroupIterator(Iterator, size_t count, DestinationType) return ret; } - ptrdiff_t opBinary(string op : "-")(auto ref const typeof(this) right) const + ptrdiff_t opBinary(string op : "-")(auto scope ref const typeof(this) right) scope const { return (this._iterator - right._iterator) / count; } - bool opEquals()(ref const typeof(this) right) const + bool opEquals()(scope ref const typeof(this) right) scope const { return this._iterator == right._iterator; } - ptrdiff_t opCmp()(ref const typeof(this) right) const + ptrdiff_t opCmp()(scope ref const typeof(this) right) scope const { static if (isPointer!Iterator) return this._iterator - right._iterator; @@ -1062,7 +1062,7 @@ struct BytegroupIterator(Iterator, size_t count, DestinationType) } } -auto SlideIterator__map(Iterator, size_t params, alias fun0, alias fun)(ref SlideIterator!(Iterator, params, fun0) it) +auto SlideIterator__map(Iterator, size_t params, alias fun0, alias fun)(SlideIterator!(Iterator, params, fun0) it) { return SlideIterator!(Iterator, params, fun)(it._iterator); } @@ -1353,7 +1353,7 @@ struct SliceIterator(Iterator, size_t N = 1, SliceKind kind = Contiguous) mixin(std_ops); } -public auto FieldIterator__map(Field, alias fun)(ref FieldIterator!(Field) it) +public auto FieldIterator__map(Field, alias fun)(FieldIterator!(Field) it) { import mir.ndslice.field: _mapField; auto field = it._field._mapField!fun; @@ -1398,7 +1398,7 @@ struct FieldIterator(Field) static alias __map(alias fun) = FieldIterator__map!(Field, fun); /// - _Slice!() opSlice(size_t dimension)(size_t i, size_t j) const + _Slice!() opSlice(size_t dimension)(size_t i, size_t j) scope const { return typeof(return)(i, j); } @@ -1415,7 +1415,7 @@ struct FieldIterator(Field) auto ref opUnary(string op : "*")() { return _field[_index]; } - void opUnary(string op)() + void opUnary(string op)() scope if (op == "++" || op == "--") { mixin(op ~ `_index;`); } @@ -1434,7 +1434,7 @@ struct FieldIterator(Field) { mixin (`return _field[_index + index] ` ~ op ~ `= value;`); } } - void opOpAssign(string op)(ptrdiff_t index) + void opOpAssign(string op)(ptrdiff_t index) scope if (op == "+" || op == "-") { mixin(`_index ` ~ op ~ `= index;`); } @@ -1446,13 +1446,13 @@ struct FieldIterator(Field) return ret; } - ptrdiff_t opBinary(string op : "-")(auto ref const typeof(this) right) const + ptrdiff_t opBinary(string op : "-")(auto scope ref const typeof(this) right) scope const { return this._index - right._index; } - bool opEquals()(ref const typeof(this) right) const + bool opEquals()(scope ref const typeof(this) right) scope const { return this._index == right._index; } - ptrdiff_t opCmp()(ref const typeof(this) right) const + ptrdiff_t opCmp()(scope ref const typeof(this) right) scope const { return this._index - right._index; } /// @@ -1472,7 +1472,7 @@ struct FieldIterator(Field) } } -auto FlattenedIterator__map(Iterator, size_t N, SliceKind kind, alias fun)(ref FlattenedIterator!(Iterator, N, kind) it) +auto FlattenedIterator__map(Iterator, size_t N, SliceKind kind, alias fun)(FlattenedIterator!(Iterator, N, kind) it) { import mir.ndslice.topology: map; auto slice = it._slice.map!fun; @@ -1540,7 +1540,7 @@ struct FlattenedIterator(Iterator, size_t N, SliceKind kind) return *_slice._iterator; } - void opUnary(string op)() + void opUnary(string op)() scope if (op == "--" || op == "++") { foreach_reverse (i; Iota!N) @@ -1583,12 +1583,12 @@ struct FlattenedIterator(Iterator, size_t N, SliceKind kind) static if (isMutable!(_slice.DeepElement) && !_slice.hasAccessByRef) /// - auto opIndexAssign(E)(auto ref E elem, size_t index) + auto ref opIndexAssign(E)(auto scope ref E elem, size_t index) scope return { return _slice._iterator[getShift(index)] = elem; } - void opOpAssign(string op : "+")(ptrdiff_t n) + void opOpAssign(string op : "+")(ptrdiff_t n) scope { ptrdiff_t _shift; n += _indexes[$ - 1]; @@ -1615,7 +1615,7 @@ struct FlattenedIterator(Iterator, size_t N, SliceKind kind) _slice._iterator += _shift; } - void opOpAssign(string op : "-")(ptrdiff_t n) + void opOpAssign(string op : "-")(ptrdiff_t n) scope { this += -n; } auto opBinary(string op)(ptrdiff_t index) @@ -1626,7 +1626,7 @@ struct FlattenedIterator(Iterator, size_t N, SliceKind kind) return ret; } - ptrdiff_t opBinary(string op : "-")(auto ref const typeof(this) right) const + ptrdiff_t opBinary(string op : "-")(auto scope ref const typeof(this) right) scope const { ptrdiff_t ret = this._indexes[0] - right._indexes[0]; foreach (i; Iota!(1, N)) @@ -1637,7 +1637,7 @@ struct FlattenedIterator(Iterator, size_t N, SliceKind kind) return ret; } - bool opEquals()(ref const typeof(this) right) const + bool opEquals()(scope ref const typeof(this) right) scope const { foreach_reverse (i; Iota!N) if (this._indexes[i] != right._indexes[i]) @@ -1645,7 +1645,7 @@ struct FlattenedIterator(Iterator, size_t N, SliceKind kind) return true; } - ptrdiff_t opCmp()(ref const typeof(this) right) const + ptrdiff_t opCmp()(scope ref const typeof(this) right) scope const { foreach (i; Iota!(N - 1)) if (auto ret = this._indexes[i] - right._indexes[i]) @@ -1768,7 +1768,7 @@ struct StairsIterator(Iterator, string direction) return (_iterator + shift).sliced(newLength); } - void opUnary(string op)() + void opUnary(string op)() scope if (op == "--" || op == "++") { static if (op == "++") @@ -1790,7 +1790,7 @@ struct StairsIterator(Iterator, string direction) } } - void opOpAssign(string op)(ptrdiff_t index) + void opOpAssign(string op)(ptrdiff_t index) scope if (op == "-" || op == "+") { static if (op == direction) @@ -1817,7 +1817,7 @@ struct StairsIterator(Iterator, string direction) return ret; } - ptrdiff_t opBinary(string op : "-")(auto ref const typeof(this) right) const + ptrdiff_t opBinary(string op : "-")(auto scope ref const typeof(this) right) scope const { static if (direction == "+") return this._length - right._length; @@ -1825,10 +1825,10 @@ struct StairsIterator(Iterator, string direction) return right._length - this._length; } - bool opEquals()(ref const typeof(this) right) const + bool opEquals()(scope ref const typeof(this) right) scope const { return this._length == right._length; } - ptrdiff_t opCmp()(ref const typeof(this) right) const + ptrdiff_t opCmp()(scope ref const typeof(this) right) scope const { return this - right; } } diff --git a/source/mir/ndslice/ndfield.d b/source/mir/ndslice/ndfield.d index a6020604..35b2539e 100644 --- a/source/mir/ndslice/ndfield.d +++ b/source/mir/ndslice/ndfield.d @@ -56,7 +56,7 @@ private template _indexes_range(size_t begin, size_t count) /// struct Cartesian(NdFields...) - if (NdFields.length > 1) + if (NdFields.length > 1) { /// NdFields _fields; @@ -81,45 +81,45 @@ struct Cartesian(NdFields...) } /// - size_t length(size_t d = 0)() const @property + size_t length(size_t d = 0)() @safe scope const @property { - foreach(f, ref field; _fields) + foreach(f, NdField; NdFields) static if (M!f <= d && M!(f + 1) > d) { enum d = d - M!f; static if (d) - return field.length!(d - M!f); + return _fields[f].length!(d - M!f); else - return field.length; + return _fields[f].length; } } /// - size_t[N] shape()() const @property + size_t[N] shape()() @safe scope const @property { typeof(return) ret; - foreach(f, ref field; _fields) + foreach(f, NdField; NdFields) { - static if (hasShape!(NdFields[f])) + static if (hasShape!NdField) { - auto s = field.shape; + auto s = _fields[f].shape; foreach(j; Iota!(s.length)) ret[M!f + j] = s[j]; } else { - ret[M!f] = field.length; + ret[M!f] = _fields[f].length; } } return ret; } /// - size_t elementCount()() const @property + size_t elementCount()() @safe scope const @property { size_t ret = 1; - foreach (ref field; _fields) - ret *= field.elementCount; + foreach (f, NdField; NdFields) + ret *= _fields[f].elementCount; return ret; } @@ -168,33 +168,33 @@ struct Kronecker(alias fun, NdFields...) private enum N = DimensionCount!(NdFields[$-1]); /// - size_t length(size_t d = 0)() const @property + size_t length(size_t d = 0)() scope const @property { static if (d == 0) { - size_t ret = _fields[0].length; - foreach(ref field; _fields[1 .. $]) - ret *= field.length; + size_t ret = 1; + foreach (f, NdField; NdFields) + ret *= _fields[f].length; } else { - size_t ret = _fields[0].length!d; - foreach(ref field; _fields[1 .. $]) - ret *= field.length!d; + size_t ret = 1; + foreach (f, NdField; NdFields) + ret *= _fields[f].length!d; } return ret; } /// - size_t[N] shape()() const @property + size_t[N] shape()() scope const @property { static if (N > 1) { - size_t[N] ret = _fields[0].shape; - foreach(ref field; _fields[1 .. $]) + size_t[N] ret = 1; + foreach (f, NdField; NdFields) { - auto s = field.shape; + auto s = _fields[f].shape; foreach(i; Iota!N) ret[i] *= s[i]; } @@ -202,20 +202,19 @@ struct Kronecker(alias fun, NdFields...) } else { - size_t[1] ret; - ret[0] = _fields[0].length; - foreach(ref field; _fields[1 .. $]) - ret[0] *= field.length; + size_t[1] ret = 1; + foreach (f, NdField; NdFields) + ret[0] *= _fields[f].length; return ret; } } /// - size_t elementCount()() const @property + size_t elementCount()() scope const @property { size_t ret = 1; - foreach (ref field; _fields) - ret *= field.elementCount; + foreach (f, NdField; NdFields) + ret *= _fields[f].elementCount; ret; } @@ -226,18 +225,18 @@ struct Kronecker(alias fun, NdFields...) size_t[N][NdFields.length] ind; else size_t[NdFields.length] ind; - foreach_reverse (f, ref field; _fields) + foreach_reverse (f, NdField; NdFields) { static if (f) { static if (hasShape!(NdFields[f])) { - auto s = field.shape; + auto s = _fields[f].shape; } else { size_t[1] s; - s[0] = field.length; + s[0] = _fields[f].length; } static if (N > 1) { diff --git a/source/mir/ndslice/topology.d b/source/mir/ndslice/topology.d index 5e6e89ff..1cd948fc 100644 --- a/source/mir/ndslice/topology.d +++ b/source/mir/ndslice/topology.d @@ -622,16 +622,14 @@ iota } /// -pure nothrow +pure nothrow @nogc version(mir_test) unittest { int[6] data; auto slice = iota([2, 3], data.ptr); - auto array = - [[data.ptr + 0, data.ptr + 1, data.ptr + 2], - [data.ptr + 3, data.ptr + 4, data.ptr + 5]]; - - assert(slice == array); + assert(slice[0, 0] == data.ptr); + assert(slice[0, 1] == data.ptr + 1); + assert(slice[1, 0] == data.ptr + 3); } /// @@ -2553,20 +2551,23 @@ See_Also: $(HTTP en.wikipedia.org/wiki/Map_(higher-order_function), Map (higher-order function)) +/ @optmath auto vmap(Iterator, size_t N, SliceKind kind, Callable) - (Slice!(Iterator, N, kind) slice, auto ref return Callable callable) @safe + ( + Slice!(Iterator, N, kind) slice, + Callable callable, + ) { alias It = VmapIterator!(Iterator, Callable); return Slice!(It, N, kind)(slice._lengths, slice._strides, It(slice._iterator, callable)); } /// ditto -auto vmap(T, Callable)(T[] array, auto ref return Callable callable) +auto vmap(T, Callable)(T[] array, Callable callable) { return vmap(array.sliced, callable); } /// ditto -auto vmap(T, Callable)(T withAsSlice, auto ref return Callable callable) +auto vmap(T, Callable)(T withAsSlice, Callable callable) if (hasAsSlice!T) { return vmap(withAsSlice.asSlice, callable); @@ -3060,7 +3061,7 @@ See_also: $(LREF chopped), $(LREF pairwise). +/ Slice!(SubSliceIterator!(Iterator, Sliceable), N, kind) subSlices(Iterator, size_t N, SliceKind kind, Sliceable)( - auto ref Sliceable sliceable, + Sliceable sliceable, Slice!(Iterator, N, kind) slices, ) { @@ -3111,7 +3112,7 @@ Returns: See_also: $(LREF pairwise), $(LREF subSlices). +/ Slice!(ChopIterator!(Iterator, Sliceable)) chopped(Iterator, Sliceable)( - auto ref Sliceable sliceable, + Sliceable sliceable, Slice!Iterator bounds, ) in @@ -3134,7 +3135,7 @@ do { } } - return typeof(return)([size_t(length)], ChopIterator!(Iterator, Sliceable)(bounds._iterator, sliceable)); + return typeof(return)([size_t(length)], sizediff_t[0].init, ChopIterator!(Iterator, Sliceable)(bounds._iterator, sliceable)); } /// ditto From 64c12fe4e9d5614576b0001786616cbf0b59a8d6 Mon Sep 17 00:00:00 2001 From: Ilya Yaroshenko Date: Sat, 10 Nov 2018 23:57:51 +0700 Subject: [PATCH 3/6] rcarray & dip1000 upgrade --- doc/Makefile | 6 +- dub.sdl | 9 +- meson.build | 3 +- source/mir/algorithm/iteration.d | 72 ++-- source/mir/algorithm/setops.d | 14 +- source/mir/array/allocation.d | 11 +- source/mir/combinatorics/package.d | 40 +-- source/mir/container/binaryheap.d | 28 +- source/mir/interpolate/constant.d | 101 ++---- source/mir/interpolate/linear.d | 121 ++----- source/mir/interpolate/pchip.d | 30 +- source/mir/interpolate/spline.d | 214 ++++++------ source/mir/math/sum.d | 2 +- source/mir/ndslice/field.d | 10 +- source/mir/ndslice/fuse.d | 4 +- source/mir/ndslice/iterator.d | 67 ++-- source/mir/ndslice/slice.d | 523 ++++++++++++++++------------- source/mir/ndslice/topology.d | 195 ++++++----- source/mir/rcarray.d | 415 +++++++++++++++++++++++ source/mir/series.d | 6 +- 20 files changed, 1110 insertions(+), 761 deletions(-) create mode 100644 source/mir/rcarray.d diff --git a/doc/Makefile b/doc/Makefile index c8211e83..7103052e 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -28,11 +28,11 @@ ARTWORK_DIR=$(DOC_SOURCE_DIR)/artwork # packages and their modules. MIR_PACKAGES = mir mir/ndslice mir/ndslice/connect mir/math mir/math/func mir/array mir/interpolate mir/graph mir/combinatorics mir/container mir/algorithm -PACKAGE_mir = range series +PACKAGE_mir = range rcarray series +PACKAGE_mir_algorithm = iteration setops PACKAGE_mir_array = allocation PACKAGE_mir_combinatorics = package -PACKAGE_mir_algorithm = iteration setops PACKAGE_mir_container = binaryheap PACKAGE_mir_graph = tarjan package PACKAGE_mir_interpolate = package constant linear spline pchip utility @@ -46,8 +46,8 @@ PACKAGE_mir_ndslice = \ concatenation\ dynamic\ field\ - iterator\ fuse\ + iterator\ mutation\ ndfield\ package\ diff --git a/dub.sdl b/dub.sdl index 3e2df5f9..93a66d0f 100644 --- a/dub.sdl +++ b/dub.sdl @@ -5,7 +5,7 @@ authors "Ilya Yaroshenko" "Sebastian Wilzbach" "John Michael Hall" copyright "Copyright © 2016 - 2018, Ilya Yaroshenko; see also information per file." license "BSL-1.0" -dependency "mir-core" version=">=0.0.7 <1.0.0" +dependency "mir-core" version=">=0.0.10 <1.0.0" buildType "unittest" { buildOptions "unittests" "debugMode" "debugInfo" @@ -19,3 +19,10 @@ buildType "unittest-release" { buildOptions "unittests" "releaseMode" "optimize" "inline" "noBoundsCheck" versions "mir_test" } + +configuration "default" { +} + +configuration "dips" { + dflags "-dip25" "-dip1000" "-dip1008" +} diff --git a/meson.build b/meson.build index 3f718343..3dcbf2ca 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,4 @@ -project('mir-algorithm', 'd', version : '3.0.0', license: 'BSL-1.0') +project('mir-algorithm', 'd', version : '4.0.0', license: 'BSL-1.0') mir_algorithm_dir = include_directories('source/', 'include/') @@ -40,6 +40,7 @@ mir_algorithm_src = [ 'source/mir/ndslice/topology.d', 'source/mir/ndslice/traits.d', 'source/mir/range.d', + 'source/mir/rcarray.d', 'source/mir/series.d', ] diff --git a/source/mir/algorithm/iteration.d b/source/mir/algorithm/iteration.d index 59873d50..33eed6f3 100644 --- a/source/mir/algorithm/iteration.d +++ b/source/mir/algorithm/iteration.d @@ -131,7 +131,7 @@ private struct BitSliceAccelerator(Field, I = typeof(Field.init[size_t.init])) } } -const: +scope const: bool isCentralProblem() { @@ -504,13 +504,13 @@ const: Сount bits until set bit count is reached. Works with ndslices created with $(REF bitwise, mir,ndslice,topology), $(REF bitSlice, mir,ndslice,allocation). Returns: bit count if set bit count is reached or `-1` otherwise. +/ -sizediff_t nBitsToCount(Field, I)(Slice!(FieldIterator!(BitField!(Field, I))) bitSlice, size_t count) +sizediff_t nBitsToCount(Field, I)(scope Slice!(FieldIterator!(BitField!(Field, I))) bitSlice, size_t count) { return BitSliceAccelerator!(Field, I)(bitSlice).nBitsToCount(count); } ///ditto -sizediff_t nBitsToCount(Field, I)(Slice!(RetroIterator!(FieldIterator!(BitField!(Field, I)))) bitSlice, size_t count) +sizediff_t nBitsToCount(Field, I)(scope Slice!(RetroIterator!(FieldIterator!(BitField!(Field, I)))) bitSlice, size_t count) { import mir.ndslice.topology: retro; return BitSliceAccelerator!(Field, I)(bitSlice.retro).retroNBitsToCount(count); @@ -654,7 +654,7 @@ else private enum Mir_disable_inlining_in_reduce = false; } -S reduceImpl(alias fun, S, Slices...)(S seed, Slices slices) +S reduceImpl(alias fun, S, Slices...)(S seed, scope Slices slices) { do { @@ -701,7 +701,7 @@ template reduce(alias fun) Returns: the accumulated `result` +/ - @optmath auto reduce(S, Slices...)(S seed, Slices slices) + @optmath auto reduce(S, Slices...)(S seed, scope Slices slices) if (Slices.length) { static if (Slices.length > 1) @@ -724,7 +724,7 @@ template reduce(alias fun) } else version(Mir_disable_inlining_in_reduce) //As above, but with inlining disabled. - @optmath auto reduce(S, Slices...)(S seed, Slices slices) + @optmath auto reduce(S, Slices...)(S seed, scope Slices slices) if (Slices.length) { static if (Slices.length > 1) @@ -909,7 +909,7 @@ version(mir_test) unittest assert(a == 7); } -void eachImpl(alias fun, Slices...)(Slices slices) +void eachImpl(alias fun, Slices...)(scope Slices slices) { foreach(ref slice; slices) assert(!slice.empty); @@ -947,7 +947,7 @@ template each(alias fun) Params: slices = One or more slices, ranges, and arrays. +/ - @optmath auto each(Slices...)(Slices slices) + @optmath auto each(Slices...)(scope Slices slices) if (Slices.length) { static if (Slices.length > 1) @@ -1068,7 +1068,7 @@ template eachUploPair(alias fun, bool includeDiagonal = false) Params: matrix = Square matrix. +/ - auto eachUploPair(Iterator, SliceKind kind)(Slice!(Iterator, 2, kind) matrix) + auto eachUploPair(Iterator, SliceKind kind)(scope Slice!(Iterator, 2, kind) matrix) in { assert(matrix.length!0 == matrix.length!1, "matrix must be square."); @@ -1267,7 +1267,7 @@ unittest 2, 3].sliced(2, 2).isSymmetric == true); } -bool minPosImpl(alias fun, Iterator, size_t N, SliceKind kind)(ref size_t[N] backwardIndex, ref Iterator iterator, Slice!(Iterator, N, kind) slice) +bool minPosImpl(alias fun, Iterator, size_t N, SliceKind kind)(scope ref size_t[N] backwardIndex, scope ref Iterator iterator, Slice!(Iterator, N, kind) slice) { auto bis = backwardIndex[0]; do @@ -1293,7 +1293,7 @@ bool minPosImpl(alias fun, Iterator, size_t N, SliceKind kind)(ref size_t[N] bac return bis != backwardIndex[0]; } -bool[2] minmaxPosImpl(alias fun, Iterator, size_t N, SliceKind kind)(ref size_t[2][N] backwardIndex, ref Iterator[2] iterator, Slice!(Iterator, N, kind) slice) +bool[2] minmaxPosImpl(alias fun, Iterator, size_t N, SliceKind kind)(scope ref size_t[2][N] backwardIndex, scope ref Iterator[2] iterator, Slice!(Iterator, N, kind) slice) { size_t[2] bis = backwardIndex[0]; do @@ -1358,7 +1358,6 @@ template minmaxPos(alias pred = "a < b") @optmath Slice!(Iterator, N, kind == Contiguous && N > 1 ? Canonical : kind)[2] minmaxPos(Iterator, size_t N, SliceKind kind)(Slice!(Iterator, N, kind) slice) { - import mir.ndslice.topology: map; typeof(return) pret; if (!slice.anyEmpty) { @@ -1432,7 +1431,6 @@ template minmaxIndex(alias pred = "a < b") +/ @optmath size_t[N][2] minmaxIndex(Iterator, size_t N, SliceKind kind)(Slice!(Iterator, N, kind) slice) { - import mir.ndslice.topology: map; typeof(return) pret = size_t.max; if (!slice.anyEmpty) { @@ -1501,13 +1499,10 @@ template minPos(alias pred = "a < b") @optmath Slice!(Iterator, N, kind == Contiguous && N > 1 ? Canonical : kind) minPos(Iterator, size_t N, SliceKind kind)(Slice!(Iterator, N, kind) slice) { - typeof(return) ret; - import mir.ndslice.topology: map; + typeof(return) ret = { _iterator : slice._iterator }; if (!slice.anyEmpty) { - auto iterator = slice._iterator; - minPosImpl!(pred, Iterator, N, kind)(ret._lengths, iterator, slice); - ret._iterator = iterator; + minPosImpl!(pred, Iterator, N, kind)(ret._lengths, ret._iterator, slice); } auto strides = slice.strides; foreach(i; Iota!(0, ret.S)) @@ -1576,7 +1571,6 @@ template minIndex(alias pred = "a < b") @optmath size_t[N] minIndex(Iterator, size_t N, SliceKind kind)(Slice!(Iterator, N, kind) slice) { size_t[N] ret = size_t.max; - import mir.ndslice.topology: map; if (!slice.anyEmpty) { ret = slice.shape; @@ -1635,7 +1629,7 @@ unittest assert(s[index] == -8); } -bool findImpl(alias fun, size_t N, Slices...)(ref size_t[N] backwardIndex, Slices slices) +bool findImpl(alias fun, size_t N, Slices...)(scope ref size_t[N] backwardIndex, Slices slices) if (Slices.length) { static if (__traits(isSame, fun, naryFun!"a") && is(S : Slice!(FieldIterator!(BitField!(Field, I))), Field, I)) @@ -1927,7 +1921,7 @@ version(mir_test) unittest assert(bi == [0, 0]); } -size_t anyImpl(alias fun, Slices...)(Slices slices) +size_t anyImpl(alias fun, Slices...)(scope Slices slices) if (Slices.length) { static if (__traits(isSame, fun, naryFun!"a") && is(S : Slice!(FieldIterator!(BitField!(Field, I))), Field, I)) @@ -1983,7 +1977,7 @@ template any(alias pred = "a") Constraints: All slices must have the same shape. +/ - @optmath bool any(Slices...)(Slices slices) + @optmath bool any(Slices...)(scope Slices slices) if ((Slices.length == 1 || !__traits(isSame, pred, "a")) && Slices.length) { static if (Slices.length > 1) @@ -2087,7 +2081,7 @@ version(mir_test) unittest [8, 8, 5]]); } -size_t allImpl(alias fun, Slices...)(Slices slices) +size_t allImpl(alias fun, Slices...)(scope Slices slices) if (Slices.length) { static if (__traits(isSame, fun, naryFun!"a") && is(S : Slice!(FieldIterator!(BitField!(Field, I))), Field, I)) @@ -2143,7 +2137,7 @@ template all(alias pred = "a") Constraints: All slices must have the same shape. +/ - @optmath bool all(Slices...)(Slices slices) + @optmath bool all(Slices...)(scope Slices slices) if ((Slices.length == 1 || !__traits(isSame, pred, "a")) && Slices.length) { static if (Slices.length > 1) @@ -2273,7 +2267,7 @@ template count(alias fun) Constraints: All slices must have the same shape. +/ - @optmath size_t count(Slices...)(Slices slices) + @optmath size_t count(Slices...)(scope Slices slices) if (Slices.length) { static if (Slices.length > 1) @@ -2392,7 +2386,7 @@ template equal(alias pred = "a == b") Returns: `true` any of the elements verify `pred` and `false` otherwise. +/ - bool equal(Slices...)(Slices slices) + bool equal(Slices...)(scope Slices slices) if (Slices.length >= 2) { enum msg = "all arguments must be slices" ~ tailErrorMessage!(); @@ -2450,7 +2444,7 @@ version(mir_test) unittest } ptrdiff_t cmpImpl(alias pred, A, B) - (A sl1, B sl2) + (scope A sl1, scope B sl2) if (DimensionCount!A == DimensionCount!B) { for (;;) @@ -2505,7 +2499,7 @@ template cmp(alias pred = "a < b") element of `sl1` according to `pred`. +/ ptrdiff_t cmp(A, B) - (A sl1, B sl2) + (scope A sl1, scope B sl2) if (DimensionCount!A == DimensionCount!B) { auto b = sl2.anyEmpty; @@ -2580,7 +2574,7 @@ version(mir_test) unittest assert(cmp(sl1[0 .. $ - 1, 0 .. $ - 3], sl1[0 .. $, 0 .. $ - 3]) < 0); } -size_t countImpl(alias fun, Slices...)(Slices slices) +size_t countImpl(alias fun, Slices...)(scope Slices slices) { size_t ret; alias S = Slices[0]; @@ -2642,7 +2636,7 @@ private template frontSelectFrontOf(size_t N, string input) /++ Returns: max length across all dimensions. +/ -size_t maxLength(S)(auto ref S s) +size_t maxLength(S)(auto ref scope S s) if (hasShape!S) { auto shape = s.shape; @@ -2685,7 +2679,7 @@ template eachLower(alias fun) For k < 0, more diagonals above the main diagonal will have the function applied. +/ - void eachLower(Inputs...)(Inputs inputs) + void eachLower(Inputs...)(scope Inputs inputs) if (((Inputs.length > 1) && (isIntegral!(Inputs[$ - 1]))) || (Inputs.length)) @@ -3150,7 +3144,7 @@ template eachUpper(alias fun) For k < 0, more diagonals above the main diagonal will have the function applied. +/ - void eachUpper(Inputs...)(Inputs inputs) + void eachUpper(Inputs...)(scope Inputs inputs) if (((Inputs.length > 1) && (isIntegral!(Inputs[$ - 1]))) || (Inputs.length)) @@ -3612,12 +3606,12 @@ struct Uniq(alias pred, Range) // AliasSeq!_input = forward!input; // } - auto opSlice()() + ref opSlice() inout { return this; } - void popFront()() + void popFront() scope { assert(!empty, "Attempting to popFront an empty uniq."); auto last = _input.front; @@ -3628,7 +3622,7 @@ struct Uniq(alias pred, Range) while (!_input.empty && pred(last, _input.front)); } - @property ElementType!Range front()() + @property ElementType!Range front() { assert(!empty, "Attempting to fetch the front of an empty uniq."); return _input.front; @@ -3636,7 +3630,7 @@ struct Uniq(alias pred, Range) static if (isBidirectionalRange!Range) { - void popBack()() + void popBack() scope { assert(!empty, "Attempting to popBack an empty uniq."); auto last = _input.back; @@ -3647,7 +3641,7 @@ struct Uniq(alias pred, Range) while (!_input.empty && pred(last, _input.back)); } - @property ElementType!Range back()() + @property ElementType!Range back() scope return { assert(!empty, "Attempting to fetch the back of an empty uniq."); return _input.back; @@ -3660,12 +3654,12 @@ struct Uniq(alias pred, Range) } else { - @property bool empty()() { return _input.empty; } + @property bool empty() const { return _input.empty; } } static if (isForwardRange!Range) { - @property typeof(this) save()() { + @property typeof(this) save() scope return { return typeof(this)(_input.save); } } diff --git a/source/mir/algorithm/setops.d b/source/mir/algorithm/setops.d index d318ca87..bfa00346 100644 --- a/source/mir/algorithm/setops.d +++ b/source/mir/algorithm/setops.d @@ -54,7 +54,7 @@ struct MultiwayMerge(alias less, RangeOfRanges) @disable this(this); /// - static bool compFront()(auto ref ElementType!RangeOfRanges a, auto ref ElementType!RangeOfRanges b) + static bool compFront(ElementType!RangeOfRanges a, ElementType!RangeOfRanges b) { // revert comparison order so we get the smallest elements first return less(b.front, a.front); @@ -64,7 +64,7 @@ struct MultiwayMerge(alias less, RangeOfRanges) BinaryHeap!(compFront, RangeOfRanges) _heap; /// - this()(auto ref RangeOfRanges ror) + this(RangeOfRanges ror) @nogc { import std.algorithm.mutation : remove, SwapStrategy; @@ -75,17 +75,17 @@ struct MultiwayMerge(alias less, RangeOfRanges) } /// - @property bool empty()() { return _heap.empty; } + @property bool empty() scope const { return _heap.empty; } /// - @property auto ref front()() + @property auto ref front() { assert(!empty); return _heap.front.front; } /// - void popFront()() + void popFront() scope @safe { _heap._store.front.popFront; if (!_heap._store.front.empty) @@ -98,7 +98,7 @@ struct MultiwayMerge(alias less, RangeOfRanges) /// Ditto MultiwayMerge!(naryFun!less, RangeOfRanges) multiwayMerge (alias less = "a < b", RangeOfRanges) -(auto ref RangeOfRanges ror) +(RangeOfRanges ror) { return typeof(return)(ror); } @@ -147,7 +147,7 @@ Returns: A range of the union of the ranges in `ror`. See also: $(LREF multiwayMerge) */ -auto multiwayUnion(alias less = "a < b", RangeOfRanges)(auto ref RangeOfRanges ror) +auto multiwayUnion(alias less = "a < b", RangeOfRanges)(RangeOfRanges ror) { import mir.functional: not; import mir.algorithm.iteration : Uniq; diff --git a/source/mir/array/allocation.d b/source/mir/array/allocation.d index 33a4eea1..48729ff3 100644 --- a/source/mir/array/allocation.d +++ b/source/mir/array/allocation.d @@ -26,7 +26,7 @@ import mir.functional; import mir.primitives; import std.traits; -import std.range.primitives: isInfinite, isInputRange; +import std.range.primitives: isInfinite, isInputRange, ElementType; /** * Allocates an array and initializes it with copies of the elements @@ -40,12 +40,15 @@ import std.range.primitives: isInfinite, isInputRange; * allocated and initialized array */ auto array(Range)(Range r) -if (isIterable!Range && !isInfinite!Range && !isStaticArray!Range || isPointer!Range && isIterable!(PointerTarget!Range)) +if ((isInputRange!Range || isIterable!Range) && !isInfinite!Range && !isStaticArray!Range || isPointer!Range && isIterable!(PointerTarget!Range)) { - static if (isPointer!Range) + static if (isIterable!Range) + alias E = ForeachType!Range; + else + static if (isPointer!Range && isIterable!(PointerTarget!Range)) alias E = ForeachType!(PointerTarget!Range); else - alias E = ForeachType!Range; + alias E = ElementType!Range; if (__ctfe) { diff --git a/source/mir/combinatorics/package.d b/source/mir/combinatorics/package.d index 9b5eb7bc..6f484c61 100644 --- a/source/mir/combinatorics/package.d +++ b/source/mir/combinatorics/package.d @@ -236,13 +236,13 @@ struct IndexedRoR(Collection, Range) } /// ditto - void popFront() + void popFront() scope { c.popFront; } /// ditto - bool empty()() @property const + bool empty()() @property scope const { return c.empty; } @@ -250,13 +250,13 @@ struct IndexedRoR(Collection, Range) static if (hasLength!Collection) { /// ditto - @property size_t length()() const + @property size_t length()() scope const { return c.length; } /// - @property size_t[2] shape()() const + @property size_t[2] shape()() scope const { return c.shape; } @@ -420,7 +420,7 @@ struct Permutations(T) } /// ditto - void popFront()() @safe pure nothrow @nogc + void popFront()() scope @safe pure nothrow @nogc { import std.algorithm.mutation : swapAt; @@ -448,19 +448,19 @@ struct Permutations(T) } /// ditto - @property bool empty()() @safe pure nothrow @nogc const + @property bool empty()() @safe pure nothrow @nogc scope const { return _empty; } /// ditto - @property size_t length()() @safe pure nothrow @nogc const + @property size_t length()() @safe pure nothrow @nogc scope const { return _max_states - _pos; } /// - @property size_t[2] shape()() const + @property size_t[2] shape()() scope const { return [length, indices.length]; } @@ -651,7 +651,7 @@ public: } /// ditto - void popFront()() @safe pure nothrow @nogc + void popFront()() scope @safe pure nothrow @nogc { assert(!empty); _pos++; @@ -676,19 +676,19 @@ public: } /// ditto - @property size_t length()() @safe pure nothrow @nogc const + @property size_t length()() @safe pure nothrow @nogc scope const { return _max_states - _pos; } /// ditto - @property bool empty()() @safe pure nothrow @nogc const + @property bool empty()() @safe pure nothrow @nogc scope const { return _pos == _max_states; } /// - @property size_t[2] shape()() const + @property size_t[2] shape()() scope const { return [length, _state.length]; } @@ -915,7 +915,7 @@ public: } /// ditto - void popFront()() @safe pure nothrow @nogc + void popFront()() scope @safe pure nothrow @nogc { assert(!empty); pos++; @@ -954,19 +954,19 @@ public: } /// ditto - @property size_t length()() @safe pure nothrow @nogc const + @property size_t length()() @safe pure nothrow @nogc scope const { return max_states - pos; } /// ditto - @property bool empty()() @safe pure nothrow @nogc const + @property bool empty()() @safe pure nothrow @nogc scope const { return pos == max_states; } /// - @property size_t[2] shape()() const + @property size_t[2] shape()() scope const { return [length, state.length]; } @@ -1232,7 +1232,7 @@ public: } /// ditto - void popFront()() @safe pure nothrow @nogc + void popFront()() scope @safe pure nothrow @nogc { assert(!empty); pos++; @@ -1260,19 +1260,19 @@ public: } /// ditto - @property size_t length()() @safe pure nothrow @nogc const + @property size_t length()() @safe pure nothrow @nogc scope const { return max_states - pos; } /// ditto - @property bool empty()() @safe pure nothrow @nogc const + @property bool empty()() @safe pure nothrow @nogc scope const { return pos == max_states; } /// - @property size_t[2] shape()() const + @property size_t[2] shape()() scope const { return [length, state.length]; } diff --git a/source/mir/container/binaryheap.d b/source/mir/container/binaryheap.d index 58dee011..083f5a50 100644 --- a/source/mir/container/binaryheap.d +++ b/source/mir/container/binaryheap.d @@ -86,7 +86,7 @@ if (isRandomAccessRange!(Store) || isRandomAccessRange!(typeof(Store.init[]))) // Convenience accessors // Asserts that the heap property is respected. - private void assertValid()() + private void assertValid() scope { debug { @@ -115,7 +115,7 @@ public: $(D Store) is a container with $(D insertBack)). Performs $(BIGOH min(r.length, initialSize)) evaluations of $(D less). +/ - this()(Store s, size_t initialSize = size_t.max) + this(Store s, size_t initialSize = size_t.max) { acquire(s, initialSize); } @@ -124,7 +124,7 @@ public: Takes ownership of a store. After this, manipulating $(D s) may make the heap work incorrectly. +/ - void acquire()(Store s, size_t initialSize = size_t.max) + void acquire(Store s, size_t initialSize = size_t.max) { _store = move(s); _length = min(_store.length, initialSize); @@ -137,7 +137,7 @@ public: Takes ownership of a store assuming it already was organized as a heap. +/ - void assume()(Store s, size_t initialSize = size_t.max) + void assume(Store s, size_t initialSize = size_t.max) { _store = move(s); _length = min(_store.length, initialSize); @@ -147,7 +147,7 @@ public: /++ Returns the _length of the heap. +/ - @property size_t length()() const scope + @property size_t length() scope const { return _length; } @@ -155,7 +155,7 @@ public: /++ Returns $(D true) if the heap is _empty, $(D false) otherwise. +/ - @property bool empty()() const scope + @property bool empty() scope const { return !length; } @@ -165,7 +165,7 @@ public: underlying store (if the store is a range) or the _capacity of the underlying store (if the store is a container). +/ - @property size_t capacity()() const scope + @property size_t capacity() scope const { static if (is(typeof(_store.capacity) : size_t)) { @@ -181,7 +181,7 @@ public: Returns a _front of the heap, which is the largest element according to `less`. +/ - @property auto ref ElementType!Store front()() + @property auto ref ElementType!Store front() scope return { assert(!empty, "Cannot call front on an empty heap."); return _store.front; @@ -193,7 +193,7 @@ public: Inserts `value` into the store. If the underlying store is a range and `length == capacity`, throws an AssertException. +/ - size_t insert()(ElementType!Store value) + size_t insert(ElementType!Store value) scope { static if (is(typeof(_store.insertBack(value)))) { @@ -232,7 +232,7 @@ public: /++ Removes the largest element from the heap. +/ - void removeFront()() + void removeFront() scope { assert(!empty, "Cannot call removeFront on an empty heap."); if (--_length) @@ -249,7 +249,7 @@ public: reasons you may want to use $(D removeFront) with heaps of objects that are expensive to copy. +/ - auto ref removeAny()() + auto ref removeAny() scope { removeFront(); return _store[_length]; @@ -258,7 +258,7 @@ public: /++ Replaces the largest element in the store with `value`. +/ - void replaceFront()(ElementType!Store value) + void replaceFront(ElementType!Store value) scope { // must replace the top assert(!empty, "Cannot call replaceFront on an empty heap."); @@ -275,7 +275,7 @@ public: scenarios where the smallest $(D k) elements of a set of candidates must be collected. +/ - bool conditionalInsert()(ElementType!Store value) + bool conditionalInsert(ElementType!Store value) scope { if (_length < _store.length) { @@ -297,7 +297,7 @@ public: method exchanges store.front and value and returns $(D true). Otherwise, it leaves the heap unaffected and returns $(D false). +/ - bool conditionalSwap()(ref ElementType!Store value) + bool conditionalSwap(ref ElementType!Store value) scope { assert(_length == _store.length); assert(!_store.empty, "Cannot swap front of an empty heap."); diff --git a/source/mir/interpolate/constant.d b/source/mir/interpolate/constant.d index 0630e6e8..38df91d0 100644 --- a/source/mir/interpolate/constant.d +++ b/source/mir/interpolate/constant.d @@ -40,7 +40,6 @@ version(mir_test) import std.traits; -import std.meta: AliasSeq, staticMap; import mir.primitives; import mir.ndslice.slice; import mir.internal.utility; @@ -66,6 +65,8 @@ template constant(T, size_t N = 1, FirstGridIterator = immutable(T)*, NextGridIt { static if (N > 1) pragma(msg, "Warning: multivariate constant interpolant was not tested."); + import std.meta: AliasSeq; + @optmath: private alias GridIterators = AliasSeq!(FirstGridIterator, NextGridIterators); @@ -82,17 +83,9 @@ template constant(T, size_t N = 1, FirstGridIterator = immutable(T)*, NextGridIt +/ Constant!(T, N, GridIterators) constant(yIterator, SliceKind ykind)( GridVectors grid, - scope Slice!(yIterator, 1, ykind) values, - bool forceCopyValues = false - ) pure + scope Slice!(yIterator, 1, ykind) values + ) pure @trusted { - static if (__traits(compiles, typeof(return)(grid, values))) - { - if (!forceCopyValues) - { - return typeof(return)(grid, values); - } - } import std.algorithm.mutation: move; auto ret = typeof(return)(grid); ret._data[] = values; @@ -106,92 +99,52 @@ Multivariate constant interpolant with nodes on rectilinear grid. struct Constant(F, size_t N = 1, FirstGridIterator = immutable(F)*, NextGridIterators = Repeat!(N - 1, FirstGridIterator)) if (N && N <= 6 && NextGridIterators.length == N - 1) { + import mir.rcarray; + import std.meta: AliasSeq, staticMap; + package alias GridIterators = AliasSeq!(FirstGridIterator, NextGridIterators); package alias GridVectors = staticMap!(GridVector, GridIterators); @optmath: /// Aligned buffer allocated with `mir.internal.memory`. $(RED For internal use.) - Slice!(F*, N) _data; + mir_slice!(mir_rci!F, N) _data; /// Grid iterators. $(RED For internal use.) GridIterators _grid; - /// - bool _ownsData; import mir.utility: min, max; package enum alignment = min(64u, F.sizeof).max(size_t.sizeof); - package ref shared(sizediff_t) counter() @trusted @property - { - assert(_ownsData); - auto p = cast(shared sizediff_t*) _data.ptr; - return *(p - 1); - } - - /// - this(this) @safe nothrow @nogc - { - import core.atomic: atomicOp; - if (_ownsData) - counter.atomicOp!"+="(1); - } - /++ - Frees _data if $(LREF Spline._freeData) is true. +/ - ~this() @trusted nothrow @nogc + this(GridVectors grid) scope @safe @nogc { - import mir.internal.memory; - import core.atomic: atomicOp; - - if (_ownsData) - if (counter.atomicOp!"-="(1) <= 0) - alignedFree(cast(void*)(_data.ptr) - alignment); - } - - /++ - +/ - this()(GridVectors grid) @trusted nothrow @nogc - { - import mir.internal.memory; - import mir.ndslice.topology: iota; - + size_t length = 1; size_t[N] shape; + enum msg = "constant interpolant: minimal allowed length for the grid equals 1."; + version(D_Exceptions) + static immutable exc = new Exception(msg); foreach(i, ref x; grid) { - assert(x.length >= 1, "constant interpolant: minimal allowed length for the grid equals 1."); - shape[i] = x.length; - } - - auto data_ptr = cast(F*) (alignedAllocate(F.sizeof * shape.iota.elementCount + alignment, alignment) + alignment); - if(data_ptr is null) - assert(0, "No memory"); - - this._data = data_ptr.sliced(shape); - this._grid = staticMap!(iter, grid); - this._ownsData = true; - this.counter = 1; - } - - /++ - +/ - this()(GridVectors grid, Slice!(immutable(F)*, N) values) @trusted nothrow @nogc - { - foreach(i, ref x; grid) - { - assert(x.length >= 1, "constant interpolant: minimal allowed length for the grid equals 1."); - assert(values.length!i == x.length, "grid length should mutch to the values length"); + if (x.length < 1) + { + version(D_Exceptions) + throw exc; + else + assert(0, msg); + } + length *= shape[i] = x.length; } - this._data = values; + auto rca = mir_rcarray!F(length, alignment); + this._data = rca.asSlice.sliced(shape); this._grid = staticMap!(iter, grid); - this._ownsData = false; } @trusted: /// - GridVectors[dimension] grid(size_t dimension = 0)() const @property + GridVectors[dimension] grid(size_t dimension = 0)() scope return const @property if (dimension < N) { return _grid[dimension].sliced(_data._lengths[dimension]); @@ -200,14 +153,14 @@ struct Constant(F, size_t N = 1, FirstGridIterator = immutable(F)*, NextGridIter /++ Returns: intervals count. +/ - size_t intervalCount(size_t dimension = 0)() const @property + size_t intervalCount(size_t dimension = 0)() scope const @property { assert(_data._lengths[dimension] > 0); return _data._lengths[dimension] - 0; } /// - size_t[N] gridShape()() const @property + size_t[N] gridShape()() scope const @property { return _data.shape; } @@ -225,7 +178,7 @@ struct Constant(F, size_t N = 1, FirstGridIterator = immutable(F)*, NextGridIter Complexity: `O(log(grid.length))` +/ - auto opCall(X...)(in X xs) const + auto opCall(X...)(in X xs) scope const if (X.length == N) // @FUTURE@ // X.length == N || derivative == 0 && X.length && X.length <= N diff --git a/source/mir/interpolate/linear.d b/source/mir/interpolate/linear.d index 9d068c93..d7ba0319 100644 --- a/source/mir/interpolate/linear.d +++ b/source/mir/interpolate/linear.d @@ -14,7 +14,6 @@ T2=$(TR $(TDNW $(LREF $1)) $(TD $+)) module mir.interpolate.linear; import std.traits; -private alias AliasSeq(T...) = T; import mir.primitives; import mir.ndslice.slice; import mir.math.common: optmath; @@ -40,8 +39,10 @@ Constraints: Returns: $(LREF Linear) +/ template linear(T, size_t N = 1, FirstGridIterator = immutable(T)*, NextGridIterators = Repeat!(N - 1, FirstGridIterator)) - // if (isFloatingPoint!T && is(T == Unqual!T) && N <= 6) + if (mir.internal.utility.isFloatingPoint!T && is(T == Unqual!T) && N <= 6) { + import std.meta: AliasSeq; + private alias GridIterators = AliasSeq!(FirstGridIterator, NextGridIterators); private alias GridVectors = Linear!(T, N, GridIterators).GridVectors; @@ -59,16 +60,8 @@ template linear(T, size_t N = 1, FirstGridIterator = immutable(T)*, NextGridIter Linear!(T, N, GridIterators) linear(yIterator, SliceKind ykind)( GridVectors grid, scope Slice!(yIterator, N, ykind) values, - bool forceCopyValues = false - ) + ) pure @trusted { - static if (__traits(compiles, typeof(return)(grid, values))) - { - if (!forceCopyValues) - { - return typeof(return)(grid, values); - } - } import std.algorithm.mutation: move; auto ret = typeof(return)(grid); ret._data[] = values; @@ -121,10 +114,12 @@ version(mir_test) ///// compute test data //// auto test_grid = cartesian(x0 + 1.23, x1 + 3.23); auto real_data = test_grid.map!f; - auto interp_data = test_grid.vmap(interpolant); + ()@trusted{ + auto interp_data = test_grid.vmap(interpolant); - ///// verify result //// - assert(all!appreq(interp_data, real_data)); + ///// verify result //// + assert(all!appreq(interp_data, real_data)); + }(); //// check derivatives //// auto z0 = 1.23; @@ -167,10 +162,12 @@ version(mir_test) ///// compute test data //// auto test_grid = cartesian(x0 + 1.23, x1 + 3.23, x2 - 3); auto real_data = test_grid.map!f; - auto interp_data = test_grid.vmap(interpolant); + ()@trusted{ + auto interp_data = test_grid.vmap(interpolant); - ///// verify result //// - assert(all!appreq(interp_data, real_data)); + ///// verify result //// + assert(all!appreq(interp_data, real_data)); + }(); //// check derivatives //// auto z0 = 1.23; @@ -191,94 +188,50 @@ Multivariate linear interpolant with nodes on rectilinear grid. struct Linear(F, size_t N = 1, FirstGridIterator = immutable(F)*, NextGridIterators...) if (N && N <= 6 && NextGridIterators.length == N - 1) { - import std.meta: staticMap; + import mir.rcarray; + import std.meta: AliasSeq, staticMap; + package alias GridIterators = AliasSeq!(FirstGridIterator, NextGridIterators); package alias GridVectors = staticMap!(GridVector, GridIterators); /// $(RED For internal use.) - Slice!(F*, N) _data; + mir_slice!(mir_rci!F, N) _data; /// Grid iterators. $(RED For internal use.) GridIterators _grid; - /// - bool _ownsData; import mir.utility: min, max; package enum alignment = min(64u, F.sizeof).max(size_t.sizeof); - package ref shared(sizediff_t) counter() @trusted @property - { - assert(_ownsData); - auto p = cast(shared sizediff_t*) _data.ptr; - return *(p - 1); - } - - /// - this(this) @safe nothrow @nogc - { - import core.atomic: atomicOp; - if (_ownsData) - counter.atomicOp!"+="(1); - } - - /++ - Frees _data if $(LREF Spline._freeData) is true. - +/ - ~this() @trusted nothrow @nogc - { - import mir.internal.memory; - import core.atomic: atomicOp; - - if (_ownsData) - if (counter.atomicOp!"-="(1) <= 0) - alignedFree(cast(void*)(_data.ptr) - alignment); - } - /++ +/ - this()(GridVectors grid) @trusted nothrow @nogc + this(GridVectors grid) scope @safe @nogc { - import mir.internal.memory; - import mir.ndslice.topology: iota; - + size_t length = 1; size_t[N] shape; + enum msg = "linear interpolant: minimal allowed length for the grid equals 2."; + version(D_Exceptions) + static immutable exc = new Exception(msg); foreach(i, ref x; grid) { - assert(x.length >= 2, "linear interpolation: minimal allowed length for the grid equals 2."); - shape[i] = x.length; - } - - auto data_ptr = cast(F*) (alignedAllocate(F.sizeof * shape.iota.elementCount + alignment, alignment) + alignment); - if(data_ptr is null) - assert(0, "No memory"); - - this._data = data_ptr.sliced(shape); - this._grid = staticMap!(iter, grid); - this._ownsData = true; - this.counter = 1; - } - - /++ - +/ - this()(GridVectors grid, Slice!(immutable(F)*, N) values) @trusted nothrow @nogc - { - import mir.internal.memory; - import mir.ndslice.topology: iota; - - foreach(i, ref x; grid) - { - assert(x.length >= 2, "linear interpolation: minimal allowed length for the grid equals 2."); - assert(values.length!i == x.length, "grid length should mutch to the values length"); + if (x.length < 2) + { + version(D_Exceptions) + throw exc; + else + assert(0, msg); + } + length *= shape[i] = x.length; } - this._data = values; + auto rca = mir_rcarray!F(length, alignment); + this._data = rca.asSlice.sliced(shape); this._grid = staticMap!(iter, grid); - this._ownsData = false; } @trusted: /// - GridVectors[dimension] grid(size_t dimension = 0)() const @property + GridVectors[dimension] grid(size_t dimension = 0)() scope return const @property if (dimension < N) { return _grid[dimension].sliced(_data._lengths[dimension]); @@ -287,14 +240,14 @@ struct Linear(F, size_t N = 1, FirstGridIterator = immutable(F)*, NextGridIterat /++ Returns: intervals count. +/ - size_t intervalCount(size_t dimension = 0)() const @property + size_t intervalCount(size_t dimension = 0)() scope const @property { assert(_data._lengths[dimension] > 1); return _data._lengths[dimension] - 1; } /// - size_t[N] gridShape()() const @property + size_t[N] gridShape()() scope const @property { return _data.shape; } @@ -311,7 +264,7 @@ struct Linear(F, size_t N = 1, FirstGridIterator = immutable(F)*, NextGridIterat Complexity: `O(log(grid.length))` +/ - auto opCall(X...)(in X xs) const @trusted + auto opCall(X...)(in X xs) scope const @trusted if (X.length == N) // @FUTURE@ // X.length == N || derivative == 0 && X.length && X.length <= N diff --git a/source/mir/interpolate/pchip.d b/source/mir/interpolate/pchip.d index ac2f6f08..cdcf400e 100644 --- a/source/mir/interpolate/pchip.d +++ b/source/mir/interpolate/pchip.d @@ -58,7 +58,7 @@ template pchip(T, size_t N = 1, FirstGridIterator = immutable(T)*, NextGridItera /// version(mir_test) -@safe nothrow unittest +@safe unittest { import std.math: approxEqual; import mir.ndslice.allocation: slice; @@ -70,20 +70,22 @@ version(mir_test) auto interpolant = pchip!double(x, y); auto xs = x[0 .. $ - 1] + 0.5; - auto ys = xs.vmap(interpolant); - - assert(ys.approxEqual([ - 5.333333333333334, - 2.500000000000000, - 10.000000000000000, - 4.288971807628524, - 11.202580845771145, - 16.250000000000000, - 17.962962962962962, - 5.558593750000000, - 17.604662698412699, - ])); + () @trusted { + auto ys = xs.vmap(interpolant); + + assert(ys.approxEqual([ + 5.333333333333334, + 2.500000000000000, + 10.000000000000000, + 4.288971807628524, + 11.202580845771145, + 16.250000000000000, + 17.962962962962962, + 5.558593750000000, + 17.604662698412699, + ])); + }(); } // Check direction equality diff --git a/source/mir/interpolate/spline.d b/source/mir/interpolate/spline.d index 4a507cd1..d8d46707 100644 --- a/source/mir/interpolate/spline.d +++ b/source/mir/interpolate/spline.d @@ -34,7 +34,7 @@ import mir.ndslice.traits; @fmamath: /// -@safe pure nothrow version(mir_test) unittest +@trusted pure version(mir_test) unittest { import std.math: approxEqual; import mir.ndslice.slice: sliced; @@ -111,66 +111,70 @@ import mir.ndslice.traits; auto interpolant = x.spline!double(y); // default boundary condition is 'not-a-knot' auto xs = x + 0.5; - auto ys = xs.vmap(interpolant); - - auto r = - [ 5.56971848, - 9.30342403, - 4.44139761, - -0.74740285, - 3.00994108, - 1.50750417, - 1.73144979, - 2.64860361, - 0.64413911, - 10.81768928]; - - assert(all!approxEqual(ys, r)); - - // first derivative - auto d1 = xs.vmap(interpolant.aliasCall!"withDerivative").map!"a[1]"; - auto r1 = - [-4.51501279, - 2.15715986, - -7.28363308, - -2.14050449, - 0.03693092, - -0.49618999, - 0.58109933, - -0.52926703, - 0.7819035 , - 6.70632693]; - assert(all!approxEqual(d1, r1)); - - // second derivative - auto d2 = xs.vmap(interpolant.aliasCall!"withTwoDerivatives").map!"a[2]"; - auto r2 = - [ 7.07104751, - -2.62293241, - -0.01468508, - 5.70609505, - -2.02358911, - 0.72142061, - 0.25275483, - -0.6133589 , - 1.26894416, - 2.68067146]; - assert(all!approxEqual(d2, r2)); - - // third derivative (6 * a) - auto d3 = xs.vmap(interpolant.aliasCall!("opCall", 3)).map!"a[3]"; - auto r3 = - [-3.23132664, - -3.23132664, - 14.91047457, - -3.46891432, - 1.88520325, - -0.16559031, - -0.44056064, - 0.47057577, - 0.47057577, - 0.47057577]; - assert(all!approxEqual(d3, r3)); + + ()@trusted{ + + auto ys = xs.vmap(interpolant); + + auto r = + [ 5.56971848, + 9.30342403, + 4.44139761, + -0.74740285, + 3.00994108, + 1.50750417, + 1.73144979, + 2.64860361, + 0.64413911, + 10.81768928]; + + assert(all!approxEqual(ys, r)); + + // first derivative + auto d1 = xs.vmap(interpolant.aliasCall!"withDerivative").map!"a[1]"; + auto r1 = + [-4.51501279, + 2.15715986, + -7.28363308, + -2.14050449, + 0.03693092, + -0.49618999, + 0.58109933, + -0.52926703, + 0.7819035 , + 6.70632693]; + assert(all!approxEqual(d1, r1)); + + // second derivative + auto d2 = xs.vmap(interpolant.aliasCall!"withTwoDerivatives").map!"a[2]"; + auto r2 = + [ 7.07104751, + -2.62293241, + -0.01468508, + 5.70609505, + -2.02358911, + 0.72142061, + 0.25275483, + -0.6133589 , + 1.26894416, + 2.68067146]; + assert(all!approxEqual(d2, r2)); + + // third derivative (6 * a) + auto d3 = xs.vmap(interpolant.aliasCall!("opCall", 3)).map!"a[3]"; + auto r3 = + [-3.23132664, + -3.23132664, + 14.91047457, + -3.46891432, + 1.88520325, + -0.16559031, + -0.44056064, + 0.47057577, + 0.47057577, + 0.47057577]; + assert(all!approxEqual(d3, r3)); + }(); } import std.stdio; @@ -197,7 +201,9 @@ version(mir_test) 0.03314357, 0.03335896, 0.03355892, 0.03375674, 0.03396413, 0.03419436, 0.03446018, 0.03477529, 0.03515072, 0.0356 ]; - assert(approxEqual(xs.sliced.vmap(interpolation), data, 1e-4, 1e-4)); + ()@trusted{ + assert(approxEqual(xs.sliced.vmap(interpolation), data, 1e-4, 1e-4)); + }(); } /// R^2 -> R: Bicubic interpolation @@ -435,88 +441,60 @@ Multivariate cubic spline with nodes on rectilinear grid. struct Spline(F, size_t N = 1, FirstGridIterator = immutable(F)*, NextGridIterators...) if (N && N <= 6 && NextGridIterators.length == N - 1) { + import mir.rcarray; + package alias GridIterators = AliasSeq!(FirstGridIterator, NextGridIterators); package alias GridVectors = staticMap!(GridVector, GridIterators); @fmamath: /// Aligned buffer allocated with `mir.internal.memory`. $(RED For internal use.) - Slice!(F[2 ^^ N]*, N) _data; + mir_slice!(mir_rci!(F[2 ^^ N]), N) _data; /// Grid iterators. $(RED For internal use.) GridIterators _grid; import mir.utility: min, max; package enum alignment = min(64u, F[2 ^^ N].sizeof).max(size_t.sizeof); - package ref shared(sizediff_t) counter() @trusted @property - { - auto p = cast(shared sizediff_t*) _data.ptr; - return *(p - 1); - } - - /// - this(this) @safe nothrow @nogc - { - import core.atomic: atomicOp; - counter.atomicOp!"+="(1); - } - - /++ - Frees _data if $(LREF Spline._freeData) is true. +/ - ~this() @trusted nothrow @nogc + this()(GridVectors grid) @trusted @nogc { - import mir.internal.memory; - import core.atomic: atomicOp; - - if (_data.ptr) - if (counter.atomicOp!"-="(1) <= 0) - alignedFree(cast(void*)(_data.ptr) - alignment); - } - - /++ - +/ - this()(GridVectors grid) @trusted nothrow @nogc - { - import mir.internal.memory; - import mir.ndslice.topology: iota; - + size_t length = 1; size_t[N] shape; + enum msg = "linear interpolant: minimal allowed length for the grid equals 2."; + version(D_Exceptions) + static immutable exc = new Exception(msg); foreach(i, ref x; grid) { - assert(x.length >= 2, "cubic spline interpolant: minimal allowed length for the grid equals 2."); - shape[i] = x.length; - // assert(x.length == values.length!i, "grid[" ~ i.stringof ~ - // "].length should be equal to values.length!" ~ i.stringof ~ "."); + if (x.length < 2) + { + version(D_Exceptions) + throw exc; + else + assert(0, msg); + } + length *= shape[i] = x.length; } - auto data_ptr = cast(F[2 ^^ N]*) (alignedAllocate(F[2 ^^ N].sizeof * shape.iota.elementCount + alignment, alignment) + alignment); - if(data_ptr is null) - assert(0); - - this._data = data_ptr.sliced(shape); - debug - { - this._data.opIndexAssign(F[2 ^^ N].init); - } + auto rca = mir_rcarray!(F[2 ^^ N])(length, alignment); + this._data = rca.asSlice.sliced(shape); this._grid = staticMap!(iter, grid); - this.counter = 1; } - package static auto pickDataSubslice(D)(auto ref D data, size_t index) @trusted + package static auto pickDataSubslice(D)(auto scope ref D data, size_t index) @trusted { auto strides = data.strides; foreach (i; Iota!(strides.length)) strides[i] *= DeepElementType!D.length; - return Slice!(F*, strides.length, Universal)(data.shape, strides, data.iterator.ptr + index); + return Slice!(F*, strides.length, Universal)(data.shape, strides, data._iterator._iterator.ptr + index); } /++ Assigns function values to the internal memory. $(RED For internal use.) +/ - void _values(SliceKind kind, Iterator)(scope Slice!(Iterator, N, kind) values) @property @trusted + void _values(SliceKind kind, Iterator)(scope Slice!(Iterator, N, kind) values) scope @property @trusted { assert(values.shape == _data.shape, "'values' should have the same shape as the .gridShape"); pickDataSubslice(_data, 0)[] = values; @@ -531,7 +509,7 @@ struct Spline(F, size_t N = 1, FirstGridIterator = immutable(F)*, NextGridIterat $(RED For internal use.) +/ - void _computeDerivatives()(SplineBoundaryCondition!F lbc, SplineBoundaryCondition!F rbc) @trusted nothrow @nogc + void _computeDerivatives()(SplineBoundaryCondition!F lbc, SplineBoundaryCondition!F rbc) scope @trusted nothrow @nogc { import mir.internal.memory; import mir.algorithm.iteration: maxLength; @@ -549,7 +527,7 @@ struct Spline(F, size_t N = 1, FirstGridIterator = immutable(F)*, NextGridIterat /// ditto pragma(inline, false) - void _computeDerivativesTemp()(SplineBoundaryCondition!F lbc, SplineBoundaryCondition!F rbc, Slice!(F*) temp) @system nothrow @nogc + void _computeDerivativesTemp()(SplineBoundaryCondition!F lbc, SplineBoundaryCondition!F rbc, Slice!(F*) temp) scope @system nothrow @nogc { import mir.internal.memory; import mir.algorithm.iteration: maxLength, each; @@ -590,7 +568,7 @@ struct Spline(F, size_t N = 1, FirstGridIterator = immutable(F)*, NextGridIterat @trusted: /// - GridVectors[dimension] grid(size_t dimension = 0)() const @property + GridVectors[dimension] grid(size_t dimension = 0)() scope return const @property if (dimension < N) { return _grid[dimension].sliced(_data._lengths[dimension]); @@ -599,14 +577,14 @@ struct Spline(F, size_t N = 1, FirstGridIterator = immutable(F)*, NextGridIterat /++ Returns: intervals count. +/ - size_t intervalCount(size_t dimension = 0)() const @property + size_t intervalCount(size_t dimension = 0)() scope const @property { assert(_data._lengths[dimension] > 1); return _data._lengths[dimension] - 1; } /// - size_t[N] gridShape()() const @property + size_t[N] gridShape()() scope const @property { return _data.shape; } @@ -622,7 +600,7 @@ struct Spline(F, size_t N = 1, FirstGridIterator = immutable(F)*, NextGridIterat /// template opCall(uint derivative : 2) { - auto opCall(X...)(in X xs) const + auto opCall(X...)(in X xs) scope const if (X.length == N) // @FUTURE@ // X.length == N || derivative == 0 && X.length && X.length <= N @@ -653,7 +631,7 @@ struct Spline(F, size_t N = 1, FirstGridIterator = immutable(F)*, NextGridIterat Complexity: `O(log(points.length))` +/ - auto opCall(X...)(in X xs) const @trusted + auto opCall(X...)(in X xs) scope const @trusted if (X.length == N) // @FUTURE@ // X.length == N || derivative == 0 && X.length && X.length <= N diff --git a/source/mir/math/sum.d b/source/mir/math/sum.d index 2d0040ed..9b32db12 100644 --- a/source/mir/math/sum.d +++ b/source/mir/math/sum.d @@ -1024,7 +1024,7 @@ public: } ///Returns the value of the sum. - T sum()() const + T sum()() scope const { /++ Returns the value of the sum, rounded to the nearest representable diff --git a/source/mir/ndslice/field.d b/source/mir/ndslice/field.d index 7868d2fc..c55855ce 100644 --- a/source/mir/ndslice/field.d +++ b/source/mir/ndslice/field.d @@ -1,7 +1,7 @@ /++ This is a submodule of $(MREF mir,ndslice). -Field is a type with `opIndex(ptrdiff_t index)` primitive. +Field is a type with `opIndex()(ptrdiff_t index)` primitive. An iterator can be created on top of a field using $(SUBREF iterator, FieldIterator). An ndslice can be created on top of a field using $(SUBREF slice, slicedField). @@ -238,7 +238,7 @@ struct ZipField(Fields...) if (Fields.length > 1) { @optmath: - import mir.functional: RefTuple, Ref; + import mir.functional: RefTuple, Ref, _ref; import std.meta: anySatisfy; /// @@ -750,14 +750,14 @@ struct LinspaceField(T) @optmath: /// - size_t length() scope const @property + size_t length(size_t dimension = 0)() scope const @property + if (dimension == 0) { return _length; } /// - size_t[1] shape(size_t dimension = 0)() scope const @property @nogc - if (dimension == 0) + size_t[1] shape()() scope const @property @nogc { return [_length]; } diff --git a/source/mir/ndslice/fuse.d b/source/mir/ndslice/fuse.d index 11306d2c..bfe2143f 100644 --- a/source/mir/ndslice/fuse.d +++ b/source/mir/ndslice/fuse.d @@ -95,7 +95,7 @@ template fuse(Dimensions...) ret.each!(emplaceRef!T)(r); } } - return R(ret._lengths, ret._strides, (() @trusted => cast(T*)ret._iterator)()); + return R(ret._structure, (() @trusted => cast(T*)ret._iterator)()); } } @@ -244,7 +244,7 @@ auto fuseCells(S)(S cells) auto ret = cells.fuseCellsShape.uninitSlice!UT; ret.fuseCellsAssign!(emplaceRef!T) = cells; alias R = Slice!(T*, ret.N); - return R(ret._lengths, ret._strides, (() @trusted => cast(T*)ret._iterator)()); + return R(ret._structure, (() @trusted => cast(T*)ret._iterator)()); } } diff --git a/source/mir/ndslice/iterator.d b/source/mir/ndslice/iterator.d index eda304d5..1c8bb057 100644 --- a/source/mir/ndslice/iterator.d +++ b/source/mir/ndslice/iterator.d @@ -66,7 +66,7 @@ enum std_ops = q{ return ret; } - ptrdiff_t opBinary(string op : "-")(auto scope ref const typeof(this) right) scope const + ptrdiff_t opBinary(string op : "-")(scope ref const typeof(this) right) scope const { return this._iterator - right._iterator; } bool opEquals()(scope ref const typeof(this) right) scope const @@ -228,13 +228,13 @@ struct RetroIterator(Iterator) /// auto lightConst()() const @property { - return RetroIterator!(LightConstOf!Iterator)(mir.qualifier.lightConst(_iterator)); + return RetroIterator!(LightConstOf!Iterator)(.lightConst(_iterator)); } /// auto lightImmutable()() immutable @property { - return RetroIterator!(LightImmutableOf!Iterator)(mir.qualifier.lightImmutable(_iterator)); + return RetroIterator!(LightImmutableOf!Iterator)(.lightImmutable(_iterator)); } /// @@ -250,7 +250,7 @@ struct RetroIterator(Iterator) { --_iterator; } auto ref opIndex()(ptrdiff_t index) - { return *(_iterator - index); } + { return _iterator[-index]; } void opOpAssign(string op : "-")(ptrdiff_t index) scope { _iterator += index; } @@ -266,7 +266,7 @@ struct RetroIterator(Iterator) return ret; } - ptrdiff_t opBinary(string op : "-")(auto scope ref const typeof(this) right) scope const + ptrdiff_t opBinary(string op : "-")(scope ref const typeof(this) right) scope const { return right._iterator - this._iterator; } bool opEquals()(scope ref const typeof(this) right) scope const @@ -381,7 +381,7 @@ struct StrideIterator(Iterator) return ret; } - ptrdiff_t opBinary(string op : "-")(auto scope ref const typeof(this) right) scope const + ptrdiff_t opBinary(string op : "-")(scope ref const typeof(this) right) scope const { return (this._iterator - right._iterator) / _stride; } bool opEquals()(scope ref const typeof(this) right) scope const @@ -458,7 +458,7 @@ package template _zip_fronts(Iterators...) { enum i = Iterators.length - 1; static if (__traits(compiles, &Iterators[i].init[sizediff_t.init])) - enum _zip_fronts = _zip_fronts!(Iterators[0 .. i]) ~ "Ref!(typeof(*Iterators[" ~ i.stringof ~ "].init))(*_iterators[" ~ i.stringof ~ "]), "; + enum _zip_fronts = _zip_fronts!(Iterators[0 .. i]) ~ "_ref(*_iterators[" ~ i.stringof ~ "]), "; else enum _zip_fronts = _zip_fronts!(Iterators[0 .. i]) ~ "*_iterators[" ~ i.stringof ~ "], "; } @@ -472,7 +472,7 @@ package template _zip_index(Iterators...) { enum i = Iterators.length - 1; static if (__traits(compiles, &Iterators[i].init[sizediff_t.init])) - enum _zip_index = _zip_index!(Iterators[0 .. i]) ~ "Ref!(typeof(_iterators[" ~ i.stringof ~ "][index]))(_iterators[" ~ i.stringof ~ "][index]), "; + enum _zip_index = _zip_index!(Iterators[0 .. i]) ~ "_ref(_iterators[" ~ i.stringof ~ "][index]), "; else enum _zip_index = _zip_index!(Iterators[0 .. i]) ~ "_iterators[" ~ i.stringof ~ "][index], "; } @@ -489,7 +489,9 @@ struct ZipIterator(Iterators...) if (Iterators.length > 1) { @optmath: - import mir.functional: RefTuple, Ref; + import std.traits: ConstOf, ImmutableOf; + import std.meta: staticMap; + import mir.functional: RefTuple, Ref, _ref; /// Iterators _iterators; @@ -518,6 +520,13 @@ struct ZipIterator(Iterators...) auto opUnary(string op : "*")() { return mixin("RefTuple!(_zip_types!Iterators)(" ~ _zip_fronts!Iterators ~ ")"); } + + auto opUnary(string op : "*")() const + { return mixin("RefTuple!(_zip_types!Iterators)(" ~ _zip_fronts!Iterators ~ ")"); } + + auto opUnary(string op : "*")() immutable + { return mixin("RefTuple!(_zip_types!Iterators)(" ~ _zip_fronts!Iterators ~ ")"); } + void opUnary(string op)() scope if (op == "++" || op == "--") { @@ -553,7 +562,7 @@ struct ZipIterator(Iterators...) return ret; } - ptrdiff_t opBinary(string op : "-")(auto scope ref const typeof(this) right) scope const + ptrdiff_t opBinary(string op : "-")(scope ref const typeof(this) right) scope const { return this._iterators[0] - right._iterators[0]; } bool opEquals()(scope ref const typeof(this) right) scope const @@ -698,7 +707,7 @@ struct CachedIterator(Iterator, CacheIterator, FlagIterator) return ret; } - ptrdiff_t opBinary(string op : "-")(auto scope ref const typeof(this) right) scope const + ptrdiff_t opBinary(string op : "-")(scope ref const typeof(this) right) scope const { return (this._iterator - right._iterator) / count; } bool opEquals()(scope ref const typeof(this) right) scope const @@ -728,7 +737,7 @@ private enum map_primitives = q{ return _fun(*_iterator); } - auto ref opIndex()(ptrdiff_t index) + auto ref opIndex()(ptrdiff_t index) scope { static if (is(typeof(_iterator[0]) : RefTuple!T, T...)) { @@ -741,7 +750,7 @@ private enum map_primitives = q{ static if (!__traits(compiles, &opIndex(ptrdiff_t.init))) { - auto ref opIndexAssign(T)(auto ref T value, ptrdiff_t index) + auto ref opIndexAssign(T)(auto ref T value, ptrdiff_t index) scope { static if (is(typeof(_iterator[0]) : RefTuple!T, T...)) { @@ -944,7 +953,7 @@ struct MemberIterator(Iterator, string member) static if (!__traits(compiles, &opIndex(ptrdiff_t.init))) { - auto ref opIndexAssign(T)(auto ref T value, ptrdiff_t index) + auto ref opIndexAssign(T)(auto ref T value, ptrdiff_t index) scope { return __traits(getMember, _iterator[index], member) = value; } @@ -1047,7 +1056,7 @@ struct BytegroupIterator(Iterator, size_t count, DestinationType) return ret; } - ptrdiff_t opBinary(string op : "-")(auto scope ref const typeof(this) right) scope const + ptrdiff_t opBinary(string op : "-")(scope ref const typeof(this) right) scope const { return (this._iterator - right._iterator) / count; } bool opEquals()(scope ref const typeof(this) right) scope const @@ -1175,7 +1184,7 @@ struct IndexIterator(Iterator, Field) return _field[*_iterator]; } - auto ref opIndex(ptrdiff_t index) + auto ref opIndex()(ptrdiff_t index) { static if (is(typeof(_iterator[0]) : RefTuple!T, T...)) { @@ -1188,7 +1197,7 @@ struct IndexIterator(Iterator, Field) static if (!__traits(compiles, &opIndex(ptrdiff_t.init))) { - auto ref opIndexAssign(T)(auto ref T value, ptrdiff_t index) + auto ref opIndexAssign(T)(auto ref T value, ptrdiff_t index) scope { static if (is(typeof(_iterator[0]) : RefTuple!T, T...)) { @@ -1260,7 +1269,7 @@ struct SubSliceIterator(Iterator, Sliceable) return _sliceable[i[0] .. i[1]]; } - auto ref opIndex(ptrdiff_t index) + auto ref opIndex()(ptrdiff_t index) { auto i = _iterator[index]; return _sliceable[i[0] .. i[1]]; @@ -1302,7 +1311,7 @@ struct ChopIterator(Iterator, Sliceable) return _sliceable[*_iterator .. _iterator[1]]; } - auto ref opIndex(ptrdiff_t index) + auto ref opIndex()(ptrdiff_t index) { return _sliceable[_iterator[index] .. _iterator[index + 1]]; } @@ -1322,32 +1331,30 @@ struct SliceIterator(Iterator, size_t N = 1, SliceKind kind = Contiguous) /// alias Element = Slice!(Iterator, N, kind); /// - size_t[Element.N] _lengths; - /// - ptrdiff_t[Element.S] _strides; + Element._Structure _structure; /// Iterator _iterator; /// auto lightConst()() const @property { - return SliceIterator!(LightConstOf!Iterator, N, kind)(_lengths, _strides, .lightConst(_iterator)); + return SliceIterator!(LightConstOf!Iterator, N, kind)(_structure, .lightConst(_iterator)); } /// auto lightImmutable()() immutable @property { - return SliceIterator!(LightImmutableOf!Iterator, N, kind)(_lengths, _strides, .lightImmutable(_iterator)); + return SliceIterator!(LightImmutableOf!Iterator, N, kind)(_structure, .lightImmutable(_iterator)); } auto opUnary(string op : "*")() { - return Element(_lengths, _strides, _iterator); + return Element(_structure, _iterator); } auto opIndex()(ptrdiff_t index) { - return Element(_lengths, _strides, _iterator + index); + return Element(_structure, _iterator + index); } mixin(std_ops); @@ -1446,7 +1453,7 @@ struct FieldIterator(Field) return ret; } - ptrdiff_t opBinary(string op : "-")(auto scope ref const typeof(this) right) scope const + ptrdiff_t opBinary(string op : "-")(scope ref const typeof(this) right) scope const { return this._index - right._index; } bool opEquals()(scope ref const typeof(this) right) scope const @@ -1583,7 +1590,7 @@ struct FlattenedIterator(Iterator, size_t N, SliceKind kind) static if (isMutable!(_slice.DeepElement) && !_slice.hasAccessByRef) /// - auto ref opIndexAssign(E)(auto scope ref E elem, size_t index) scope return + auto ref opIndexAssign(E)(scope ref E elem, size_t index) scope return { return _slice._iterator[getShift(index)] = elem; } @@ -1626,7 +1633,7 @@ struct FlattenedIterator(Iterator, size_t N, SliceKind kind) return ret; } - ptrdiff_t opBinary(string op : "-")(auto scope ref const typeof(this) right) scope const + ptrdiff_t opBinary(string op : "-")(scope ref const typeof(this) right) scope const { ptrdiff_t ret = this._indexes[0] - right._indexes[0]; foreach (i; Iota!(1, N)) @@ -1817,7 +1824,7 @@ struct StairsIterator(Iterator, string direction) return ret; } - ptrdiff_t opBinary(string op : "-")(auto scope ref const typeof(this) right) scope const + ptrdiff_t opBinary(string op : "-")(scope ref const typeof(this) right) scope const { static if (direction == "+") return this._length - right._length; diff --git a/source/mir/ndslice/slice.d b/source/mir/ndslice/slice.d index f74edc1b..bb6a9c56 100644 --- a/source/mir/ndslice/slice.d +++ b/source/mir/ndslice/slice.d @@ -242,7 +242,7 @@ auto sliced(size_t N, Iterator)(Iterator iterator, size_t[N] lengths...) assert(lengthsProduct(_lengths) <= iterator.length, "array length should be greater or equal to the product of constructed ndslice lengths"); auto ptr = iterator.length ? &iterator[0] : null; - return Slice!(typeof(C.init[0])*, N)(_lengths, _strides[0 .. 0], ptr); + return Slice!(typeof(C.init[0])*, N)(_lengths, ptr); } else { @@ -254,7 +254,7 @@ auto sliced(size_t N, Iterator)(Iterator iterator, size_t[N] lengths...) iterator = iterator + 34; iterator -= 34; } - return Slice!(C, N)(_lengths, _strides[0 .. 0], iterator); + return Slice!(C, N)(_lengths, iterator); } } @@ -318,7 +318,7 @@ Params: Returns: 1-dimensional slice +/ -auto sliced(T)(T[] array) @safe +auto sliced(T)(T[] array) { return .sliced(array, [array.length]); } @@ -345,18 +345,14 @@ Slice!(Iterator, N, kind) (Slice!(Iterator, 1, kind) slice, size_t[N] lengths...) if (N) { - auto c = Slice!(Iterator, N)(lengths, sizediff_t[0].init, slice._iterator); - static if (kind == Contiguous) + typeof(return)._Structure structure; + structure[0] = lengths; + static if (kind != Contiguous) { - return c; - } - else - { - auto u = c.universal; - foreach (i; Iota!N) - u._strides[i] *= slice._strides[0]; - return u; + import mir.ndslice.topology: iota; + structure[1] = structure[0].iota.strides; } + return typeof(return)(structure, slice._iterator); } /// @@ -673,12 +669,12 @@ struct mir_slice(Iterator_, size_t N_ = 1, SliceKind kind_ = Contiguous, Labels_ else { static if (kind == Universal || dimension == N - 1) - alias Element = Slice!(Iterator, N - 1, Universal); + alias Element = mir_slice!(Iterator, N - 1, Universal); else static if (N == 2 || kind == Contiguous && dimension == 0) - alias Element = Slice!(Iterator, N - 1); + alias Element = mir_slice!(Iterator, N - 1); else - alias Element = Slice!(Iterator, N - 1, Canonical); + alias Element = mir_slice!(Iterator, N - 1, Canonical); } } @@ -713,22 +709,41 @@ struct mir_slice(Iterator_, size_t N_ = 1, SliceKind kind_ = Contiguous, Labels_ && Slices.length <= N && allSatisfy!(templateOr!isSlice, Slices); - /// - public size_t[N] _lengths; - /// - public ptrdiff_t[S] _strides; + static if (S) + { + /// + public alias _Structure = AliasSeq!(size_t[N], ptrdiff_t[S]); + /// + _Structure _structure; + /// + public alias _lengths = _structure[0]; + /// + public alias _strides = _structure[1]; + } + else + { + /// + public alias _Structure = AliasSeq!(size_t[N]); + /// + _Structure _structure; + /// + public alias _lengths = _structure[0]; + /// + public enum ptrdiff_t[S] _strides = ptrdiff_t[S].init; + } + /// public Iterator _iterator; /// public Labels _labels; - sizediff_t backIndex(size_t dimension = 0)() @safe @property const + sizediff_t backIndex(size_t dimension = 0)() @safe @property scope const if (dimension < N) { return _stride!dimension * (_lengths[dimension] - 1); } - size_t indexStride(size_t I)(size_t[I] _indexes) @safe const + size_t indexStride(size_t I)(size_t[I] _indexes) @safe scope const { static if (_indexes.length) { @@ -781,93 +796,93 @@ struct mir_slice(Iterator_, size_t N_ = 1, SliceKind kind_ = Contiguous, Labels_ public: - static if (S == 0) - { + // static if (S == 0) + // { /// Defined for Contiguous Slice only - this()(size_t[N] lengths, in ptrdiff_t[] empty, Iterator iterator, Labels labels) - { - version(LDC) pragma(inline, true); - assert(empty.length == 0); - this._lengths = lengths; - this._iterator = iterator; - } - - /// ditto - this()(size_t[N] lengths, Iterator iterator, Labels labels) - { - version(LDC) pragma(inline, true); - this._lengths = lengths; - this._iterator = iterator; - } - - /// ditto - this()(size_t[N] lengths, in ptrdiff_t[] empty, ref Iterator iterator, ref Labels labels) - { - version(LDC) pragma(inline, true); - assert(empty.length == 0); - this._lengths = lengths; - this._iterator = iterator; - } - - /// ditto - this()(size_t[N] lengths, ref Iterator iterator, ref Labels labels) - { - version(LDC) pragma(inline, true); - this._lengths = lengths; - this._iterator = iterator; - } - } - - version(LDC) - private enum classicConstructor = true; - else - private enum classicConstructor = S > 0; - - static if (classicConstructor) - { + // this()(size_t[N] lengths, in ptrdiff_t[] empty, Iterator iterator, Labels labels) + // { + // version(LDC) pragma(inline, true); + // assert(empty.length == 0); + // this._lengths = lengths; + // this._iterator = iterator; + // } + + // /// ditto + // this()(size_t[N] lengths, Iterator iterator, Labels labels) + // { + // version(LDC) pragma(inline, true); + // this._lengths = lengths; + // this._iterator = iterator; + // } + + // /// ditto + // this()(size_t[N] lengths, in ptrdiff_t[] empty, Iterator iterator, Labels labels) + // { + // version(LDC) pragma(inline, true); + // assert(empty.length == 0); + // this._lengths = lengths; + // this._iterator = iterator; + // } + + // /// ditto + // this()(size_t[N] lengths, Iterator iterator, Labels labels) + // { + // version(LDC) pragma(inline, true); + // this._lengths = lengths; + // this._iterator = iterator; + // } + // } + + // version(LDC) + // private enum classicConstructor = true; + // else + // private enum classicConstructor = S > 0; + + // static if (classicConstructor) + // { /// Defined for Canonical and Universal Slices (DMD, GDC, LDC) and for Contiguous Slices (LDC) - this()(size_t[N] lengths, ptrdiff_t[S] strides, Iterator iterator, Labels labels) - { - version(LDC) pragma(inline, true); - this._lengths = lengths; - this._strides = strides; - this._iterator = iterator; - this._labels = labels; - } - - /// ditto - this()(size_t[N] lengths, ptrdiff_t[S] strides, ref Iterator iterator, ref Labels labels) - { - version(LDC) pragma(inline, true); - this._lengths = lengths; - this._strides = strides; - this._iterator = iterator; - this._labels = labels; - } - } - - /// Construct from null - this()(typeof(null)) - { - version(LDC) pragma(inline, true); - } - - static if (doUnittest) - /// - @safe pure version(mir_test) unittest - { - import mir.ndslice.slice; - alias Array = Slice!(double*); - Array a = null; - auto b = Array(null); - assert(a.empty); - assert(b.empty); - - auto fun(Array a = null) - { + // this()(size_t[N] lengths, ptrdiff_t[S] strides, Iterator iterator, Labels labels) + // { + // version(LDC) pragma(inline, true); + // this._lengths = lengths; + // this._strides = strides; + // this._iterator = iterator; + // this._labels = labels; + // } + + // /// ditto + // this()(size_t[N] lengths, ptrdiff_t[S] strides, ref Iterator iterator, Labels labels) + // { + // version(LDC) pragma(inline, true); + // this._lengths = lengths; + // this._strides = strides; + // this._iterator = iterator; + // this._labels = labels; + // } + // } + + // /// Construct from null + // this()(typeof(null)) + // { + // version(LDC) pragma(inline, true); + // } + + // static if (doUnittest) + // /// + // @safe pure version(mir_test) unittest + // { + // import mir.ndslice.slice; + // alias Array = Slice!(double*); + // Array a = null; + // auto b = Array(null); + // assert(a.empty); + // assert(b.empty); + + // auto fun(Array a = null) + // { - } - } + // } + // } static if (doUnittest) /// Creates a 2-dimentional slice with custom strides. @@ -891,34 +906,34 @@ public: } /// - auto lightImmutable()() immutable @property + auto lightImmutable()() scope return immutable @property { - import mir.qualifier: lightImmutable; - return Slice!(LightImmutableOf!Iterator, N, kind)(_lengths, _strides, lightImmutable(_iterator)); + import mir.qualifier: LightImmutableOf, lightImmutable; + return Slice!(LightImmutableOf!Iterator, N, kind)(_structure, _iterator.lightImmutable); } /// ditto - auto lightConst()() const @property + auto lightConst()() scope return const @property { - import mir.qualifier: lightConst; - return Slice!(LightConstOf!Iterator, N, kind)(_lengths, _strides, lightConst(_iterator)); + import mir.qualifier: LightConstOf, lightConst; + return Slice!(LightConstOf!Iterator, N, kind)(_structure, _iterator.lightConst); } /// ditto - auto lightConst()() immutable @property + auto lightConst()() scope return immutable @property { return this.lightImmutable; } /// ditto - auto ref opIndex(Indexes...)(Indexes indexes) const @trusted + auto ref opIndex(Indexes...)(Indexes indexes) scope return const @trusted if (isPureSlice!Indexes || isIndexedSlice!Indexes || isIndexSlice!Indexes) { return this.lightConst[indexes]; } /// ditto - auto ref opIndex(Indexes...)(Indexes indexes) immutable @trusted + auto ref opIndex(Indexes...)(Indexes indexes) scope return immutable @trusted if (isPureSlice!Indexes || isIndexedSlice!Indexes || isIndexSlice!Indexes) { return this.lightImmutable[indexes]; @@ -932,18 +947,18 @@ public: /++ Cast to const and immutable slices in case of underlying range is a pointer. +/ - auto toImmutable()() immutable @trusted pure nothrow @nogc + auto toImmutable()() scope return immutable @trusted pure nothrow @nogc { alias It = immutable(Unqual!(PointerTarget!Iterator))*; - return Slice!(It, N, kind)(_lengths, _strides, _iterator); + return Slice!(It, N, kind)(_structure, _iterator); } /// ditto - auto toConst()() const @trusted pure nothrow @nogc + auto toConst()() scope return const @trusted pure nothrow @nogc { version(LDC) pragma(inline, true); alias It = const(Unqual!(PointerTarget!Iterator))*; - return Slice!(It, N, kind)(_lengths, _strides, _iterator); + return Slice!(It, N, kind)(_structure, _iterator); } static if (!is(Slice!(const(Unqual!(PointerTarget!Iterator))*, N, kind) == This)) @@ -1024,24 +1039,33 @@ public: Returns: Iterator (pointer) to the $(LREF Slice.first) element. +/ - auto iterator()() inout @property + auto iterator()() inout scope return @property { return _iterator; } /++ +/ - auto label(size_t dimension)() @trusted inout @property + auto label(size_t dimension)() scope return @trusted inout @property if (dimension <= L) { return label.sliced(_lengths[dimension]); } static if (kind == Contiguous && isPointer!Iterator) - /++ - `ptr` alias is available only if the slice kind is $(LREF Contiguous) contiguous and the $(LREF Slice.iterator) is a pointers. - +/ - alias ptr = iterator; + /++ + `ptr` alias is available only if the slice kind is $(LREF Contiguous) contiguous and the $(LREF Slice.iterator) is a pointers. + +/ + alias ptr = iterator; + else + { + import mir.rcarray: mir_rci; + static if (kind == Contiguous && is(Iterator : mir_rci!ET, ET)) + auto ptr() scope return inout @property + { + return _iterator._iterator; + } + } /++ Field (array) data. @@ -1050,7 +1074,7 @@ public: Constraints: Field is defined only for contiguous slices. +/ - auto field()() @trusted @property + auto field()() scope return @trusted @property { static assert(kind == Contiguous, "Slice.field is defined only for contiguous slices. Slice kind is " ~ kind.stringof); static if (is(typeof(_iterator[size_t(0) .. elementCount]))) @@ -1087,7 +1111,7 @@ public: Returns: static array of lengths See_also: $(LREF .Slice.structure) +/ - size_t[N] shape()() @trusted @property const + size_t[N] shape()() @trusted @property scope const { return _lengths[0 .. N]; } @@ -1114,7 +1138,7 @@ public: Returns: static array of lengths See_also: $(LREF .Slice.structure) +/ - ptrdiff_t[N] strides()() @trusted @property const + ptrdiff_t[N] strides()() @trusted @property scope const { static if (N <= S) return _strides[0 .. N]; @@ -1176,9 +1200,9 @@ public: Returns: static array of lengths and static array of strides See_also: $(LREF .Slice.shape) +/ - Structure!(N) structure()() @safe @property const + Structure!N structure()() @safe @property scope const { - return typeof(return)(_lengths[0 .. N], strides); + return typeof(return)(_lengths, strides); } static if (doUnittest) @@ -1217,7 +1241,7 @@ public: /++ Save primitive. +/ - auto save()() @safe @property + auto save()() scope return inout @property { return this; } @@ -1239,13 +1263,12 @@ public: auto sl = slice!int(2, 3).save; } - /++ Multidimensional `length` property. Returns: length of the corresponding dimension See_also: $(LREF .Slice.shape), $(LREF .Slice.structure) +/ - size_t length(size_t dimension = 0)() @safe @property const + size_t length(size_t dimension = 0)() @safe @property scope const if (dimension < N) { return _lengths[dimension]; @@ -1270,7 +1293,7 @@ public: Returns: stride of the corresponding dimension See_also: $(LREF .Slice.structure) +/ - sizediff_t _stride(size_t dimension = 0)() @safe @property const + sizediff_t _stride(size_t dimension = 0)() @safe @property scope const if (dimension < N) { static if (dimension < S) @@ -1321,7 +1344,7 @@ public: /++ Multidimensional input range primitive. +/ - bool empty(size_t dimension = 0)() @safe @property const + bool empty(size_t dimension = 0)() @safe @property scope const if (dimension < N) { return _lengths[dimension] == 0; @@ -1329,43 +1352,42 @@ public: ///ditto static if (N == 1) - auto ref Element!dimension front(size_t dimension = 0)() @trusted @property - if (dimension < N) + auto ref front(size_t dimension = 0)() scope return @trusted @property + if (dimension == 0) { assert(!empty!dimension); return *_iterator; } else - Element!dimension front(size_t dimension = 0)() @safe @property + Element!dimension front(size_t dimension = 0)() scope return @property if (dimension < N) { - size_t[typeof(return).N] lengths_; - ptrdiff_t[max(typeof(return).S, size_t(1))] strides_; + typeof(return)._Structure structure_ = typeof(return)._Structure.init; foreach (i; Iota!(typeof(return).N)) { enum j = i >= dimension ? i + 1 : i; - lengths_[i] = _lengths[j]; + structure_[0][i] = _lengths[j]; } static if (!typeof(return).S || typeof(return).S + 1 == S) - alias s =_strides; + alias s = _strides; else auto s = strides; foreach (i; Iota!(typeof(return).S)) { enum j = i >= dimension ? i + 1 : i; - strides_[i] = s[j]; + structure_[1][i] = s[j]; } - return typeof(return)(lengths_, strides_[0 .. typeof(return).S], _iterator); + return typeof(return)(structure_, _iterator); } static if (N == 1 && isMutable!DeepElement && !hasAccessByRef) { ///ditto - auto ref front(size_t dimension = 0, T)(auto ref T value) @trusted @property + auto ref front(size_t dimension = 0, T)(T value) scope return @trusted @property if (dimension == 0) { // check assign safety @@ -1384,7 +1406,7 @@ public: ///ditto static if (N == 1) auto ref Element!dimension - back(size_t dimension = 0)() @trusted @property + back(size_t dimension = 0)() scope return @trusted @property if (dimension < N) { assert(!empty!dimension); @@ -1392,16 +1414,16 @@ public: } else auto ref Element!dimension - back(size_t dimension = 0)() @trusted @property + back(size_t dimension = 0)() scope return @trusted @property if (dimension < N) { assert(!empty!dimension); - size_t[typeof(return).N] lengths_; - ptrdiff_t[max(typeof(return).S, size_t(1))] strides_; + typeof(return)._Structure structure_; + foreach (i; Iota!(typeof(return).N)) { enum j = i >= dimension ? i + 1 : i; - lengths_[i] = _lengths[j]; + structure_[0][i] = _lengths[j]; } static if (!typeof(return).S || typeof(return).S + 1 == S) @@ -1412,16 +1434,16 @@ public: foreach (i; Iota!(typeof(return).S)) { enum j = i >= dimension ? i + 1 : i; - strides_[i] = s[j]; + structure_[1][i] = s[j]; } - return typeof(return)(lengths_, strides_[0 .. typeof(return).S], _iterator + backIndex!dimension); + return typeof(return)(structure_, _iterator + backIndex!dimension); } static if (N == 1 && isMutable!DeepElement && !hasAccessByRef) { ///ditto - auto ref back(size_t dimension = 0, T)(auto ref T value) @trusted @property + auto ref back(size_t dimension = 0, T)(T value) scope return @trusted @property if (dimension == 0) { // check assign safety @@ -1527,7 +1549,7 @@ public: assert(slice.shape == cast(size_t[3])[0, 0, 0]); } - package(mir) ptrdiff_t lastIndex()() @safe const @property + package(mir) ptrdiff_t lastIndex()() @safe @property scope const { static if (kind == Contiguous) { @@ -1546,7 +1568,7 @@ public: static if (N > 1) { /// Accesses the first deep element of the slice. - auto ref first()() @trusted @property + auto ref first()() scope return @trusted @property { assert(!anyEmpty); return *_iterator; @@ -1554,7 +1576,7 @@ public: static if (isMutable!DeepElement && !hasAccessByRef) ///ditto - auto ref first(T)(auto ref T value) @trusted @property + auto ref first(T)(T value) scope return @trusted @property { assert(!anyEmpty); static if (__traits(compiles, *_iterator = value)) @@ -1573,7 +1595,7 @@ public: } /// Accesses the last deep element of the slice. - auto ref last()() @trusted @property + auto ref last()() @trusted scope return @property { assert(!anyEmpty); return _iterator[lastIndex]; @@ -1581,7 +1603,7 @@ public: static if (isMutable!DeepElement && !hasAccessByRef) ///ditto - auto ref last(T)(auto ref T value) @trusted @property + auto ref last(T)(T value) @trusted scope return @property { assert(!anyEmpty); return _iterator[lastIndex] = value; @@ -1605,7 +1627,7 @@ public: /+ Returns: `true` if for any dimension of completely unpacked slice the length equals to `0`, and `false` otherwise. +/ - private bool anyRUEmpty()() @trusted const + private bool anyRUEmpty()() @trusted @property scope const { static if (isInstanceOf!(SliceIterator, Iterator)) { @@ -1620,7 +1642,7 @@ public: /++ Returns: `true` if for any dimension the length equals to `0`, and `false` otherwise. +/ - bool anyEmpty()() @trusted const + bool anyEmpty()() @trusted @property scope const { return _lengths[0 .. N].anyEmptyShape; } @@ -1641,18 +1663,23 @@ public: Returns: `this[$-index[0], $-index[1], ..., $-index[N-1]]` +/ - auto ref backward()(size_t[N] index) @safe + auto ref backward()(size_t[N] index) scope return { foreach (i; Iota!N) index[i] = _lengths[i] - index[i]; return this[index]; } - auto ref backward()(size_t[N] index) @safe const + /// ditto + auto ref backward()(size_t[N] index) scope return const { - foreach (i; Iota!N) - index[i] = _lengths[i] - index[i]; - return this[index]; + return this.lightConst.backward(index); + } + + /// ditto + auto ref backward()(size_t[N] index) scope return const + { + return this.lightConst.backward(index); } static if (doUnittest) @@ -1667,7 +1694,7 @@ public: /++ Returns: Total number of elements in a slice +/ - size_t elementCount()() @safe const + size_t elementCount()() @safe @property scope const { size_t len = 1; foreach (i; Iota!N) @@ -1706,7 +1733,7 @@ public: end = final index of the sub-slice (noninclusive) Returns: ndslice with `length!dimension` equal to `end - begin`. +/ - auto select(size_t dimension)(size_t begin, size_t end) + auto select(size_t dimension)(size_t begin, size_t end) scope return { static if (kind == Contiguous && dimension) { @@ -1740,7 +1767,7 @@ public: n = count of elements for the dimension Returns: ndslice with `length!dimension` equal to `n`. +/ - auto selectFront(size_t dimension)(size_t n) + auto selectFront(size_t dimension)(size_t n) scope return { static if (kind == Contiguous && dimension) { @@ -1772,7 +1799,7 @@ public: n = count of elements for the dimension Returns: ndslice with `length!dimension` equal to `n`. +/ - auto selectBack(size_t dimension)(size_t n) + auto selectBack(size_t dimension)(size_t n) scope return { static if (kind == Contiguous && dimension) { @@ -1801,7 +1828,7 @@ public: /++ Overloading `==` and `!=` +/ - bool opEquals(IteratorR, SliceKind rkind)(const Slice!(IteratorR, N, rkind) rslice) @trusted const + bool opEquals(IteratorR, SliceKind rkind)(const Slice!(IteratorR, N, rkind) rslice) @trusted scope const { static if ( !hasReference!(typeof(this)) @@ -1820,7 +1847,7 @@ public: } /// ditto - bool opEquals(T)(T[] arr) @trusted const + bool opEquals(T)(scope const(T)[] arr) @trusted scope const { auto slice = this.lightConst; if (slice.length != arr.length) @@ -1861,7 +1888,7 @@ public: assert(iota(2, 3).slice[0 .. $ - 2] == iota([4, 3], 2)[0 .. $ - 4]); } - _Slice!() opSlice(size_t dimension)(size_t i, size_t j) @safe const + _Slice!() opSlice(size_t dimension)(size_t i, size_t j) @safe scope const if (dimension < N) in { @@ -1879,40 +1906,61 @@ public: /++ $(BOLD Fully defined index) +/ - auto ref opIndex(size_t I)(size_t[I] _indexes...) @trusted - if (I && I <= N) + auto ref opIndex()(size_t[N] _indexes...) scope return @trusted + { + return _iterator[indexStride(_indexes)]; + } + + /// ditto + auto ref opIndex()(size_t[N] _indexes...) scope return const @trusted { - static if (I == N) + static if (is(typeof(_iterator[indexStride(_indexes)]))) return _iterator[indexStride(_indexes)]; else - { - enum size_t diff = N - I; - alias Ret = Slice!(Iterator, diff, diff == 1 && kind == Canonical ? Contiguous : kind); - static if (S) - return Ret(_lengths[I .. N], _strides[I .. S], _iterator + indexStride(_indexes)); - else - return Ret(_lengths[I .. N], _strides, _iterator + indexStride(_indexes)); - } + return lightConst[_indexes]; } /// ditto - auto ref opIndex(size_t I)(size_t[I] _indexes...) @trusted const - if (I && I <= N) + auto ref opIndex()(size_t[N] _indexes...) scope return immutable @trusted { - return this[][_indexes]; + static if (is(typeof(_iterator[indexStride(_indexes)]))) + return _iterator[indexStride(_indexes)]; + else + return lightImmutable[_indexes]; + } + + /++ + $(BOLD Partially defined index) + +/ + auto opIndex(size_t I)(size_t[I] _indexes...) scope return @trusted + if (I && I < N) + { + enum size_t diff = N - I; + alias Ret = Slice!(Iterator, diff, diff == 1 && kind == Canonical ? Contiguous : kind); + static if (I < S) + return Ret(_lengths[I .. N], _strides[I .. S], _iterator + indexStride(_indexes)); + else + return Ret(_lengths[I .. N], _iterator + indexStride(_indexes)); } /// ditto - auto ref opIndex(size_t I)(size_t[I] _indexes...) @trusted immutable - if (I && I <= N) + auto opIndex(size_t I)(size_t[I] _indexes...) scope return const + if (I && I < N) { - return this[][_indexes]; + return this.lightConst[_indexes]; + } + + /// ditto + auto opIndex(size_t I)(size_t[I] _indexes...) scope return immutable + if (I && I < N) + { + return this.lightImmutable[_indexes]; } /++ $(BOLD Partially or fully defined slice.) +/ - auto opIndex(Slices...)(Slices slices) @trusted + auto opIndex(Slices...)(Slices slices) scope return @trusted if (isPureSlice!Slices) { static if (Slices.length) @@ -1933,8 +1981,8 @@ public: else enum K = Canonical; alias Ret = Slice!(Iterator, N - F, K); - size_t[Ret.N] lengths_; - ptrdiff_t[max(Ret.S, size_t(1))] strides_; + Ret._Structure structure_; + enum bool shrink = kind == Canonical && slices.length == N; static if (shrink) { @@ -1949,7 +1997,7 @@ public: else { stride += slice.i; - lengths_[j!i] = slice.j - slice.i; + structure_[0][j!i] = slice.j - slice.i; } } } @@ -1965,8 +2013,8 @@ public: else { stride += _strides[i] * slice.i; - lengths_[j!i] = slice.j - slice.i; - strides_[j!i] = _strides[i]; + structure_[0][j!i] = slice.j - slice.i; + structure_[1][j!i] = _strides[i]; } } } @@ -1983,20 +2031,21 @@ public: else { stride += ball * slice.i; - lengths_[j!i] = slice.j - slice.i; + structure_[0][j!i] = slice.j - slice.i; static if (j!i < Ret.S) - strides_[j!i] = ball; + structure_[1][j!i] = ball; } static if (i) ball *= _lengths[i]; } } foreach (i; Iota!(Slices.length, N)) - lengths_[i - F] = _lengths[i]; + structure_[0][i - F] = _lengths[i]; foreach (i; Iota!(Slices.length, N)) static if (Ret.S > i - F) - strides_[i - F] = _strides[i]; - return Ret(lengths_, strides_[0 .. Ret.S], _iterator + stride); + structure_[1][i - F] = _strides[i]; + + return Ret(structure_, _iterator + stride); } else { @@ -2023,10 +2072,10 @@ public: /++ $(BOLD Indexed slice.) +/ - auto opIndex(Slices...)(Slices slices) + auto opIndex(Slices...)(scope return Slices slices) scope return if (isIndexedSlice!Slices) { - import mir.ndslice.topology: indexed, cartesian, map; + import mir.ndslice.topology: indexed, cartesian; static if (Slices.length == 1) alias index = slices[0]; else @@ -2104,7 +2153,7 @@ public: Note: Does not allocate neither new slice nor a closure. +/ - auto opUnary(string op)() + auto opUnary(string op)() scope return if (op == "*" || op == "~" || op == "-" || op == "+") { import mir.ndslice.topology: map; @@ -2140,7 +2189,7 @@ public: Note: Does not allocate neither new slice nor a closure. +/ - auto opBinary(string op, T)(T value) @nogc + auto opBinary(string op, T)(scope return T value) scope return if(!isSlice!T) { import mir.ndslice.topology: vmap; @@ -2148,7 +2197,7 @@ public: } /// ditto - auto opBinaryRight(string op, T)(T value) @nogc + auto opBinaryRight(string op, T)(scope return T value) scope return if(!isSlice!T) { import mir.ndslice.topology: vmap; @@ -2192,7 +2241,8 @@ public: $(BR) Does not allocate neither new slice nor a closure. +/ - auto opBinary(string op, RIterator, size_t RN, SliceKind rkind) (Slice!(RIterator, RN, rkind) rhs) @nogc + auto opBinary(string op, RIterator, size_t RN, SliceKind rkind) + (scope return Slice!(RIterator, RN, rkind) rhs) scope return if(N == RN && (kind == Contiguous && rkind == Contiguous || N == 1) && op != "~") { import mir.ndslice.topology: zip, map; @@ -2216,7 +2266,7 @@ public: See_also: $(LREF Slice.idup) +/ Slice!(Unqual!DeepElement*, N) - dup()() @property + dup()() scope @property { if (__ctfe) { @@ -2241,14 +2291,14 @@ public: /// ditto Slice!(immutable(DeepElement)*, N) - dup()() const @property + dup()() scope const @property { this[].dup; } /// ditto Slice!(immutable(DeepElement)*, N) - dup()() immutable @property + dup()() scope immutable @property { this[].dup; } @@ -2271,7 +2321,7 @@ public: See_also: $(LREF Slice.dup) +/ Slice!(immutable(DeepElement)*, N) - idup()() @property + idup()() scope @property { if (__ctfe) { @@ -2296,14 +2346,14 @@ public: /// ditto Slice!(immutable(DeepElement)*, N) - idup()() const @property + idup()() scope const @property { this[].idup; } /// ditto Slice!(immutable(DeepElement)*, N) - idup()() immutable @property + idup()() scope immutable @property { this[].idup; } @@ -2322,8 +2372,8 @@ public: static if (isMutable!DeepElement) { - private void opIndexOpAssignImplSlice(string op, RIterator, size_t RN, SliceKind rkind)(Slice!(RIterator, RN, rkind) value) - @safe + private void opIndexOpAssignImplSlice(string op, RIterator, size_t RN, SliceKind rkind) + (scope Slice!(RIterator, RN, rkind) value) scope { static if (N > 1 && RN == N && kind == Contiguous && rkind == Contiguous) { @@ -2378,8 +2428,8 @@ public: /++ Assignment of a value of `Slice` type to a $(B fully defined slice). +/ - auto opIndexAssign(RIterator, size_t RN, SliceKind rkind, Slices...)(Slice!(RIterator, RN, rkind) value, Slices slices) - @safe + auto opIndexAssign(RIterator, size_t RN, SliceKind rkind, Slices...) + (scope Slice!(RIterator, RN, rkind) value, Slices slices) scope return if (isFullPureSlice!Slices || isIndexedSlice!Slices) { auto sl = this[slices]; @@ -2443,7 +2493,7 @@ public: [4, 5, 6, 7]]); } - void opIndexOpAssignImplArray(string op, T, Slices...)(T[] value) @safe + void opIndexOpAssignImplArray(string op, T, Slices...)(T[] value) scope { auto ls = this; assert(ls.length == value.length, __FUNCTION__ ~ ": argument must have the same length."); @@ -2504,7 +2554,7 @@ public: /++ Assignment of a regular multidimensional array to a $(B fully defined slice). +/ - auto opIndexAssign(T, Slices...)(T[] value, Slices slices) @safe + auto opIndexAssign(T, Slices...)(T[] value, Slices slices) scope return if ((isFullPureSlice!Slices || isIndexedSlice!Slices) && !isDynamicArray!DeepElement && DynamicArrayDimensionsCount!(T[]) <= typeof(this[slices]).N) @@ -2555,7 +2605,7 @@ public: } - private void opIndexOpAssignImplConcatenation(string op, T)(T value) @safe + private void opIndexOpAssignImplConcatenation(string op, T)(T value) scope { auto sl = this; static if (concatenationDimension!T) @@ -2587,7 +2637,7 @@ public: } /// - auto opIndexAssign(T, Slices...)(T concatenation, Slices slices) @safe + auto opIndexAssign(T, Slices...)(T concatenation, Slices slices) scope return if ((isFullPureSlice!Slices || isIndexedSlice!Slices) && isConcatenation!T) { auto sl = this[slices]; @@ -2599,7 +2649,7 @@ public: /++ Assignment of a value (e.g. a number) to a $(B fully defined slice). +/ - auto opIndexAssign(T, Slices...)(T value, Slices slices) @safe + auto opIndexAssign(T, Slices...)(T value, Slices slices) scope return if ((isFullPureSlice!Slices || isIndexedSlice!Slices) && (!isDynamicArray!T || isDynamicArray!DeepElement) && !isSlice!T @@ -2654,7 +2704,7 @@ public: /++ Assignment of a value (e.g. a number) to a $(B fully defined index). +/ - auto ref opIndexAssign(T)(auto ref T value, size_t[N] _indexes...) @trusted + auto ref opIndexAssign(T)(T value, size_t[N] _indexes...) scope return @trusted { // check assign safety static auto ref fun(ref DeepElement t, ref T v) @safe @@ -2687,7 +2737,7 @@ public: /++ Op Assignment `op=` of a value (e.g. a number) to a $(B fully defined index). +/ - auto ref opIndexOpAssign(string op, T)(auto ref T value, size_t[N] _indexes...) @trusted + auto ref opIndexOpAssign(string op, T)(T value, size_t[N] _indexes...) scope return @trusted { // check op safety static auto ref fun(ref DeepElement t, ref T v) @safe @@ -2728,8 +2778,7 @@ public: Op Assignment `op=` of a value of `Slice` type to a $(B fully defined slice). +/ auto opIndexOpAssign(string op, RIterator, SliceKind rkind, size_t RN, Slices...) - (Slice!(RIterator, RN, rkind) value, Slices slices) - @safe + (Slice!(RIterator, RN, rkind) value, Slices slices) scope return if (isFullPureSlice!Slices || isIndexedSlice!Slices) { auto sl = this[slices]; @@ -2795,8 +2844,7 @@ public: /++ Op Assignment `op=` of a regular multidimensional array to a $(B fully defined slice). +/ - auto opIndexOpAssign(string op, T, Slices...)(T[] value, Slices slices) - @safe + auto opIndexOpAssign(string op, T, Slices...)(T[] value, Slices slices) scope return if (isFullPureSlice!Slices && !isDynamicArray!DeepElement && DynamicArrayDimensionsCount!(T[]) <= typeof(this[slices]).N) @@ -2843,8 +2891,7 @@ public: [2, 2, 3, 3]]); } - private void opIndexOpAssignImplValue(string op, T)(T value) - @safe + private void opIndexOpAssignImplValue(string op, T)(T value) scope return { static if (N > 1 && kind == Contiguous) { @@ -2874,8 +2921,7 @@ public: /++ Op Assignment `op=` of a value (e.g. a number) to a $(B fully defined slice). +/ - auto opIndexOpAssign(string op, T, Slices...)(T value, Slices slices) - @safe + auto opIndexOpAssign(string op, T, Slices...)(T value, Slices slices) scope return if ((isFullPureSlice!Slices || isIndexedSlice!Slices) && (!isDynamicArray!T || isDynamicArray!DeepElement) && !isSlice!T @@ -2905,8 +2951,7 @@ public: } /// - auto opIndexOpAssign(string op,T, Slices...)(T concatenation, Slices slices) - @safe + auto opIndexOpAssign(string op,T, Slices...)(T concatenation, Slices slices) scope return if ((isFullPureSlice!Slices || isIndexedSlice!Slices) && isConcatenation!T) { auto sl = this[slices]; @@ -2931,7 +2976,7 @@ public: /++ Increment `++` and Decrement `--` operators for a $(B fully defined index). +/ - auto ref opIndexUnary(string op)(size_t[N] _indexes...) + auto ref opIndexUnary(string op)(size_t[N] _indexes...) scope return @trusted // @@@workaround@@@ for Issue 16473 //if (op == `++` || op == `--`) @@ -2973,8 +3018,7 @@ public: assert(a[[1, 2]] == 1); } - private void opIndexUnaryImpl(string op, Slices...)(Slices slices) - @safe + private void opIndexUnaryImpl(string op, Slices...)(Slices slices) scope { auto ls = this; do @@ -2996,8 +3040,7 @@ public: /++ Increment `++` and Decrement `--` operators for a $(B fully defined slice). +/ - void opIndexUnary(string op, Slices...)(Slices slices) - @safe + void opIndexUnary(string op, Slices...)(Slices slices) scope return if (isFullPureSlice!Slices && (op == `++` || op == `--`)) { auto sl = this[slices]; @@ -3282,8 +3325,8 @@ private bool _checkAssignLengths( size_t LN, size_t RN, SliceKind lkind, SliceKind rkind, ) - (Slice!(LIterator, LN, lkind) ls, - Slice!(RIterator, RN, rkind) rs) + (scope Slice!(LIterator, LN, lkind) ls, + scope Slice!(RIterator, RN, rkind) rs) { static if (isInstanceOf!(SliceIterator, LIterator)) { diff --git a/source/mir/ndslice/topology.d b/source/mir/ndslice/topology.d index 1cd948fc..a8cc0239 100644 --- a/source/mir/ndslice/topology.d +++ b/source/mir/ndslice/topology.d @@ -308,12 +308,7 @@ Slice!(Iterator, N) return slice; else { - alias Ret = typeof(return); - size_t[Ret.N] lengths; - auto strides = sizediff_t[Ret.S].init; - foreach (i; Iota!(slice.N)) - lengths[i] = slice._lengths[i]; - return Ret(lengths, strides, slice._iterator); + return typeof(return)(slice._lengths, slice._iterator); } } @@ -397,16 +392,15 @@ ipack(size_t P, Iterator, size_t N, SliceKind kind)(Slice!(Iterator, N, kind) sl cast(ptrdiff_t[P]) sl._strides[0 .. P], It( cast(size_t[EN]) sl._lengths[P .. $], - sizediff_t[0].init, sl._iterator)); else - return Ret( - cast( size_t[P]) sl._lengths[0 .. P], - cast(ptrdiff_t[P]) sl._strides[0 .. P], - It( - cast( size_t[EN]) sl._lengths[P .. $], - cast(ptrdiff_t[ES]) sl._strides[P .. $ - (It.Element.kind == Canonical)], - sl._iterator)); + return Ret( + cast( size_t[P]) sl._lengths[0 .. P], + cast(ptrdiff_t[P]) sl._strides[0 .. P], + It( + cast( size_t[EN]) sl._lengths[P .. $], + cast(ptrdiff_t[ES]) sl._strides[P .. $ - (It.Element.kind == Canonical)], + sl._iterator)); } /// @@ -446,8 +440,7 @@ Slice!(Iterator, N + M, min(innerKind, Canonical)) auto strides = sizediff_t[Ret.S].init; auto outerStrides = slice.strides; auto innerStrides = Slice!(Iterator, M, innerKind)( - slice._iterator._lengths, - slice._iterator._strides, + slice._iterator._structure, slice._iterator._iterator, ).strides; foreach(i; Iota!N) @@ -455,7 +448,7 @@ Slice!(Iterator, N + M, min(innerKind, Canonical)) foreach(i; Iota!N) strides[i] = outerStrides[i]; foreach(i; Iota!M) - lengths[N + i] = slice._iterator._lengths[i]; + lengths[N + i] = slice._iterator._structure[0][i]; foreach(i; Iota!(Ret.S - N)) strides[N + i] = innerStrides[i]; return Ret(lengths, strides, slice._iterator._iterator); @@ -477,11 +470,9 @@ evertPack(Iterator, size_t M, SliceKind innerKind, size_t N, SliceKind outerKind (Slice!(SliceIterator!(Iterator, M, innerKind), N, outerKind) slice) { return typeof(return)( - slice._iterator._lengths, - slice._iterator._strides, + slice._iterator._structure, typeof(return).Iterator( - slice._lengths, - slice._strides, + slice._structure, slice._iterator._iterator)); } @@ -1036,18 +1027,27 @@ in } body { + size_t[N] rls = rlengths; size_t[N] lengths; foreach (dimension; Iota!N) - lengths[dimension] = slice._lengths[dimension] >= rlengths[dimension] ? - slice._lengths[dimension] - rlengths[dimension] + 1 : 0; + lengths[dimension] = slice._lengths[dimension] >= rls[dimension] ? + slice._lengths[dimension] - rls[dimension] + 1 : 0; auto rstrides = slice.strides; - return typeof(return)( - lengths, - rstrides, - typeof(return).Iterator( - rlengths, - rstrides[0 .. typeof(return).DeepElement.S], - slice._iterator)); + static if (typeof(return).DeepElement.S) + return typeof(return)( + lengths, + rstrides, + typeof(return).Iterator( + rls, + rstrides[0 .. typeof(return).DeepElement.S], + slice._iterator)); + else + return typeof(return)( + lengths, + rstrides, + typeof(return).Iterator( + rls, + slice._iterator)); } /// @@ -1225,8 +1225,8 @@ Slice!(Iterator, M, kind) reshape else { alias Ret = typeof(return); - size_t[Ret.N] lengths; - auto strides = sizediff_t[Ret.S].init; + Ret._Structure structure; + alias lengths = structure[0]; foreach (i; Iota!M) lengths[i] = rlengths[i]; @@ -1282,20 +1282,20 @@ Slice!(Iterator, M, kind) reshape } assert((oi == N) == (ni == M)); - strides[nj - 1] = slice._strides[oj - 1]; + structure[1][nj - 1] = slice._strides[oj - 1]; foreach_reverse (i; ni .. nj - 1) - strides[i] = lengths[i + 1] * strides[i + 1]; + structure[1][i] = lengths[i + 1] * structure[1][i + 1]; } } foreach (i; Iota!(M, Ret.N)) lengths[i] = slice._lengths[i + N - M]; static if (M < Ret.S) foreach (i; Iota!(M, Ret.S)) - strides[i] = slice._strides[i + N - M]; + structure[1][i] = slice._strides[i + N - M]; err = 0; - return Ret(lengths, strides, slice._iterator); + return Ret(structure, slice._iterator); R: - return Ret(lengths, strides, slice._iterator.init); + return Ret(structure, slice._iterator.init); } } @@ -1414,12 +1414,10 @@ Slice!(FlattenedIterator!(Iterator, N, kind)) (Slice!(Iterator, N, kind) slice) if (N != 1 && kind != Contiguous) { - alias Ret = typeof(return); - size_t[Ret.N] lengths; - auto strides = sizediff_t[Ret.S].init; + size_t[typeof(return).N] lengths; sizediff_t[typeof(return)._iterator._indexes.length] indexes; lengths[0] = slice.elementCount; - return Ret(lengths, strides, FlattenedIterator!(Iterator, N, kind)(indexes, slice)); + return typeof(return)(lengths, FlattenedIterator!(Iterator, N, kind)(indexes, slice)); } /// ditto @@ -1436,7 +1434,7 @@ Slice!Iterator { size_t[typeof(return).N] lengths; lengths[0] = slice.elementCount; - return typeof(return)(lengths, sizediff_t[0].init, slice._iterator); + return typeof(return)(lengths, slice._iterator); } } @@ -1819,8 +1817,9 @@ Slice!(FieldIterator!(RepeatField!T), M, Universal) repeat(T, size_t M)(T value, size_t[M] lengths...) if (M && !isSlice!T) { + size_t[M] ls = lengths; return typeof(return)( - lengths, + ls, sizediff_t[M].init, typeof(return).Iterator(0, RepeatField!T(cast(RepeatField!T.UT) value))); } @@ -1832,12 +1831,12 @@ Slice!(SliceIterator!(Iterator, N, kind), M, Universal) (Slice!(Iterator, N, kind) slice, size_t[M] lengths...) if (M) { + size_t[M] ls = lengths; return typeof(return)( - lengths, + ls, sizediff_t[M].init, typeof(return).Iterator( - slice._lengths, - slice._strides, + slice._structure, slice._iterator)); } @@ -2032,20 +2031,28 @@ auto retro static if (kind == Contiguous || kind == Canonical) { size_t[slice.N] lengths; - sizediff_t[slice.S] strides; foreach (i; Iota!(slice.N)) lengths[i] = slice._lengths[i]; - foreach (i; Iota!(slice.S)) - strides[i] = slice._strides[i]; + static if (slice.S) + { + sizediff_t[slice.S] strides; + foreach (i; Iota!(slice.S)) + strides[i] = slice._strides[i]; + alias structure = AliasSeq!(lengths, strides); + } + else + { + alias structure = lengths; + } static if (is(Iterator : RetroIterator!It, It)) { alias Ret = Slice!(It, N, kind); - return Ret(lengths, strides, slice._iterator._iterator - slice.lastIndex); + return Ret(structure, slice._iterator._iterator - slice.lastIndex); } else { alias Ret = Slice!(RetroIterator!Iterator, N, kind); - return Ret(lengths, strides, RetroIterator!Iterator(slice._iterator + slice.lastIndex)); + return Ret(structure, RetroIterator!Iterator(slice._iterator + slice.lastIndex)); } } else @@ -2104,17 +2111,16 @@ auto bitwise alias It = FieldIterator!(BitField!Iterator); } alias Ret = Slice!(It, N, kind); - size_t[Ret.N] lengths; - auto strides = sizediff_t[Ret.S].init; + Ret._Structure structure_; foreach(i; Iota!(Ret.N)) - lengths[i] = slice._lengths[i]; - lengths[$ - 1] *= I.sizeof * 8; + structure_[0][i] = slice._lengths[i]; + structure_[0][$ - 1] *= I.sizeof * 8; foreach(i; Iota!(Ret.S)) - strides[i] = slice._strides[i]; + structure_[1][i] = slice._strides[i]; static if (simplified) - return Ret(lengths, strides, It(slice._iterator._index * I.sizeof * 8, BitField!Field(slice._iterator._field))); + return Ret(structure_, It(slice._iterator._index * I.sizeof * 8, BitField!Field(slice._iterator._field))); else - return Ret(lengths, strides, It(0, BitField!Iterator(slice._iterator))); + return Ret(structure_, It(0, BitField!Iterator(slice._iterator))); } /// ditto @@ -2207,18 +2213,17 @@ auto bitpack alias It = FieldIterator!(BitpackField!(Iterator, pack)); } alias Ret = Slice!(It, N, kind); - size_t[Ret.N] lengths; - auto strides = sizediff_t[Ret.S].init; + Ret._Structure structure; foreach(i; Iota!(Ret.N)) - lengths[i] = slice._lengths[i]; - lengths[$ - 1] *= I.sizeof * 8; - lengths[$ - 1] /= pack; + structure[0][i] = slice._lengths[i]; + structure[0][$ - 1] *= I.sizeof * 8; + structure[0][$ - 1] /= pack; foreach(i; Iota!(Ret.S)) - strides[i] = slice._strides[i]; + structure[1][i] = slice._strides[i]; static if (simplified) - return Ret(lengths, strides, It(slice._iterator._index * I.sizeof * 8 / pack, BitpackField!(Field, pack)(slice._iterator._field))); + return Ret(structure, It(slice._iterator._index * I.sizeof * 8 / pack, BitpackField!(Field, pack)(slice._iterator._field))); else - return Ret(lengths, strides, It(0, BitpackField!(Iterator, pack)(slice._iterator))); + return Ret(structure, It(0, BitpackField!(Iterator, pack)(slice._iterator))); } /// ditto @@ -2268,11 +2273,9 @@ bytegroup (Slice!(Iterator, N, kind) slice) if ((kind == Contiguous || kind == Canonical) && group) { - alias Ret = typeof(return); - size_t[Ret.N] lengths; - lengths = slice._lengths; - lengths[$ - 1] /= group; - return Ret(lengths, slice._strides, BytegroupIterator!(Iterator, group, DestinationType)(slice._iterator)); + auto structure = slice._structure; + structure[0][$ - 1] /= group; + return typeof(return)(structure, BytegroupIterator!(Iterator, group, DestinationType)(slice._iterator)); } @@ -2369,7 +2372,7 @@ template map(fun...) auto map(Iterator, size_t N, SliceKind kind) (Slice!(Iterator, N, kind) slice) { - return Slice!(typeof(_mapIterator!f(slice._iterator)), N, kind)(slice._lengths, slice._strides, _mapIterator!f(slice._iterator)); + return Slice!(typeof(_mapIterator!f(slice._iterator)), N, kind)(slice._structure, _mapIterator!f(slice._iterator)); } /// ditto @@ -2552,22 +2555,22 @@ See_Also: +/ @optmath auto vmap(Iterator, size_t N, SliceKind kind, Callable) ( - Slice!(Iterator, N, kind) slice, - Callable callable, + scope return Slice!(Iterator, N, kind) slice, + scope return Callable callable, ) { alias It = VmapIterator!(Iterator, Callable); - return Slice!(It, N, kind)(slice._lengths, slice._strides, It(slice._iterator, callable)); + return Slice!(It, N, kind)(slice._structure, It(slice._iterator, callable)); } /// ditto -auto vmap(T, Callable)(T[] array, Callable callable) +auto vmap(T, Callable)(scope return T[] array, scope return Callable callable) { return vmap(array.sliced, callable); } /// ditto -auto vmap(T, Callable)(T withAsSlice, Callable callable) +auto vmap(T, Callable)(scope return T withAsSlice, scope return Callable callable) if (hasAsSlice!T) { return vmap(withAsSlice.asSlice, callable); @@ -2690,7 +2693,6 @@ private auto hideStride static if (kind == Universal) return Slice!(StrideIterator!Iterator)( slice._lengths, - sizediff_t[0].init, StrideIterator!Iterator(slice._strides[0], slice._iterator)); else return slice; @@ -2705,12 +2707,10 @@ private auto unhideStride static if (kind == Universal) { alias Ret = SliceKind!(It, N, Universal); - size_t[Ret.N] lengths; - auto strides = sizediff_t[Ret.S].init; - foreach(i; Iota!(Ret.N)) - lengths[i] = slice._lengths[i]; + auto strides = slice._strides; foreach(i; Iota!(Ret.S)) strides[i] = slice._strides[i] * slice._iterator._stride; + return Slice!(It, N, Universal)(slice._lengths, strides, slice._iterator._iterator); } else return slice.universal.unhideStride; @@ -2739,8 +2739,7 @@ Slice!(CachedIterator!(Iterator, CacheIterator, FlagIterator), N, kind) assert(original.shape == caches.shape, "caches.shape should be equal to original.shape"); assert(original.shape == flags.shape, "flags.shape should be equal to original.shape"); return typeof(return)( - original._lengths, - original._strides, + original._structure, IteratorOf!(typeof(return))( original._iterator, caches._iterator, @@ -2839,8 +2838,7 @@ Slice!(CachedIterator!(Iterator, typeof(Iterator.init[0])*, FieldIterator!(BitFi else alias newSlice = uninitSlice; return typeof(return)( - original._lengths, - original._strides, + original._structure, IteratorOf!(typeof(return))( original._iterator, newSlice!C(original._lengths)._iterator, @@ -3015,8 +3013,7 @@ Slice!(IndexIterator!(Iterator, Field), N, kind) (Field source, Slice!(Iterator, N, kind) indexes) { return typeof(return)( - indexes._lengths, - indexes._strides, + indexes._structure, IndexIterator!(Iterator, Field)( indexes._iterator, source)); @@ -3066,8 +3063,7 @@ Slice!(SubSliceIterator!(Iterator, Sliceable), N, kind) ) { return typeof(return)( - slices._lengths, - slices._strides, + slices._structure, SubSliceIterator!(Iterator, Sliceable)(slices._iterator, sliceable) ); } @@ -3135,7 +3131,7 @@ do { } } - return typeof(return)([size_t(length)], sizediff_t[0].init, ChopIterator!(Iterator, Sliceable)(bounds._iterator, sliceable)); + return typeof(return)([size_t(length)], ChopIterator!(Iterator, Sliceable)(bounds._iterator, sliceable)); } /// ditto @@ -3199,13 +3195,11 @@ auto zip enum kind = maxElem(staticMap!(kindOf, Slices)); alias Iterator = ZipIterator!(staticMap!(_IteratorOf, Slices)); alias Ret = Slice!(Iterator, N, kind); - size_t[Ret.N] lengths; - auto strides = sizediff_t[Ret.S].init; - foreach (i; Iota!(Ret.N)) - lengths[i] = slices[0]._lengths[i]; + Ret._Structure structure; + structure[0] = slices[0]._lengths; foreach (i; Iota!(Ret.S)) - strides[i] = slices[0]._strides[i]; - return Ret(lengths, strides, mixin("Iterator(" ~ _iotaArgs!(Slices.length, "slices[", "]._iterator, ") ~ ")")); + structure[1][i] = slices[0]._strides[i]; + return Ret(structure, mixin("Iterator(" ~ _iotaArgs!(Slices.length, "slices[", "]._iterator, ") ~ ")")); } } else @@ -3263,7 +3257,7 @@ auto unzip { enum size_t i = name - 'a'; static assert(i < Iterators.length, `unzip: constraint: size_t(name - 'a') < Iterators.length`); - return Slice!(Iterators[i], N, kind)(slice._lengths, slice._strides, slice._iterator._iterators[i]).unhideStride; + return Slice!(Iterators[i], N, kind)(slice._structure, slice._iterator._iterators[i]).unhideStride; } /// @@ -3323,8 +3317,7 @@ template slide(size_t params, alias fun) alias I = SlideIterator!(_IteratorOf!(typeof(s)), params, fun); return Slice!(I)( - s._lengths, - s._strides, + s._structure, I(s._iterator)); } @@ -4178,7 +4171,7 @@ template member(string name) +/ Slice!(MemberIterator!(Iterator, name), N, kind) member(Iterator, size_t N, SliceKind kind)(Slice!(Iterator, N, kind) slice) { - return typeof(return)(slice._lengths, slice._strides, MemberIterator!(Iterator, name)(slice._iterator)); + return typeof(return)(slice._structure, MemberIterator!(Iterator, name)(slice._iterator)); } /// ditto diff --git a/source/mir/rcarray.d b/source/mir/rcarray.d new file mode 100644 index 00000000..c5752a97 --- /dev/null +++ b/source/mir/rcarray.d @@ -0,0 +1,415 @@ +/++ ++/ +module mir.rcarray; + +private static immutable allocationExcMsg = "mir_rcarray: out of memory arror."; + +version (D_Exceptions) +{ + static immutable allocationExc = new Exception(allocationExcMsg); +} + +private template preferCppLinkage(T) +{ + static if (is(T == immutable) || is(T == shared)) + enum preferCppLinkage = false; + else + static if (is(T == class) || is(T == struct) || is(T == union) || is(T == interface)) + enum preferCppLinkage = __traits(getLinkage, T) == "C++"; + else + static if (__traits(isScalar, T)) + static if (is(T : U*, U)) + enum preferCppLinkage = .preferCppLinkage!U; + else + enum preferCppLinkage = true; + else + enum preferCppLinkage = false; + +} + +/// +version(mir_test) +unittest +{ + struct S {} + extern(C++) struct C {} + static assert (preferCppLinkage!double); + static assert (preferCppLinkage!(const double)); + static assert (!preferCppLinkage!(immutable double)); + static assert (!preferCppLinkage!S); + static assert (preferCppLinkage!C); + static assert (preferCppLinkage!(const C)); + static assert (!preferCppLinkage!(immutable C)); +} + +// extern(C++) +// enum C {e, b} +// pragma(msg, __traits(getLinkage, C)); + +/++ +Thread safe reference counting array. + +`__xdtor` if any is used to destruct objects. + +The implementation never adds roots into the GC. ++/ +struct mir_rcarray(T) + if (T.alignof <= 16) +{ + enum cppSupport = preferCppLinkage!T; + + private struct Context + { + shared size_t counter; + size_t length; + union + { + pure nothrow @nogc bool function(void[]) _function; + pure nothrow @nogc bool function(void* ctx, void[]) _delegate; + } + void* _delegateContext; + } + + static assert(Context.sizeof % 16 == 0); + + /// + private Context* _context; + + // private inout(Context)* _context() inout @trusted pure nothrow @nogc scope + // { + // return cast(Context*) _contextCode; + // } + + // private void _context(Context * context) @trusted pure nothrow @nogc scope + // { + // _contextCode = cast(size_t) context; + // } + + /// + this(this) scope @safe pure nothrow @nogc + { + import core.atomic: atomicOp; + if (_context !is null) with(*_context) + { + if (counter) + { + counter.atomicOp!"+="(1); + } + } + } + + private void dec()() scope + { + import core.atomic: atomicOp; + if (_context !is null) with(*_context) + { + if (counter) + { + if (counter.atomicOp!"-="(1) == 0) + { + import mir.conv: xdestroy; + T[] array; + ()@trusted { array = (cast(T*)(_context + 1))[0 .. length]; }(); + xdestroy(array); + auto p = cast(void*) _context; + () @trusted { + with(*_context) + { + if (_delegateContext !is null) + { + size_t size = length * T.sizeof + Context.sizeof; + _delegate(_delegateContext, p[0 .. size]); + } + else + if (_function !is null) + { + size_t size = length * T.sizeof + Context.sizeof; + _function(p[0 .. size]); + } + else + { + import mir.internal.memory: free; + free(p); + } + } + }(); + } + } + } + } + + static if (cppSupport) extern(C++) + { + /// + pragma(inline, false) + ~this() scope nothrow @nogc + { + dec(); + } + + /// + pragma(inline, false) + bool initialize(size_t length, uint alignment = T.alignof, bool deallocate = true) scope @safe nothrow @nogc + { + return initializeImpl(length, alignment, deallocate); + } + + // /// + // this(ref typeof(this) rhs) @safe pure nothrow @nogc + // { + // this._context = rhs._context; + // this.__xpostblit; + // } + } + else + { + pragma(inline, false) + ~this() scope nothrow @nogc + { + dec(); + } + + pragma(inline, false) + bool initialize(size_t length, uint alignment = T.alignof, bool deallocate = true) scope @safe nothrow @nogc + { + return initializeImpl(length, alignment, deallocate); + } + } + + /++ + Params: + length = array length + deallocate = Flag, never deallocates memory if `false`. + +/ + this(size_t length, uint alignment = T.alignof, bool deallocate = true) scope @trusted @nogc + { + if (!initialize(length, alignment, deallocate)) + { + version(D_Exceptions) + { + throw allocationExc; + } + else + { + assert(0, allocationExcMsg); + } + } + } + + private bool initializeImpl()(size_t length, uint alignment, bool deallocate) scope @trusted nothrow @nogc + { + if (length == 0) + { + _context = null; + return true; + } + import mir.internal.memory: malloc, alignedAllocate; + if (alignment <= 16) + { + _context = cast(Context*) malloc(length * T.sizeof + Context.sizeof); + *_context = Context.init; + if (_context is null) + return false; + } + else + { + _context = cast(Context*) alignedAllocate(length * T.sizeof + Context.sizeof, alignment); + *_context = Context.init; + if (_context is null) + return false; + version(Posix) {} // common free + else + { + import mir.internal.memory: alignedFree; + static bool feeFun(void[] p) + { + alignedFree(p.ptr); + return true; + } + _context._function = &feeFun; + } + } + + _context.length = length; + _context.counter = deallocate; // 0 + import mir.conv: uninitializedFillDefault; + import std.traits: Unqual; + uninitializedFillDefault((cast(Unqual!T*)(_context + 1))[0 .. _context.length]); + return true; + } + + /// + size_t length() @safe scope pure nothrow @nogc @property + { + return _context !is null ? _context.length : 0; + } + + /// + size_t counter() @safe scope pure nothrow @nogc @property + { + return _context !is null ? _context.counter : 0; + } + + /// + inout(T)* ptr() @system scope inout + { + return _context !is null ? cast(inout(T)*)(_context + 1) : null; + } + + /// + ref opIndex(size_t i) @trusted scope inout + { + assert(_context); + assert(i < _context.length); + return (cast(inout(T)*)(_context + 1))[i]; + } + + /// + bool opEquals(typeof(null)) @safe scope pure nothrow @nogc @property + { + return _context is null; + } + + /// + inout(T)[] opIndex() @trusted scope inout + { + return _context !is null ? (cast(inout(T)*)(_context + 1))[0 .. _context.length] : null; + } + + mir_rcarray!(const T) lightConst() const @nogc nothrow @trusted + { + return cast(typeof(return)) this; + } + + mir_rcarray!(immutable T) lightImmutable() immutable @nogc nothrow @trusted + { + return cast(typeof(return)) this; + } + + size_t opDollar(size_t pos : 0)() @safe scope pure nothrow @nogc + { + return _context !is null ? _context.length : 0; + } + + auto asSlice()() scope return @property + { + import mir.ndslice.slice: mir_slice; + alias It = mir_rci!T; + return mir_slice!It([length], It((()@trusted => ptr)(), this)); + } +} + +/// +@safe pure @nogc +unittest +{ + auto a = mir_rcarray!double(10); + foreach(i, ref e; a) + e = i; + auto b = a; + assert(b[$ - 1] == 9); + foreach(i, ref e; b) + assert(e == i); + b[4] = 100; + assert(a[4] == 100); + + import mir.ndslice.slice; + auto s = a.toSlice; + static assert(is(typeof(s) == Slice!(RCI!double))); + static assert(is(typeof(s) == mir_slice!(mir_rci!double))); +} + +/++ +Thread safe reference counting iterator. ++/ +struct mir_rci(T) +{ + T* _iterator; + + // private inout(T)* _iterator() inout @trusted pure nothrow @nogc scope + // { + // return cast(T*) _iteratorCode; + // } + + // private void _iterator(T * iterator) @trusted pure nothrow @nogc scope + // { + // _iteratorCode = cast(size_t) iterator; + // } + + /// + mir_rcarray!T _array; + + /// + mir_rci!(const T) lightConst()() const @property + { return typeof(return)(_iterator, _array.lightConst); } + + /// + mir_rci!(immutable T) lightImmutable()() immutable @property + { return typeof(return)(_iterator, _array.lightImmutable); } + + /// + ref inout(T) opUnary(string op : "*")() inout scope return + { return *_iterator; } + + /// + ref inout(T) opIndex(ptrdiff_t index) inout scope return + { return _iterator[index]; } + + /// + void opUnary(string op)() scope + if (op == "--" || op == "++") + { mixin(op ~ "_iterator;"); } + + /// + void opOpAssign(string op)(ptrdiff_t index) scope + if (op == "-" || op == "+") + { mixin("_iterator " ~ op ~ "= index;"); } + + /// + mir_rci!T opBinary(string op)(ptrdiff_t index) + if (op == "+" || op == "-") + { return mir_rci!T(_iterator + index, _array); } + + /// + mir_rci!(const T) opBinary(string op)(ptrdiff_t index) const + if (op == "+" || op == "-") + { return mir_rci!T(_iterator + index, _array); } + + /// + mir_rci!(immutable T) opBinary(string op)(ptrdiff_t index) immutable + if (op == "+" || op == "-") + { return mir_rci!T(_iterator + index, _array); } + + /// + ptrdiff_t opBinary(string op : "-")(scope ref const typeof(this) right) scope const + { return this._iterator - right._iterator; } + + /// + bool opEquals()(scope ref const typeof(this) right) scope const + { return this._iterator == right._iterator; } + + /// + ptrdiff_t opCmp()(scope ref const typeof(this) right) scope const + { return this._iterator - right._iterator; } +} + +/// ditto +alias RCI = mir_rci; + +unittest +{ + import mir.ndslice; + + alias rcvec = Slice!(RCI!double); + + RCI!double a, b; + auto c = a - b; + + void foo(scope ref rcvec x, scope ref rcvec y) + { + x[] = y[]; + x[1] = y[1]; + x[1 .. $] = y[1 .. $]; + x = x.save; + } +} diff --git a/source/mir/series.d b/source/mir/series.d index 5560dca0..62f39952 100644 --- a/source/mir/series.d +++ b/source/mir/series.d @@ -2108,9 +2108,9 @@ private auto unionSeriesImplPrivate(IndexIterator, Iterator, size_t N, SliceKind static if (N == 2) // fast path { alias algo = troykaSeriesImpl!( - (auto ref key, auto ref left) => left, - (auto ref key, auto ref left, auto ref right) => left, - (auto ref key, auto ref right) => right, + (auto scope ref key, auto scope return ref left) => left, + (auto scope ref key, auto scope ref left, auto scope return ref right) => left, + (auto scope ref key, auto scope return ref right) => right, ); algo!(I, E)(seriesTuple[0], seriesTuple[1], ret); } From cc4680b8f7e9fc2b4683e91d72bbb1cbe30f7dd5 Mon Sep 17 00:00:00 2001 From: Ilya Yaroshenko Date: Sun, 11 Nov 2018 00:32:50 +0700 Subject: [PATCH 4/6] fix meson --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 3dcbf2ca..972ebbdd 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,4 @@ -project('mir-algorithm', 'd', version : '4.0.0', license: 'BSL-1.0') +project('mir-algorithm', 'd', version : '3.1.0', license: 'BSL-1.0') mir_algorithm_dir = include_directories('source/', 'include/') From 108c16d427106c17a0683e1760444a3e437292b3 Mon Sep 17 00:00:00 2001 From: Ilya Yaroshenko Date: Sun, 11 Nov 2018 00:44:54 +0700 Subject: [PATCH 5/6] fix docs --- index.d | 1 + source/mir/rcarray.d | 24 +++++++++++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/index.d b/index.d index feac600e..8abbac97 100644 --- a/index.d +++ b/index.d @@ -16,6 +16,7 @@ $(BOOKTABLE , $(TR $(TDNW $(MREF mir,algorithm,setops)) $(TD Mir & BetterC rework of Phobos.)) $(TR $(TDNW $(MREF mir,algorithm,iteration)) $(TD Mir & BetterC rework of Phobos.)) $(LEADINGROW Containers) + $(TR $(TDNW $(MREF mir,rcarray)) $(TD Thread safe reference count array and the iterator to adopt it to ndslice.)) $(TR $(TDNW $(MREF mir,series)★) $(TD Generic series suitable for time-series or semi-immutable ordered maps with CPU cache friendly binary search.)) $(TR $(TDNW $(MREF mir,container,binaryheap)★) $(TD Mir & BetterC rework of Phobos.)) $(LEADINGROW Graphs) diff --git a/source/mir/rcarray.d b/source/mir/rcarray.d index c5752a97..b79d3468 100644 --- a/source/mir/rcarray.d +++ b/source/mir/rcarray.d @@ -179,6 +179,7 @@ struct mir_rcarray(T) /++ Params: length = array length + alignment = alignment, must be power of 2 deallocate = Flag, never deallocates memory if `false`. +/ this(size_t length, uint alignment = T.alignof, bool deallocate = true) scope @trusted @nogc @@ -324,6 +325,7 @@ Thread safe reference counting iterator. +/ struct mir_rci(T) { + /// T* _iterator; // private inout(T)* _iterator() inout @trusted pure nothrow @nogc scope @@ -396,20 +398,36 @@ struct mir_rci(T) /// ditto alias RCI = mir_rci; -unittest +/// +@nogc unittest +{ + import mir.ndslice; + import mir.rcarray; + auto array = mir_rcarray!double(10); + auto slice = array.asSlice; + static assert(is(typeof(slice) == Slice!(RCI!double))); + auto matrix = slice.sliced(2, 5); + static assert(is(typeof(matrix) == Slice!(RCI!double, 2))); + array[7] = 44; + assert(matrix[1, 2] == 44); +} + +/// +@nogc unittest { import mir.ndslice; + import mir.rcarray; alias rcvec = Slice!(RCI!double); RCI!double a, b; - auto c = a - b; + size_t c = a - b; void foo(scope ref rcvec x, scope ref rcvec y) { x[] = y[]; x[1] = y[1]; - x[1 .. $] = y[1 .. $]; + x[1 .. $] += y[1 .. $]; x = x.save; } } From 733c71ff53c7a36e1b186b2eec971e4f470d26ce Mon Sep 17 00:00:00 2001 From: Ilya Yaroshenko Date: Sun, 11 Nov 2018 00:47:27 +0700 Subject: [PATCH 6/6] fix docs --- source/mir/interpolate/constant.d | 1 - source/mir/interpolate/linear.d | 1 - 2 files changed, 2 deletions(-) diff --git a/source/mir/interpolate/constant.d b/source/mir/interpolate/constant.d index 38df91d0..b21dee90 100644 --- a/source/mir/interpolate/constant.d +++ b/source/mir/interpolate/constant.d @@ -76,7 +76,6 @@ template constant(T, size_t N = 1, FirstGridIterator = immutable(T)*, NextGridIt Params: grid = immutable `x` values for interpolant values = `f(x)` values for interpolant - forceCopyValues = always copy `values` if set Constraints: `grid` and `values` must have the same length >= 3 Returns: $(LREF Spline) diff --git a/source/mir/interpolate/linear.d b/source/mir/interpolate/linear.d index d7ba0319..30baf93c 100644 --- a/source/mir/interpolate/linear.d +++ b/source/mir/interpolate/linear.d @@ -52,7 +52,6 @@ template linear(T, size_t N = 1, FirstGridIterator = immutable(T)*, NextGridIter Params: grid = immutable `x` values for interpolant values = `f(x)` values for interpolant - forceCopyValues = always copy `values` if set Constraints: `grid` and `values` must have the same length >= 2 Returns: $(LREF Spline)