21 Commits

Author SHA1 Message Date
2946fd7f81 Update dmd to 2.078.2 2018-02-15 18:33:54 +01:00
2cda82eeea Fix handling of misaligned bytes in fill 2018-02-04 07:23:56 +01:00
e9f70853c6 Fix #12 2018-02-02 16:13:55 +01:00
4aaa71a7d0 Format ranges 2018-02-02 14:34:36 +01:00
cbc68c2c43 Implement formatting for enums 2018-02-01 16:29:13 +01:00
048ddf21ff Replace body with do 2018-01-31 12:05:06 +01:00
fd02c411e1 Update latest dmd version to 2.078.1 2018-01-23 05:21:19 +01:00
b69d737845 Add typeid formatting tests 2018-01-16 17:44:09 +01:00
904451ccaa Remove moved and deprecated conv module 2018-01-14 19:13:12 +01:00
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
30 changed files with 696 additions and 704 deletions

View File

@ -7,9 +7,9 @@ os:
language: d
d:
- dmd-2.077.0
- dmd-2.078.2
- 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.2)' ]; 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.2 | *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.2
arch: x64
- DC: dmd
DVersion: 2.077.0
DVersion: 2.078.2
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

@ -37,6 +37,11 @@ _D5tanya6memory2op10fillMemoryFNaNbNiAvmZv:
mov %rsi, %r8
// If the length is less than the number of misaligned bytes,
// write one byte at a time and exit
cmp %rax, %rcx
jg aligned_1
naligned:
mov %dl, (%r8) // Write a byte

View File

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

View File

