Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
c1864cf473 | |||
8db1851c5c | |||
12de700706 | |||
78a8afdf75 | |||
3c996d7c57 | |||
2a68048fc1 | |||
907f7a4e61 | |||
670328c047 | |||
7fe69ccc5c | |||
26c3532e28 | |||
75ce854192 | |||
9e16d84f9e |
@ -7,9 +7,9 @@ os:
|
||||
language: d
|
||||
|
||||
d:
|
||||
- dmd-2.077.0
|
||||
- dmd-2.078.0
|
||||
- dmd-2.077.1
|
||||
- dmd-2.076.1
|
||||
- dmd-2.075.1
|
||||
|
||||
env:
|
||||
matrix:
|
||||
@ -22,7 +22,7 @@ addons:
|
||||
- gcc-multilib
|
||||
|
||||
before_script:
|
||||
- if [ "$PS1" = '(dmd-2.077.0)' ]; then
|
||||
- if [ "$PS1" = '(dmd-2.078.0)' ]; then
|
||||
export UNITTEST="unittest-cov";
|
||||
fi
|
||||
|
||||
|
13
README.md
13
README.md
@ -12,8 +12,8 @@ Tanya is a general purpose library for D programming language.
|
||||
Its aim is to simplify the manual memory management in D and to provide a
|
||||
guarantee with @nogc attribute that there are no hidden allocations on the
|
||||
Garbage Collector heap. Everything in the library is usable in @nogc code.
|
||||
Tanya extends Phobos functionality and provides alternative implementations for
|
||||
data structures and utilities that depend on the Garbage Collector in Phobos.
|
||||
Tanya provides data structures and utilities to facilitate painless systems
|
||||
programming in D.
|
||||
|
||||
* [API Documentation](https://docs.caraus.io/tanya)
|
||||
* [Contribution guidelines](CONTRIBUTING.md)
|
||||
@ -149,9 +149,9 @@ There are more containers in the `tanya.container` package.
|
||||
|
||||
| DMD | GCC |
|
||||
|:-------:|:--------------:|
|
||||
| 2.077.0 | *gdc-5* branch |
|
||||
| 2.078.0 | *gdc-5* branch |
|
||||
| 2.077.1 | |
|
||||
| 2.076.1 | |
|
||||
| 2.075.1 | |
|
||||
|
||||
### Current status
|
||||
|
||||
@ -161,13 +161,10 @@ Following modules are under development:
|
||||
|----------|:---------:|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| BitArray | bitvector | [](https://travis-ci.org/caraus-ecms/tanya) [](https://ci.appveyor.com/project/belka-ew/tanya/branch/bitvector) |
|
||||
| TLS | crypto | [](https://travis-ci.org/caraus-ecms/tanya) [](https://ci.appveyor.com/project/belka-ew/tanya/branch/crypto) |
|
||||
| File IO | io | [](https://travis-ci.org/caraus-ecms/tanya) [](https://ci.appveyor.com/project/belka-ew/tanya/branch/io) |
|
||||
|
||||
### Release management
|
||||
|
||||
3-week release cycle.
|
||||
|
||||
Deprecated features are removed after one release (in approximately 6 weeks after deprecating).
|
||||
Deprecated features are removed after one release that includes these deprecations.
|
||||
|
||||
## Further characteristics
|
||||
|
||||
|
16
appveyor.yml
16
appveyor.yml
@ -4,10 +4,16 @@ os: Visual Studio 2015
|
||||
environment:
|
||||
matrix:
|
||||
- DC: dmd
|
||||
DVersion: 2.077.0
|
||||
DVersion: 2.078.0
|
||||
arch: x64
|
||||
- DC: dmd
|
||||
DVersion: 2.077.0
|
||||
DVersion: 2.078.0
|
||||
arch: x86
|
||||
- DC: dmd
|
||||
DVersion: 2.077.1
|
||||
arch: x64
|
||||
- DC: dmd
|
||||
DVersion: 2.077.1
|
||||
arch: x86
|
||||
- DC: dmd
|
||||
DVersion: 2.076.1
|
||||
@ -15,12 +21,6 @@ environment:
|
||||
- DC: dmd
|
||||
DVersion: 2.076.1
|
||||
arch: x86
|
||||
- DC: dmd
|
||||
DVersion: 2.075.1
|
||||
arch: x64
|
||||
- DC: dmd
|
||||
DVersion: 2.075.1
|
||||
arch: x86
|
||||
|
||||
skip_tags: true
|
||||
|
||||
|
7
dub.json
7
dub.json
@ -12,7 +12,12 @@
|
||||
"configurations": [
|
||||
{
|
||||
"name": "library",
|
||||
"targetType": "library",
|
||||
"targetType": "staticLibrary",
|
||||
"versions": ["TanyaPhobos"]
|
||||
},
|
||||
{
|
||||
"name": "dynamic",
|
||||
"targetType": "dynamicLibrary",
|
||||
"versions": ["TanyaPhobos"]
|
||||
},
|
||||
{
|
||||
|
@ -264,7 +264,8 @@ if (is(Unqual!E == char))
|
||||
body
|
||||
{
|
||||
dchar chr;
|
||||
ubyte units, mask;
|
||||
ubyte units;
|
||||
int mask;
|
||||
const(char)* it = this.begin;
|
||||
|
||||
if (*it & 0x80)
|
||||
|
@ -323,9 +323,9 @@ private HP raise2Power10(const HP value, int power)
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a float value, returns the significant bits in bits, and the position
|
||||
* of the decimal point in $(D_PARAM exponent). +/-Inf and NaN are specified
|
||||
* by special values returned in the $(D_PARAM exponent). Sing bit is set in
|
||||
* Given a float value, returns the significant bits, and the position of the
|
||||
* decimal point in $(D_PARAM exponent). +/-Inf and NaN are specified by
|
||||
* special values returned in the $(D_PARAM exponent). Sing bit is set in
|
||||
* $(D_PARAM sign).
|
||||
*/
|
||||
private const(char)[] real2String(double value,
|
||||
@ -505,35 +505,9 @@ if (T.sizeof == U.sizeof)
|
||||
copy((&src)[0 .. 1], (&dest)[0 .. 1]);
|
||||
}
|
||||
|
||||
package(tanya) String format(string fmt, Args...)(auto ref Args args)
|
||||
private void formatReal(T)(ref T arg, ref String result)
|
||||
if (isFloatingPoint!T)
|
||||
{
|
||||
String result;
|
||||
|
||||
static if (is(Unqual!(Args[0]) == typeof(null)))
|
||||
{
|
||||
result.insertBack("null");
|
||||
}
|
||||
else static if(is(Unqual!(Args[0]) == bool))
|
||||
{
|
||||
result.insertBack(args[0] ? "true" : "false");
|
||||
}
|
||||
else static if (isSomeString!(Args[0])) // String
|
||||
{
|
||||
if (args[0] is null)
|
||||
{
|
||||
result.insertBack("null");
|
||||
}
|
||||
else
|
||||
{
|
||||
result.insertBack(args[0]);
|
||||
}
|
||||
}
|
||||
else static if (isSomeChar!(Args[0])) // Char
|
||||
{
|
||||
result.insertBack(args[0]);
|
||||
}
|
||||
else static if (isFloatingPoint!(Args[0])) // Float
|
||||
{
|
||||
char[512] buffer; // Big enough for e+308 or e-307.
|
||||
char[8] tail = 0;
|
||||
char[] bufferSlice = buffer[64 .. $];
|
||||
@ -542,7 +516,7 @@ package(tanya) String format(string fmt, Args...)(auto ref Args args)
|
||||
int decimalPoint;
|
||||
|
||||
// Read the double into a string.
|
||||
auto realString = real2String(args[0], buffer, decimalPoint, negative);
|
||||
auto realString = real2String(arg, buffer, decimalPoint, negative);
|
||||
auto length = cast(uint) realString.length;
|
||||
|
||||
// Clamp the precision and delete extra zeros after clamp.
|
||||
@ -551,9 +525,7 @@ package(tanya) String format(string fmt, Args...)(auto ref Args args)
|
||||
{
|
||||
length = precision;
|
||||
}
|
||||
while ((length > 1)
|
||||
&& (precision != 0)
|
||||
&& (realString[length - 1] == '0'))
|
||||
while ((length > 1) && (precision != 0) && (realString[length - 1] == '0'))
|
||||
{
|
||||
--precision;
|
||||
--length;
|
||||
@ -566,7 +538,7 @@ package(tanya) String format(string fmt, Args...)(auto ref Args args)
|
||||
if (decimalPoint == special)
|
||||
{
|
||||
result.insertBack(realString);
|
||||
goto ParamEnd;
|
||||
return;
|
||||
}
|
||||
|
||||
// Should we use sceintific notation?
|
||||
@ -727,8 +699,83 @@ package(tanya) String format(string fmt, Args...)(auto ref Args args)
|
||||
|
||||
result.insertBack(buffer[64 .. length]); // Number.
|
||||
result.insertBack(tail[1 .. tail[0] + 1]); // Tail.
|
||||
}
|
||||
|
||||
private void formatStruct(T)(ref T arg, ref String result)
|
||||
if (is(T == struct))
|
||||
{
|
||||
template pred(alias f)
|
||||
{
|
||||
static if (f == "this")
|
||||
{
|
||||
// Exclude context pointer from nested structs.
|
||||
enum bool pred = false;
|
||||
}
|
||||
else static if (isPointer!(Args[0])) // Pointer
|
||||
else
|
||||
{
|
||||
enum bool pred = !isSomeFunction!(__traits(getMember, arg, f));
|
||||
}
|
||||
}
|
||||
alias fields = Filter!(pred, __traits(allMembers, T));
|
||||
|
||||
static if (fields.length > 0)
|
||||
{
|
||||
printToString!"{}"(result, __traits(getMember, arg, fields[0]));
|
||||
foreach (field; fields[1 .. $])
|
||||
{
|
||||
result.insertBack(", ");
|
||||
printToString!"{}"(result, __traits(getMember, arg, field));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ref String printToString(string fmt, Args...)(return ref String result,
|
||||
auto ref Args args)
|
||||
{
|
||||
alias Arg = Args[0];
|
||||
|
||||
static if (is(Unqual!Arg == typeof(null))) // null
|
||||
{
|
||||
result.insertBack("null");
|
||||
}
|
||||
else static if(is(Unqual!Arg == bool)) // Boolean
|
||||
{
|
||||
result.insertBack(args[0] ? "true" : "false");
|
||||
}
|
||||
else static if (isSomeChar!Arg || isSomeString!Arg) // String or char
|
||||
{
|
||||
result.insertBack(args[0]);
|
||||
}
|
||||
else static if (isInputRange!Arg
|
||||
&& !isInfinite!Arg
|
||||
&& isSomeChar!(ElementType!Arg)) // Stringish range
|
||||
{
|
||||
result.insertBack(args[0]);
|
||||
}
|
||||
else static if (is(Unqual!(typeof(args[0].stringify())) == String))
|
||||
{
|
||||
result.insertBack(args[0].stringify()[]);
|
||||
}
|
||||
else static if (is(Arg == class))
|
||||
{
|
||||
result.insertBack(args[0] is null ? "null" : args[0].toString());
|
||||
}
|
||||
else static if (is(Arg == interface))
|
||||
{
|
||||
result.insertBack(Arg.classinfo.name);
|
||||
}
|
||||
else static if (is(Arg == struct))
|
||||
{
|
||||
result.insertBack(Arg.stringof);
|
||||
result.insertBack('(');
|
||||
formatStruct(args[0], result);
|
||||
result.insertBack(')');
|
||||
}
|
||||
else static if (isFloatingPoint!Arg) // Float
|
||||
{
|
||||
formatReal(args[0], result);
|
||||
}
|
||||
else static if (isPointer!Arg) // Pointer
|
||||
{
|
||||
char[size_t.sizeof * 2] buffer;
|
||||
size_t position = buffer.length;
|
||||
@ -744,20 +791,26 @@ package(tanya) String format(string fmt, Args...)(auto ref Args args)
|
||||
result.insertBack("0x");
|
||||
result.insertBack(buffer[position .. $]);
|
||||
}
|
||||
else static if (isIntegral!(Args[0])) // Integer
|
||||
else static if (isIntegral!Arg) // Integer
|
||||
{
|
||||
char[21] buffer;
|
||||
result.insertBack(integral2String(args[0], buffer));
|
||||
}
|
||||
else
|
||||
{
|
||||
static assert(false);
|
||||
static assert(false,
|
||||
"Formatting type " ~ Arg.stringof ~ " is not supported");
|
||||
}
|
||||
ParamEnd:
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
package(tanya) String format(string fmt, Args...)(auto ref Args args)
|
||||
{
|
||||
String formatted;
|
||||
return printToString!fmt(formatted, args);
|
||||
}
|
||||
|
||||
// One argument tests.
|
||||
@nogc pure @safe unittest
|
||||
{
|
||||
@ -772,7 +825,7 @@ ParamEnd:
|
||||
|
||||
// String printing.
|
||||
assert(format!"{}"("Some weired string") == "Some weired string");
|
||||
assert(format!"{}"(cast(string) null) == "null");
|
||||
assert(format!"{}"(cast(string) null) == "");
|
||||
assert(format!"{}"('c') == "c");
|
||||
|
||||
// Integer.
|
||||
@ -826,6 +879,93 @@ ParamEnd:
|
||||
assert(format!"{}"(cast(void*) null) == "0x0");
|
||||
}
|
||||
|
||||
// Structs.
|
||||
@nogc pure @safe unittest
|
||||
{
|
||||
static struct WithoutStringify1
|
||||
{
|
||||
int a;
|
||||
void func()
|
||||
{
|
||||
}
|
||||
}
|
||||
assert(format!"{}"(WithoutStringify1(6)) == "WithoutStringify1(6)");
|
||||
|
||||
static struct WithoutStringify2
|
||||
{
|
||||
}
|
||||
assert(format!"{}"(WithoutStringify2()) == "WithoutStringify2()");
|
||||
|
||||
static struct WithoutStringify3
|
||||
{
|
||||
int a = -2;
|
||||
int b = 8;
|
||||
}
|
||||
assert(format!"{}"(WithoutStringify3()) == "WithoutStringify3(-2, 8)");
|
||||
|
||||
struct Nested
|
||||
{
|
||||
int i;
|
||||
|
||||
void func()
|
||||
{
|
||||
}
|
||||
}
|
||||
assert(format!"{}"(Nested()) == "Nested(0)");
|
||||
|
||||
static struct WithStringify
|
||||
{
|
||||
String stringify() const @nogc nothrow pure @safe
|
||||
{
|
||||
return String("stringify method");
|
||||
}
|
||||
}
|
||||
assert(format!"{}"(WithStringify()) == "stringify method");
|
||||
}
|
||||
|
||||
// Aggregate types.
|
||||
@system unittest // Object.toString has no attributes.
|
||||
{
|
||||
import tanya.memory;
|
||||
import tanya.memory.smartref;
|
||||
|
||||
interface I
|
||||
{
|
||||
}
|
||||
class A : I
|
||||
{
|
||||
}
|
||||
auto instance = defaultAllocator.unique!A();
|
||||
assert(format!"{}"(instance.get()) == instance.get.toString());
|
||||
assert(format!"{}"(cast(I) instance.get()) == I.classinfo.name);
|
||||
assert(format!"{}"(cast(A) null) == "null");
|
||||
}
|
||||
|
||||
// Ranges.
|
||||
@nogc pure @safe unittest
|
||||
{
|
||||
static struct Stringish
|
||||
{
|
||||
string content = "Some content";
|
||||
|
||||
immutable(char) front() const @nogc nothrow pure @safe
|
||||
{
|
||||
return this.content[0];
|
||||
}
|
||||
|
||||
void popFront() @nogc nothrow pure @safe
|
||||
{
|
||||
this.content = this.content[1 .. $];
|
||||
}
|
||||
|
||||
bool empty() const @nogc nothrow pure @safe
|
||||
{
|
||||
return this.content.length == 0;
|
||||
}
|
||||
}
|
||||
assert(format!"{}"(Stringish()) == "Some content");
|
||||
}
|
||||
|
||||
private struct FormatSpec
|
||||
{
|
||||
}
|
||||
|
@ -393,7 +393,9 @@ struct Integer
|
||||
T opCast(T)() const
|
||||
if (isIntegral!T && isSigned!T)
|
||||
{
|
||||
return this.sign ? -(cast(Unsigned!T) this) : cast(Unsigned!T) this;
|
||||
return this.sign
|
||||
? cast(T) -(cast(Promoted!(Unsigned!T)) (cast(Unsigned!T) this))
|
||||
: cast(Unsigned!T) this;
|
||||
}
|
||||
|
||||
///
|
||||
@ -1072,7 +1074,7 @@ struct Integer
|
||||
assert(h1 == 79);
|
||||
|
||||
h2 = ~h1;
|
||||
assert(h2 == ~cast(ubyte) 79);
|
||||
assert(h2 == cast(ubyte) ~79);
|
||||
}
|
||||
|
||||
/// ditto
|
||||
|
@ -275,13 +275,37 @@ enum bool isTemplate(alias T) = __traits(isTemplate, T);
|
||||
static assert(!isTemplate!(S!int));
|
||||
}
|
||||
|
||||
deprecated("Use is(T == interface) instead")
|
||||
/**
|
||||
* Tests whether $(D_PARAM T) is an interface.
|
||||
*
|
||||
* Params:
|
||||
* T = A type.
|
||||
*
|
||||
* Returns: $(D_KEYWORD true) if $(D_PARAM T) is an interface,
|
||||
* $(D_KEYWORD false) otherwise.
|
||||
*/
|
||||
enum bool isInterface(T) = is(T == interface);
|
||||
|
||||
deprecated("Use is(T == class) instead")
|
||||
/**
|
||||
* Tests whether $(D_PARAM T) is a class.
|
||||
*
|
||||
* Params:
|
||||
* T = A type.
|
||||
*
|
||||
* Returns: $(D_KEYWORD true) if $(D_PARAM T) is a class,
|
||||
* $(D_KEYWORD false) otherwise.
|
||||
*/
|
||||
enum bool isClass(T) = is(T == class);
|
||||
|
||||
deprecated("Use is(T == struct) instead")
|
||||
/**
|
||||
* Tests whether $(D_PARAM T) is a struct.
|
||||
*
|
||||
* Params:
|
||||
* T = A type.
|
||||
*
|
||||
* Returns: $(D_KEYWORD true) if $(D_PARAM T) is a struct,
|
||||
* $(D_KEYWORD false) otherwise.
|
||||
*/
|
||||
enum bool isStruct(T) = is(T == struct);
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user