Remove resizeArray alias
This commit is contained in:
parent
d0ada39fa7
commit
b90c56395c
@ -8,8 +8,8 @@
|
|||||||
* Copyright: Eugene Wissner 2016.
|
* Copyright: Eugene Wissner 2016.
|
||||||
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
|
||||||
* Mozilla Public License, v. 2.0).
|
* Mozilla Public License, v. 2.0).
|
||||||
* Authors: $(LINK2 mailto:belka@caraus.de, Eugene Wissner)
|
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
|
||||||
*/
|
*/
|
||||||
module tanya.math.random;
|
module tanya.math.random;
|
||||||
|
|
||||||
import std.digest.sha;
|
import std.digest.sha;
|
||||||
@ -27,20 +27,20 @@ enum maxGather = 128;
|
|||||||
*/
|
*/
|
||||||
class EntropyException : Exception
|
class EntropyException : Exception
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Params:
|
* Params:
|
||||||
* msg = Message to output.
|
* msg = Message to output.
|
||||||
* file = The file where the exception occurred.
|
* file = The file where the exception occurred.
|
||||||
* line = The line number where the exception occurred.
|
* line = The line number where the exception occurred.
|
||||||
* next = The previous exception in the chain of exceptions, if any.
|
* next = The previous exception in the chain of exceptions, if any.
|
||||||
*/
|
*/
|
||||||
this(string msg,
|
this(string msg,
|
||||||
string file = __FILE__,
|
string file = __FILE__,
|
||||||
size_t line = __LINE__,
|
size_t line = __LINE__,
|
||||||
Throwable next = null) pure @safe nothrow const @nogc
|
Throwable next = null) pure @safe nothrow const @nogc
|
||||||
{
|
{
|
||||||
super(msg, file, line, next);
|
super(msg, file, line, next);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -48,103 +48,103 @@ class EntropyException : Exception
|
|||||||
*/
|
*/
|
||||||
abstract class EntropySource
|
abstract class EntropySource
|
||||||
{
|
{
|
||||||
/// Amount of already generated entropy.
|
/// Amount of already generated entropy.
|
||||||
protected ushort size_;
|
protected ushort size_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns: Minimum bytes required from the entropy source.
|
* Returns: Minimum bytes required from the entropy source.
|
||||||
*/
|
*/
|
||||||
@property immutable(ubyte) threshold() const @safe pure nothrow;
|
@property immutable(ubyte) threshold() const @safe pure nothrow;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns: Whether this entropy source is strong.
|
* Returns: Whether this entropy source is strong.
|
||||||
*/
|
*/
|
||||||
@property immutable(bool) strong() const @safe pure nothrow;
|
@property immutable(bool) strong() const @safe pure nothrow;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns: Amount of already generated entropy.
|
* Returns: Amount of already generated entropy.
|
||||||
*/
|
*/
|
||||||
@property ushort size() const @safe pure nothrow
|
@property ushort size() const @safe pure nothrow
|
||||||
{
|
{
|
||||||
return size_;
|
return size_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Params:
|
* Params:
|
||||||
* size = Amount of already generated entropy. Cannot be smaller than the
|
* size = Amount of already generated entropy. Cannot be smaller than the
|
||||||
* already set value.
|
* already set value.
|
||||||
*/
|
*/
|
||||||
@property void size(ushort size) @safe pure nothrow
|
@property void size(ushort size) @safe pure nothrow
|
||||||
{
|
{
|
||||||
size_ = size;
|
size_ = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Poll the entropy source.
|
* Poll the entropy source.
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* output = Buffer to save the generate random sequence (the method will
|
* output = Buffer to save the generate random sequence (the method will
|
||||||
* to fill the buffer).
|
* to fill the buffer).
|
||||||
*
|
*
|
||||||
* Returns: Number of bytes that were copied to the $(D_PARAM output)
|
* Returns: Number of bytes that were copied to the $(D_PARAM output)
|
||||||
* or $(D_PSYMBOL Nullable!ubyte.init) on error.
|
* or $(D_PSYMBOL Nullable!ubyte.init) on error.
|
||||||
*/
|
*/
|
||||||
Nullable!ubyte poll(out ubyte[maxGather] output);
|
Nullable!ubyte poll(out ubyte[maxGather] output);
|
||||||
}
|
}
|
||||||
|
|
||||||
version (linux)
|
version (linux)
|
||||||
{
|
{
|
||||||
extern (C) long syscall(long number, ...) nothrow;
|
extern (C) long syscall(long number, ...) nothrow;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uses getrandom system call.
|
* Uses getrandom system call.
|
||||||
*/
|
*/
|
||||||
class PlatformEntropySource : EntropySource
|
class PlatformEntropySource : EntropySource
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Returns: Minimum bytes required from the entropy source.
|
* Returns: Minimum bytes required from the entropy source.
|
||||||
*/
|
*/
|
||||||
override @property immutable(ubyte) threshold() const @safe pure nothrow
|
override @property immutable(ubyte) threshold() const @safe pure nothrow
|
||||||
{
|
{
|
||||||
return 32;
|
return 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns: Whether this entropy source is strong.
|
* Returns: Whether this entropy source is strong.
|
||||||
*/
|
*/
|
||||||
override @property immutable(bool) strong() const @safe pure nothrow
|
override @property immutable(bool) strong() const @safe pure nothrow
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Poll the entropy source.
|
* Poll the entropy source.
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* output = Buffer to save the generate random sequence (the method will
|
* output = Buffer to save the generate random sequence (the method will
|
||||||
* to fill the buffer).
|
* to fill the buffer).
|
||||||
*
|
*
|
||||||
* Returns: Number of bytes that were copied to the $(D_PARAM output)
|
* Returns: Number of bytes that were copied to the $(D_PARAM output)
|
||||||
* or $(D_PSYMBOL Nullable!ubyte.init) on error.
|
* or $(D_PSYMBOL Nullable!ubyte.init) on error.
|
||||||
*/
|
*/
|
||||||
override Nullable!ubyte poll(out ubyte[maxGather] output) nothrow
|
override Nullable!ubyte poll(out ubyte[maxGather] output) nothrow
|
||||||
out (length)
|
out (length)
|
||||||
{
|
{
|
||||||
assert(length <= maxGather);
|
assert(length <= maxGather);
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
// int getrandom(void *buf, size_t buflen, unsigned int flags);
|
// int getrandom(void *buf, size_t buflen, unsigned int flags);
|
||||||
auto length = syscall(318, output.ptr, output.length, 0);
|
auto length = syscall(318, output.ptr, output.length, 0);
|
||||||
Nullable!ubyte ret;
|
Nullable!ubyte ret;
|
||||||
|
|
||||||
if (length >= 0)
|
if (length >= 0)
|
||||||
{
|
{
|
||||||
ret = cast(ubyte) length;
|
ret = cast(ubyte) length;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -156,165 +156,165 @@ version (linux)
|
|||||||
*
|
*
|
||||||
* output = entropy.random;
|
* output = entropy.random;
|
||||||
*
|
*
|
||||||
* defaultAllocator.finalize(entropy);
|
* defaultAllocator.dispose(entropy);
|
||||||
* ---
|
* ---
|
||||||
*/
|
*/
|
||||||
class Entropy
|
class Entropy
|
||||||
{
|
{
|
||||||
/// Entropy sources.
|
/// Entropy sources.
|
||||||
protected EntropySource[] sources;
|
protected EntropySource[] sources;
|
||||||
|
|
||||||
private ubyte sourceCount_;
|
private ubyte sourceCount_;
|
||||||
|
|
||||||
private shared Allocator allocator;
|
private shared Allocator allocator;
|
||||||
|
|
||||||
/// Entropy accumulator.
|
/// Entropy accumulator.
|
||||||
protected SHA!(maxGather * 8, 512) accumulator;
|
protected SHA!(maxGather * 8, 512) accumulator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Params:
|
* Params:
|
||||||
* maxSources = Maximum amount of entropy sources can be set.
|
* maxSources = Maximum amount of entropy sources can be set.
|
||||||
* allocator = Allocator to allocate entropy sources available on the
|
* allocator = Allocator to allocate entropy sources available on the
|
||||||
* system.
|
* system.
|
||||||
*/
|
*/
|
||||||
this(size_t maxSources = 20, shared Allocator allocator = defaultAllocator)
|
this(size_t maxSources = 20, shared Allocator allocator = defaultAllocator)
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(maxSources > 0 && maxSources <= ubyte.max);
|
assert(maxSources > 0 && maxSources <= ubyte.max);
|
||||||
assert(allocator !is null);
|
assert(allocator !is null);
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
allocator.resizeArray(sources, maxSources);
|
allocator.resize(sources, maxSources);
|
||||||
|
|
||||||
version (linux)
|
version (linux)
|
||||||
{
|
{
|
||||||
this ~= allocator.make!PlatformEntropySource;
|
this ~= allocator.make!PlatformEntropySource;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns: Amount of the registered entropy sources.
|
* Returns: Amount of the registered entropy sources.
|
||||||
*/
|
*/
|
||||||
@property ubyte sourceCount() const @safe pure nothrow
|
@property ubyte sourceCount() const @safe pure nothrow
|
||||||
{
|
{
|
||||||
return sourceCount_;
|
return sourceCount_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an entropy source.
|
* Add an entropy source.
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* source = Entropy source.
|
* source = Entropy source.
|
||||||
*
|
*
|
||||||
* Returns: $(D_PSYMBOL this).
|
* Returns: $(D_PSYMBOL this).
|
||||||
*
|
*
|
||||||
* See_Also:
|
* See_Also:
|
||||||
* $(D_PSYMBOL EntropySource)
|
* $(D_PSYMBOL EntropySource)
|
||||||
*/
|
*/
|
||||||
Entropy opOpAssign(string Op)(EntropySource source) @safe pure nothrow
|
Entropy opOpAssign(string Op)(EntropySource source) @safe pure nothrow
|
||||||
if (Op == "~")
|
if (Op == "~")
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(sourceCount_ <= sources.length);
|
assert(sourceCount_ <= sources.length);
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
sources[sourceCount_++] = source;
|
sources[sourceCount_++] = source;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns: Generated random sequence.
|
* Returns: Generated random sequence.
|
||||||
*
|
*
|
||||||
* Throws: $(D_PSYMBOL EntropyException) if no strong entropy source was
|
* Throws: $(D_PSYMBOL EntropyException) if no strong entropy source was
|
||||||
* registered or it failed.
|
* registered or it failed.
|
||||||
*/
|
*/
|
||||||
@property ubyte[blockSize] random()
|
@property ubyte[blockSize] random()
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(sourceCount_ > 0, "No entropy sources defined.");
|
assert(sourceCount_ > 0, "No entropy sources defined.");
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
bool haveStrong;
|
bool haveStrong;
|
||||||
ushort done;
|
ushort done;
|
||||||
ubyte[blockSize] output;
|
ubyte[blockSize] output;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
ubyte[maxGather] buffer;
|
ubyte[maxGather] buffer;
|
||||||
|
|
||||||
// Run through our entropy sources
|
// Run through our entropy sources
|
||||||
for (ubyte i; i < sourceCount; ++i)
|
for (ubyte i; i < sourceCount; ++i)
|
||||||
{
|
{
|
||||||
auto outputLength = sources[i].poll(buffer);
|
auto outputLength = sources[i].poll(buffer);
|
||||||
|
|
||||||
if (!outputLength.isNull)
|
if (!outputLength.isNull)
|
||||||
{
|
{
|
||||||
if (outputLength > 0)
|
if (outputLength > 0)
|
||||||
{
|
{
|
||||||
update(i, buffer, outputLength);
|
update(i, buffer, outputLength);
|
||||||
sources[i].size = cast(ushort) (sources[i].size + outputLength);
|
sources[i].size = cast(ushort) (sources[i].size + outputLength);
|
||||||
}
|
}
|
||||||
if (sources[i].size < sources[i].threshold)
|
if (sources[i].size < sources[i].threshold)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (sources[i].strong)
|
else if (sources[i].strong)
|
||||||
{
|
{
|
||||||
haveStrong = true;
|
haveStrong = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
done = 257;
|
done = 257;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (++done < 256);
|
while (++done < 256);
|
||||||
|
|
||||||
if (!haveStrong)
|
if (!haveStrong)
|
||||||
{
|
{
|
||||||
throw allocator.make!EntropyException("No strong entropy source defined.");
|
throw allocator.make!EntropyException("No strong entropy source defined.");
|
||||||
}
|
}
|
||||||
|
|
||||||
output = accumulator.finish();
|
output = accumulator.finish();
|
||||||
|
|
||||||
// Reset accumulator and counters and recycle existing entropy
|
// Reset accumulator and counters and recycle existing entropy
|
||||||
accumulator.start();
|
accumulator.start();
|
||||||
|
|
||||||
// Perform second SHA-512 on entropy
|
// Perform second SHA-512 on entropy
|
||||||
output = sha512Of(output);
|
output = sha512Of(output);
|
||||||
|
|
||||||
for (ubyte i = 0; i < sourceCount; ++i)
|
for (ubyte i = 0; i < sourceCount; ++i)
|
||||||
{
|
{
|
||||||
sources[i].size = 0;
|
sources[i].size = 0;
|
||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update entropy accumulator.
|
* Update entropy accumulator.
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* sourceId = Entropy source index in $(D_PSYMBOL sources).
|
* sourceId = Entropy source index in $(D_PSYMBOL sources).
|
||||||
* data = Data got from the entropy source.
|
* data = Data got from the entropy source.
|
||||||
* length = Length of the received data.
|
* length = Length of the received data.
|
||||||
*/
|
*/
|
||||||
protected void update(in ubyte sourceId,
|
protected void update(in ubyte sourceId,
|
||||||
ref ubyte[maxGather] data,
|
ref ubyte[maxGather] data,
|
||||||
ubyte length) @safe pure nothrow
|
ubyte length) @safe pure nothrow
|
||||||
{
|
{
|
||||||
ubyte[2] header;
|
ubyte[2] header;
|
||||||
|
|
||||||
if (length > blockSize)
|
if (length > blockSize)
|
||||||
{
|
{
|
||||||
data[0..64] = sha512Of(data);
|
data[0..64] = sha512Of(data);
|
||||||
length = blockSize;
|
length = blockSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
header[0] = sourceId;
|
header[0] = sourceId;
|
||||||
header[1] = length;
|
header[1] = length;
|
||||||
|
|
||||||
accumulator.put(header);
|
accumulator.put(header);
|
||||||
accumulator.put(data[0..length]);
|
accumulator.put(data[0..length]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,59 +23,61 @@ public import tanya.memory.allocator;
|
|||||||
*/
|
*/
|
||||||
mixin template DefaultAllocator()
|
mixin template DefaultAllocator()
|
||||||
{
|
{
|
||||||
/// Allocator.
|
/// Allocator.
|
||||||
protected shared Allocator allocator_;
|
protected shared Allocator allocator_;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Params:
|
* Params:
|
||||||
* allocator = The allocator should be used.
|
* allocator = The allocator should be used.
|
||||||
*/
|
*
|
||||||
this(shared Allocator allocator)
|
* Precondition: $(D_INLINECODE allocator_ !is null)
|
||||||
in
|
*/
|
||||||
{
|
this(shared Allocator allocator)
|
||||||
assert(allocator !is null);
|
in
|
||||||
}
|
{
|
||||||
body
|
assert(allocator !is null);
|
||||||
{
|
}
|
||||||
this.allocator_ = allocator;
|
body
|
||||||
}
|
{
|
||||||
|
this.allocator_ = allocator;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This property checks if the allocator was set in the constructor
|
* This property checks if the allocator was set in the constructor
|
||||||
* and sets it to the default one, if not.
|
* and sets it to the default one, if not.
|
||||||
*
|
*
|
||||||
* Returns: Used allocator.
|
* Returns: Used allocator.
|
||||||
*
|
*
|
||||||
* Postcondition: $(D_INLINECODE allocator_ !is null)
|
* Postcondition: $(D_INLINECODE allocator !is null)
|
||||||
*/
|
*/
|
||||||
protected @property shared(Allocator) allocator() nothrow @safe @nogc
|
protected @property shared(Allocator) allocator() nothrow @safe @nogc
|
||||||
out (allocator)
|
out (allocator)
|
||||||
{
|
{
|
||||||
assert(allocator !is null);
|
assert(allocator !is null);
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
if (allocator_ is null)
|
if (allocator_ is null)
|
||||||
{
|
{
|
||||||
allocator_ = defaultAllocator;
|
allocator_ = defaultAllocator;
|
||||||
}
|
}
|
||||||
return allocator_;
|
return allocator_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
@property shared(Allocator) allocator() const nothrow @trusted @nogc
|
@property shared(Allocator) allocator() const nothrow @trusted @nogc
|
||||||
out (allocator)
|
out (allocator)
|
||||||
{
|
{
|
||||||
assert(allocator !is null);
|
assert(allocator !is null);
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
if (allocator_ is null)
|
if (allocator_ is null)
|
||||||
{
|
{
|
||||||
return defaultAllocator;
|
return defaultAllocator;
|
||||||
}
|
}
|
||||||
return cast(shared Allocator) allocator_;
|
return cast(shared Allocator) allocator_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// From druntime
|
// From druntime
|
||||||
@ -85,28 +87,28 @@ shared Allocator allocator;
|
|||||||
|
|
||||||
shared static this() nothrow @trusted @nogc
|
shared static this() nothrow @trusted @nogc
|
||||||
{
|
{
|
||||||
import tanya.memory.mmappool;
|
import tanya.memory.mmappool;
|
||||||
allocator = MmapPool.instance;
|
allocator = MmapPool.instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property ref shared(Allocator) defaultAllocator() nothrow @safe @nogc
|
@property ref shared(Allocator) defaultAllocator() nothrow @safe @nogc
|
||||||
out (allocator)
|
out (allocator)
|
||||||
{
|
{
|
||||||
assert(allocator !is null);
|
assert(allocator !is null);
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
return allocator;
|
return allocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property void defaultAllocator(shared(Allocator) allocator) nothrow @safe @nogc
|
@property void defaultAllocator(shared(Allocator) allocator) nothrow @safe @nogc
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
assert(allocator !is null);
|
assert(allocator !is null);
|
||||||
}
|
}
|
||||||
body
|
body
|
||||||
{
|
{
|
||||||
.allocator = allocator;
|
.allocator = allocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -114,101 +116,92 @@ body
|
|||||||
* object of type $(D_PARAM T).
|
* object of type $(D_PARAM T).
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* T = Object type.
|
* T = Object type.
|
||||||
*/
|
*/
|
||||||
template stateSize(T)
|
template stateSize(T)
|
||||||
{
|
{
|
||||||
static if (is(T == class) || is(T == interface))
|
static if (is(T == class) || is(T == interface))
|
||||||
{
|
{
|
||||||
enum stateSize = __traits(classInstanceSize, T);
|
enum stateSize = __traits(classInstanceSize, T);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
enum stateSize = T.sizeof;
|
enum stateSize = T.sizeof;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Params:
|
* Params:
|
||||||
* size = Raw size.
|
* size = Raw size.
|
||||||
* alignment = Alignment.
|
* alignment = Alignment.
|
||||||
*
|
*
|
||||||
* Returns: Aligned size.
|
* Returns: Aligned size.
|
||||||
*/
|
*/
|
||||||
size_t alignedSize(in size_t size, in size_t alignment = 8) pure nothrow @safe @nogc
|
size_t alignedSize(in size_t size, in size_t alignment = 8) pure nothrow @safe @nogc
|
||||||
{
|
{
|
||||||
return (size - 1) / alignment * alignment + alignment;
|
return (size - 1) / alignment * alignment + alignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal function used to create, resize or destroy a dynamic array. It
|
* Internal function used to create, resize or destroy a dynamic array. It
|
||||||
* throws $(D_PSYMBOL OutOfMemoryError) if $(D_PARAM Throws) is set. The new
|
* may throw $(D_PSYMBOL OutOfMemoryError). The new
|
||||||
* allocated part of the array is initialized only if $(D_PARAM Init)
|
* allocated part of the array is initialized only if $(D_PARAM Init)
|
||||||
* is set. This function can be trusted only in the data structures that
|
* is set. This function can be trusted only in the data structures that
|
||||||
* can ensure that the array is allocated/rellocated/deallocated with the
|
* can ensure that the array is allocated/rellocated/deallocated with the
|
||||||
* same allocator.
|
* same allocator.
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* T = Element type of the array being created.
|
* T = Element type of the array being created.
|
||||||
* Init = If should be initialized.
|
* Init = If should be initialized.
|
||||||
* Throws = If $(D_PSYMBOL OutOfMemoryError) should be throwsn.
|
* allocator = The allocator used for getting memory.
|
||||||
* allocator = The allocator used for getting memory.
|
* array = A reference to the array being changed.
|
||||||
* array = A reference to the array being changed.
|
* length = New array length.
|
||||||
* length = New array length.
|
|
||||||
*
|
*
|
||||||
* Returns: $(D_KEYWORD true) upon success, $(D_KEYWORD false) if memory could
|
* Returns: $(D_PARAM array).
|
||||||
* not be reallocated. In the latter
|
|
||||||
*/
|
*/
|
||||||
package(tanya) bool resize(T,
|
package(tanya) T[] resize(T,
|
||||||
bool Init = true,
|
bool Init = true)
|
||||||
bool Throws = true)
|
(shared Allocator allocator,
|
||||||
(shared Allocator allocator,
|
auto ref T[] array,
|
||||||
ref T[] array,
|
const size_t length) @trusted
|
||||||
in size_t length) @trusted
|
|
||||||
{
|
{
|
||||||
void[] buf = array;
|
void[] buf = array;
|
||||||
static if (Init)
|
static if (Init)
|
||||||
{
|
{
|
||||||
immutable oldLength = array.length;
|
const oldLength = array.length;
|
||||||
}
|
}
|
||||||
if (!allocator.reallocate(buf, length * T.sizeof))
|
if (!allocator.reallocate(buf, length * T.sizeof))
|
||||||
{
|
{
|
||||||
static if (Throws)
|
onOutOfMemoryError;
|
||||||
{
|
}
|
||||||
onOutOfMemoryError;
|
// Casting from void[] is unsafe, but we know we cast to the original type.
|
||||||
}
|
array = cast(T[]) buf;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Casting from void[] is unsafe, but we know we cast to the original type.
|
|
||||||
array = cast(T[]) buf;
|
|
||||||
|
|
||||||
static if (Init)
|
static if (Init)
|
||||||
{
|
{
|
||||||
if (oldLength < length)
|
if (oldLength < length)
|
||||||
{
|
{
|
||||||
array[oldLength .. $] = T.init;
|
array[oldLength .. $] = T.init;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return array;
|
||||||
}
|
}
|
||||||
package(tanya) alias resizeArray = resize;
|
|
||||||
|
|
||||||
///
|
private unittest
|
||||||
unittest
|
|
||||||
{
|
{
|
||||||
int[] p;
|
int[] p;
|
||||||
|
|
||||||
defaultAllocator.resizeArray(p, 20);
|
p = defaultAllocator.resize(p, 20);
|
||||||
assert(p.length == 20);
|
assert(p.length == 20);
|
||||||
|
|
||||||
defaultAllocator.resizeArray(p, 30);
|
p = defaultAllocator.resize(p, 30);
|
||||||
assert(p.length == 30);
|
assert(p.length == 30);
|
||||||
|
|
||||||
defaultAllocator.resizeArray(p, 10);
|
p = defaultAllocator.resize(p, 10);
|
||||||
assert(p.length == 10);
|
assert(p.length == 10);
|
||||||
|
|
||||||
defaultAllocator.resizeArray(p, 0);
|
p = defaultAllocator.resize(p, 0);
|
||||||
assert(p is null);
|
assert(p is null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -217,101 +210,101 @@ unittest
|
|||||||
* allocator.
|
* allocator.
|
||||||
*
|
*
|
||||||
* Params:
|
* Params:
|
||||||
* T = Type of $(D_PARAM p).
|
* T = Type of $(D_PARAM p).
|
||||||
* allocator = Allocator the $(D_PARAM p) was allocated with.
|
* allocator = Allocator the $(D_PARAM p) was allocated with.
|
||||||
* p = Object or array to be destroyed.
|
* p = Object or array to be destroyed.
|
||||||
*/
|
*/
|
||||||
void dispose(T)(shared Allocator allocator, auto ref T* p)
|
void dispose(T)(shared Allocator allocator, auto ref T* p)
|
||||||
{
|
{
|
||||||
static if (hasElaborateDestructor!T)
|
static if (hasElaborateDestructor!T)
|
||||||
{
|
{
|
||||||
destroy(*p);
|
destroy(*p);
|
||||||
}
|
}
|
||||||
() @trusted { allocator.deallocate((cast(void*) p)[0 .. T.sizeof]); }();
|
() @trusted { allocator.deallocate((cast(void*) p)[0 .. T.sizeof]); }();
|
||||||
p = null;
|
p = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
void dispose(T)(shared Allocator allocator, auto ref T p)
|
void dispose(T)(shared Allocator allocator, auto ref T p)
|
||||||
if (is(T == class) || is(T == interface))
|
if (is(T == class) || is(T == interface))
|
||||||
{
|
{
|
||||||
if (p is null)
|
if (p is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
static if (is(T == interface))
|
static if (is(T == interface))
|
||||||
{
|
{
|
||||||
version(Windows)
|
version(Windows)
|
||||||
{
|
{
|
||||||
import core.sys.windows.unknwn : IUnknown;
|
import core.sys.windows.unknwn : IUnknown;
|
||||||
static assert(!is(T: IUnknown), "COM interfaces can't be destroyed in "
|
static assert(!is(T: IUnknown), "COM interfaces can't be destroyed in "
|
||||||
~ __PRETTY_FUNCTION__);
|
~ __PRETTY_FUNCTION__);
|
||||||
}
|
}
|
||||||
auto ob = cast(Object) p;
|
auto ob = cast(Object) p;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
alias ob = p;
|
alias ob = p;
|
||||||
}
|
}
|
||||||
auto ptr = cast(void *) ob;
|
auto ptr = cast(void *) ob;
|
||||||
|
|
||||||
auto support = ptr[0 .. typeid(ob).initializer.length];
|
auto support = ptr[0 .. typeid(ob).initializer.length];
|
||||||
scope (success)
|
scope (success)
|
||||||
{
|
{
|
||||||
() @trusted { allocator.deallocate(support); }();
|
() @trusted { allocator.deallocate(support); }();
|
||||||
p = null;
|
p = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ppv = cast(void**) ptr;
|
auto ppv = cast(void**) ptr;
|
||||||
if (!*ppv)
|
if (!*ppv)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto pc = cast(ClassInfo*) *ppv;
|
auto pc = cast(ClassInfo*) *ppv;
|
||||||
scope (exit)
|
scope (exit)
|
||||||
{
|
{
|
||||||
*ppv = null;
|
*ppv = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto c = *pc;
|
auto c = *pc;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
// Assume the destructor is @nogc. Leave it nothrow since the destructor
|
// Assume the destructor is @nogc. Leave it nothrow since the destructor
|
||||||
// shouldn't throw and if it does, it is an error anyway.
|
// shouldn't throw and if it does, it is an error anyway.
|
||||||
if (c.destructor)
|
if (c.destructor)
|
||||||
{
|
{
|
||||||
(cast(void function (Object) nothrow @safe @nogc) c.destructor)(ob);
|
(cast(void function (Object) nothrow @safe @nogc) c.destructor)(ob);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while ((c = c.base) !is null);
|
while ((c = c.base) !is null);
|
||||||
|
|
||||||
if (ppv[1]) // if monitor is not null
|
if (ppv[1]) // if monitor is not null
|
||||||
{
|
{
|
||||||
_d_monitordelete(cast(Object) ptr, true);
|
_d_monitordelete(cast(Object) ptr, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto.
|
/// Ditto.
|
||||||
void dispose(T)(shared Allocator allocator, auto ref T[] p)
|
void dispose(T)(shared Allocator allocator, auto ref T[] p)
|
||||||
{
|
{
|
||||||
static if (hasElaborateDestructor!(typeof(p[0])))
|
static if (hasElaborateDestructor!(typeof(p[0])))
|
||||||
{
|
{
|
||||||
import std.algorithm.iteration;
|
import std.algorithm.iteration;
|
||||||
p.each!(e => destroy(e));
|
p.each!(e => destroy(e));
|
||||||
}
|
}
|
||||||
() @trusted { allocator.deallocate(p); }();
|
() @trusted { allocator.deallocate(p); }();
|
||||||
p = null;
|
p = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
struct S
|
struct S
|
||||||
{
|
{
|
||||||
~this()
|
~this()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto p = cast(S[]) defaultAllocator.allocate(S.sizeof);
|
auto p = cast(S[]) defaultAllocator.allocate(S.sizeof);
|
||||||
|
|
||||||
defaultAllocator.dispose(p);
|
defaultAllocator.dispose(p);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user