Remove resizeArray alias

This commit is contained in:
Eugen Wissner 2017-03-19 06:10:27 +01:00
parent d0ada39fa7
commit b90c56395c
2 changed files with 423 additions and 430 deletions

View File

@ -8,8 +8,8 @@
* Copyright: Eugene Wissner 2016.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/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;
import std.digest.sha;
@ -27,20 +27,20 @@ enum maxGather = 128;
*/
class EntropyException : Exception
{
/**
* Params:
* msg = Message to output.
* 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) pure @safe nothrow const @nogc
{
super(msg, file, line, next);
}
/**
* Params:
* msg = Message to output.
* 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) pure @safe nothrow const @nogc
{
super(msg, file, line, next);
}
}
/**
@ -48,103 +48,103 @@ class EntropyException : Exception
*/
abstract class EntropySource
{
/// Amount of already generated entropy.
protected ushort size_;
/// Amount of already generated entropy.
protected ushort size_;
/**
* Returns: Minimum bytes required from the entropy source.
*/
@property immutable(ubyte) threshold() const @safe pure nothrow;
/**
* Returns: Minimum bytes required from the entropy source.
*/
@property immutable(ubyte) threshold() const @safe pure nothrow;
/**
* Returns: Whether this entropy source is strong.
*/
@property immutable(bool) strong() const @safe pure nothrow;
/**
* Returns: Whether this entropy source is strong.
*/
@property immutable(bool) strong() const @safe pure nothrow;
/**
* Returns: Amount of already generated entropy.
*/
@property ushort size() const @safe pure nothrow
{
return size_;
}
/**
* Returns: Amount of already generated entropy.
*/
@property ushort size() const @safe pure nothrow
{
return size_;
}
/**
* Params:
* size = Amount of already generated entropy. Cannot be smaller than the
* already set value.
*/
@property void size(ushort size) @safe pure nothrow
{
size_ = size;
}
/**
* Params:
* size = Amount of already generated entropy. Cannot be smaller than the
* already set value.
*/
@property void size(ushort size) @safe pure nothrow
{
size_ = size;
}
/**
* Poll the entropy source.
*
* Params:
* output = Buffer to save the generate random sequence (the method will
* to fill the buffer).
*
* Returns: Number of bytes that were copied to the $(D_PARAM output)
* or $(D_PSYMBOL Nullable!ubyte.init) on error.
*/
Nullable!ubyte poll(out ubyte[maxGather] output);
/**
* Poll the entropy source.
*
* Params:
* output = Buffer to save the generate random sequence (the method will
* to fill the buffer).
*
* Returns: Number of bytes that were copied to the $(D_PARAM output)
* or $(D_PSYMBOL Nullable!ubyte.init) on error.
*/
Nullable!ubyte poll(out ubyte[maxGather] output);
}
version (linux)
{
extern (C) long syscall(long number, ...) nothrow;
extern (C) long syscall(long number, ...) nothrow;
/**
* Uses getrandom system call.
*/
class PlatformEntropySource : EntropySource
{
/**
* Returns: Minimum bytes required from the entropy source.
*/
override @property immutable(ubyte) threshold() const @safe pure nothrow
{
return 32;
}
/**
* Uses getrandom system call.
*/
class PlatformEntropySource : EntropySource
{
/**
* Returns: Minimum bytes required from the entropy source.
*/
override @property immutable(ubyte) threshold() const @safe pure nothrow
{
return 32;
}
/**
* Returns: Whether this entropy source is strong.
*/
override @property immutable(bool) strong() const @safe pure nothrow
{
return true;
}
/**
* Returns: Whether this entropy source is strong.
*/
override @property immutable(bool) strong() const @safe pure nothrow
{
return true;
}
/**
* Poll the entropy source.
*
* Params:
* output = Buffer to save the generate random sequence (the method will
* to fill the buffer).
*
* Returns: Number of bytes that were copied to the $(D_PARAM output)
* or $(D_PSYMBOL Nullable!ubyte.init) on error.
*/
override Nullable!ubyte poll(out ubyte[maxGather] output) nothrow
out (length)
{
assert(length <= maxGather);
}
body
{
// int getrandom(void *buf, size_t buflen, unsigned int flags);
auto length = syscall(318, output.ptr, output.length, 0);
Nullable!ubyte ret;
/**
* Poll the entropy source.
*
* Params:
* output = Buffer to save the generate random sequence (the method will
* to fill the buffer).
*
* Returns: Number of bytes that were copied to the $(D_PARAM output)
* or $(D_PSYMBOL Nullable!ubyte.init) on error.
*/
override Nullable!ubyte poll(out ubyte[maxGather] output) nothrow
out (length)
{
assert(length <= maxGather);
}
body
{
// int getrandom(void *buf, size_t buflen, unsigned int flags);
auto length = syscall(318, output.ptr, output.length, 0);
Nullable!ubyte ret;
if (length >= 0)
{
ret = cast(ubyte) length;
}
return ret;
}
}
if (length >= 0)
{
ret = cast(ubyte) length;
}
return ret;
}
}
}
/**
@ -156,165 +156,165 @@ version (linux)
*
* output = entropy.random;
*
* defaultAllocator.finalize(entropy);
* defaultAllocator.dispose(entropy);
* ---
*/
class Entropy
{
/// Entropy sources.
protected EntropySource[] sources;
/// Entropy sources.
protected EntropySource[] sources;
private ubyte sourceCount_;
private ubyte sourceCount_;
private shared Allocator allocator;
private shared Allocator allocator;
/// Entropy accumulator.
protected SHA!(maxGather * 8, 512) accumulator;
/// Entropy accumulator.
protected SHA!(maxGather * 8, 512) accumulator;
/**
* Params:
* maxSources = Maximum amount of entropy sources can be set.
* allocator = Allocator to allocate entropy sources available on the
* system.
*/
this(size_t maxSources = 20, shared Allocator allocator = defaultAllocator)
in
{
assert(maxSources > 0 && maxSources <= ubyte.max);
assert(allocator !is null);
}
body
{
allocator.resizeArray(sources, maxSources);
/**
* Params:
* maxSources = Maximum amount of entropy sources can be set.
* allocator = Allocator to allocate entropy sources available on the
* system.
*/
this(size_t maxSources = 20, shared Allocator allocator = defaultAllocator)
in
{
assert(maxSources > 0 && maxSources <= ubyte.max);
assert(allocator !is null);
}
body
{
allocator.resize(sources, maxSources);
version (linux)
{
this ~= allocator.make!PlatformEntropySource;
}
}
version (linux)
{
this ~= allocator.make!PlatformEntropySource;
}
}
/**
* Returns: Amount of the registered entropy sources.
*/
@property ubyte sourceCount() const @safe pure nothrow
{
return sourceCount_;
}
/**
* Returns: Amount of the registered entropy sources.
*/
@property ubyte sourceCount() const @safe pure nothrow
{
return sourceCount_;
}
/**
* Add an entropy source.
*
* Params:
* source = Entropy source.
*
* Returns: $(D_PSYMBOL this).
*
* See_Also:
* $(D_PSYMBOL EntropySource)
*/
Entropy opOpAssign(string Op)(EntropySource source) @safe pure nothrow
if (Op == "~")
in
{
assert(sourceCount_ <= sources.length);
}
body
{
sources[sourceCount_++] = source;
return this;
}
/**
* Add an entropy source.
*
* Params:
* source = Entropy source.
*
* Returns: $(D_PSYMBOL this).
*
* See_Also:
* $(D_PSYMBOL EntropySource)
*/
Entropy opOpAssign(string Op)(EntropySource source) @safe pure nothrow
if (Op == "~")
in
{
assert(sourceCount_ <= sources.length);
}
body
{
sources[sourceCount_++] = source;
return this;
}
/**
* Returns: Generated random sequence.
*
* Throws: $(D_PSYMBOL EntropyException) if no strong entropy source was
* registered or it failed.
*/
@property ubyte[blockSize] random()
in
{
assert(sourceCount_ > 0, "No entropy sources defined.");
}
body
{
bool haveStrong;
ushort done;
ubyte[blockSize] output;
/**
* Returns: Generated random sequence.
*
* Throws: $(D_PSYMBOL EntropyException) if no strong entropy source was
* registered or it failed.
*/
@property ubyte[blockSize] random()
in
{
assert(sourceCount_ > 0, "No entropy sources defined.");
}
body
{
bool haveStrong;
ushort done;
ubyte[blockSize] output;
do
{
ubyte[maxGather] buffer;
do
{
ubyte[maxGather] buffer;
// Run through our entropy sources
for (ubyte i; i < sourceCount; ++i)
{
auto outputLength = sources[i].poll(buffer);
// Run through our entropy sources
for (ubyte i; i < sourceCount; ++i)
{
auto outputLength = sources[i].poll(buffer);
if (!outputLength.isNull)
{
if (outputLength > 0)
{
update(i, buffer, outputLength);
sources[i].size = cast(ushort) (sources[i].size + outputLength);
}
if (sources[i].size < sources[i].threshold)
{
continue;
}
else if (sources[i].strong)
{
haveStrong = true;
}
}
done = 257;
}
}
while (++done < 256);
if (!outputLength.isNull)
{
if (outputLength > 0)
{
update(i, buffer, outputLength);
sources[i].size = cast(ushort) (sources[i].size + outputLength);
}
if (sources[i].size < sources[i].threshold)
{
continue;
}
else if (sources[i].strong)
{
haveStrong = true;
}
}
done = 257;
}
}
while (++done < 256);
if (!haveStrong)
{
throw allocator.make!EntropyException("No strong entropy source defined.");
}
if (!haveStrong)
{
throw allocator.make!EntropyException("No strong entropy source defined.");
}
output = accumulator.finish();
output = accumulator.finish();
// Reset accumulator and counters and recycle existing entropy
accumulator.start();
// Reset accumulator and counters and recycle existing entropy
accumulator.start();
// Perform second SHA-512 on entropy
output = sha512Of(output);
// Perform second SHA-512 on entropy
output = sha512Of(output);
for (ubyte i = 0; i < sourceCount; ++i)
{
sources[i].size = 0;
}
return output;
}
for (ubyte i = 0; i < sourceCount; ++i)
{
sources[i].size = 0;
}
return output;
}
/**
* Update entropy accumulator.
*
* Params:
* sourceId = Entropy source index in $(D_PSYMBOL sources).
* data = Data got from the entropy source.
* length = Length of the received data.
*/
protected void update(in ubyte sourceId,
ref ubyte[maxGather] data,
ubyte length) @safe pure nothrow
{
ubyte[2] header;
/**
* Update entropy accumulator.
*
* Params:
* sourceId = Entropy source index in $(D_PSYMBOL sources).
* data = Data got from the entropy source.
* length = Length of the received data.
*/
protected void update(in ubyte sourceId,
ref ubyte[maxGather] data,
ubyte length) @safe pure nothrow
{
ubyte[2] header;
if (length > blockSize)
{
data[0..64] = sha512Of(data);
length = blockSize;
}
if (length > blockSize)
{
data[0..64] = sha512Of(data);
length = blockSize;
}
header[0] = sourceId;
header[1] = length;
header[0] = sourceId;
header[1] = length;
accumulator.put(header);
accumulator.put(data[0..length]);
}
accumulator.put(header);
accumulator.put(data[0..length]);
}
}

View File

@ -23,59 +23,61 @@ public import tanya.memory.allocator;
*/
mixin template DefaultAllocator()
{
/// Allocator.
protected shared Allocator allocator_;
/// Allocator.
protected shared Allocator allocator_;
/**
* Params:
* allocator = The allocator should be used.
*/
this(shared Allocator allocator)
in
{
assert(allocator !is null);
}
body
{
this.allocator_ = allocator;
}
/**
* Params:
* allocator = The allocator should be used.
*
* Precondition: $(D_INLINECODE allocator_ !is null)
*/
this(shared Allocator allocator)
in
{
assert(allocator !is null);
}
body
{
this.allocator_ = allocator;
}
/**
* This property checks if the allocator was set in the constructor
* and sets it to the default one, if not.
*
* Returns: Used allocator.
*
* Postcondition: $(D_INLINECODE allocator_ !is null)
*/
protected @property shared(Allocator) allocator() nothrow @safe @nogc
out (allocator)
{
assert(allocator !is null);
}
body
{
if (allocator_ is null)
{
allocator_ = defaultAllocator;
}
return allocator_;
}
/**
* This property checks if the allocator was set in the constructor
* and sets it to the default one, if not.
*
* Returns: Used allocator.
*
* Postcondition: $(D_INLINECODE allocator !is null)
*/
protected @property shared(Allocator) allocator() nothrow @safe @nogc
out (allocator)
{
assert(allocator !is null);
}
body
{
if (allocator_ is null)
{
allocator_ = defaultAllocator;
}
return allocator_;
}
/// Ditto.
@property shared(Allocator) allocator() const nothrow @trusted @nogc
out (allocator)
{
assert(allocator !is null);
}
body
{
if (allocator_ is null)
{
return defaultAllocator;
}
return cast(shared Allocator) allocator_;
}
/// Ditto.
@property shared(Allocator) allocator() const nothrow @trusted @nogc
out (allocator)
{
assert(allocator !is null);
}
body
{
if (allocator_ is null)
{
return defaultAllocator;
}
return cast(shared Allocator) allocator_;
}
}
// From druntime
@ -85,28 +87,28 @@ shared Allocator allocator;
shared static this() nothrow @trusted @nogc
{
import tanya.memory.mmappool;
allocator = MmapPool.instance;
import tanya.memory.mmappool;
allocator = MmapPool.instance;
}
@property ref shared(Allocator) defaultAllocator() nothrow @safe @nogc
out (allocator)
{
assert(allocator !is null);
assert(allocator !is null);
}
body
{
return allocator;
return allocator;
}
@property void defaultAllocator(shared(Allocator) allocator) nothrow @safe @nogc
in
{
assert(allocator !is null);
assert(allocator !is null);
}
body
{
.allocator = allocator;
.allocator = allocator;
}
/**
@ -114,101 +116,92 @@ body
* object of type $(D_PARAM T).
*
* Params:
* T = Object type.
* T = Object type.
*/
template stateSize(T)
{
static if (is(T == class) || is(T == interface))
{
enum stateSize = __traits(classInstanceSize, T);
}
else
{
enum stateSize = T.sizeof;
}
static if (is(T == class) || is(T == interface))
{
enum stateSize = __traits(classInstanceSize, T);
}
else
{
enum stateSize = T.sizeof;
}
}
/**
* Params:
* size = Raw size.
* alignment = Alignment.
* size = Raw size.
* alignment = Alignment.
*
* Returns: Aligned size.
*/
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
* 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)
* is set. This function can be trusted only in the data structures that
* can ensure that the array is allocated/rellocated/deallocated with the
* same allocator.
*
* Params:
* T = Element type of the array being created.
* Init = If should be initialized.
* Throws = If $(D_PSYMBOL OutOfMemoryError) should be throwsn.
* allocator = The allocator used for getting memory.
* array = A reference to the array being changed.
* length = New array length.
* T = Element type of the array being created.
* Init = If should be initialized.
* allocator = The allocator used for getting memory.
* array = A reference to the array being changed.
* length = New array length.
*
* Returns: $(D_KEYWORD true) upon success, $(D_KEYWORD false) if memory could
* not be reallocated. In the latter
* Returns: $(D_PARAM array).
*/
package(tanya) bool resize(T,
bool Init = true,
bool Throws = true)
(shared Allocator allocator,
ref T[] array,
in size_t length) @trusted
package(tanya) T[] resize(T,
bool Init = true)
(shared Allocator allocator,
auto ref T[] array,
const size_t length) @trusted
{
void[] buf = array;
static if (Init)
{
immutable oldLength = array.length;
}
if (!allocator.reallocate(buf, length * T.sizeof))
{
static if (Throws)
{
onOutOfMemoryError;
}
return false;
}
// Casting from void[] is unsafe, but we know we cast to the original type.
array = cast(T[]) buf;
void[] buf = array;
static if (Init)
{
const oldLength = array.length;
}
if (!allocator.reallocate(buf, length * T.sizeof))
{
onOutOfMemoryError;
}
// Casting from void[] is unsafe, but we know we cast to the original type.
array = cast(T[]) buf;
static if (Init)
{
if (oldLength < length)
{
array[oldLength .. $] = T.init;
}
}
return true;
static if (Init)
{
if (oldLength < length)
{
array[oldLength .. $] = T.init;
}
}
return array;
}
package(tanya) alias resizeArray = resize;
///
unittest
private unittest
{
int[] p;
int[] p;
defaultAllocator.resizeArray(p, 20);
assert(p.length == 20);
p = defaultAllocator.resize(p, 20);
assert(p.length == 20);
defaultAllocator.resizeArray(p, 30);
assert(p.length == 30);
p = defaultAllocator.resize(p, 30);
assert(p.length == 30);
defaultAllocator.resizeArray(p, 10);
assert(p.length == 10);
p = defaultAllocator.resize(p, 10);
assert(p.length == 10);
defaultAllocator.resizeArray(p, 0);
assert(p is null);
p = defaultAllocator.resize(p, 0);
assert(p is null);
}
/**
@ -217,101 +210,101 @@ unittest
* allocator.
*
* Params:
* T = Type of $(D_PARAM p).
* allocator = Allocator the $(D_PARAM p) was allocated with.
* p = Object or array to be destroyed.
* T = Type of $(D_PARAM p).
* allocator = Allocator the $(D_PARAM p) was allocated with.
* p = Object or array to be destroyed.
*/
void dispose(T)(shared Allocator allocator, auto ref T* p)
{
static if (hasElaborateDestructor!T)
{
destroy(*p);
}
() @trusted { allocator.deallocate((cast(void*) p)[0 .. T.sizeof]); }();
p = null;
static if (hasElaborateDestructor!T)
{
destroy(*p);
}
() @trusted { allocator.deallocate((cast(void*) p)[0 .. T.sizeof]); }();
p = null;
}
/// Ditto.
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)
{
return;
}
static if (is(T == interface))
{
version(Windows)
{
import core.sys.windows.unknwn : IUnknown;
static assert(!is(T: IUnknown), "COM interfaces can't be destroyed in "
~ __PRETTY_FUNCTION__);
}
auto ob = cast(Object) p;
}
else
{
alias ob = p;
}
auto ptr = cast(void *) ob;
if (p is null)
{
return;
}
static if (is(T == interface))
{
version(Windows)
{
import core.sys.windows.unknwn : IUnknown;
static assert(!is(T: IUnknown), "COM interfaces can't be destroyed in "
~ __PRETTY_FUNCTION__);
}
auto ob = cast(Object) p;
}
else
{
alias ob = p;
}
auto ptr = cast(void *) ob;
auto support = ptr[0 .. typeid(ob).initializer.length];
scope (success)
{
() @trusted { allocator.deallocate(support); }();
p = null;
}
auto support = ptr[0 .. typeid(ob).initializer.length];
scope (success)
{
() @trusted { allocator.deallocate(support); }();
p = null;
}
auto ppv = cast(void**) ptr;
if (!*ppv)
{
return;
}
auto pc = cast(ClassInfo*) *ppv;
scope (exit)
{
*ppv = null;
}
auto ppv = cast(void**) ptr;
if (!*ppv)
{
return;
}
auto pc = cast(ClassInfo*) *ppv;
scope (exit)
{
*ppv = null;
}
auto c = *pc;
do
{
// Assume the destructor is @nogc. Leave it nothrow since the destructor
// shouldn't throw and if it does, it is an error anyway.
if (c.destructor)
{
(cast(void function (Object) nothrow @safe @nogc) c.destructor)(ob);
}
}
while ((c = c.base) !is null);
auto c = *pc;
do
{
// Assume the destructor is @nogc. Leave it nothrow since the destructor
// shouldn't throw and if it does, it is an error anyway.
if (c.destructor)
{
(cast(void function (Object) nothrow @safe @nogc) c.destructor)(ob);
}
}
while ((c = c.base) !is null);
if (ppv[1]) // if monitor is not null
{
_d_monitordelete(cast(Object) ptr, true);
}
if (ppv[1]) // if monitor is not null
{
_d_monitordelete(cast(Object) ptr, true);
}
}
/// Ditto.
void dispose(T)(shared Allocator allocator, auto ref T[] p)
{
static if (hasElaborateDestructor!(typeof(p[0])))
{
import std.algorithm.iteration;
p.each!(e => destroy(e));
}
() @trusted { allocator.deallocate(p); }();
p = null;
static if (hasElaborateDestructor!(typeof(p[0])))
{
import std.algorithm.iteration;
p.each!(e => destroy(e));
}
() @trusted { allocator.deallocate(p); }();
p = null;
}
unittest
{
struct S
{
~this()
{
}
}
auto p = cast(S[]) defaultAllocator.allocate(S.sizeof);
struct S
{
~this()
{
}
}
auto p = cast(S[]) defaultAllocator.allocate(S.sizeof);
defaultAllocator.dispose(p);
defaultAllocator.dispose(p);
}