12 Commits

Author SHA1 Message Date
c1864cf473 Add dynamic library target 2018-01-13 06:21:42 +01:00
8db1851c5c Update dmd to 2.078.0 2018-01-04 05:36:46 +01:00
12de700706 Fix formatting null class references 2017-12-16 09:42:57 +01:00
78a8afdf75 Format stringish ranges 2017-12-15 22:42:18 +01:00
3c996d7c57 Add struct formatting 2017-12-14 19:47:13 +01:00
2a68048fc1 Put real formatting code into a separate function 2017-12-09 10:02:54 +01:00
907f7a4e61 Remove IO branch 2017-12-09 09:53:23 +01:00
670328c047 Drop support for 2.075.1 2017-12-08 10:58:39 +01:00
7fe69ccc5c format: Aggregate types 2017-12-08 10:56:59 +01:00
26c3532e28 Wrap formatting into printToString
printToString gets the output string as argument and can be called
recursive with the same output string to format ranges.
2017-12-03 19:53:06 +01:00
75ce854192 Support dmd 2.077.1 2017-12-02 10:40:40 +01:00
9e16d84f9e Reintroduce isStruct, isClass and isInterface
since they can be useful for generic programming.
2017-11-29 19:53:28 +01:00
8 changed files with 381 additions and 212 deletions

View File

@ -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

View File

@ -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 | [![bitvector](https://travis-ci.org/caraus-ecms/tanya.svg?branch=bitvector)](https://travis-ci.org/caraus-ecms/tanya) [![bitvector](https://ci.appveyor.com/api/projects/status/djkmverdfsylc7ti/branch/bitvector?svg=true)](https://ci.appveyor.com/project/belka-ew/tanya/branch/bitvector) |
| TLS | crypto | [![crypto](https://travis-ci.org/caraus-ecms/tanya.svg?branch=crypto)](https://travis-ci.org/caraus-ecms/tanya) [![crypto](https://ci.appveyor.com/api/projects/status/djkmverdfsylc7ti/branch/crypto?svg=true)](https://ci.appveyor.com/project/belka-ew/tanya/branch/crypto) |
| File IO | io | [![io](https://travis-ci.org/caraus-ecms/tanya.svg?branch=io)](https://travis-ci.org/caraus-ecms/tanya) [![io](https://ci.appveyor.com/api/projects/status/djkmverdfsylc7ti/branch/io?svg=true)](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

View File

@ -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

View File

@ -12,7 +12,12 @@
"configurations": [
{
"name": "library",
"targetType": "library",
"targetType": "staticLibrary",
"versions": ["TanyaPhobos"]
},
{
"name": "dynamic",
"targetType": "dynamicLibrary",
"versions": ["TanyaPhobos"]
},
{

View File

@ -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)

View File

@ -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
{
}

View File

@ -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

View File

@ -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);
/**