Replace tuples with custom types
This commit is contained in:
parent
5453c646f6
commit
90797a48be
@ -5,7 +5,7 @@
|
||||
/*
|
||||
* Internal package used by containers that rely on entries/nodes.
|
||||
*
|
||||
* Copyright: Eugene Wissner 2016-2020.
|
||||
* Copyright: Eugene Wissner 2016-2022.
|
||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||
* Mozilla Public License, v. 2.0).
|
||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||
@ -19,7 +19,6 @@ import tanya.memory.allocator;
|
||||
import tanya.memory.lifetime;
|
||||
import tanya.meta.trait;
|
||||
import tanya.meta.transform;
|
||||
import tanya.typecons;
|
||||
|
||||
package struct SEntry(T)
|
||||
{
|
||||
@ -54,7 +53,11 @@ package struct Bucket(K, V = void)
|
||||
}
|
||||
else
|
||||
{
|
||||
alias KV = Tuple!(K, "key", V, "value");
|
||||
package struct KV
|
||||
{
|
||||
package K key;
|
||||
package V value;
|
||||
}
|
||||
KV kv;
|
||||
}
|
||||
BucketStatus status = BucketStatus.empty;
|
||||
|
@ -38,7 +38,7 @@
|
||||
*
|
||||
* More advanced formatting is currently not implemented.
|
||||
*
|
||||
* Copyright: Eugene Wissner 2017-2020.
|
||||
* Copyright: Eugene Wissner 2017-2022.
|
||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||
* Mozilla Public License, v. 2.0).
|
||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||
@ -56,7 +56,6 @@ import tanya.meta.metafunction;
|
||||
import tanya.meta.trait;
|
||||
import tanya.meta.transform;
|
||||
import tanya.range;
|
||||
import tanya.typecons : Tuple;
|
||||
|
||||
// Returns the last part of buffer with converted number.
|
||||
package(tanya) char[] integral2String(T)(T number, return ref char[21] buffer)
|
||||
@ -940,6 +939,12 @@ private struct uint128
|
||||
{
|
||||
ulong[2] data;
|
||||
|
||||
private struct DivMod
|
||||
{
|
||||
uint128 quotient;
|
||||
uint128 remainder;
|
||||
}
|
||||
|
||||
this(ulong upper, ulong lower) @nogc nothrow pure @safe
|
||||
{
|
||||
this.data[0] = upper;
|
||||
@ -1174,7 +1179,7 @@ private struct uint128
|
||||
return this.data[1];
|
||||
}
|
||||
|
||||
Tuple!(uint128, uint128) divMod(ulong rhs) const @nogc nothrow pure @safe
|
||||
DivMod divMod(ulong rhs) const @nogc nothrow pure @safe
|
||||
in
|
||||
{
|
||||
assert(rhs != uint128(), "Division by 0");
|
||||
@ -1197,22 +1202,22 @@ private struct uint128
|
||||
typeof(return) result;
|
||||
for (ubyte x = this.bits; x > 0; --x)
|
||||
{
|
||||
result[0] = result[0] << 1;
|
||||
result[1] = result[1] << 1;
|
||||
result.quotient = result.quotient << 1;
|
||||
result.remainder = result.remainder << 1;
|
||||
|
||||
if ((this >> (x - 1U)) & 1)
|
||||
{
|
||||
++result[1];
|
||||
++result.remainder;
|
||||
}
|
||||
|
||||
if (result[1] >= rhs)
|
||||
if (result.remainder >= rhs)
|
||||
{
|
||||
if (result[1].data[1] < rhs)
|
||||
if (result.remainder.data[1] < rhs)
|
||||
{
|
||||
--result[1].data[0];
|
||||
--result.remainder.data[0];
|
||||
}
|
||||
result[1].data[1] -= rhs;
|
||||
++result[0];
|
||||
result.remainder.data[1] -= rhs;
|
||||
++result.quotient;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@ -1220,12 +1225,12 @@ private struct uint128
|
||||
|
||||
uint128 opBinary(string op : "/")(ulong rhs)
|
||||
{
|
||||
return divMod(rhs)[0];
|
||||
return divMod(rhs).quotient;
|
||||
}
|
||||
|
||||
uint128 opBinary(string op : "%")(ulong rhs) const
|
||||
{
|
||||
return divMod(rhs)[1];
|
||||
return divMod(rhs).remainder;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1302,12 +1307,12 @@ do
|
||||
enum ulong power19 = cast(ulong) 1e19;
|
||||
|
||||
auto qr = leftBoundary.divMod(power19);
|
||||
auto low = cast(ulong) qr[1];
|
||||
const lowFactor = cast(ulong) (qr[0] % power19);
|
||||
auto low = cast(ulong) qr.remainder;
|
||||
const lowFactor = cast(ulong) (qr.quotient % power19);
|
||||
|
||||
qr = rightBoundary.divMod(power19);
|
||||
auto high = cast(ulong) qr[1];
|
||||
const highFactor = cast(ulong) (qr[0] % power19);
|
||||
auto high = cast(ulong) qr.remainder;
|
||||
const highFactor = cast(ulong) (qr.quotient % power19);
|
||||
size_t digitIndex;
|
||||
|
||||
if (lowFactor != highFactor)
|
||||
|
@ -16,7 +16,6 @@ module tanya.math.random;
|
||||
|
||||
import std.typecons;
|
||||
import tanya.memory.allocator;
|
||||
import tanya.typecons;
|
||||
|
||||
/// Maximum amount gathered from the entropy sources.
|
||||
enum maxGather = 128;
|
||||
|
@ -1,154 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* Type constructors.
|
||||
*
|
||||
* This module contains templates that allow to build new types from the
|
||||
* available ones.
|
||||
*
|
||||
* Copyright: Eugene Wissner 2017-2020.
|
||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||
* Mozilla Public License, v. 2.0).
|
||||
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/typecons.d,
|
||||
* tanya/typecons.d)
|
||||
*/
|
||||
module tanya.typecons;
|
||||
|
||||
import tanya.format;
|
||||
import tanya.memory.lifetime;
|
||||
import tanya.meta.metafunction;
|
||||
import tanya.meta.trait;
|
||||
|
||||
/**
|
||||
* $(D_PSYMBOL Tuple) can store two or more heterogeneous objects.
|
||||
*
|
||||
* The objects can by accessed by index as `obj[0]` and `obj[1]` or by optional
|
||||
* names (e.g. `obj.first`).
|
||||
*
|
||||
* $(D_PARAM Specs) contains a list of object types and names. First
|
||||
* comes the object type, then an optional string containing the name.
|
||||
* If you want the object be accessible only by its index (`0` or `1`),
|
||||
* just skip the name.
|
||||
*
|
||||
* Params:
|
||||
* Specs = Field types and names.
|
||||
*
|
||||
* See_Also: $(D_PSYMBOL tuple).
|
||||
*/
|
||||
template Tuple(Specs...)
|
||||
{
|
||||
template parseSpecs(size_t fieldCount, Specs...)
|
||||
{
|
||||
static if (Specs.length == 0)
|
||||
{
|
||||
alias parseSpecs = AliasSeq!();
|
||||
}
|
||||
else static if (is(Specs[0]) && fieldCount < 2)
|
||||
{
|
||||
static if (is(typeof(Specs[1]) == string))
|
||||
{
|
||||
alias parseSpecs
|
||||
= AliasSeq!(Pack!(Specs[0], Specs[1]),
|
||||
parseSpecs!(fieldCount + 1, Specs[2 .. $]));
|
||||
}
|
||||
else
|
||||
{
|
||||
alias parseSpecs
|
||||
= AliasSeq!(Pack!(Specs[0]),
|
||||
parseSpecs!(fieldCount + 1, Specs[1 .. $]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
static assert(false, "Invalid argument: " ~ Specs[0].stringof);
|
||||
}
|
||||
}
|
||||
|
||||
alias ChooseType(alias T) = T.Seq[0];
|
||||
alias ParsedSpecs = parseSpecs!(0, Specs);
|
||||
|
||||
static assert(ParsedSpecs.length > 1, "Invalid argument count");
|
||||
|
||||
private string formatAliases(size_t n, Specs...)()
|
||||
{
|
||||
static if (Specs.length == 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
else
|
||||
{
|
||||
string fieldAlias;
|
||||
static if (Specs[0].length == 2)
|
||||
{
|
||||
char[21] buffer;
|
||||
fieldAlias = "alias " ~ Specs[0][1] ~ " = expand["
|
||||
~ integral2String(n, buffer).idup ~ "];";
|
||||
}
|
||||
return fieldAlias ~ formatAliases!(n + 1, Specs[1 .. $])();
|
||||
}
|
||||
}
|
||||
|
||||
struct Tuple
|
||||
{
|
||||
/// Field types.
|
||||
alias Types = Map!(ChooseType, ParsedSpecs);
|
||||
|
||||
// Create field aliases.
|
||||
mixin(formatAliases!(0, ParsedSpecs[0 .. $])());
|
||||
|
||||
/// Represents the values of the $(D_PSYMBOL Tuple) as a list of values.
|
||||
Types expand;
|
||||
|
||||
alias expand this;
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
@nogc nothrow pure @safe unittest
|
||||
{
|
||||
auto pair = Tuple!(int, "first", string, "second")(1, "second");
|
||||
assert(pair.first == 1);
|
||||
assert(pair[0] == 1);
|
||||
assert(pair.second == "second");
|
||||
assert(pair[1] == "second");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new $(D_PSYMBOL Tuple).
|
||||
*
|
||||
* Params:
|
||||
* Names = Field names.
|
||||
*
|
||||
* See_Also: $(D_PSYMBOL Tuple).
|
||||
*/
|
||||
template tuple(Names...)
|
||||
{
|
||||
/**
|
||||
* Creates a new $(D_PSYMBOL Tuple).
|
||||
*
|
||||
* Params:
|
||||
* Args = Field types.
|
||||
* args = Field values.
|
||||
*
|
||||
* Returns: Newly created $(D_PSYMBOL Tuple).
|
||||
*/
|
||||
auto tuple(Args...)(auto ref Args args)
|
||||
if (Args.length >= Names.length && isTypeTuple!Args)
|
||||
{
|
||||
alias Zipped = ZipWith!(AliasSeq, Pack!Args, Pack!Names);
|
||||
alias Nameless = Args[Names.length .. $];
|
||||
|
||||
return Tuple!(Zipped, Nameless)(forward!args);
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
@nogc nothrow pure @safe unittest
|
||||
{
|
||||
auto t = tuple!("one", "two")(20, 5);
|
||||
assert(t.one == 20);
|
||||
assert(t.two == 5);
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
module tanya.tests.typecons;
|
||||
|
||||
import tanya.test.stub;
|
||||
import tanya.typecons;
|
||||
|
||||
@nogc nothrow pure @safe unittest
|
||||
{
|
||||
static assert(is(Tuple!(int, int)));
|
||||
static assert(!is(Tuple!(int, 5)));
|
||||
|
||||
static assert(is(Tuple!(int, "first", int)));
|
||||
static assert(is(Tuple!(int, "first", int, "second")));
|
||||
static assert(is(Tuple!(int, "first", int)));
|
||||
|
||||
static assert(is(Tuple!(int, int, "second")));
|
||||
static assert(!is(Tuple!("first", int, "second", int)));
|
||||
static assert(!is(Tuple!(int, int, int)));
|
||||
|
||||
static assert(!is(Tuple!(int, "first")));
|
||||
|
||||
static assert(!is(Tuple!(int, double, char)));
|
||||
static assert(!is(Tuple!(int, "first", double, "second", char, "third")));
|
||||
}
|
Loading…
Reference in New Issue
Block a user