module std.experimental.ndslice.internal; import std.traits; import std.meta; //: AliasSeq, anySatisfy, Filter, Reverse; package: enum string tailErrorMessage( string fun = __FUNCTION__, string pfun = __PRETTY_FUNCTION__) = " - - - Error in function " ~ fun ~ " - - - Function prototype " ~ pfun ~ " _____"; mixin template _DefineRet() { alias Ret = typeof(return); static if (hasElaborateAssign!(Ret.PureRange)) Ret ret; else Ret ret = void; } mixin template DimensionsCountCTError() { static assert(Dimensions.length <= N, "Dimensions list length = " ~ Dimensions.length.stringof ~ " should be less than or equal to N = " ~ N.stringof ~ tailErrorMessage!()); } enum DimensionsCountRTError = q{ assert(dimensions.length <= N, "Dimensions list length should be less than or equal to N = " ~ N.stringof ~ tailErrorMessage!()); }; mixin template DimensionCTError() { static assert(dimension >= 0, "dimension = " ~ dimension.stringof ~ " at position " ~ i.stringof ~ " should be greater than or equal to 0" ~ tailErrorMessage!()); static assert(dimension < N, "dimension = " ~ dimension.stringof ~ " at position " ~ i.stringof ~ " should be less than N = " ~ N.stringof ~ tailErrorMessage!()); } enum DimensionRTError = q{ static if (isSigned!(typeof(dimension))) assert(dimension >= 0, "dimension should be greater than or equal to 0" ~ tailErrorMessage!()); assert(dimension < N, "dimension should be less than N = " ~ N.stringof ~ tailErrorMessage!()); }; private alias IncFront(Seq...) = AliasSeq!(Seq[0] + 1, Seq[1 .. $]); private alias DecFront(Seq...) = AliasSeq!(Seq[0] - 1, Seq[1 .. $]); private enum bool isNotZero(alias t) = t != 0; alias NSeqEvert(Seq...) = Filter!(isNotZero, DecFront!(Reverse!(IncFront!Seq))); alias Parts(Seq...) = DecAll!(IncFront!Seq); alias Snowball(Seq...) = AliasSeq!(size_t.init, SnowballImpl!(size_t.init, Seq)); private template SnowballImpl(size_t val, Seq...) { static if (Seq.length == 0) alias SnowballImpl = AliasSeq!(); else alias SnowballImpl = AliasSeq!(Seq[0] + val, SnowballImpl!(Seq[0] + val, Seq[1 .. $])); } private template DecAll(Seq...) { static if (Seq.length == 0) alias DecAll = AliasSeq!(); else alias DecAll = AliasSeq!(Seq[0] - 1, DecAll!(Seq[1 .. $])); } template SliceFromSeq(Range, Seq...) { static if (Seq.length == 0) alias SliceFromSeq = Range; else { import std.experimental.ndslice.slice: Slice; alias SliceFromSeq = SliceFromSeq!(Slice!(Seq[$ - 1], Range), Seq[0 .. $ - 1]); } } template DynamicArrayDimensionsCount(T) { static if(isDynamicArray!T) enum size_t DynamicArrayDimensionsCount = 1 + DynamicArrayDimensionsCount!(typeof(T.init[0])); else enum size_t DynamicArrayDimensionsCount = 0; } bool isPermutation(size_t N)(auto ref in size_t[N] perm) { int[N] mask; if (isValidPartialPermutationImpl(perm, mask) == false) return false; foreach (e; mask) if (e == false) return false; return true; } bool isValidPartialPermutation(size_t N)(in size_t[] perm) { int[N] mask; return isValidPartialPermutationImpl(perm, mask); } private bool isValidPartialPermutationImpl(size_t N)(in size_t[] perm, ref int[N] mask) { if (perm.length == 0) return false; foreach (j; perm) { if (j >= N) return false; if (mask[j]) //duplicate return false; mask[j] = true; } return true; } enum isIndex(I) = is(I : size_t); private enum isReference(P) = hasIndirections!P || isFunctionPointer!P || is(P == interface); enum hasReference(T) = anySatisfy!(isReference, RepresentationTypeTuple!T); alias ImplicitlyUnqual(T) = Select!(isImplicitlyConvertible!(T, Unqual!T), Unqual!T, T); //TODO: replace with `static foreach` template Iota(size_t i, size_t j) { static assert(i <= j, "Iota: i should be less than or equal to j"); static if (i == j) alias Iota = AliasSeq!(); else alias Iota = AliasSeq!(i, Iota!(i + 1, j)); } template Repeat(T, size_t N) { static if (N) alias Repeat = AliasSeq!(Repeat!(T, N - 1), T); else alias Repeat = AliasSeq!(); } size_t lengthsProduct(size_t N)(auto ref in size_t[N] lengths) { size_t length = lengths[0]; foreach (i; Iota!(1, N)) length *= lengths[i]; return length; } pure nothrow unittest { const size_t[3] lengths = [3, 4, 5]; assert(lengthsProduct(lengths) == 60); assert(lengthsProduct([3, 4, 5]) == 60); } enum canSave(T) = isPointer!T || isDynamicArray!T || __traits(compiles, { T r1 = T.init; auto s1 = r1.save; static assert (is(typeof(s1) == T)); }); struct _Slice { size_t i, j; }