Compare commits
40 Commits
Author | SHA1 | Date | |
---|---|---|---|
c1864cf473 | |||
8db1851c5c | |||
12de700706 | |||
78a8afdf75 | |||
3c996d7c57 | |||
2a68048fc1 | |||
907f7a4e61 | |||
670328c047 | |||
7fe69ccc5c | |||
26c3532e28 | |||
75ce854192 | |||
9e16d84f9e | |||
7e7bf40f70 | |||
642717883e | |||
85be35c5e0 | |||
664298f038 | |||
c199cdd47c | |||
3a24e9e462 | |||
f334e6a1a0 | |||
72d5760589 | |||
b28dde9d8e | |||
b612e978bf | |||
02d1d8218b | |||
fbf6ec5250 | |||
ac317aa9d6 | |||
10022d158c | |||
a38242d0ac | |||
a84c71f26d | |||
7797f0a1fe | |||
4bbc8b510a | |||
87ea1f98dc | |||
9422888b6c | |||
13407fcf8a | |||
e06cc5a071 | |||
12fb9ff9f6 | |||
392cdcf192 | |||
09b6655b9a | |||
7a2768340e | |||
414d7a11a8 | |||
0d69c7fc79 |
@ -7,9 +7,9 @@ os:
|
|||||||
language: d
|
language: d
|
||||||
|
|
||||||
d:
|
d:
|
||||||
|
- dmd-2.078.0
|
||||||
|
- dmd-2.077.1
|
||||||
- dmd-2.076.1
|
- dmd-2.076.1
|
||||||
- dmd-2.075.1
|
|
||||||
- dmd-2.074.1
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
matrix:
|
matrix:
|
||||||
@ -22,7 +22,7 @@ addons:
|
|||||||
- gcc-multilib
|
- gcc-multilib
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- if [ "$PS1" = '(dmd-2.076.1)' ]; then
|
- if [ "$PS1" = '(dmd-2.078.0)' ]; then
|
||||||
export UNITTEST="unittest-cov";
|
export UNITTEST="unittest-cov";
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
17
README.md
17
README.md
@ -12,10 +12,9 @@ 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
|
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
|
guarantee with @nogc attribute that there are no hidden allocations on the
|
||||||
Garbage Collector heap. Everything in the library is usable in @nogc code.
|
Garbage Collector heap. Everything in the library is usable in @nogc code.
|
||||||
Tanya extends Phobos functionality and provides alternative implementations for
|
Tanya provides data structures and utilities to facilitate painless systems
|
||||||
data structures and utilities that depend on the Garbage Collector in Phobos.
|
programming in D.
|
||||||
|
|
||||||
* [Bug tracker](https://issues.caraus.io/projects/tanya/issues)
|
|
||||||
* [API Documentation](https://docs.caraus.io/tanya)
|
* [API Documentation](https://docs.caraus.io/tanya)
|
||||||
* [Contribution guidelines](CONTRIBUTING.md)
|
* [Contribution guidelines](CONTRIBUTING.md)
|
||||||
|
|
||||||
@ -24,6 +23,7 @@ data structures and utilities that depend on the Garbage Collector in Phobos.
|
|||||||
|
|
||||||
Tanya consists of the following packages and (top-level) modules:
|
Tanya consists of the following packages and (top-level) modules:
|
||||||
|
|
||||||
|
* `algorithm`: Collection of generic algorithms.
|
||||||
* `async`: Event loop (epoll, kqueue and IOCP).
|
* `async`: Event loop (epoll, kqueue and IOCP).
|
||||||
* `container`: Queue, Array, Singly and doubly linked lists, Buffers, UTF-8
|
* `container`: Queue, Array, Singly and doubly linked lists, Buffers, UTF-8
|
||||||
string, Hash set.
|
string, Hash set.
|
||||||
@ -149,9 +149,9 @@ There are more containers in the `tanya.container` package.
|
|||||||
|
|
||||||
| DMD | GCC |
|
| DMD | GCC |
|
||||||
|:-------:|:--------------:|
|
|:-------:|:--------------:|
|
||||||
| 2.076.1 | *gdc-5* branch |
|
| 2.078.0 | *gdc-5* branch |
|
||||||
| 2.075.1 | |
|
| 2.077.1 | |
|
||||||
| 2.074.1 | |
|
| 2.076.1 | |
|
||||||
|
|
||||||
### Current status
|
### 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) |
|
| 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) |
|
| 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
|
### Release management
|
||||||
|
|
||||||
3-week release cycle.
|
Deprecated features are removed after one release that includes these deprecations.
|
||||||
|
|
||||||
Deprecated features are removed after one release (in approximately 6 weeks after deprecating).
|
|
||||||
|
|
||||||
## Further characteristics
|
## Further characteristics
|
||||||
|
|
||||||
|
24
appveyor.yml
24
appveyor.yml
@ -3,24 +3,24 @@ os: Visual Studio 2015
|
|||||||
|
|
||||||
environment:
|
environment:
|
||||||
matrix:
|
matrix:
|
||||||
|
- DC: dmd
|
||||||
|
DVersion: 2.078.0
|
||||||
|
arch: x64
|
||||||
|
- DC: dmd
|
||||||
|
DVersion: 2.078.0
|
||||||
|
arch: x86
|
||||||
|
- DC: dmd
|
||||||
|
DVersion: 2.077.1
|
||||||
|
arch: x64
|
||||||
|
- DC: dmd
|
||||||
|
DVersion: 2.077.1
|
||||||
|
arch: x86
|
||||||
- DC: dmd
|
- DC: dmd
|
||||||
DVersion: 2.076.1
|
DVersion: 2.076.1
|
||||||
arch: x64
|
arch: x64
|
||||||
- DC: dmd
|
- DC: dmd
|
||||||
DVersion: 2.076.1
|
DVersion: 2.076.1
|
||||||
arch: x86
|
arch: x86
|
||||||
- DC: dmd
|
|
||||||
DVersion: 2.075.1
|
|
||||||
arch: x64
|
|
||||||
- DC: dmd
|
|
||||||
DVersion: 2.075.1
|
|
||||||
arch: x86
|
|
||||||
- DC: dmd
|
|
||||||
DVersion: 2.074.1
|
|
||||||
arch: x64
|
|
||||||
- DC: dmd
|
|
||||||
DVersion: 2.074.1
|
|
||||||
arch: x86
|
|
||||||
|
|
||||||
skip_tags: true
|
skip_tags: true
|
||||||
|
|
||||||
|
7
dub.json
7
dub.json
@ -12,7 +12,12 @@
|
|||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "library",
|
"name": "library",
|
||||||
"targetType": "library",
|
"targetType": "staticLibrary",
|
||||||
|
"versions": ["TanyaPhobos"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dynamic",
|
||||||
|
"targetType": "dynamicLibrary",
|
||||||
"versions": ["TanyaPhobos"]
|
"versions": ["TanyaPhobos"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
275
source/tanya/algorithm/mutation.d
Normal file
275
source/tanya/algorithm/mutation.d
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Algorithms that modify its arguments.
|
||||||
|
*
|
||||||
|
* Copyright: Eugene Wissner 2017.
|
||||||
|
* 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/algorithm/mutation.d,
|
||||||
|
* tanya/algorithm/mutation.d)
|
||||||
|
*/
|
||||||
|
module tanya.algorithm.mutation;
|
||||||
|
|
||||||
|
import tanya.memory.op;
|
||||||
|
import tanya.meta.trait;
|
||||||
|
|
||||||
|
private void deinitialize(bool zero, T)(ref T value)
|
||||||
|
{
|
||||||
|
static if (is(T == U[S], U, size_t S))
|
||||||
|
{
|
||||||
|
foreach (ref e; value)
|
||||||
|
{
|
||||||
|
deinitialize!zero(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static if (isNested!T)
|
||||||
|
{
|
||||||
|
// Don't override the context pointer.
|
||||||
|
enum size_t size = T.sizeof - (void*).sizeof;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
enum size_t size = T.sizeof;
|
||||||
|
}
|
||||||
|
static if (zero)
|
||||||
|
{
|
||||||
|
fill!0((cast(void*) &value)[0 .. size]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
copy(typeid(T).initializer()[0 .. size], (&value)[0 .. 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves $(D_PARAM source) into $(D_PARAM target) assuming that
|
||||||
|
* $(D_PARAM target) isn't initialized.
|
||||||
|
*
|
||||||
|
* Moving the $(D_PARAM source) copies it into the $(D_PARAM target) and places
|
||||||
|
* the $(D_PARAM source) into a valid but unspecified state, which means that
|
||||||
|
* after moving $(D_PARAM source) can be destroyed or assigned a new value, but
|
||||||
|
* accessing it yields an unspecified value. No postblits or destructors are
|
||||||
|
* called. If the $(D_PARAM target) should be destroyed before, use
|
||||||
|
* $(D_PSYMBOL move).
|
||||||
|
*
|
||||||
|
* $(D_PARAM source) and $(D_PARAM target) must be different objects.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* T = Object type.
|
||||||
|
* source = Source object.
|
||||||
|
* target = Target object.
|
||||||
|
*
|
||||||
|
* See_Also: $(D_PSYMBOL move),
|
||||||
|
* $(D_PSYMBOL hasElaborateCopyConstructor),
|
||||||
|
* $(D_PSYMBOL hasElaborateDestructor).
|
||||||
|
*
|
||||||
|
* Precondition: `&source !is &target`.
|
||||||
|
*/
|
||||||
|
void moveEmplace(T)(ref T source, ref T target) @system
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(&source !is &target, "Source and target must be different");
|
||||||
|
}
|
||||||
|
body
|
||||||
|
{
|
||||||
|
static if (is(T == struct) || isStaticArray!T)
|
||||||
|
{
|
||||||
|
copy((&source)[0 .. 1], (&target)[0 .. 1]);
|
||||||
|
|
||||||
|
static if (hasElaborateCopyConstructor!T || hasElaborateDestructor!T)
|
||||||
|
{
|
||||||
|
if (typeid(T).initializer().ptr is null)
|
||||||
|
{
|
||||||
|
deinitialize!true(source);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
deinitialize!false(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
target = source;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@nogc nothrow pure @system unittest
|
||||||
|
{
|
||||||
|
static struct S
|
||||||
|
{
|
||||||
|
int member = 5;
|
||||||
|
|
||||||
|
this(this) @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
S source, target = void;
|
||||||
|
moveEmplace(source, target);
|
||||||
|
assert(target.member == 5);
|
||||||
|
|
||||||
|
int x1 = 5, x2;
|
||||||
|
moveEmplace(x1, x2);
|
||||||
|
assert(x2 == 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is pure.
|
||||||
|
@nogc nothrow pure @system unittest
|
||||||
|
{
|
||||||
|
struct S
|
||||||
|
{
|
||||||
|
this(this)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
S source, target = void;
|
||||||
|
static assert(is(typeof({ moveEmplace(source, target); })));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Moves nested.
|
||||||
|
@nogc nothrow pure @system unittest
|
||||||
|
{
|
||||||
|
struct Nested
|
||||||
|
{
|
||||||
|
void method() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Nested source, target = void;
|
||||||
|
moveEmplace(source, target);
|
||||||
|
assert(source == target);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emplaces static arrays.
|
||||||
|
@nogc nothrow pure @system unittest
|
||||||
|
{
|
||||||
|
static struct S
|
||||||
|
{
|
||||||
|
size_t member;
|
||||||
|
this(size_t i) @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
this.member = i;
|
||||||
|
}
|
||||||
|
~this() @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
S[2] source = [ S(5), S(5) ], target = void;
|
||||||
|
moveEmplace(source, target);
|
||||||
|
assert(source[0].member == 0);
|
||||||
|
assert(target[0].member == 5);
|
||||||
|
assert(source[1].member == 0);
|
||||||
|
assert(target[1].member == 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves $(D_PARAM source) into $(D_PARAM target) assuming that
|
||||||
|
* $(D_PARAM target) isn't initialized.
|
||||||
|
*
|
||||||
|
* Moving the $(D_PARAM source) copies it into the $(D_PARAM target) and places
|
||||||
|
* the $(D_PARAM source) into a valid but unspecified state, which means that
|
||||||
|
* after moving $(D_PARAM source) can be destroyed or assigned a new value, but
|
||||||
|
* accessing it yields an unspecified value. $(D_PARAM target) is destroyed before
|
||||||
|
* the new value is assigned. If $(D_PARAM target) isn't initialized and
|
||||||
|
* therefore shouldn't be destroyed, $(D_PSYMBOL moveEmplace) can be used.
|
||||||
|
*
|
||||||
|
* If $(D_PARAM target) isn't specified, $(D_PSYMBOL move) returns the source
|
||||||
|
* as rvalue without calling its copy constructor or destructor.
|
||||||
|
*
|
||||||
|
* $(D_PARAM source) and $(D_PARAM target) are the same object,
|
||||||
|
* $(D_PSYMBOL move) does nothing.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* T = Object type.
|
||||||
|
* source = Source object.
|
||||||
|
* target = Target object.
|
||||||
|
*
|
||||||
|
* See_Also: $(D_PSYMBOL moveEmplace).
|
||||||
|
*/
|
||||||
|
void move(T)(ref T source, ref T target)
|
||||||
|
{
|
||||||
|
if ((() @trusted => &source is &target)())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
static if (hasElaborateDestructor!T)
|
||||||
|
{
|
||||||
|
target.__xdtor();
|
||||||
|
}
|
||||||
|
(() @trusted => moveEmplace(source, target))();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ditto
|
||||||
|
T move(T)(ref T source) @trusted
|
||||||
|
{
|
||||||
|
T target = void;
|
||||||
|
moveEmplace(source, target);
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
static struct S
|
||||||
|
{
|
||||||
|
int member = 5;
|
||||||
|
|
||||||
|
this(this) @nogc nothrow pure @safe
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
S source, target = void;
|
||||||
|
move(source, target);
|
||||||
|
assert(target.member == 5);
|
||||||
|
assert(move(target).member == 5);
|
||||||
|
|
||||||
|
int x1 = 5, x2;
|
||||||
|
move(x1, x2);
|
||||||
|
assert(x2 == 5);
|
||||||
|
assert(move(x2) == 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Moves if source is target.
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
int x = 5;
|
||||||
|
move(x, x);
|
||||||
|
assert(x == 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exchanges the values of $(D_PARAM a) and $(D_PARAM b).
|
||||||
|
*
|
||||||
|
* $(D_PSYMBOL swap) moves the contents of $(D_PARAM a) and $(D_PARAM b)
|
||||||
|
* without calling its postblits or destructors.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* a = The first object.
|
||||||
|
* a = The second object.
|
||||||
|
*/
|
||||||
|
void swap(T)(ref T a, ref T b) @trusted
|
||||||
|
{
|
||||||
|
T tmp = void;
|
||||||
|
moveEmplace(a, tmp);
|
||||||
|
moveEmplace(b, a);
|
||||||
|
moveEmplace(tmp, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
int a = 3, b = 5;
|
||||||
|
swap(a, b);
|
||||||
|
assert(a == 5);
|
||||||
|
assert(b == 3);
|
||||||
|
}
|
17
source/tanya/algorithm/package.d
Normal file
17
source/tanya/algorithm/package.d
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collection of generic algorithms.
|
||||||
|
*
|
||||||
|
* Copyright: Eugene Wissner 2017.
|
||||||
|
* 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/algorithm/package.d,
|
||||||
|
* tanya/algorithm/package.d)
|
||||||
|
*/
|
||||||
|
module tanya.algorithm;
|
||||||
|
|
||||||
|
public import tanya.algorithm.mutation;
|
@ -16,8 +16,13 @@ module tanya.container.array;
|
|||||||
|
|
||||||
import core.checkedint;
|
import core.checkedint;
|
||||||
import std.algorithm.comparison;
|
import std.algorithm.comparison;
|
||||||
import std.algorithm.mutation;
|
import std.algorithm.mutation : bringToFront,
|
||||||
|
copy,
|
||||||
|
fill,
|
||||||
|
initializeAll,
|
||||||
|
uninitializedFill;
|
||||||
import std.meta;
|
import std.meta;
|
||||||
|
import tanya.algorithm.mutation;
|
||||||
import tanya.exception;
|
import tanya.exception;
|
||||||
import tanya.memory;
|
import tanya.memory;
|
||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
@ -264,7 +269,10 @@ struct Array(T)
|
|||||||
{
|
{
|
||||||
// Move each element.
|
// Move each element.
|
||||||
reserve(init.length_);
|
reserve(init.length_);
|
||||||
moveEmplaceAll(init.data[0 .. init.length_], this.data[0 .. init.length_]);
|
foreach (ref target; this.data[0 .. init.length_])
|
||||||
|
{
|
||||||
|
moveEmplace(*init.data++, target);
|
||||||
|
}
|
||||||
this.length_ = init.length_;
|
this.length_ = init.length_;
|
||||||
// Destructor of init should destroy it here.
|
// Destructor of init should destroy it here.
|
||||||
}
|
}
|
||||||
@ -506,7 +514,6 @@ struct Array(T)
|
|||||||
{
|
{
|
||||||
allocator.deallocate(buf);
|
allocator.deallocate(buf);
|
||||||
}
|
}
|
||||||
const T* end = this.data + this.length_;
|
|
||||||
for (T* src = this.data, dest = cast(T*) buf; src != end; ++src, ++dest)
|
for (T* src = this.data, dest = cast(T*) buf; src != end; ++src, ++dest)
|
||||||
{
|
{
|
||||||
moveEmplace(*src, *dest);
|
moveEmplace(*src, *dest);
|
||||||
@ -632,6 +639,11 @@ struct Array(T)
|
|||||||
assert(v.removeBack(3) == 0);
|
assert(v.removeBack(3) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private @property inout(T)* end() inout
|
||||||
|
{
|
||||||
|
return this.data + this.length_;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove all elements beloning to $(D_PARAM r).
|
* Remove all elements beloning to $(D_PARAM r).
|
||||||
*
|
*
|
||||||
@ -652,8 +664,11 @@ struct Array(T)
|
|||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
auto end = this.data + this.length;
|
auto target = r.begin;
|
||||||
moveAll(Range(this, r.end, end), Range(this, r.begin, end));
|
for (auto source = r.end; source != end; ++source, ++target)
|
||||||
|
{
|
||||||
|
move(*source, *target);
|
||||||
|
}
|
||||||
length = length - r.length;
|
length = length - r.length;
|
||||||
return Range(this, r.begin, this.data + length);
|
return Range(this, r.begin, this.data + length);
|
||||||
}
|
}
|
||||||
@ -683,7 +698,7 @@ struct Array(T)
|
|||||||
if (isImplicitlyConvertible!(R, T))
|
if (isImplicitlyConvertible!(R, T))
|
||||||
{
|
{
|
||||||
reserve(this.length + 1);
|
reserve(this.length + 1);
|
||||||
moveEmplace(el, *(this.data + this.length_));
|
moveEmplace(el, *end);
|
||||||
++this.length_;
|
++this.length_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,11 +15,12 @@
|
|||||||
module tanya.container.list;
|
module tanya.container.list;
|
||||||
|
|
||||||
import std.algorithm.comparison;
|
import std.algorithm.comparison;
|
||||||
import std.algorithm.mutation;
|
|
||||||
import std.algorithm.searching;
|
import std.algorithm.searching;
|
||||||
|
import tanya.algorithm.mutation;
|
||||||
import tanya.container.entry;
|
import tanya.container.entry;
|
||||||
import tanya.memory;
|
import tanya.memory;
|
||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
|
import tanya.meta.transform;
|
||||||
import tanya.range.array;
|
import tanya.range.array;
|
||||||
import tanya.range.primitive;
|
import tanya.range.primitive;
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
*/
|
*/
|
||||||
module tanya.container.queue;
|
module tanya.container.queue;
|
||||||
|
|
||||||
import std.algorithm.mutation;
|
import tanya.algorithm.mutation;
|
||||||
import tanya.container.entry;
|
import tanya.container.entry;
|
||||||
import tanya.exception;
|
import tanya.exception;
|
||||||
import tanya.memory;
|
import tanya.memory;
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
module tanya.container.set;
|
module tanya.container.set;
|
||||||
|
|
||||||
import std.algorithm.mutation;
|
import tanya.algorithm.mutation;
|
||||||
import tanya.container;
|
import tanya.container;
|
||||||
import tanya.container.entry;
|
import tanya.container.entry;
|
||||||
import tanya.memory;
|
import tanya.memory;
|
||||||
|
@ -27,9 +27,10 @@
|
|||||||
module tanya.container.string;
|
module tanya.container.string;
|
||||||
|
|
||||||
import std.algorithm.comparison;
|
import std.algorithm.comparison;
|
||||||
import std.algorithm.mutation;
|
import std.algorithm.mutation : bringToFront, copy;
|
||||||
import std.algorithm.searching;
|
import std.algorithm.searching;
|
||||||
static import std.range;
|
static import std.range;
|
||||||
|
import tanya.algorithm.mutation;
|
||||||
import tanya.memory;
|
import tanya.memory;
|
||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
import tanya.meta.transform;
|
import tanya.meta.transform;
|
||||||
@ -263,7 +264,8 @@ if (is(Unqual!E == char))
|
|||||||
body
|
body
|
||||||
{
|
{
|
||||||
dchar chr;
|
dchar chr;
|
||||||
ubyte units, mask;
|
ubyte units;
|
||||||
|
int mask;
|
||||||
const(char)* it = this.begin;
|
const(char)* it = this.begin;
|
||||||
|
|
||||||
if (*it & 0x80)
|
if (*it & 0x80)
|
||||||
|
@ -14,9 +14,17 @@
|
|||||||
*/
|
*/
|
||||||
module tanya.conv;
|
module tanya.conv;
|
||||||
|
|
||||||
|
import tanya.container.string;
|
||||||
|
import tanya.format;
|
||||||
import tanya.memory;
|
import tanya.memory;
|
||||||
import tanya.memory.op;
|
import tanya.memory.op;
|
||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
|
import tanya.meta.transform;
|
||||||
|
|
||||||
|
version (unittest)
|
||||||
|
{
|
||||||
|
import tanya.test.assertion;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new object of type $(D_PARAM T) in $(D_PARAM memory) with the
|
* Constructs a new object of type $(D_PARAM T) in $(D_PARAM memory) with the
|
||||||
@ -233,3 +241,469 @@ body
|
|||||||
}
|
}
|
||||||
static assert(is(typeof(emplace!F((void[]).init))));
|
static assert(is(typeof(emplace!F((void[]).init))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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).
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
auto val = 5.to!int();
|
||||||
|
assert(val == 5);
|
||||||
|
static assert(is(typeof(val) == int));
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
int val = 5;
|
||||||
|
assert(val.to!int() == 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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).
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
// ubyte -> ushort
|
||||||
|
assert((cast(ubyte) 0).to!ushort == 0);
|
||||||
|
assert((cast(ubyte) 1).to!ushort == 1);
|
||||||
|
assert((cast(ubyte) (ubyte.max - 1)).to!ushort == ubyte.max - 1);
|
||||||
|
assert((cast(ubyte) ubyte.max).to!ushort == ubyte.max);
|
||||||
|
|
||||||
|
// ubyte -> short
|
||||||
|
assert((cast(ubyte) 0).to!short == 0);
|
||||||
|
assert((cast(ubyte) 1).to!short == 1);
|
||||||
|
assert((cast(ubyte) (ubyte.max - 1)).to!short == ubyte.max - 1);
|
||||||
|
assert((cast(ubyte) ubyte.max).to!short == ubyte.max);
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc pure @safe unittest
|
||||||
|
{
|
||||||
|
// ubyte <- ushort
|
||||||
|
assert((cast(ushort) 0).to!ubyte == 0);
|
||||||
|
assert((cast(ushort) 1).to!ubyte == 1);
|
||||||
|
assert((cast(ushort) (ubyte.max - 1)).to!ubyte == ubyte.max - 1);
|
||||||
|
assert((cast(ushort) ubyte.max).to!ubyte == ubyte.max);
|
||||||
|
|
||||||
|
// ubyte <- short
|
||||||
|
assert((cast(short) 0).to!ubyte == 0);
|
||||||
|
assert((cast(short) 1).to!ubyte == 1);
|
||||||
|
assert((cast(short) (ubyte.max - 1)).to!ubyte == ubyte.max - 1);
|
||||||
|
assert((cast(short) ubyte.max).to!ubyte == ubyte.max);
|
||||||
|
|
||||||
|
// short <-> int
|
||||||
|
assert(short.min.to!int == short.min);
|
||||||
|
assert((short.min + 1).to!int == short.min + 1);
|
||||||
|
assert((cast(short) -1).to!int == -1);
|
||||||
|
assert((cast(short) 0).to!int == 0);
|
||||||
|
assert((cast(short) 1).to!int == 1);
|
||||||
|
assert((short.max - 1).to!int == short.max - 1);
|
||||||
|
assert(short.max.to!int == short.max);
|
||||||
|
|
||||||
|
assert((cast(int) short.min).to!short == short.min);
|
||||||
|
assert((cast(int) short.min + 1).to!short == short.min + 1);
|
||||||
|
assert((cast(int) -1).to!short == -1);
|
||||||
|
assert((cast(int) 0).to!short == 0);
|
||||||
|
assert((cast(int) 1).to!short == 1);
|
||||||
|
assert((cast(int) short.max - 1).to!short == short.max - 1);
|
||||||
|
assert((cast(int) short.max).to!short == short.max);
|
||||||
|
|
||||||
|
// uint <-> int
|
||||||
|
assert((cast(uint) 0).to!int == 0);
|
||||||
|
assert((cast(uint) 1).to!int == 1);
|
||||||
|
assert((cast(uint) (int.max - 1)).to!int == int.max - 1);
|
||||||
|
assert((cast(uint) int.max).to!int == int.max);
|
||||||
|
|
||||||
|
assert((cast(int) 0).to!uint == 0);
|
||||||
|
assert((cast(int) 1).to!uint == 1);
|
||||||
|
assert((cast(int) (int.max - 1)).to!uint == int.max - 1);
|
||||||
|
assert((cast(int) int.max).to!uint == int.max);
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc pure @safe unittest
|
||||||
|
{
|
||||||
|
assertThrown!ConvException(&to!(short, int), int.min);
|
||||||
|
assertThrown!ConvException(&to!(short, int), int.max);
|
||||||
|
assertThrown!ConvException(&to!(ushort, uint), uint.max);
|
||||||
|
assertThrown!ConvException(&to!(uint, int), -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
enum Test : int
|
||||||
|
{
|
||||||
|
one,
|
||||||
|
two,
|
||||||
|
}
|
||||||
|
assert(Test.one.to!int == 0);
|
||||||
|
assert(Test.two.to!int == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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).
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@nogc pure @safe unittest
|
||||||
|
{
|
||||||
|
assert(1.5.to!int == 1);
|
||||||
|
assert(2147483646.5.to!int == 2147483646);
|
||||||
|
assert((-2147483647.5).to!int == -2147483647);
|
||||||
|
assert(2147483646.5.to!uint == 2147483646);
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc pure @safe unittest
|
||||||
|
{
|
||||||
|
assertThrown!ConvException(&to!(int, double), 2147483647.5);
|
||||||
|
assertThrown!ConvException(&to!(int, double), -2147483648.5);
|
||||||
|
assertThrown!ConvException(&to!(uint, double), -21474.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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).
|
||||||
|
*/
|
||||||
|
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 ~ "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@nogc pure @safe unittest
|
||||||
|
{
|
||||||
|
enum Test : int
|
||||||
|
{
|
||||||
|
one,
|
||||||
|
two,
|
||||||
|
}
|
||||||
|
static assert(is(typeof(1.to!Test) == Test));
|
||||||
|
assert(0.to!Test == Test.one);
|
||||||
|
assert(1.to!Test == Test.two);
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc pure @safe unittest
|
||||||
|
{
|
||||||
|
enum Test : uint
|
||||||
|
{
|
||||||
|
one,
|
||||||
|
two,
|
||||||
|
}
|
||||||
|
assertThrown!ConvException(&to!(Test, int), 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@nogc pure @safe unittest
|
||||||
|
{
|
||||||
|
assert(!0.0.to!bool);
|
||||||
|
assert(0.2.to!bool);
|
||||||
|
assert(0.5.to!bool);
|
||||||
|
assert(1.0.to!bool);
|
||||||
|
|
||||||
|
assert(!0.to!bool);
|
||||||
|
assert(1.to!bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc pure @safe unittest
|
||||||
|
{
|
||||||
|
assertThrown!ConvException(&to!(bool, int), -1);
|
||||||
|
assertThrown!ConvException(&to!(bool, int), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ditto
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@nogc pure @safe unittest
|
||||||
|
{
|
||||||
|
assert("true".to!bool);
|
||||||
|
assert(!"false".to!bool);
|
||||||
|
assert(String("true").to!bool);
|
||||||
|
assert(!String("false").to!bool);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc pure @safe unittest
|
||||||
|
{
|
||||||
|
assertThrown!ConvException(() => "1".to!bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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).
|
||||||
|
*/
|
||||||
|
To to(To, From)(From from)
|
||||||
|
if (is(Unqual!From == bool) && isNumeric!To && !is(Unqual!To == Unqual!From))
|
||||||
|
{
|
||||||
|
return from;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
assert(true.to!float == 1.0);
|
||||||
|
assert(true.to!double == 1.0);
|
||||||
|
assert(true.to!ubyte == 1);
|
||||||
|
assert(true.to!byte == 1);
|
||||||
|
assert(true.to!ushort == 1);
|
||||||
|
assert(true.to!short == 1);
|
||||||
|
assert(true.to!uint == 1);
|
||||||
|
assert(true.to!int == 1);
|
||||||
|
|
||||||
|
assert(false.to!float == 0);
|
||||||
|
assert(false.to!double == 0);
|
||||||
|
assert(false.to!ubyte == 0);
|
||||||
|
assert(false.to!byte == 0);
|
||||||
|
assert(false.to!ushort == 0);
|
||||||
|
assert(false.to!short == 0);
|
||||||
|
assert(false.to!uint == 0);
|
||||||
|
assert(false.to!int == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts $(D_PARAM From) to a $(D_PSYMBOL String).
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* From = Source type.
|
||||||
|
* To = Target type.
|
||||||
|
* from = Source value.
|
||||||
|
*
|
||||||
|
* Returns: $(D_PARAM from) converted to $(D_PSYMBOL String).
|
||||||
|
*/
|
||||||
|
To to(To, From)(auto ref From from)
|
||||||
|
if (is(Unqual!To == String))
|
||||||
|
{
|
||||||
|
return format!"{}"(from);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
assert(true.to!String == "true");
|
||||||
|
assert(false.to!String == "false");
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
static assert(is(typeof((const String("true")).to!bool)));
|
||||||
|
static assert(is(typeof(false.to!(const String) == "false")));
|
||||||
|
}
|
||||||
|
@ -20,6 +20,11 @@ import tanya.memory.op;
|
|||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
import tanya.meta.transform;
|
import tanya.meta.transform;
|
||||||
|
|
||||||
|
version (unittest)
|
||||||
|
{
|
||||||
|
import tanya.test.assertion;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thrown if a type conversion fails.
|
* Thrown if a type conversion fails.
|
||||||
*/
|
*/
|
||||||
@ -51,6 +56,7 @@ final class ConvException : Exception
|
|||||||
*
|
*
|
||||||
* Returns: $(D_PARAM from).
|
* Returns: $(D_PARAM from).
|
||||||
*/
|
*/
|
||||||
|
deprecated("Use tanya.conv.to instead")
|
||||||
template to(To)
|
template to(To)
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@ -72,20 +78,6 @@ template to(To)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
|
||||||
pure nothrow @safe @nogc unittest
|
|
||||||
{
|
|
||||||
auto val = 5.to!int();
|
|
||||||
assert(val == 5);
|
|
||||||
static assert(is(typeof(val) == int));
|
|
||||||
}
|
|
||||||
|
|
||||||
private pure nothrow @safe @nogc unittest
|
|
||||||
{
|
|
||||||
int val = 5;
|
|
||||||
assert(val.to!int() == 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs checked conversion from an integral type $(D_PARAM From) to an
|
* Performs checked conversion from an integral type $(D_PARAM From) to an
|
||||||
* integral type $(D_PARAM To).
|
* integral type $(D_PARAM To).
|
||||||
@ -100,6 +92,7 @@ private pure nothrow @safe @nogc unittest
|
|||||||
* Throws: $(D_PSYMBOL ConvException) if $(D_PARAM from) is too small or too
|
* Throws: $(D_PSYMBOL ConvException) if $(D_PARAM from) is too small or too
|
||||||
* large to be represented by $(D_PARAM To).
|
* large to be represented by $(D_PARAM To).
|
||||||
*/
|
*/
|
||||||
|
deprecated("Use tanya.conv.to instead")
|
||||||
To to(To, From)(From from)
|
To to(To, From)(From from)
|
||||||
if (isIntegral!From
|
if (isIntegral!From
|
||||||
&& isIntegral!To
|
&& isIntegral!To
|
||||||
@ -148,135 +141,6 @@ if (isIntegral!From
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private pure nothrow @safe @nogc unittest
|
|
||||||
{
|
|
||||||
// ubyte -> ushort
|
|
||||||
assert((cast(ubyte) 0).to!ushort == 0);
|
|
||||||
assert((cast(ubyte) 1).to!ushort == 1);
|
|
||||||
assert((cast(ubyte) (ubyte.max - 1)).to!ushort == ubyte.max - 1);
|
|
||||||
assert((cast(ubyte) ubyte.max).to!ushort == ubyte.max);
|
|
||||||
|
|
||||||
// ubyte -> short
|
|
||||||
assert((cast(ubyte) 0).to!short == 0);
|
|
||||||
assert((cast(ubyte) 1).to!short == 1);
|
|
||||||
assert((cast(ubyte) (ubyte.max - 1)).to!short == ubyte.max - 1);
|
|
||||||
assert((cast(ubyte) ubyte.max).to!short == ubyte.max);
|
|
||||||
}
|
|
||||||
|
|
||||||
private unittest
|
|
||||||
{
|
|
||||||
// ubyte <- ushort
|
|
||||||
assert((cast(ushort) 0).to!ubyte == 0);
|
|
||||||
assert((cast(ushort) 1).to!ubyte == 1);
|
|
||||||
assert((cast(ushort) (ubyte.max - 1)).to!ubyte == ubyte.max - 1);
|
|
||||||
assert((cast(ushort) ubyte.max).to!ubyte == ubyte.max);
|
|
||||||
|
|
||||||
// ubyte <- short
|
|
||||||
assert((cast(short) 0).to!ubyte == 0);
|
|
||||||
assert((cast(short) 1).to!ubyte == 1);
|
|
||||||
assert((cast(short) (ubyte.max - 1)).to!ubyte == ubyte.max - 1);
|
|
||||||
assert((cast(short) ubyte.max).to!ubyte == ubyte.max);
|
|
||||||
|
|
||||||
// short <-> int
|
|
||||||
assert(short.min.to!int == short.min);
|
|
||||||
assert((short.min + 1).to!int == short.min + 1);
|
|
||||||
assert((cast(short) -1).to!int == -1);
|
|
||||||
assert((cast(short) 0).to!int == 0);
|
|
||||||
assert((cast(short) 1).to!int == 1);
|
|
||||||
assert((short.max - 1).to!int == short.max - 1);
|
|
||||||
assert(short.max.to!int == short.max);
|
|
||||||
|
|
||||||
assert((cast(int) short.min).to!short == short.min);
|
|
||||||
assert((cast(int) short.min + 1).to!short == short.min + 1);
|
|
||||||
assert((cast(int) -1).to!short == -1);
|
|
||||||
assert((cast(int) 0).to!short == 0);
|
|
||||||
assert((cast(int) 1).to!short == 1);
|
|
||||||
assert((cast(int) short.max - 1).to!short == short.max - 1);
|
|
||||||
assert((cast(int) short.max).to!short == short.max);
|
|
||||||
|
|
||||||
// uint <-> int
|
|
||||||
assert((cast(uint) 0).to!int == 0);
|
|
||||||
assert((cast(uint) 1).to!int == 1);
|
|
||||||
assert((cast(uint) (int.max - 1)).to!int == int.max - 1);
|
|
||||||
assert((cast(uint) int.max).to!int == int.max);
|
|
||||||
|
|
||||||
assert((cast(int) 0).to!uint == 0);
|
|
||||||
assert((cast(int) 1).to!uint == 1);
|
|
||||||
assert((cast(int) (int.max - 1)).to!uint == int.max - 1);
|
|
||||||
assert((cast(int) int.max).to!uint == int.max);
|
|
||||||
}
|
|
||||||
|
|
||||||
private unittest
|
|
||||||
{
|
|
||||||
ConvException exception;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
assert(int.min.to!short == int.min);
|
|
||||||
}
|
|
||||||
catch (ConvException e)
|
|
||||||
{
|
|
||||||
exception = e;
|
|
||||||
}
|
|
||||||
assert(exception !is null);
|
|
||||||
defaultAllocator.dispose(exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
private unittest
|
|
||||||
{
|
|
||||||
ConvException exception;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
assert(int.max.to!short == int.max);
|
|
||||||
}
|
|
||||||
catch (ConvException e)
|
|
||||||
{
|
|
||||||
exception = e;
|
|
||||||
}
|
|
||||||
assert(exception !is null);
|
|
||||||
defaultAllocator.dispose(exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
private unittest
|
|
||||||
{
|
|
||||||
ConvException exception;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
assert(uint.max.to!ushort == ushort.max);
|
|
||||||
}
|
|
||||||
catch (ConvException e)
|
|
||||||
{
|
|
||||||
exception = e;
|
|
||||||
}
|
|
||||||
assert(exception !is null);
|
|
||||||
defaultAllocator.dispose(exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
private unittest
|
|
||||||
{
|
|
||||||
ConvException exception;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
assert((-1).to!uint == -1);
|
|
||||||
}
|
|
||||||
catch (ConvException e)
|
|
||||||
{
|
|
||||||
exception = e;
|
|
||||||
}
|
|
||||||
assert(exception !is null);
|
|
||||||
defaultAllocator.dispose(exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
private @nogc unittest
|
|
||||||
{
|
|
||||||
enum Test : int
|
|
||||||
{
|
|
||||||
one,
|
|
||||||
two,
|
|
||||||
}
|
|
||||||
assert(Test.one.to!int == 0);
|
|
||||||
assert(Test.two.to!int == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts $(D_PARAM from) to a boolean.
|
* Converts $(D_PARAM from) to a boolean.
|
||||||
*
|
*
|
||||||
@ -296,6 +160,7 @@ private @nogc unittest
|
|||||||
*
|
*
|
||||||
* Throws: $(D_PSYMBOL ConvException) if $(D_PARAM from) isn't convertible.
|
* Throws: $(D_PSYMBOL ConvException) if $(D_PARAM from) isn't convertible.
|
||||||
*/
|
*/
|
||||||
|
deprecated("Use tanya.conv.to instead")
|
||||||
To to(To, From)(From from)
|
To to(To, From)(From from)
|
||||||
if (isNumeric!From && is(Unqual!To == bool) && !is(Unqual!To == Unqual!From))
|
if (isNumeric!From && is(Unqual!To == bool) && !is(Unqual!To == Unqual!From))
|
||||||
{
|
{
|
||||||
@ -316,49 +181,8 @@ if (isNumeric!From && is(Unqual!To == bool) && !is(Unqual!To == Unqual!From))
|
|||||||
"Positive number overflow");
|
"Positive number overflow");
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
|
||||||
@nogc unittest
|
|
||||||
{
|
|
||||||
assert(!0.0.to!bool);
|
|
||||||
assert(0.2.to!bool);
|
|
||||||
assert(0.5.to!bool);
|
|
||||||
assert(1.0.to!bool);
|
|
||||||
|
|
||||||
assert(!0.to!bool);
|
|
||||||
assert(1.to!bool);
|
|
||||||
}
|
|
||||||
|
|
||||||
private @nogc unittest
|
|
||||||
{
|
|
||||||
ConvException exception;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
assert((-1).to!bool);
|
|
||||||
}
|
|
||||||
catch (ConvException e)
|
|
||||||
{
|
|
||||||
exception = e;
|
|
||||||
}
|
|
||||||
assert(exception !is null);
|
|
||||||
defaultAllocator.dispose(exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
private @nogc unittest
|
|
||||||
{
|
|
||||||
ConvException exception;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
assert(2.to!bool);
|
|
||||||
}
|
|
||||||
catch (ConvException e)
|
|
||||||
{
|
|
||||||
exception = e;
|
|
||||||
}
|
|
||||||
assert(exception !is null);
|
|
||||||
defaultAllocator.dispose(exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
|
deprecated("Use tanya.conv.to instead")
|
||||||
To to(To, From)(auto ref const From from)
|
To to(To, From)(auto ref const From from)
|
||||||
if ((is(From == String) || isSomeString!From) && is(Unqual!To == bool))
|
if ((is(From == String) || isSomeString!From) && is(Unqual!To == bool))
|
||||||
{
|
{
|
||||||
@ -374,31 +198,6 @@ if ((is(From == String) || isSomeString!From) && is(Unqual!To == bool))
|
|||||||
"String doesn't contain a boolean value");
|
"String doesn't contain a boolean value");
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
|
||||||
@nogc unittest
|
|
||||||
{
|
|
||||||
assert("true".to!bool);
|
|
||||||
assert(!"false".to!bool);
|
|
||||||
assert(String("true").to!bool);
|
|
||||||
assert(!String("false").to!bool);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private @nogc unittest
|
|
||||||
{
|
|
||||||
ConvException exception;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
assert("1".to!bool);
|
|
||||||
}
|
|
||||||
catch (ConvException e)
|
|
||||||
{
|
|
||||||
exception = e;
|
|
||||||
}
|
|
||||||
assert(exception !is null);
|
|
||||||
defaultAllocator.dispose(exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a boolean to $(D_PARAM To).
|
* Converts a boolean to $(D_PARAM To).
|
||||||
*
|
*
|
||||||
@ -415,54 +214,21 @@ private @nogc unittest
|
|||||||
*
|
*
|
||||||
* Returns: $(D_PARAM from) converted to $(D_PARAM To).
|
* Returns: $(D_PARAM from) converted to $(D_PARAM To).
|
||||||
*/
|
*/
|
||||||
|
deprecated("Use tanya.conv.to instead")
|
||||||
To to(To, From)(const From from)
|
To to(To, From)(const From from)
|
||||||
if (is(Unqual!From == bool) && isNumeric!To && !is(Unqual!To == Unqual!From))
|
if (is(Unqual!From == bool) && isNumeric!To && !is(Unqual!To == Unqual!From))
|
||||||
{
|
{
|
||||||
return from;
|
return from;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
|
||||||
pure nothrow @safe @nogc unittest
|
|
||||||
{
|
|
||||||
assert(true.to!float == 1.0);
|
|
||||||
assert(true.to!double == 1.0);
|
|
||||||
assert(true.to!ubyte == 1);
|
|
||||||
assert(true.to!byte == 1);
|
|
||||||
assert(true.to!ushort == 1);
|
|
||||||
assert(true.to!short == 1);
|
|
||||||
assert(true.to!uint == 1);
|
|
||||||
assert(true.to!int == 1);
|
|
||||||
|
|
||||||
assert(false.to!float == 0);
|
|
||||||
assert(false.to!double == 0);
|
|
||||||
assert(false.to!ubyte == 0);
|
|
||||||
assert(false.to!byte == 0);
|
|
||||||
assert(false.to!ushort == 0);
|
|
||||||
assert(false.to!short == 0);
|
|
||||||
assert(false.to!uint == 0);
|
|
||||||
assert(false.to!int == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
|
deprecated("Use tanya.conv.to instead")
|
||||||
To to(To, From)(const From from)
|
To to(To, From)(const From from)
|
||||||
if (is(Unqual!From == bool) && is(Unqual!To == String))
|
if (is(Unqual!From == bool) && is(Unqual!To == String))
|
||||||
{
|
{
|
||||||
return String(from ? "true" : "false");
|
return String(from ? "true" : "false");
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
|
||||||
@nogc unittest
|
|
||||||
{
|
|
||||||
assert(true.to!String == "true");
|
|
||||||
assert(false.to!String == "false");
|
|
||||||
}
|
|
||||||
|
|
||||||
private @nogc unittest
|
|
||||||
{
|
|
||||||
static assert(is(typeof((const String("true")).to!bool)));
|
|
||||||
static assert(is(typeof(false.to!(const String) == "false")));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a floating point number to an integral type.
|
* Converts a floating point number to an integral type.
|
||||||
*
|
*
|
||||||
@ -477,6 +243,7 @@ private @nogc unittest
|
|||||||
* Throws: $(D_PSYMBOL ConvException) if
|
* Throws: $(D_PSYMBOL ConvException) if
|
||||||
* $(D_INLINECODE from < To.min || from > To.max).
|
* $(D_INLINECODE from < To.min || from > To.max).
|
||||||
*/
|
*/
|
||||||
|
deprecated("Use tanya.conv.to instead")
|
||||||
To to(To, From)(From from)
|
To to(To, From)(From from)
|
||||||
if (isFloatingPoint!From
|
if (isFloatingPoint!From
|
||||||
&& isIntegral!To
|
&& isIntegral!To
|
||||||
@ -496,60 +263,6 @@ if (isFloatingPoint!From
|
|||||||
return cast(To) from;
|
return cast(To) from;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
|
||||||
@nogc unittest
|
|
||||||
{
|
|
||||||
assert(1.5.to!int == 1);
|
|
||||||
assert(2147483646.5.to!int == 2147483646);
|
|
||||||
assert((-2147483647.5).to!int == -2147483647);
|
|
||||||
assert(2147483646.5.to!uint == 2147483646);
|
|
||||||
}
|
|
||||||
|
|
||||||
private @nogc unittest
|
|
||||||
{
|
|
||||||
ConvException exception;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
assert(2147483647.5.to!int == 2147483647);
|
|
||||||
}
|
|
||||||
catch (ConvException e)
|
|
||||||
{
|
|
||||||
exception = e;
|
|
||||||
}
|
|
||||||
assert(exception !is null);
|
|
||||||
defaultAllocator.dispose(exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
private @nogc unittest
|
|
||||||
{
|
|
||||||
ConvException exception;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
assert((-2147483648.5).to!int == -2147483648);
|
|
||||||
}
|
|
||||||
catch (ConvException e)
|
|
||||||
{
|
|
||||||
exception = e;
|
|
||||||
}
|
|
||||||
assert(exception !is null);
|
|
||||||
defaultAllocator.dispose(exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
private @nogc unittest
|
|
||||||
{
|
|
||||||
ConvException exception;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
assert((-21474.5).to!uint == -21474);
|
|
||||||
}
|
|
||||||
catch (ConvException e)
|
|
||||||
{
|
|
||||||
exception = e;
|
|
||||||
}
|
|
||||||
assert(exception !is null);
|
|
||||||
defaultAllocator.dispose(exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs checked conversion from an integral type $(D_PARAM From) to an
|
* Performs checked conversion from an integral type $(D_PARAM From) to an
|
||||||
* $(D_KEYWORD enum).
|
* $(D_KEYWORD enum).
|
||||||
@ -564,6 +277,7 @@ private @nogc unittest
|
|||||||
* Throws: $(D_PSYMBOL ConvException) if $(D_PARAM from) is not a member of
|
* Throws: $(D_PSYMBOL ConvException) if $(D_PARAM from) is not a member of
|
||||||
* $(D_PSYMBOL To).
|
* $(D_PSYMBOL To).
|
||||||
*/
|
*/
|
||||||
|
deprecated("Use tanya.conv.to instead")
|
||||||
To to(To, From)(From from)
|
To to(To, From)(From from)
|
||||||
if (isIntegral!From && is(To == enum))
|
if (isIntegral!From && is(To == enum))
|
||||||
{
|
{
|
||||||
@ -577,115 +291,3 @@ if (isIntegral!From && is(To == enum))
|
|||||||
throw make!ConvException(defaultAllocator,
|
throw make!ConvException(defaultAllocator,
|
||||||
"Value not found in enum '" ~ To.stringof ~ "'");
|
"Value not found in enum '" ~ To.stringof ~ "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
|
||||||
@nogc unittest
|
|
||||||
{
|
|
||||||
enum Test : int
|
|
||||||
{
|
|
||||||
one,
|
|
||||||
two,
|
|
||||||
}
|
|
||||||
static assert(is(typeof(1.to!Test) == Test));
|
|
||||||
assert(0.to!Test == Test.one);
|
|
||||||
assert(1.to!Test == Test.two);
|
|
||||||
}
|
|
||||||
|
|
||||||
private @nogc unittest
|
|
||||||
{
|
|
||||||
enum Test : uint
|
|
||||||
{
|
|
||||||
one,
|
|
||||||
two,
|
|
||||||
}
|
|
||||||
|
|
||||||
ConvException exception;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
assert(5.to!Test == Test.one);
|
|
||||||
}
|
|
||||||
catch (ConvException e)
|
|
||||||
{
|
|
||||||
exception = e;
|
|
||||||
}
|
|
||||||
assert(exception !is null);
|
|
||||||
defaultAllocator.dispose(exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the last part of buffer with converted number.
|
|
||||||
package(tanya) char[] number2String(T)(const T number,
|
|
||||||
return ref char[21] buffer)
|
|
||||||
if (isIntegral!T)
|
|
||||||
{
|
|
||||||
// abs the integer.
|
|
||||||
ulong n64 = number < 0 ? -cast(long) number : number;
|
|
||||||
|
|
||||||
char* start = buffer[].ptr + buffer.sizeof - 1;
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
// Do in 32-bit chunks (avoid lots of 64-bit divides even with constant
|
|
||||||
// denominators).
|
|
||||||
char* o = start - 8;
|
|
||||||
uint n;
|
|
||||||
if (n64 >= 100000000)
|
|
||||||
{
|
|
||||||
n = n64 % 100000000;
|
|
||||||
n64 /= 100000000;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
n = cast(uint) n64;
|
|
||||||
n64 = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (n)
|
|
||||||
{
|
|
||||||
*--start = cast(char) (n % 10) + '0';
|
|
||||||
n /= 10;
|
|
||||||
}
|
|
||||||
// Ignore the leading zero if it was the last part of the integer.
|
|
||||||
if (n64 == 0)
|
|
||||||
{
|
|
||||||
if ((start[0] == '0')
|
|
||||||
&& (start != (buffer[].ptr + buffer.sizeof -1)))
|
|
||||||
{
|
|
||||||
++start;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Copy leading zeros if it wasn't the most significant part of the
|
|
||||||
// integer.
|
|
||||||
while (start != o)
|
|
||||||
{
|
|
||||||
*--start = '0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the length that we have copied.
|
|
||||||
uint l = cast(uint) ((buffer[].ptr + buffer.sizeof - 1) - start);
|
|
||||||
if (l == 0)
|
|
||||||
{
|
|
||||||
*--start = '0';
|
|
||||||
l = 1;
|
|
||||||
}
|
|
||||||
else if (number < 0) // Set the sign.
|
|
||||||
{
|
|
||||||
*--start = '-';
|
|
||||||
++l;
|
|
||||||
}
|
|
||||||
|
|
||||||
return buffer[$ - l - 1 .. $ - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Converting an integer to string.
|
|
||||||
private pure nothrow @system @nogc unittest
|
|
||||||
{
|
|
||||||
char[21] buf;
|
|
||||||
|
|
||||||
assert(number2String(80, buf) == "80");
|
|
||||||
assert(number2String(-80, buf) == "-80");
|
|
||||||
assert(number2String(0, buf) == "0");
|
|
||||||
assert(number2String(uint.max, buf) == "4294967295");
|
|
||||||
assert(number2String(int.min, buf) == "-2147483648");
|
|
||||||
}
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -14,11 +14,14 @@
|
|||||||
*/
|
*/
|
||||||
module tanya.math.mp;
|
module tanya.math.mp;
|
||||||
|
|
||||||
import std.algorithm;
|
import std.algorithm.comparison;
|
||||||
|
import std.algorithm.mutation : copy, fill, reverse;
|
||||||
import std.range;
|
import std.range;
|
||||||
|
import tanya.algorithm.mutation;
|
||||||
import tanya.container.array;
|
import tanya.container.array;
|
||||||
import tanya.encoding.ascii;
|
import tanya.encoding.ascii;
|
||||||
import tanya.memory;
|
import tanya.memory;
|
||||||
|
static import tanya.memory.op;
|
||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
import tanya.meta.transform;
|
import tanya.meta.transform;
|
||||||
|
|
||||||
@ -104,7 +107,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
this(shared Allocator allocator) pure nothrow @safe @nogc
|
this(shared Allocator allocator) @nogc nothrow pure @safe
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(allocator !is null);
|
assert(allocator !is null);
|
||||||
@ -156,7 +159,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
ubyte[8] range = [ 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xdd, 0xee ];
|
ubyte[8] range = [ 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xdd, 0xee ];
|
||||||
auto integer = Integer(Sign.positive, range[]);
|
auto integer = Integer(Sign.positive, range[]);
|
||||||
@ -187,7 +190,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
ubyte[8] range = [ 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xdd, 0xee ];
|
ubyte[8] range = [ 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xdd, 0xee ];
|
||||||
@ -204,17 +207,17 @@ struct Integer
|
|||||||
/**
|
/**
|
||||||
* Copies the integer.
|
* Copies the integer.
|
||||||
*/
|
*/
|
||||||
this(this) nothrow @trusted @nogc
|
this(this) @nogc nothrow pure @safe
|
||||||
{
|
{
|
||||||
auto tmp = allocator.resize!digit(null, this.size);
|
auto tmp = allocator.resize!digit(null, this.size);
|
||||||
this.rep[0 .. this.size].copy(tmp);
|
tanya.memory.op.copy(this.rep[0 .. this.size], tmp);
|
||||||
this.rep = tmp;
|
this.rep = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroys the integer.
|
* Destroys the integer.
|
||||||
*/
|
*/
|
||||||
~this() nothrow @trusted @nogc
|
~this() @nogc nothrow pure @safe
|
||||||
{
|
{
|
||||||
allocator.resize(this.rep, 0);
|
allocator.resize(this.rep, 0);
|
||||||
}
|
}
|
||||||
@ -224,7 +227,7 @@ struct Integer
|
|||||||
];
|
];
|
||||||
|
|
||||||
// Counts the number of LSBs before the first non-zero bit.
|
// Counts the number of LSBs before the first non-zero bit.
|
||||||
private ptrdiff_t countLSBs() const pure nothrow @safe @nogc
|
private ptrdiff_t countLSBs() const @nogc nothrow pure @safe
|
||||||
{
|
{
|
||||||
if (this.size == 0)
|
if (this.size == 0)
|
||||||
{
|
{
|
||||||
@ -256,7 +259,7 @@ struct Integer
|
|||||||
/**
|
/**
|
||||||
* Returns: Number of bytes in the two's complement representation.
|
* Returns: Number of bytes in the two's complement representation.
|
||||||
*/
|
*/
|
||||||
@property size_t length() const pure nothrow @safe @nogc
|
@property size_t length() const @nogc nothrow pure @safe
|
||||||
{
|
{
|
||||||
if (this.sign)
|
if (this.sign)
|
||||||
{
|
{
|
||||||
@ -280,7 +283,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
private nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
Integer i;
|
Integer i;
|
||||||
@ -336,11 +339,12 @@ struct Integer
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
ref Integer opAssign(T)(ref T value) @trusted
|
ref Integer opAssign(T)(ref T value)
|
||||||
if (is(Unqual!T == Integer))
|
if (is(Unqual!T == Integer))
|
||||||
{
|
{
|
||||||
this.rep = allocator.resize(this.rep, value.size);
|
this.rep = allocator.resize(this.rep, value.size);
|
||||||
value.rep[0 .. value.size].copy(this.rep[0 .. value.size]);
|
tanya.memory.op.copy(value.rep[0 .. value.size],
|
||||||
|
this.rep[0 .. value.size]);
|
||||||
this.size = value.size;
|
this.size = value.size;
|
||||||
this.sign = value.sign;
|
this.sign = value.sign;
|
||||||
|
|
||||||
@ -348,7 +352,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
ref Integer opAssign(T)(T value) nothrow @safe @nogc
|
ref Integer opAssign(T)(T value)
|
||||||
if (is(T == Integer))
|
if (is(T == Integer))
|
||||||
{
|
{
|
||||||
swap(this.rep, value.rep);
|
swap(this.rep, value.rep);
|
||||||
@ -389,11 +393,13 @@ struct Integer
|
|||||||
T opCast(T)() const
|
T opCast(T)() const
|
||||||
if (isIntegral!T && isSigned!T)
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
auto integer = Integer(79);
|
auto integer = Integer(79);
|
||||||
assert(cast(ushort) integer == 79);
|
assert(cast(ushort) integer == 79);
|
||||||
@ -424,7 +430,7 @@ struct Integer
|
|||||||
* Typically very fast. Also fixes the sign if there
|
* Typically very fast. Also fixes the sign if there
|
||||||
* are no more leading digits
|
* are no more leading digits
|
||||||
*/
|
*/
|
||||||
void contract() nothrow @safe @nogc
|
void contract() @nogc nothrow pure @safe
|
||||||
{
|
{
|
||||||
/* decrease size while the most significant digit is
|
/* decrease size while the most significant digit is
|
||||||
* zero.
|
* zero.
|
||||||
@ -441,7 +447,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void grow(const size_t size) nothrow @trusted @nogc
|
private void grow(const size_t size) @nogc nothrow pure @safe
|
||||||
{
|
{
|
||||||
if (this.rep.length >= size)
|
if (this.rep.length >= size)
|
||||||
{
|
{
|
||||||
@ -452,7 +458,7 @@ struct Integer
|
|||||||
this.rep[oldLength .. $].fill(digit.init);
|
this.rep[oldLength .. $].fill(digit.init);
|
||||||
}
|
}
|
||||||
|
|
||||||
private size_t countBits() const pure nothrow @safe @nogc
|
private size_t countBits() const @nogc nothrow pure @safe
|
||||||
{
|
{
|
||||||
if (this.size == 0)
|
if (this.size == 0)
|
||||||
{
|
{
|
||||||
@ -470,7 +476,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void add(ref const Integer summand, ref Integer sum)
|
private void add(ref const Integer summand, ref Integer sum)
|
||||||
const nothrow @safe @nogc
|
const @nogc nothrow pure @safe
|
||||||
{
|
{
|
||||||
const(digit)[] max, min;
|
const(digit)[] max, min;
|
||||||
|
|
||||||
@ -521,7 +527,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void add(const digit summand, ref Integer sum)
|
private void add(const digit summand, ref Integer sum)
|
||||||
const nothrow @safe @nogc
|
const @nogc nothrow pure @safe
|
||||||
{
|
{
|
||||||
sum.grow(this.size + 2);
|
sum.grow(this.size + 2);
|
||||||
|
|
||||||
@ -547,7 +553,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void subtract(ref const Integer subtrahend, ref Integer difference)
|
private void subtract(ref const Integer subtrahend, ref Integer difference)
|
||||||
const nothrow @safe @nogc
|
const @nogc nothrow pure @safe
|
||||||
{
|
{
|
||||||
difference.grow(this.size);
|
difference.grow(this.size);
|
||||||
|
|
||||||
@ -583,7 +589,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void subtract(const digit subtrahend, ref Integer difference)
|
private void subtract(const digit subtrahend, ref Integer difference)
|
||||||
const nothrow @safe @nogc
|
const @nogc nothrow pure @safe
|
||||||
{
|
{
|
||||||
difference.grow(this.size);
|
difference.grow(this.size);
|
||||||
|
|
||||||
@ -612,7 +618,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compare the magnitude.
|
// Compare the magnitude.
|
||||||
private int compare(ref const Integer that) const pure nothrow @safe @nogc
|
private int compare(ref const Integer that) const @nogc nothrow pure @safe
|
||||||
{
|
{
|
||||||
if (this.size > that.size)
|
if (this.size > that.size)
|
||||||
{
|
{
|
||||||
@ -661,7 +667,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
auto integer1 = Integer(1019);
|
auto integer1 = Integer(1019);
|
||||||
auto integer2 = Integer(1019);
|
auto integer2 = Integer(1019);
|
||||||
@ -707,7 +713,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
auto integer = Integer(1019);
|
auto integer = Integer(1019);
|
||||||
|
|
||||||
@ -731,7 +737,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
auto integer = Integer(1019);
|
auto integer = Integer(1019);
|
||||||
|
|
||||||
@ -767,7 +773,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
auto h1 = Integer(1019);
|
auto h1 = Integer(1019);
|
||||||
@ -809,7 +815,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
auto h1 = Integer(3);
|
auto h1 = Integer(3);
|
||||||
@ -853,7 +859,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
auto h1 = Integer(123);
|
auto h1 = Integer(123);
|
||||||
auto h2 = Integer(456);
|
auto h2 = Integer(456);
|
||||||
@ -885,7 +891,7 @@ struct Integer
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
auto h1 = Integer(18);
|
auto h1 = Integer(18);
|
||||||
auto h2 = Integer(4);
|
auto h2 = Integer(4);
|
||||||
@ -937,7 +943,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
auto integer = Integer(4294967294);
|
auto integer = Integer(4294967294);
|
||||||
integer >>= 10;
|
integer >>= 10;
|
||||||
@ -1005,7 +1011,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
auto integer = Integer(4294967295);
|
auto integer = Integer(4294967295);
|
||||||
integer <<= 1;
|
integer <<= 1;
|
||||||
@ -1023,7 +1029,10 @@ struct Integer
|
|||||||
Integer opUnary(string op : "~")() const
|
Integer opUnary(string op : "~")() const
|
||||||
{
|
{
|
||||||
auto ret = Integer(this, allocator);
|
auto ret = Integer(this, allocator);
|
||||||
ret.rep[0 .. ret.size].each!((ref a) => a = ~a & mask);
|
foreach (ref a; ret.rep[0 .. ret.size])
|
||||||
|
{
|
||||||
|
a = ~a & mask;
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1049,7 +1058,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
auto h1 = Integer(79);
|
auto h1 = Integer(79);
|
||||||
Integer h2;
|
Integer h2;
|
||||||
@ -1065,7 +1074,7 @@ struct Integer
|
|||||||
assert(h1 == 79);
|
assert(h1 == 79);
|
||||||
|
|
||||||
h2 = ~h1;
|
h2 = ~h1;
|
||||||
assert(h2 == ~cast(ubyte) 79);
|
assert(h2 == cast(ubyte) ~79);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
@ -1102,7 +1111,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
Integer integer;
|
Integer integer;
|
||||||
|
|
||||||
@ -1172,7 +1181,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Shift right a certain amount of digits.
|
// Shift right a certain amount of digits.
|
||||||
private void shiftRight(const size_t operand) nothrow @safe @nogc
|
private void shiftRight(const size_t operand) @nogc nothrow pure @safe
|
||||||
{
|
{
|
||||||
if (operand == 0)
|
if (operand == 0)
|
||||||
{
|
{
|
||||||
@ -1191,7 +1200,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Shift left a certain amount of digits.
|
// Shift left a certain amount of digits.
|
||||||
private void shiftLeft(const size_t operand) nothrow @safe @nogc
|
private void shiftLeft(const size_t operand) @nogc nothrow pure @safe
|
||||||
{
|
{
|
||||||
if (operand == 0)
|
if (operand == 0)
|
||||||
{
|
{
|
||||||
@ -1213,7 +1222,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void multiply(const digit factor, ref Integer product)
|
private void multiply(const digit factor, ref Integer product)
|
||||||
const nothrow @safe @nogc
|
const @nogc nothrow pure @safe
|
||||||
{
|
{
|
||||||
product.grow(this.size + 1);
|
product.grow(this.size + 1);
|
||||||
product.sign = this.sign;
|
product.sign = this.sign;
|
||||||
@ -1239,7 +1248,7 @@ struct Integer
|
|||||||
|
|
||||||
private void multiply(ref const Integer factor,
|
private void multiply(ref const Integer factor,
|
||||||
ref Integer product,
|
ref Integer product,
|
||||||
const size_t digits) const nothrow @safe @nogc
|
const size_t digits) const @nogc nothrow pure @safe
|
||||||
{
|
{
|
||||||
Integer intermediate;
|
Integer intermediate;
|
||||||
intermediate.grow(digits);
|
intermediate.grow(digits);
|
||||||
@ -1270,8 +1279,7 @@ struct Integer
|
|||||||
|
|
||||||
private void divide(Q, ARGS...)(ref const Integer divisor,
|
private void divide(Q, ARGS...)(ref const Integer divisor,
|
||||||
auto ref Q quotient,
|
auto ref Q quotient,
|
||||||
ref ARGS args)
|
ref ARGS args) const
|
||||||
const nothrow @safe @nogc
|
|
||||||
if ((is(Q : typeof(null))
|
if ((is(Q : typeof(null))
|
||||||
|| (is(Q : Integer) && __traits(isRef, quotient)))
|
|| (is(Q : Integer) && __traits(isRef, quotient)))
|
||||||
&& (ARGS.length == 0 || (ARGS.length == 1 && is(ARGS[0] : Integer))))
|
&& (ARGS.length == 0 || (ARGS.length == 1 && is(ARGS[0] : Integer))))
|
||||||
@ -1404,7 +1412,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Integer square() nothrow @safe @nogc
|
private Integer square() @nogc nothrow pure @safe
|
||||||
{
|
{
|
||||||
Integer result;
|
Integer result;
|
||||||
const resultSize = 2 * this.size + 1;
|
const resultSize = 2 * this.size + 1;
|
||||||
@ -1444,7 +1452,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns 2^^n.
|
// Returns 2^^n.
|
||||||
private Integer exp2(size_t n) const nothrow @safe @nogc
|
private Integer exp2(size_t n) const @nogc nothrow pure @safe
|
||||||
{
|
{
|
||||||
auto ret = Integer(allocator);
|
auto ret = Integer(allocator);
|
||||||
const bytes = n / digitBitCount;
|
const bytes = n / digitBitCount;
|
||||||
@ -1459,7 +1467,7 @@ struct Integer
|
|||||||
/**
|
/**
|
||||||
* Returns: Two's complement representation of the integer.
|
* Returns: Two's complement representation of the integer.
|
||||||
*/
|
*/
|
||||||
Array!ubyte toArray() const nothrow @safe @nogc
|
Array!ubyte toArray() const @nogc nothrow pure @safe
|
||||||
out (array)
|
out (array)
|
||||||
{
|
{
|
||||||
assert(array.length == length);
|
assert(array.length == length);
|
||||||
@ -1512,7 +1520,7 @@ struct Integer
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
auto integer = Integer(0x66778899aabbddee);
|
auto integer = Integer(0x66778899aabbddee);
|
||||||
@ -1521,6 +1529,14 @@ struct Integer
|
|||||||
auto array = integer.toArray();
|
auto array = integer.toArray();
|
||||||
assert(equal(array[], expected[]));
|
assert(equal(array[], expected[]));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
{
|
||||||
|
Integer integer;
|
||||||
|
assert(integer.toArray().length == 0);
|
||||||
|
}
|
||||||
{
|
{
|
||||||
auto integer = Integer(0x03);
|
auto integer = Integer(0x03);
|
||||||
ubyte[1] expected = [ 0x03 ];
|
ubyte[1] expected = [ 0x03 ];
|
||||||
|
@ -21,9 +21,11 @@
|
|||||||
*/
|
*/
|
||||||
module tanya.math;
|
module tanya.math;
|
||||||
|
|
||||||
|
import tanya.algorithm.mutation;
|
||||||
import tanya.math.mp;
|
import tanya.math.mp;
|
||||||
import tanya.math.nbtheory;
|
import tanya.math.nbtheory;
|
||||||
import tanya.meta.trait;
|
import tanya.meta.trait;
|
||||||
|
import tanya.meta.transform;
|
||||||
|
|
||||||
/// Floating-point number precisions according to IEEE-754.
|
/// Floating-point number precisions according to IEEE-754.
|
||||||
enum IEEEPrecision : ubyte
|
enum IEEEPrecision : ubyte
|
||||||
@ -79,7 +81,7 @@ if (isFloatingPoint!F)
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
pure nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
static assert(ieeePrecision!float == IEEEPrecision.single);
|
static assert(ieeePrecision!float == IEEEPrecision.single);
|
||||||
static assert(ieeePrecision!double == IEEEPrecision.double_);
|
static assert(ieeePrecision!double == IEEEPrecision.double_);
|
||||||
@ -231,7 +233,7 @@ if (isFloatingPoint!F)
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
pure nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
assert(classify(0.0) == FloatingPointClass.zero);
|
assert(classify(0.0) == FloatingPointClass.zero);
|
||||||
assert(classify(double.nan) == FloatingPointClass.nan);
|
assert(classify(double.nan) == FloatingPointClass.nan);
|
||||||
@ -253,7 +255,7 @@ pure nothrow @safe @nogc unittest
|
|||||||
assert(classify(-real.infinity) == FloatingPointClass.infinite);
|
assert(classify(-real.infinity) == FloatingPointClass.infinite);
|
||||||
}
|
}
|
||||||
|
|
||||||
private pure nothrow @nogc @safe unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
static if (ieeePrecision!float == IEEEPrecision.doubleExtended)
|
static if (ieeePrecision!float == IEEEPrecision.doubleExtended)
|
||||||
{
|
{
|
||||||
@ -300,7 +302,7 @@ if (isFloatingPoint!F)
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
pure nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
assert(!isFinite(float.infinity));
|
assert(!isFinite(float.infinity));
|
||||||
assert(!isFinite(-double.infinity));
|
assert(!isFinite(-double.infinity));
|
||||||
@ -345,7 +347,7 @@ if (isFloatingPoint!F)
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
pure nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
assert(isNaN(float.init));
|
assert(isNaN(float.init));
|
||||||
assert(isNaN(double.init));
|
assert(isNaN(double.init));
|
||||||
@ -382,7 +384,7 @@ if (isFloatingPoint!F)
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
pure nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
assert(isInfinity(float.infinity));
|
assert(isInfinity(float.infinity));
|
||||||
assert(isInfinity(-float.infinity));
|
assert(isInfinity(-float.infinity));
|
||||||
@ -436,7 +438,7 @@ if (isFloatingPoint!F)
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
pure nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
assert(!isSubnormal(0.0f));
|
assert(!isSubnormal(0.0f));
|
||||||
assert(!isSubnormal(float.nan));
|
assert(!isSubnormal(float.nan));
|
||||||
@ -496,7 +498,7 @@ if (isFloatingPoint!F)
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
pure nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
assert(!isNormal(0.0f));
|
assert(!isNormal(0.0f));
|
||||||
assert(!isNormal(float.nan));
|
assert(!isNormal(float.nan));
|
||||||
@ -547,7 +549,7 @@ if (isFloatingPoint!F)
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
pure nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
assert(signBit(-1.0f));
|
assert(signBit(-1.0f));
|
||||||
assert(!signBit(1.0f));
|
assert(!signBit(1.0f));
|
||||||
@ -659,7 +661,7 @@ body
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
pure nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
assert(pow(3, 5, 7) == 5);
|
assert(pow(3, 5, 7) == 5);
|
||||||
assert(pow(2, 2, 1) == 0);
|
assert(pow(2, 2, 1) == 0);
|
||||||
@ -673,7 +675,7 @@ pure nothrow @safe @nogc unittest
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
assert(pow(Integer(3), Integer(5), Integer(7)) == 5);
|
assert(pow(Integer(3), Integer(5), Integer(7)) == 5);
|
||||||
assert(pow(Integer(2), Integer(2), Integer(1)) == 0);
|
assert(pow(Integer(2), Integer(2), Integer(1)) == 0);
|
||||||
@ -695,13 +697,13 @@ nothrow @safe @nogc unittest
|
|||||||
* Returns: $(D_KEYWORD true) if $(D_PARAM x) is a prime number,
|
* Returns: $(D_KEYWORD true) if $(D_PARAM x) is a prime number,
|
||||||
* $(D_KEYWORD false) otherwise.
|
* $(D_KEYWORD false) otherwise.
|
||||||
*/
|
*/
|
||||||
bool isPseudoprime(ulong x) nothrow pure @safe @nogc
|
bool isPseudoprime(ulong x) @nogc nothrow pure @safe
|
||||||
{
|
{
|
||||||
return pow(2, x - 1, x) == 1;
|
return pow(2, x - 1, x) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
pure nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
assert(74623.isPseudoprime);
|
assert(74623.isPseudoprime);
|
||||||
assert(104729.isPseudoprime);
|
assert(104729.isPseudoprime);
|
||||||
@ -709,7 +711,7 @@ pure nothrow @safe @nogc unittest
|
|||||||
assert(!15485868.isPseudoprime);
|
assert(!15485868.isPseudoprime);
|
||||||
}
|
}
|
||||||
|
|
||||||
private pure nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
assert(74653.isPseudoprime);
|
assert(74653.isPseudoprime);
|
||||||
assert(74687.isPseudoprime);
|
assert(74687.isPseudoprime);
|
||||||
@ -738,3 +740,158 @@ private pure nothrow @safe @nogc unittest
|
|||||||
assert(899809363.isPseudoprime);
|
assert(899809363.isPseudoprime);
|
||||||
assert(982451653.isPseudoprime);
|
assert(982451653.isPseudoprime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines minimum of two numbers.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* x = First number.
|
||||||
|
* y = Second number.
|
||||||
|
*
|
||||||
|
* Returns: $(D_PARAM x) if $(D_PARAM x) is smaller than $(D_PSYMBOL y),
|
||||||
|
* $(D_PARAM y) otherwise.
|
||||||
|
*
|
||||||
|
* See_Also: $(D_PSYMBOL max).
|
||||||
|
*/
|
||||||
|
T min(T)(T x, T y)
|
||||||
|
if (isIntegral!T)
|
||||||
|
{
|
||||||
|
return x < y ? x : y;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
assert(min(5, 3) == 3);
|
||||||
|
assert(min(4, 4) == 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ditto
|
||||||
|
T min(T)(T x, T y)
|
||||||
|
if (isFloatingPoint!T)
|
||||||
|
{
|
||||||
|
if (isNaN(x))
|
||||||
|
{
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
if (isNaN(y))
|
||||||
|
{
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
return x < y ? x : y;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
assert(min(5.2, 3.0) == 3.0);
|
||||||
|
|
||||||
|
assert(min(5.2, double.nan) == 5.2);
|
||||||
|
assert(min(double.nan, 3.0) == 3.0);
|
||||||
|
assert(isNaN(min(double.nan, double.nan)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ditto
|
||||||
|
ref T min(T)(ref T x, ref T y)
|
||||||
|
if (is(Unqual!T == Integer))
|
||||||
|
{
|
||||||
|
return x < y ? x : y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ditto
|
||||||
|
T min(T)(T x, T y)
|
||||||
|
if (is(T == Integer))
|
||||||
|
{
|
||||||
|
return x < y ? move(x) : move(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
assert(min(Integer(5), Integer(3)) == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines maximum of two numbers.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* x = First number.
|
||||||
|
* y = Second number.
|
||||||
|
*
|
||||||
|
* Returns: $(D_PARAM x) if $(D_PARAM x) is larger than $(D_PSYMBOL y),
|
||||||
|
* $(D_PARAM y) otherwise.
|
||||||
|
*
|
||||||
|
* See_Also: $(D_PSYMBOL min).
|
||||||
|
*/
|
||||||
|
T max(T)(T x, T y)
|
||||||
|
if (isIntegral!T)
|
||||||
|
{
|
||||||
|
return x > y ? x : y;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
assert(max(5, 3) == 5);
|
||||||
|
assert(max(4, 4) == 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ditto
|
||||||
|
T max(T)(T x, T y)
|
||||||
|
if (isFloatingPoint!T)
|
||||||
|
{
|
||||||
|
if (isNaN(x))
|
||||||
|
{
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
if (isNaN(y))
|
||||||
|
{
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
return x > y ? x : y;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
assert(max(5.2, 3.0) == 5.2);
|
||||||
|
|
||||||
|
assert(max(5.2, double.nan) == 5.2);
|
||||||
|
assert(max(double.nan, 3.0) == 3.0);
|
||||||
|
assert(isNaN(max(double.nan, double.nan)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ditto
|
||||||
|
ref T max(T)(ref T x, ref T y)
|
||||||
|
if (is(Unqual!T == Integer))
|
||||||
|
{
|
||||||
|
return x > y ? x : y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ditto
|
||||||
|
T max(T)(T x, T y)
|
||||||
|
if (is(T == Integer))
|
||||||
|
{
|
||||||
|
return x > y ? move(x) : move(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
assert(max(Integer(5), Integer(3)) == 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// min/max accept const and mutable references.
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
{
|
||||||
|
Integer i1 = 5, i2 = 3;
|
||||||
|
assert(min(i1, i2) == 3);
|
||||||
|
assert(max(i1, i2) == 5);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const Integer i1 = 5, i2 = 3;
|
||||||
|
assert(min(i1, i2) == 3);
|
||||||
|
assert(max(i1, i2) == 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -51,10 +51,12 @@ private enum alignMask = size_t.sizeof - 1;
|
|||||||
*
|
*
|
||||||
* Precondition: $(D_INLINECODE source.length <= target.length).
|
* Precondition: $(D_INLINECODE source.length <= target.length).
|
||||||
*/
|
*/
|
||||||
void copy(const void[] source, void[] target) pure nothrow @trusted @nogc
|
void copy(const void[] source, void[] target) @nogc nothrow pure @trusted
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(source.length <= target.length);
|
assert(source.length <= target.length);
|
||||||
|
assert(source.length == 0 || source.ptr !is null);
|
||||||
|
assert(target.length == 0 || target.ptr !is null);
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
@ -69,7 +71,7 @@ body
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
pure nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
ubyte[9] source = [1, 2, 3, 4, 5, 6, 7, 8, 9];
|
ubyte[9] source = [1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||||
ubyte[9] target;
|
ubyte[9] target;
|
||||||
@ -77,7 +79,7 @@ pure nothrow @safe @nogc unittest
|
|||||||
assert(cmp(source, target) == 0);
|
assert(cmp(source, target) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private pure nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
ubyte[0] source, target;
|
ubyte[0] source, target;
|
||||||
@ -120,6 +122,11 @@ private template filledBytes(ubyte Byte, ubyte I = 0)
|
|||||||
* memory = Memory block.
|
* memory = Memory block.
|
||||||
*/
|
*/
|
||||||
void fill(ubyte c = 0)(void[] memory) @trusted
|
void fill(ubyte c = 0)(void[] memory) @trusted
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(memory.length == 0 || memory.ptr !is null);
|
||||||
|
}
|
||||||
|
body
|
||||||
{
|
{
|
||||||
version (TanyaNative)
|
version (TanyaNative)
|
||||||
{
|
{
|
||||||
@ -132,7 +139,7 @@ void fill(ubyte c = 0)(void[] memory) @trusted
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
pure nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
ubyte[9] memory = [1, 2, 3, 4, 5, 6, 7, 8, 9];
|
ubyte[9] memory = [1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||||
memory.fill!0();
|
memory.fill!0();
|
||||||
@ -144,7 +151,7 @@ pure nothrow @safe @nogc unittest
|
|||||||
|
|
||||||
// Stress test. Checks that `fill` can handle unaligned pointers and different
|
// Stress test. Checks that `fill` can handle unaligned pointers and different
|
||||||
// lengths.
|
// lengths.
|
||||||
pure nothrow @safe @nogc private unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
ubyte[192] memory;
|
ubyte[192] memory;
|
||||||
|
|
||||||
@ -189,10 +196,12 @@ pure nothrow @safe @nogc private unittest
|
|||||||
*
|
*
|
||||||
* Precondition: $(D_INLINECODE source.length <= target.length).
|
* Precondition: $(D_INLINECODE source.length <= target.length).
|
||||||
*/
|
*/
|
||||||
void copyBackward(const void[] source, void[] target) pure nothrow @trusted @nogc
|
void copyBackward(const void[] source, void[] target) @nogc nothrow pure @trusted
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(source.length <= target.length);
|
assert(source.length <= target.length);
|
||||||
|
assert(source.length == 0 || source.ptr !is null);
|
||||||
|
assert(target.length == 0 || target.ptr !is null);
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
@ -207,7 +216,7 @@ body
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
pure nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
ubyte[6] mem = [ 'a', 'a', 'b', 'b', 'c', 'c' ];
|
ubyte[6] mem = [ 'a', 'a', 'b', 'b', 'c', 'c' ];
|
||||||
ubyte[6] expected = [ 'a', 'a', 'a', 'a', 'b', 'b' ];
|
ubyte[6] expected = [ 'a', 'a', 'a', 'a', 'b', 'b' ];
|
||||||
@ -216,7 +225,7 @@ pure nothrow @safe @nogc unittest
|
|||||||
assert(cmp(expected, mem) == 0);
|
assert(cmp(expected, mem) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
ubyte[9] r1 = [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i' ];
|
ubyte[9] r1 = [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i' ];
|
||||||
ubyte[9] r2;
|
ubyte[9] r2;
|
||||||
@ -242,7 +251,13 @@ private nothrow @safe @nogc unittest
|
|||||||
* negative integer if $(D_INLINECODE r2 > r1),
|
* negative integer if $(D_INLINECODE r2 > r1),
|
||||||
* `0` if $(D_INLINECODE r1 == r2).
|
* `0` if $(D_INLINECODE r1 == r2).
|
||||||
*/
|
*/
|
||||||
int cmp(const void[] r1, const void[] r2) pure nothrow @trusted @nogc
|
int cmp(const void[] r1, const void[] r2) @nogc nothrow pure @trusted
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(r1.length == 0 || r1.ptr !is null);
|
||||||
|
assert(r2.length == 0 || r2.ptr !is null);
|
||||||
|
}
|
||||||
|
body
|
||||||
{
|
{
|
||||||
version (TanyaNative)
|
version (TanyaNative)
|
||||||
{
|
{
|
||||||
@ -259,7 +274,7 @@ int cmp(const void[] r1, const void[] r2) pure nothrow @trusted @nogc
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
pure nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
ubyte[4] r1 = [ 'a', 'b', 'c', 'd' ];
|
ubyte[4] r1 = [ 'a', 'b', 'c', 'd' ];
|
||||||
ubyte[3] r2 = [ 'c', 'a', 'b' ];
|
ubyte[3] r2 = [ 'c', 'a', 'b' ];
|
||||||
@ -271,7 +286,7 @@ pure nothrow @safe @nogc unittest
|
|||||||
assert(cmp(r2, r1) < 0);
|
assert(cmp(r2, r1) < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private pure nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
ubyte[16] r1 = [
|
ubyte[16] r1 = [
|
||||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
|
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
|
||||||
@ -301,7 +316,12 @@ private pure nothrow @safe @nogc unittest
|
|||||||
* couldn't be found, an empty `inout void[]` is returned.
|
* couldn't be found, an empty `inout void[]` is returned.
|
||||||
*/
|
*/
|
||||||
inout(void[]) find(return inout void[] haystack, const ubyte needle)
|
inout(void[]) find(return inout void[] haystack, const ubyte needle)
|
||||||
pure nothrow @trusted @nogc
|
@nogc nothrow pure @trusted
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert(haystack.length == 0 || haystack.ptr !is null);
|
||||||
|
}
|
||||||
|
body
|
||||||
{
|
{
|
||||||
auto length = haystack.length;
|
auto length = haystack.length;
|
||||||
const size_t needleWord = size_t.max * needle;
|
const size_t needleWord = size_t.max * needle;
|
||||||
@ -348,7 +368,7 @@ pure nothrow @trusted @nogc
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
pure nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
const ubyte[9] haystack = ['a', 'b', 'c', 'd', 'e', 'f', 'b', 'g', 'h'];
|
const ubyte[9] haystack = ['a', 'b', 'c', 'd', 'e', 'f', 'b', 'g', 'h'];
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
module tanya.memory.smartref;
|
module tanya.memory.smartref;
|
||||||
|
|
||||||
import std.algorithm.comparison;
|
import std.algorithm.comparison;
|
||||||
import std.algorithm.mutation;
|
import tanya.algorithm.mutation;
|
||||||
import tanya.conv;
|
import tanya.conv;
|
||||||
import tanya.exception;
|
import tanya.exception;
|
||||||
import tanya.memory;
|
import tanya.memory;
|
||||||
@ -611,7 +611,7 @@ body
|
|||||||
|
|
||||||
@nogc @system unittest
|
@nogc @system unittest
|
||||||
{
|
{
|
||||||
static bool destroyed = false;
|
static bool destroyed;
|
||||||
|
|
||||||
static struct F
|
static struct F
|
||||||
{
|
{
|
||||||
@ -812,7 +812,7 @@ struct Unique(T)
|
|||||||
///
|
///
|
||||||
@nogc nothrow @system unittest
|
@nogc nothrow @system unittest
|
||||||
{
|
{
|
||||||
static bool destroyed = false;
|
static bool destroyed;
|
||||||
|
|
||||||
static struct F
|
static struct F
|
||||||
{
|
{
|
||||||
|
@ -275,13 +275,37 @@ enum bool isTemplate(alias T) = __traits(isTemplate, T);
|
|||||||
static assert(!isTemplate!(S!int));
|
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);
|
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);
|
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);
|
enum bool isStruct(T) = is(T == struct);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1758,6 +1782,10 @@ template isMutable(T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Determines whether $(D_PARAM T) is a nested type, i.e. $(D_KEYWORD class),
|
||||||
|
* $(D_KEYWORD struct) or $(D_KEYWORD union), which internally stores a context
|
||||||
|
* pointer.
|
||||||
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* T = $(D_KEYWORD class), $(D_KEYWORD struct) or $(D_KEYWORD union) type.
|
* T = $(D_KEYWORD class), $(D_KEYWORD struct) or $(D_KEYWORD union) type.
|
||||||
*
|
*
|
||||||
@ -1788,6 +1816,8 @@ pure nothrow @safe unittest
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Determines whether $(D_PARAM T) is a nested function.
|
||||||
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* F = A function.
|
* F = A function.
|
||||||
*
|
*
|
||||||
@ -1809,6 +1839,8 @@ enum bool isNestedFunction(alias F) = __traits(isNested, F);
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Determines the type of the callable $(D_PARAM F).
|
||||||
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* F = A function.
|
* F = A function.
|
||||||
*
|
*
|
||||||
@ -1898,6 +1930,8 @@ if (isCallable!F)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Determines the return type of the callable $(D_PARAM F).
|
||||||
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* F = A callable object.
|
* F = A callable object.
|
||||||
*
|
*
|
||||||
@ -3055,3 +3089,60 @@ template isInnerClass(T)
|
|||||||
}
|
}
|
||||||
static assert(!isInnerClass!(RefCountedStore!int));
|
static assert(!isInnerClass!(RefCountedStore!int));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the types of all members of $(D_PARAM T).
|
||||||
|
*
|
||||||
|
* If $(D_PARAM T) is a $(D_KEYWORD struct) or $(D_KEYWORD union) or
|
||||||
|
* $(D_KEYWORD class), returns the types of all its fields. It is actually the
|
||||||
|
* same as `T.tupleof`, but the content pointer for the nested type isn't
|
||||||
|
* included.
|
||||||
|
*
|
||||||
|
* If $(D_PARAM T) is neither a $(D_KEYWORD struct) nor $(D_KEYWORD union) nor
|
||||||
|
* $(D_KEYWORD class), $(D_PSYMBOL Fields) returns an $(D_PSYMBOL AliasSeq)
|
||||||
|
* with the single element $(D_PARAM T).
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* T = A type.
|
||||||
|
*
|
||||||
|
* Returns: $(D_PARAM T)'s fields.
|
||||||
|
*/
|
||||||
|
template Fields(T)
|
||||||
|
{
|
||||||
|
static if ((is(T == struct) || is(T == union)) && isNested!T)
|
||||||
|
{
|
||||||
|
// The last element of .tupleof of a nested struct or union is "this",
|
||||||
|
// the context pointer, type "void*".
|
||||||
|
alias Fields = typeof(T.tupleof[0 .. $ - 1]);
|
||||||
|
}
|
||||||
|
else static if (is(T == class) || is(T == struct) || is(T == union))
|
||||||
|
{
|
||||||
|
alias Fields = typeof(T.tupleof);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
alias Fields = AliasSeq!T;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
@nogc nothrow pure @safe unittest
|
||||||
|
{
|
||||||
|
struct Nested
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
void func()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static assert(is(Fields!Nested == AliasSeq!int));
|
||||||
|
|
||||||
|
class C
|
||||||
|
{
|
||||||
|
uint u;
|
||||||
|
}
|
||||||
|
static assert(is(Fields!C == AliasSeq!uint));
|
||||||
|
|
||||||
|
static assert(is(Fields!short == AliasSeq!short));
|
||||||
|
}
|
||||||
|
@ -65,7 +65,7 @@ body
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
pure nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
string s = "Wenn die Wunde nicht mehr wehtut, schmerzt die Narbe";
|
string s = "Wenn die Wunde nicht mehr wehtut, schmerzt die Narbe";
|
||||||
static assert(is(typeof(s.front) == immutable char));
|
static assert(is(typeof(s.front) == immutable char));
|
||||||
@ -105,7 +105,7 @@ body
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
pure nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
string s = "Brecht";
|
string s = "Brecht";
|
||||||
static assert(is(typeof(s.back) == immutable char));
|
static assert(is(typeof(s.back) == immutable char));
|
||||||
@ -155,7 +155,7 @@ body
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
pure nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
wstring array = "Der finstere Ozean der Metaphysik. Nietzsche";
|
wstring array = "Der finstere Ozean der Metaphysik. Nietzsche";
|
||||||
|
|
||||||
@ -184,7 +184,7 @@ pure nothrow @safe @nogc unittest
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
pure nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
int[1] array;
|
int[1] array;
|
||||||
assert(!array.empty);
|
assert(!array.empty);
|
||||||
@ -209,7 +209,7 @@ pure nothrow @safe @nogc unittest
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
pure nothrow @safe @nogc unittest
|
@nogc nothrow pure @safe unittest
|
||||||
{
|
{
|
||||||
ubyte[8] array;
|
ubyte[8] array;
|
||||||
auto slice = array.save;
|
auto slice = array.save;
|
||||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user