@ -77,7 +77,7 @@ in
{
assert(&source !is &target, "Source and target must be different");
}
body
do
{
static if (is(T == struct) || isStaticArray!T)
{

View File

@ -72,7 +72,7 @@ final class StreamTransport : SocketWatcher, DuplexTransport, SocketTransport
{
assert(socket !is null);
}
body
do
{
return cast(OverlappedConnectedSocket) socket_;
}
@ -130,7 +130,7 @@ final class StreamTransport : SocketWatcher, DuplexTransport, SocketTransport
{
assert(protocol !is null);
}
body
do
{
protocol_ = protocol;
}
@ -270,7 +270,7 @@ final class IOCPLoop : Loop
{
assert(transport !is null);
}
body
do
{
transport.socket.shutdown();
defaultAllocator.dispose(transport.socket);

View File

@ -61,7 +61,7 @@ package class StreamTransport : SocketWatcher, DuplexTransport, SocketTransport
{
assert(loop !is null);
}
body
do
{
super(socket);
this.loop = loop;
@ -80,7 +80,7 @@ package class StreamTransport : SocketWatcher, DuplexTransport, SocketTransport
{
assert(socket !is null);
}
body
do
{
return cast(ConnectedSocket) socket_;
}
@ -91,7 +91,7 @@ package class StreamTransport : SocketWatcher, DuplexTransport, SocketTransport
{
assert(socket !is null);
}
body
do
{
socket_ = socket;
}
@ -120,7 +120,7 @@ package class StreamTransport : SocketWatcher, DuplexTransport, SocketTransport
{
assert(protocol !is null);
}
body
do
{
protocol_ = protocol;
}
@ -263,7 +263,7 @@ abstract class SelectorLoop : Loop
{
assert(transport !is null);
}
body
do
{
transport.socket.shutdown();
defaultAllocator.dispose(transport.socket);
@ -289,7 +289,7 @@ abstract class SelectorLoop : Loop
{
assert(transport !is null);
}
body
do
{
while (transport.input.length && transport.writeReady)
{
@ -356,7 +356,7 @@ abstract class SelectorLoop : Loop
{
assert(connection !is null);
}
body
do
{
while (true)
{

View File

@ -326,7 +326,7 @@ abstract class Loop
assert(blockTime <= 1.dur!"hours", "Too long to wait.");
assert(!blockTime.isNegative);
}
body
do
{
blockTime_ = blockTime;
}
@ -414,7 +414,7 @@ in
{
assert(loop !is null);
}
body
do
{
defaultLoop_ = loop;
}

View File

@ -72,7 +72,7 @@ abstract class SocketWatcher : Watcher
{
assert(socket !is null);
}
body
do
{
socket_ = socket;
}
@ -123,7 +123,7 @@ class ConnectionWatcher : SocketWatcher
{
assert(protocolFactory !is null, "Protocol isn't set.");
}
body
do
{
foreach (transport; incoming)
{

View File

@ -56,7 +56,7 @@ struct Range(A)
assert(begin >= container.data);
assert(end <= container.data + container.length);
}
body
do
{
this.container = &container;
this.begin = begin;
@ -87,7 +87,7 @@ struct Range(A)
{
assert(!empty);
}
body
do
{
return *this.begin;
}
@ -97,7 +97,7 @@ struct Range(A)
{
assert(!empty);
}
body
do
{
return *(this.end - 1);
}
@ -107,7 +107,7 @@ struct Range(A)
{
assert(!empty);
}
body
do
{
++this.begin;
}
@ -117,7 +117,7 @@ struct Range(A)
{
assert(!empty);
}
body
do
{
--this.end;
}
@ -127,7 +127,7 @@ struct Range(A)
{
assert(i < length);
}
body
do
{
return *(this.begin + i);
}
@ -148,7 +148,7 @@ struct Range(A)
assert(i <= j);
assert(j <= length);
}
body
do
{
return typeof(return)(*this.container, this.begin + i, this.begin + j);
}
@ -159,7 +159,7 @@ struct Range(A)
assert(i <= j);
assert(j <= length);
}
body
do
{
return typeof(return)(*this.container, this.begin + i, this.begin + j);
}
@ -333,7 +333,7 @@ struct Array(T)
{
assert(allocator !is null);
}
body
do
{
allocator_ = allocator;
}
@ -597,7 +597,7 @@ struct Array(T)
{
assert(!empty);
}
body
do
{
length = length - 1;
}
@ -619,7 +619,7 @@ struct Array(T)
{
assert(removed <= howMany);
}
body
do
{
const toRemove = min(howMany, length);
@ -662,7 +662,7 @@ struct Array(T)
assert(r.begin >= this.data);
assert(r.end <= this.data + length);
}
body
do
{
auto target = r.begin;
for (auto source = r.end; source != end; ++source, ++target)
@ -821,7 +821,7 @@ struct Array(T)
assert(r.begin >= this.data);
assert(r.end <= this.data + length);
}
body
do
{
const oldLen = length;
const offset = r.end - this.data;
@ -838,7 +838,7 @@ struct Array(T)
assert(r.begin >= this.data);
assert(r.end <= this.data + length);
}
body
do
{
return insertAfter!(T[])(r, el[]);
}
@ -852,7 +852,7 @@ struct Array(T)
assert(r.begin >= this.data);
assert(r.end <= this.data + length);
}
body
do
{
const oldLen = length;
const offset = r.end - this.data;
@ -881,7 +881,7 @@ struct Array(T)
assert(r.begin >= this.data);
assert(r.end <= this.data + length);
}
body
do
{
return insertAfter(Range(this, this.data, r.begin), el);
}
@ -894,7 +894,7 @@ struct Array(T)
assert(r.begin >= this.data);
assert(r.end <= this.data + length);
}
body
do
{
return insertBefore!(T[])(r, el[]);
}
@ -908,7 +908,7 @@ struct Array(T)
assert(r.begin >= this.data);
assert(r.end <= this.data + length);
}
body
do
{
const oldLen = length;
const offset = r.begin - this.data;
@ -1080,7 +1080,7 @@ struct Array(T)
{
assert(length > pos);
}
body
do
{
return *(this.data + pos);
}
@ -1185,7 +1185,7 @@ struct Array(T)
{
assert(!empty);
}
body
do
{
return *this.data;
}
@ -1212,7 +1212,7 @@ struct Array(T)
{
assert(!empty);
}
body
do
{
return *(this.data + length - 1);
}
@ -1245,7 +1245,7 @@ struct Array(T)
assert(i <= j);
assert(j <= length);
}
body
do
{
return typeof(return)(this, this.data + i, this.data + j);
}
@ -1257,7 +1257,7 @@ struct Array(T)
assert(i <= j);
assert(j <= length);
}
body
do
{
return typeof(return)(this, this.data + i, this.data + j);
}
@ -1328,7 +1328,7 @@ struct Array(T)
assert(i <= j);
assert(j <= length);
}
body
do
{
copy(value[], this.data[i .. j]);
return opSlice(i, j);
@ -1342,7 +1342,7 @@ struct Array(T)
assert(i <= j);
assert(j <= length);
}
body
do
{
fill(this.data[i .. j], value);
return opSlice(i, j);
@ -1356,7 +1356,7 @@ struct Array(T)
assert(j <= length);
assert(j - i == value.length);
}
body
do
{
copy(value, this.data[i .. j]);
return opSlice(i, j);

View File

@ -27,7 +27,7 @@ version (unittest)
{
assert(start < end);
}
body
do
{
auto numberRead = end - start;
for (ubyte i; i < numberRead; ++i)
@ -106,7 +106,7 @@ struct ReadBuffer(T = ubyte)
{
assert(allocator_ is null);
}
body
do
{
allocator_ = allocator;
}
@ -349,7 +349,7 @@ struct WriteBuffer(T = ubyte)
assert(size > 0);
assert(allocator !is null);
}
body
do
{
blockSize = size;
ring = size - 1;
@ -549,7 +549,7 @@ struct WriteBuffer(T = ubyte)
{
assert(length <= this.length);
}
body
do
{
auto afterRing = ring + 1;
auto oldStart = start;

View File

@ -64,7 +64,7 @@ struct SRange(L)
{
assert(!empty);
}
body
do
{
return (*this.head).content;
}
@ -74,7 +74,7 @@ struct SRange(L)
{
assert(!empty);
}
body
do
{
this.head = &(*this.head).next;
}
@ -205,7 +205,7 @@ struct SList(T)
{
assert(allocator !is null);
}
body
do
{
this.allocator_ = allocator;
}
@ -325,7 +325,7 @@ struct SList(T)
{
assert(!empty);
}
body
do
{
return this.head.content;
}
@ -467,7 +467,7 @@ struct SList(T)
{
assert(checkRangeBelonging(r));
}
body
do
{
return moveEntry(*r.head, el);
}
@ -490,7 +490,7 @@ struct SList(T)
{
assert(checkRangeBelonging(r));
}
body
do
{
size_t inserted;
foreach (e; el)
@ -519,7 +519,7 @@ struct SList(T)
{
assert(checkRangeBelonging(r));
}
body
do
{
*r.head = allocator.make!Entry(el, *r.head);
return 1;
@ -641,7 +641,7 @@ struct SList(T)
{
assert(!empty);
}
body
do
{
auto n = this.head.next;
@ -680,7 +680,7 @@ struct SList(T)
{
assert(removed <= howMany);
}
body
do
{
size_t i;
for (; i < howMany && !empty; ++i)
@ -716,7 +716,7 @@ struct SList(T)
{
assert(checkRangeBelonging(r));
}
body
do
{
auto outOfScopeList = typeof(this)(allocator);
outOfScopeList.head = *r.head;
@ -963,7 +963,7 @@ struct DRange(L)
{
assert(!empty);
}
body
do
{
return (*this.head).content;
}
@ -973,7 +973,7 @@ struct DRange(L)
{
assert(!empty);
}
body
do
{
return (*this.tail).content;
}
@ -983,7 +983,7 @@ struct DRange(L)
{
assert(!empty);
}
body
do
{
this.head = &(*this.head).next;
}
@ -993,7 +993,7 @@ struct DRange(L)
{
assert(!empty);
}
body
do
{
this.tail = &(*this.tail).prev;
}
@ -1135,7 +1135,7 @@ struct DList(T)
{
assert(allocator !is null);
}
body
do
{
this.allocator_ = allocator;
}
@ -1259,7 +1259,7 @@ struct DList(T)
{
assert(!empty);
}
body
do
{
return this.head.content;
}
@ -1272,7 +1272,7 @@ struct DList(T)
{
assert(!empty);
}
body
do
{
return this.tail.content;
}
@ -1311,17 +1311,17 @@ struct DList(T)
return 1;
}
// Creates a lsit of linked entries from a range.
// Returns count of the elements in the list.
private size_t makeList(R)(ref R el, out Entry* head, out Entry* tail) @trusted
out (retLength)
{
assert((retLength == 0 && head is null && tail is null)
|| (retLength > 0 && head !is null && tail !is null));
}
body
{
size_t retLength;
// Creates a lsit of linked entries from a range.
// Returns count of the elements in the list.
private size_t makeList(R)(ref R el, out Entry* head, out Entry* tail) @trusted
out (retLength)
{
assert((retLength == 0 && head is null && tail is null)
|| (retLength > 0 && head !is null && tail !is null));
}
do
{
size_t retLength;
if (!el.empty)
{
@ -1336,8 +1336,8 @@ struct DList(T)
tail = tail.next;
++retLength;
}
return retLength;
}
return retLength;
}
/**
* Inserts a new element at the beginning.
@ -1525,10 +1525,10 @@ struct DList(T)
{
this.head = begin;
}
else
{
else
{
this.tail.next = begin;
}
}
if (begin !is null)
{
this.tail = end;
@ -1595,7 +1595,7 @@ struct DList(T)
{
assert(checkRangeBelonging(r));
}
body
do
{
return moveFront(*r.head, el);
}
@ -1615,7 +1615,7 @@ struct DList(T)
{
assert(checkRangeBelonging(r));
}
body
do
{
auto temp = allocator.make!Entry(el, *r.head);
@ -1653,7 +1653,7 @@ struct DList(T)
{
assert(checkRangeBelonging(r));
}
body
do
{
size_t inserted;
foreach (e; el)
@ -1710,7 +1710,7 @@ struct DList(T)
{
assert(checkRangeBelonging(r));
}
body
do
{
return moveBack(*r.tail, el);
}
@ -1741,7 +1741,7 @@ struct DList(T)
{
assert(checkRangeBelonging(r));
}
body
do
{
auto temp = allocator.make!Entry(el, null, *r.tail);
@ -1779,7 +1779,7 @@ struct DList(T)
{
assert(checkRangeBelonging(r));
}
body
do
{
size_t inserted;
foreach (e; el)
@ -1896,7 +1896,7 @@ struct DList(T)
{
assert(!empty);
}
body
do
{
auto n = this.head.next;
@ -1932,7 +1932,7 @@ struct DList(T)
{
assert(!empty);
}
body
do
{
auto n = this.tail.prev;
@ -1978,7 +1978,7 @@ struct DList(T)
{
assert(removed <= howMany);
}
body
do
{
size_t i;
for (; i < howMany && !empty; ++i)
@ -2005,7 +2005,7 @@ struct DList(T)
{
assert(removed <= howMany);
}
body
do
{
size_t i;
for (; i < howMany && !empty; ++i)
@ -2041,7 +2041,7 @@ struct DList(T)
{
assert(checkRangeBelonging(r));
}
body
do
{
// Save references to the elements before and after the range.
Entry* tailNext, headPrev;

View File

@ -167,7 +167,7 @@ struct Queue(T)
{
assert(!empty);
}
body
do
{
auto n = first.next;
T ret = move(first.content);

View File

@ -76,7 +76,7 @@ struct Range(E)
assert(this.dataRange.empty
|| this.dataRange.back.status == BucketStatus.used);
}
body
do
{
do
{
@ -96,7 +96,7 @@ struct Range(E)
assert(this.dataRange.empty
|| this.dataRange.back.status == BucketStatus.used);
}
body
do
{
do
{
@ -111,7 +111,7 @@ struct Range(E)
assert(!this.dataRange.empty);
assert(this.dataRange.front.status == BucketStatus.used);
}
body
do
{
return dataRange.front.content;
}
@ -122,7 +122,7 @@ struct Range(E)
assert(!this.dataRange.empty);
assert(this.dataRange.back.status == BucketStatus.used);
}
body
do
{
return dataRange.back.content;
}
@ -180,7 +180,7 @@ struct Set(T)
{
assert(allocator !is null);
}
body
do
{
this(allocator);
rehash(n);
@ -192,7 +192,7 @@ struct Set(T)
{
assert(allocator !is null);
}
body
do
{
this.data = typeof(this.data)(allocator);
}
@ -227,7 +227,7 @@ struct Set(T)
{
assert(allocator !is null);
}
body
do
{
this.data = typeof(this.data)(init.data, allocator);
}
@ -239,7 +239,7 @@ struct Set(T)
{
assert(allocator !is null);
}
body
do
{
this.data = typeof(this.data)(move(init.data), allocator);
this.lengthIndex = init.lengthIndex;
@ -285,7 +285,7 @@ struct Set(T)
{
assert(allocator !is null);
}
body
do
{
return cast(shared Allocator) this.data.allocator;
}
@ -371,7 +371,7 @@ struct Set(T)
{
assert(buckets.length > 0);
}
body
do
{
return hash % buckets.length;
}

View File

@ -91,7 +91,7 @@ if (is(Unqual!E == char))
assert(begin >= container.data);
assert(end <= container.data + container.length);
}
body
do
{
this.container = &container;
this.begin = begin;
@ -122,7 +122,7 @@ if (is(Unqual!E == char))
{
assert(!empty);
}
body
do
{
return *this.begin;
}
@ -132,7 +132,7 @@ if (is(Unqual!E == char))
{
assert(!empty);
}
body
do
{
return *(this.end - 1);
}
@ -142,7 +142,7 @@ if (is(Unqual!E == char))
{
assert(!empty);
}
body
do
{
++this.begin;
}
@ -152,7 +152,7 @@ if (is(Unqual!E == char))
{
assert(!empty);
}
body
do
{
--this.end;
}
@ -162,7 +162,7 @@ if (is(Unqual!E == char))
{
assert(i < length);
}
body
do
{
return *(this.begin + i);
}
@ -183,7 +183,7 @@ if (is(Unqual!E == char))
assert(i <= j);
assert(j <= length);
}
body
do
{
return typeof(return)(*this.container, this.begin + i, this.begin + j);
}
@ -194,7 +194,7 @@ if (is(Unqual!E == char))
assert(i <= j);
assert(j <= length);
}
body
do
{
return typeof(return)(*this.container, this.begin + i, this.begin + j);
}
@ -233,7 +233,7 @@ if (is(Unqual!E == char))
assert(begin >= container.data);
assert(end <= container.data + container.length);
}
body
do
{
this.container = &container;
this.begin = begin;
@ -261,10 +261,11 @@ if (is(Unqual!E == char))
{
assert(chr < 0xd800 || chr > 0xdfff);
}
body
do
{
dchar chr;
ubyte units, mask;
ubyte units;
int mask;
const(char)* it = this.begin;
if (*it & 0x80)
@ -294,7 +295,7 @@ if (is(Unqual!E == char))
{
assert(!empty);
}
body
do
{
ubyte units;
if ((*begin & 0xf0) == 0xf0)
@ -437,7 +438,7 @@ struct String
{
assert(allocator !is null);
}
body
do
{
this.allocator_ = allocator;
}
@ -527,7 +528,7 @@ struct String
assert(capacity - length >= 4);
assert(src - 0x10000 < 0x100000);
}
body
do
{
auto dst = this.data + length;
@ -545,7 +546,7 @@ struct String
{
assert(capacity - length >= 3);
}
body
do
{
auto dst = this.data + length;
if (chr < 0x80)
@ -923,7 +924,7 @@ struct String
assert(j <= length);
assert(j - i == value.length);
}
body
do
{
auto target = opSlice(i, j);
copy(value, target);
@ -940,7 +941,7 @@ struct String
assert(i <= j);
assert(j <= length);
}
body
do
{
copy(value[], this.data[i .. j]);
return opSlice(i, j);
@ -956,7 +957,7 @@ struct String
assert(i <= j);
assert(j <= length);
}
body
do
{
for (auto p = this.data + i; p < this.data + j; ++p)
{
@ -1037,7 +1038,7 @@ struct String
{
assert(length > pos);
}
body
do
{
return *(this.data + pos);
}
@ -1187,7 +1188,7 @@ struct String
assert(i <= j);
assert(j <= length);
}
body
do
{
return typeof(return)(this, this.data + i, this.data + j);
}
@ -1200,7 +1201,7 @@ struct String
assert(i <= j);
assert(j <= length);
}
body
do
{
return typeof(return)(this, this.data + i, this.data + j);
}
@ -1508,7 +1509,7 @@ struct String
assert(r.begin >= this.data);
assert(r.end <= this.data + length);
}
body
do
{
auto end = this.data + this.length;
copy(ByCodeUnit!char(this, r.end, end), ByCodeUnit!char(this, r.begin, end));
@ -1561,7 +1562,7 @@ struct String
assert(r.begin >= this.data);
assert(r.end <= this.data + length);
}
body
do
{
auto oldLen = this.data + length;
const inserted = insertBack(el);
@ -1594,7 +1595,7 @@ struct String
assert(r.begin >= this.data);
assert(r.end <= this.data + length);
}
body
do
{
return insertAfter(R(this, this.data, r.begin), el);
}

View File

@ -66,7 +66,7 @@ out (result)
{
assert(memory.ptr is (() @trusted => cast(void*) result)());
}
body
do
{
copy(typeid(T).initializer, memory);
@ -91,7 +91,8 @@ in
out (result)
{
assert(memory.ptr is (() @trusted => cast(void*) result)());
}body
}
do
{
copy(typeid(T).initializer, memory);
@ -144,7 +145,7 @@ out (result)
{
assert(memory.ptr is result);
}
body
do
{
auto result = (() @trusted => cast(T*) memory.ptr)();
static if (Args.length == 1)
@ -169,7 +170,7 @@ out (result)
{
assert(memory.ptr is result);
}
body
do
{
auto result = (() @trusted => cast(T*) memory.ptr)();
static if (!hasElaborateAssign!T && isAssignable!T)

View File

@ -16,7 +16,6 @@ module tanya.format;
import tanya.container.string;
import tanya.encoding.ascii;
public import tanya.format.conv;
import tanya.math;
import tanya.memory.op;
import tanya.meta.metafunction;
@ -323,9 +322,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,86 +504,120 @@ 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;
char[512] buffer; // Big enough for e+308 or e-307.
char[8] tail = 0;
char[] bufferSlice = buffer[64 .. $];
uint precision = 6;
bool negative;
int decimalPoint;
static if (is(Unqual!(Args[0]) == typeof(null)))
// Read the double into a string.
auto realString = real2String(arg, buffer, decimalPoint, negative);
auto length = cast(uint) realString.length;
// Clamp the precision and delete extra zeros after clamp.
uint n = precision;
if (length > precision)
{
result.insertBack("null");
length = precision;
}
else static if(is(Unqual!(Args[0]) == bool))
while ((length > 1) && (precision != 0) && (realString[length - 1] == '0'))
{
result.insertBack(args[0] ? "true" : "false");
--precision;
--length;
}
else static if (isSomeString!(Args[0])) // String
if (negative)
{
if (args[0] is null)
result.insertBack('-');
}
if (decimalPoint == special)
{
result.insertBack(realString);
return;
}
// Should we use sceintific notation?
if ((decimalPoint <= -4) || (decimalPoint > cast(int) n))
{
if (precision > length)
{
result.insertBack("null");
precision = length - 1;
}
else if (precision > 0)
{
// When using scientific notation, there is one digit before the
// decimal.
--precision;
}
// Handle leading chars.
bufferSlice.front = realString[0];
bufferSlice.popFront();
if (precision != 0)
{
bufferSlice.front = period;
bufferSlice.popFront();
}
// Handle after decimal.
if ((length - 1) > precision)
{
length = precision + 1;
}
realString[1 .. length].copy(bufferSlice);
bufferSlice.popFrontExactly(length - 1);
// Dump the exponent.
tail[1] = 'e';
--decimalPoint;
if (decimalPoint < 0)
{
tail[2] = '-';
decimalPoint = -decimalPoint;
}
else
{
result.insertBack(args[0]);
tail[2] = '+';
}
n = decimalPoint >= 100 ? 5 : 4;
tail[0] = cast(char) n;
while (true)
{
tail[n] = '0' + decimalPoint % 10;
if (n <= 3)
{
break;
}
--n;
decimalPoint /= 10;
}
}
else static if (isSomeChar!(Args[0])) // Char
else
{
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 .. $];
uint precision = 6;
bool negative;
int decimalPoint;
// Read the double into a string.
auto realString = real2String(args[0], buffer, decimalPoint, negative);
auto length = cast(uint) realString.length;
// Clamp the precision and delete extra zeros after clamp.
uint n = precision;
if (length > precision)
if (decimalPoint > 0)
{
length = precision;
precision = decimalPoint < (cast(int) length)
? length - decimalPoint
: 0;
}
while ((length > 1)
&& (precision != 0)
&& (realString[length - 1] == '0'))
else
{
--precision;
--length;
precision = -decimalPoint
+ (precision > length ? length : precision);
}
if (negative)
// Handle the three decimal varieties.
if (decimalPoint <= 0)
{
result.insertBack('-');
}
if (decimalPoint == special)
{
result.insertBack(realString);
goto ParamEnd;
}
// Should we use sceintific notation?
if ((decimalPoint <= -4) || (decimalPoint > cast(int) n))
{
if (precision > length)
{
precision = length - 1;
}
else if (precision > 0)
{
// When using scientific notation, there is one digit before the
// decimal.
--precision;
}
// Handle leading chars.
bufferSlice.front = realString[0];
// Handle 0.000*000xxxx.
bufferSlice.front = '0';
bufferSlice.popFront();
if (precision != 0)
@ -592,143 +625,205 @@ package(tanya) String format(string fmt, Args...)(auto ref Args args)
bufferSlice.front = period;
bufferSlice.popFront();
}
// Handle after decimal.
if ((length - 1) > precision)
n = -decimalPoint;
if (n > precision)
{
length = precision + 1;
}
realString[1 .. length].copy(bufferSlice);
bufferSlice.popFrontExactly(length - 1);
// Dump the exponent.
tail[1] = 'e';
--decimalPoint;
if (decimalPoint < 0)
{
tail[2] = '-';
decimalPoint = -decimalPoint;
}
else
{
tail[2] = '+';
n = precision;
}
n = decimalPoint >= 100 ? 5 : 4;
fill!'0'(bufferSlice[0 .. n]);
bufferSlice.popFrontExactly(n);
tail[0] = cast(char) n;
while (true)
if ((length + n) > precision)
{
tail[n] = '0' + decimalPoint % 10;
if (n <= 3)
{
break;
}
--n;
decimalPoint /= 10;
length = precision - n;
}
realString[0 .. length].copy(bufferSlice);
bufferSlice.popFrontExactly(length);
}
else if (cast(uint) decimalPoint >= length)
{
// Handle xxxx000*000.0.
n = 0;
do
{
bufferSlice.front = realString[n];
bufferSlice.popFront();
++n;
}
while (n < length);
if (n < cast(uint) decimalPoint)
{
n = decimalPoint - n;
fill!'0'(bufferSlice[0 .. n]);
bufferSlice.popFrontExactly(n);
}
if (precision != 0)
{
bufferSlice.front = period;
bufferSlice.popFront();
}
}
else
{
if (decimalPoint > 0)
// Handle xxxxx.xxxx000*000.
n = 0;
do
{
precision = decimalPoint < (cast(int) length)
? length - decimalPoint
: 0;
}
else
{
precision = -decimalPoint
+ (precision > length ? length : precision);
}
// Handle the three decimal varieties.
if (decimalPoint <= 0)
{
// Handle 0.000*000xxxx.
bufferSlice.front = '0';
bufferSlice.front = realString[n];
bufferSlice.popFront();
if (precision != 0)
{
bufferSlice.front = period;
bufferSlice.popFront();
}
n = -decimalPoint;
if (n > precision)
{
n = precision;
}
fill!'0'(bufferSlice[0 .. n]);
bufferSlice.popFrontExactly(n);
if ((length + n) > precision)
{
length = precision - n;
}
realString[0 .. length].copy(bufferSlice);
bufferSlice.popFrontExactly(length);
++n;
}
else if (cast(uint) decimalPoint >= length)
{
// Handle xxxx000*000.0.
n = 0;
do
{
bufferSlice.front = realString[n];
bufferSlice.popFront();
++n;
}
while (n < length);
if (n < cast(uint) decimalPoint)
{
n = decimalPoint - n;
while (n < cast(uint) decimalPoint);
fill!'0'(bufferSlice[0 .. n]);
bufferSlice.popFrontExactly(n);
}
if (precision != 0)
{
bufferSlice.front = period;
bufferSlice.popFront();
}
if (precision > 0)
{
bufferSlice.front = period;
bufferSlice.popFront();
}
else
if ((length - decimalPoint) > precision)
{
// Handle xxxxx.xxxx000*000.
n = 0;
do
{
bufferSlice.front = realString[n];
bufferSlice.popFront();
++n;
}
while (n < cast(uint) decimalPoint);
length = precision + decimalPoint;
}
if (precision > 0)
{
bufferSlice.front = period;
bufferSlice.popFront();
}
if ((length - decimalPoint) > precision)
{
length = precision + decimalPoint;
}
realString[n .. length].copy(bufferSlice);
bufferSlice.popFrontExactly(length - n);
}
}
realString[n .. length].copy(bufferSlice);
bufferSlice.popFrontExactly(length - n);
// Get the length that we've copied.
length = cast(uint) (buffer.length - bufferSlice.length);
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
{
enum bool pred = !isSomeFunction!(__traits(getMember, arg, f));
}
}
alias fields = Filter!(pred, __traits(allMembers, T));
result.insertBack(T.stringof);
result.insertBack('(');
static if (fields.length > 0)
{
printToString!"{}"(result, __traits(getMember, arg, fields[0]));
foreach (field; fields[1 .. $])
{
result.insertBack(", ");
printToString!"{}"(result, __traits(getMember, arg, field));
}
}
result.insertBack(')');
}
private void formatRange(T)(ref T arg, ref String result)
if (isInputRange!T && !isInfinite!T)
{
result.insertBack('[');
if (!arg.empty)
{
printToString!"{}"(result, arg.front);
arg.popFront();
}
foreach (e; arg)
{
result.insertBack(", ");
printToString!"{}"(result, e);
}
result.insertBack(']');
}
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 (is(Arg == enum)) // Enum
{
foreach (m; __traits(allMembers, Arg))
{
if (args[0] == __traits(getMember, Arg, m))
{
result.insertBack(m);
}
}
// Get the length that we've copied.
length = cast(uint) (buffer.length - bufferSlice.length);
result.insertBack(buffer[64 .. length]); // Number.
result.insertBack(tail[1 .. tail[0] + 1]); // Tail.
}
else static if (isPointer!(Args[0])) // Pointer
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 (isInputRange!Arg && !isInfinite!Arg)
{
formatRange(args[0], result);
}
else static if (is(Unqual!(typeof(args[0].stringify())) == String))
{
static if (is(Arg == class) || is(Arg == interface))
{
if (args[0] is null)
{
result.insertBack("null");
}
else
{
result.insertBack(args[0].stringify()[]);
}
}
else
{
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))
{
formatStruct(args[0], result);
}
else static if (is(Arg == union))
{
result.insertBack(Arg.stringof);
}
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 +839,40 @@ 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);
}
// Enum.
@nogc nothrow pure @safe unittest
{
enum E1 : int
{
one,
two,
}
assert(format!"{}"(E1.one) == "one");
const E1 e1;
assert(format!"{}"(e1) == "one");
}
// One argument tests.
@nogc pure @safe unittest
{
@ -772,7 +887,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 +941,145 @@ 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");
class B
{
String stringify() @nogc nothrow pure @safe
{
return String("Class B");
}
}
assert(format!"{}"(cast(B) null) == "null");
}
// Unions.
unittest
{
union U
{
int i;
char c;
}
assert(format!"{}"(U(2)) == "U");
}
// Ranges.
@nogc pure @safe unittest
{
static struct Stringish
{
private 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");
static struct Intish
{
private int front_ = 3;
int front() const @nogc nothrow pure @safe
{
return this.front_;
}
void popFront() @nogc nothrow pure @safe
{
--this.front_;
}
bool empty() const @nogc nothrow pure @safe
{
return this.front == 0;
}
}
assert(format!"{}"(Intish()) == "[3, 2, 1]");
}
// Typeid.
nothrow pure @safe unittest
{
assert(format!"{}"(typeid(int[])) == "int[]");
class C
{
}
assert(format!"{}"(typeid(C)) == typeid(C).toString());
}
private struct FormatSpec
{
}

View File

@ -1,293 +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/. */
/**
* This module provides functions for converting between different types.
*
* Copyright: Eugene Wissner 2017.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).
* Authors: Jeff Roberts, $(LINK2 mailto:info@caraus.de, Eugene Wissner)
* Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/format/conv.d,
* tanya/format/conv.d)
*/
module tanya.format.conv;
import tanya.container.string;
import tanya.memory;
import tanya.memory.op;
import tanya.meta.trait;
import tanya.meta.transform;
version (unittest)
{
import tanya.test.assertion;
}
/**
* Thrown if a type conversion fails.
*/
final class ConvException : Exception
{
/**
* Params:
* msg = The message for the exception.
* file = The file where the exception occurred.
* line = The line number where the exception occurred.
* next = The previous exception in the chain of exceptions, if any.
*/
this(string msg,
string file = __FILE__,
size_t line = __LINE__,
Throwable next = null) @nogc @safe pure nothrow
{
super(msg, file, line, next);
}
}
/**
* If the source type $(D_PARAM From) and the target type $(D_PARAM To) are
* equal, does nothing. If $(D_PARAM From) can be implicitly converted to
* $(D_PARAM To), just returns $(D_PARAM from).
*
* Params:
* To = Target type.
*
* Returns: $(D_PARAM from).
*/
deprecated("Use tanya.conv.to instead")
template to(To)
{
/**
* Params:
* From = Source type.
* from = Source value.
*/
ref To to(From)(ref From from)
if (is(To == From))
{
return from;
}
/// ditto
To to(From)(From from)
if (is(Unqual!To == Unqual!From) || (isNumeric!From && isFloatingPoint!To))
{
return from;
}
}
/**
* Performs checked conversion from an integral type $(D_PARAM From) to an
* integral type $(D_PARAM To).
*
* Params:
* From = Source type.
* To = Target type.
* from = Source value.
*
* Returns: $(D_PARAM from) converted to $(D_PARAM To).
*
* Throws: $(D_PSYMBOL ConvException) if $(D_PARAM from) is too small or too
* large to be represented by $(D_PARAM To).
*/
deprecated("Use tanya.conv.to instead")
To to(To, From)(From from)
if (isIntegral!From
&& isIntegral!To
&& !is(Unqual!To == Unqual!From)
&& !is(To == enum))
{
static if ((isUnsigned!From && isSigned!To && From.sizeof == To.sizeof)
|| From.sizeof > To.sizeof)
{
if (from > To.max)
{
throw make!ConvException(defaultAllocator,
"Positive integer overflow");
}
}
static if (isSigned!From)
{
static if (isUnsigned!To)
{
if (from < 0)
{
throw make!ConvException(defaultAllocator,
"Negative integer overflow");
}
}
else static if (From.sizeof > To.sizeof)
{
if (from < To.min)
{
throw make!ConvException(defaultAllocator,
"Negative integer overflow");
}
}
}
static if (From.sizeof <= To.sizeof)
{
return from;
}
else static if (isSigned!To)
{
return cast(To) from;
}
else
{
return from & To.max;
}
}
/**
* Converts $(D_PARAM from) to a boolean.
*
* If $(D_PARAM From) is a numeric type, then `1` becomes $(D_KEYWORD true),
* `0` $(D_KEYWORD false). Otherwise $(D_PSYMBOL ConvException) is thrown.
*
* If $(D_PARAM To) is a string (built-in string or $(D_PSYMBOL String)),
* then `"true"` or `"false"` are converted to the appropriate boolean value.
* Otherwise $(D_PSYMBOL ConvException) is thrown.
*
* Params:
* From = Source type.
* To = Target type.
* from = Source value.
*
* Returns: $(D_KEYWORD from) converted to a boolean.
*
* Throws: $(D_PSYMBOL ConvException) if $(D_PARAM from) isn't convertible.
*/
deprecated("Use tanya.conv.to instead")
To to(To, From)(From from)
if (isNumeric!From && is(Unqual!To == bool) && !is(Unqual!To == Unqual!From))
{
if (from == 0)
{
return false;
}
else if (from < 0)
{
throw make!ConvException(defaultAllocator,
"Negative number overflow");
}
else if (from <= 1)
{
return true;
}
throw make!ConvException(defaultAllocator,
"Positive number overflow");
}
/// ditto
deprecated("Use tanya.conv.to instead")
To to(To, From)(auto ref const From from)
if ((is(From == String) || isSomeString!From) && is(Unqual!To == bool))
{
if (from == "true")
{
return true;
}
else if (from == "false")
{
return false;
}
throw make!ConvException(defaultAllocator,
"String doesn't contain a boolean value");
}
/**
* Converts a boolean to $(D_PARAM To).
*
* If $(D_PARAM To) is a numeric type, then $(D_KEYWORD true) becomes `1`,
* $(D_KEYWORD false) `0`.
*
* If $(D_PARAM To) is a $(D_PSYMBOL String), then `"true"` or `"false"`
* is returned.
*
* Params:
* From = Source type.
* To = Target type.
* from = Source value.
*
* Returns: $(D_PARAM from) converted to $(D_PARAM To).
*/
deprecated("Use tanya.conv.to instead")
To to(To, From)(const From from)
if (is(Unqual!From == bool) && isNumeric!To && !is(Unqual!To == Unqual!From))
{
return from;
}
/// ditto
deprecated("Use tanya.conv.to instead")
To to(To, From)(const From from)
if (is(Unqual!From == bool) && is(Unqual!To == String))
{
return String(from ? "true" : "false");
}
/**
* Converts a floating point number to an integral type.
*
* Params:
* From = Source type.
* To = Target type.
* from = Source value.
*
* Returns: Truncated $(D_PARAM from) (everything after the decimal point is
* dropped).
*
* Throws: $(D_PSYMBOL ConvException) if
* $(D_INLINECODE from < To.min || from > To.max).
*/
deprecated("Use tanya.conv.to instead")
To to(To, From)(From from)
if (isFloatingPoint!From
&& isIntegral!To
&& !is(Unqual!To == Unqual!From)
&& !is(To == enum))
{
if (from > To.max)
{
throw make!ConvException(defaultAllocator,
"Positive number overflow");
}
else if (from < To.min)
{
throw make!ConvException(defaultAllocator,
"Negative number overflow");
}
return cast(To) from;
}
/**
* Performs checked conversion from an integral type $(D_PARAM From) to an
* $(D_KEYWORD enum).
*
* Params:
* From = Source type.
* To = Target type.
* from = Source value.
*
* Returns: $(D_KEYWORD enum) value.
*
* Throws: $(D_PSYMBOL ConvException) if $(D_PARAM from) is not a member of
* $(D_PSYMBOL To).
*/
deprecated("Use tanya.conv.to instead")
To to(To, From)(From from)
if (isIntegral!From && is(To == enum))
{
foreach (m; EnumMembers!To)
{
if (from == m)
{
return m;
}
}
throw make!ConvException(defaultAllocator,
"Value not found in enum '" ~ To.stringof ~ "'");
}

View File

@ -112,7 +112,7 @@ struct Integer
{
assert(allocator !is null);
}
body
do
{
this.allocator_ = allocator;
}
@ -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;
}
///
@ -871,7 +873,7 @@ struct Integer
{
assert(operand.length > 0, "Division by zero.");
}
body
do
{
divide(operand, this);
return this;
@ -883,7 +885,7 @@ struct Integer
{
assert(operand.length > 0, "Division by zero.");
}
body
do
{
divide(operand, null, this);
return this;
@ -1072,7 +1074,7 @@ struct Integer
assert(h1 == 79);
h2 = ~h1;
assert(h2 == ~cast(ubyte) 79);
assert(h2 == cast(ubyte) ~79);
}
/// ditto
@ -1166,7 +1168,7 @@ struct Integer
{
assert(operand.length > 0, "Division by zero.");
}
body
do
{
mixin("return Integer(this, allocator) " ~ op ~ "= operand;");
}
@ -1285,7 +1287,7 @@ struct Integer
{
assert(divisor != 0, "Division by zero.");
}
body
do
{
if (compare(divisor) < 0)
{
@ -1470,7 +1472,7 @@ struct Integer
{
assert(array.length == length);
}
body
do
{
Array!ubyte array;

View File

@ -586,7 +586,7 @@ in
{
assert(z > 0, "Division by zero.");
}
body
do
{
G mask = G.max / 2 + 1;
H result;
@ -627,7 +627,7 @@ in
{
assert(z.length > 0, "Division by zero.");
}
body
do
{
size_t i;
auto tmp1 = Integer(x, x.allocator);

View File

@ -134,7 +134,7 @@ version (linux)
{
assert(length <= maxGather);
}
body
do
{
// int getrandom(void *buf, size_t buflen, unsigned int flags);
auto length = syscall(318, output.ptr, output.length, 0);
@ -198,7 +198,7 @@ class Entropy
assert(maxSources > 0 && maxSources <= ubyte.max);
assert(allocator !is null);
}
body
do
{
allocator.resize(sources, maxSources);
@ -234,7 +234,7 @@ class Entropy
{
assert(sourceCount_ <= sources.length);
}
body
do
{
sources[sourceCount_++] = source;
return this;
@ -251,7 +251,7 @@ class Entropy
{
assert(sourceCount_ > 0, "No entropy sources defined.");
}
body
do
{
bool haveStrong;
ushort done;

View File

@ -32,6 +32,16 @@ else
import core.stdc.string;
}
version (TanyaNative)
{
@nogc nothrow pure @system unittest
{
ubyte[2] buffer = 1;
fillMemory(buffer[1 .. $], 0);
assert(buffer[0] == 1 && buffer[1] == 0);
}
}
private enum alignMask = size_t.sizeof - 1;
/**
@ -58,7 +68,7 @@ in
assert(source.length == 0 || source.ptr !is null);
assert(target.length == 0 || target.ptr !is null);
}
body
do
{
version (TanyaNative)
{
@ -126,7 +136,7 @@ in
{
assert(memory.length == 0 || memory.ptr !is null);
}
body
do
{
version (TanyaNative)
{
@ -149,31 +159,6 @@ body
}
}
// Stress test. Checks that `fill` can handle unaligned pointers and different
// lengths.
@nogc nothrow pure @safe unittest
{
ubyte[192] memory;
foreach (j; 0 .. 192)
{
foreach (ubyte i, ref ubyte v; memory[j .. $])
{
v = i;
}
fill(memory[j .. $]);
foreach (ubyte v; memory[j .. $])
{
assert(v == 0);
}
fill!1(memory[j .. $]);
foreach (ubyte v; memory[j .. $])
{
assert(v == 1);
}
}
}
/**
* Copies starting from the end of $(D_PARAM source) into the end of
* $(D_PARAM target).
@ -203,7 +188,7 @@ in
assert(source.length == 0 || source.ptr !is null);
assert(target.length == 0 || target.ptr !is null);
}
body
do
{
version (TanyaNative)
{
@ -257,7 +242,7 @@ in
assert(r1.length == 0 || r1.ptr !is null);
assert(r2.length == 0 || r2.ptr !is null);
}
body
do
{
version (TanyaNative)
{
@ -321,7 +306,7 @@ in
{
assert(haystack.length == 0 || haystack.ptr !is null);
}
body
do
{
auto length = haystack.length;
const size_t needleWord = size_t.max * needle;

View File

@ -45,7 +45,7 @@ mixin template DefaultAllocator()
{
assert(allocator !is null);
}
body
do
{
this.allocator_ = allocator;
}
@ -63,7 +63,7 @@ mixin template DefaultAllocator()
{
assert(allocator !is null);
}
body
do
{
if (allocator_ is null)
{
@ -78,7 +78,7 @@ mixin template DefaultAllocator()
{
assert(allocator !is null);
}
body
do
{
if (allocator_ is null)
{
@ -114,7 +114,7 @@ out (allocator)
{
assert(allocator !is null);
}
body
do
{
return (cast(GetPureInstance!Allocator) &getAllocatorInstance)();
}
@ -132,7 +132,7 @@ in
{
assert(allocator !is null);
}
body
do
{
.allocator = allocator;
}
@ -403,7 +403,7 @@ in
{
assert(allocator !is null);
}
body
do
{
auto mem = (() @trusted => allocator.allocate(stateSize!T))();
if (mem is null)
@ -442,7 +442,7 @@ in
{
assert(allocator !is null);
}
body
do
{
auto mem = (() @trusted => allocator.allocate(stateSize!T))();
if (mem is null)
@ -484,7 +484,7 @@ in
assert(allocator !is null);
assert(n <= size_t.max / ElementType!T.sizeof);
}
body
do
{
auto ret = allocator.resize!(ElementType!T)(null, n);
ret.uninitializedFill(ElementType!T.init);

View File

@ -54,7 +54,7 @@ private final class RefCountedStore(T)
{
assert(this.counter > 0);
}
body
do
{
mixin("return " ~ op ~ "counter;");
}
@ -139,7 +139,7 @@ struct RefCounted(T)
{
assert(allocator !is null);
}
body
do
{
this.allocator_ = allocator;
}
@ -247,7 +247,7 @@ struct RefCounted(T)
{
assert(count > 0, "Attempted to access an uninitialized reference");
}
body
do
{
return this.storage.payload;
}
@ -501,7 +501,7 @@ in
{
assert(allocator !is null);
}
body
do
{
auto rc = typeof(return)(allocator);
@ -546,7 +546,7 @@ in
assert(allocator !is null);
assert(size <= size_t.max / ElementType!T.sizeof);
}
body
do
{
return RefCounted!T(allocator.make!T(size), allocator);
}
@ -664,7 +664,7 @@ struct Unique(T)
{
assert(allocator !is null);
}
body
do
{
this.allocator_ = allocator;
}
@ -849,7 +849,7 @@ in
{
assert(allocator !is null);
}
body
do
{
auto payload = allocator.make!(T, A)(args);
return Unique!T(payload, allocator);
@ -877,7 +877,7 @@ in
assert(allocator !is null);
assert(size <= size_t.max / ElementType!T.sizeof);
}
body
do
{
auto payload = allocator.resize!(ElementType!T)(null, size);
return Unique!T(payload, allocator);

View File

@ -275,15 +275,50 @@ 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);
/**
* Tests whether $(D_PARAM T) is a enum.
*
* Params:
* T = A type.
*
* Returns: $(D_KEYWORD true) if $(D_PARAM T) is an enum,
* $(D_KEYWORD false) otherwise.
*/
enum bool isEnum(T) = is(T == enum);
/**
* Determines whether $(D_PARAM T) is a polymorphic type, i.e. a
* $(D_KEYWORD class) or an $(D_KEYWORD interface).

View File

@ -77,7 +77,7 @@ struct NetworkOrder(uint L)
{
assert(value <= pow(2, L * 8) - 1);
}
body
do
{
this.value = value & StorageType.max;
}
@ -92,7 +92,7 @@ struct NetworkOrder(uint L)
{
assert(this.length > 0);
}
body
do
{
return this.value & 0xff;
}
@ -107,7 +107,7 @@ struct NetworkOrder(uint L)
{
assert(this.length > 0);
}
body
do
{
return (this.value >> ((this.length - 1) * 8)) & 0xff;
}
@ -122,7 +122,7 @@ struct NetworkOrder(uint L)
{
assert(this.length > 0);
}
body
do
{
this.value >>= 8;
--this.size;
@ -138,7 +138,7 @@ struct NetworkOrder(uint L)
{
assert(this.length > 0);
}
body
do
{
this.value &= StorageType.max >> ((StorageType.sizeof - this.length) * 8);
--this.size;

View File

@ -185,7 +185,7 @@ else version (Windows)
{
assert(count >= 0);
}
body
do
{
DWORD lpNumber;
BOOL result = GetOverlappedResult(overlapped.handle,
@ -259,7 +259,7 @@ else version (Windows)
{
assert(count >= 0);
}
body
do
{
DWORD lpNumber;
BOOL result = GetOverlappedResult(overlapped.handle,
@ -720,7 +720,7 @@ abstract class Socket
assert(handle != SocketType.init);
assert(handle_ == SocketType.init, "Socket handle cannot be changed");
}
body
do
{
handle_ = handle;
@ -749,7 +749,7 @@ abstract class Socket
{
assert(handle != SocketType.init);
}
body
do
{
scope (failure)
{

View File

@ -59,7 +59,7 @@ in
{
assert(array.length > 0);
}
body
do
{
return array[0];
}
@ -99,7 +99,7 @@ in
{
assert(array.length > 0);
}
body
do
{
return array[$ - 1];
}
@ -138,7 +138,7 @@ in
{
assert(array.length > 0);
}
body
do
{
array = array[1 .. $];
}
@ -149,7 +149,7 @@ in
{
assert(array.length > 0);
}
body
do
{
array = array[0 .. $ - 1];
}

View File

@ -1053,7 +1053,7 @@ in
assert(count <= range.length);
}
}
body
do
{
static if (hasSlicing!R)
{
@ -1112,7 +1112,7 @@ in
assert(count <= range.length);
}
}
body
do
{
static if (hasSlicing!R)
{