Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions std/experimental/allocator/package.d
Original file line number Diff line number Diff line change
Expand Up @@ -1600,6 +1600,132 @@ unittest //bugzilla 15721
Mallocator.instance.dispose(foo);
}

/**
Allocates a multidimensional array of elements of type T.

Params:
N = number of dimensions
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't use capital names for values, just use n

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thx for the good examples, though no exception is justified there. We should probably slowly fix those as the code gets touched instead of introducing more instances.

cc @wilzbach: all values and functions are likeThis, all types are LikeThis, aliases that may be either should generally be likeThis, modules and labels should be like_this.

T = element type of an element of the multidimensional arrat
alloc = the allocator used for getting memory
lengths = static array containing the size of each dimension

Returns:
An N-dimensional array with individual elements of type T.
*/
auto makeMultidimensionalArray(uint n, T, Allocator)(auto ref Allocator alloc, size_t[n] lengths)
{
static if (n == 1)
{
return makeArray!T(alloc, lengths[0]);
}
else
{
alias E = typeof(makeMultidimensionalArray!(n - 1, T)(alloc, lengths[1..$]));
auto ret = makeArray!E(alloc, lengths[0]);
foreach (ref e; ret)
e = makeMultidimensionalArray!(n - 1, T)(alloc, lengths[1..$]);
return ret;
}
}

///
unittest
{
import std.experimental.allocator.mallocator : Mallocator;

size_t[3] dimArray = [2, 3, 6];
auto mArray = Mallocator.instance.makeMultidimensionalArray!(dimArray.length, int)(dimArray);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

guess it's nice to also deallocate here with scope(exit)

// deallocate when exiting scope
scope(exit)
{
Mallocator.instance.disposeMultidimensionalArray(mArray);
}

assert(mArray.length == 2);
foreach (lvl2Array; mArray)
{
assert(lvl2Array.length == 3);
foreach (lvl3Array; lvl2Array)
assert(lvl3Array.length == 6);
}
}

/**
Destroys and then deallocates a multidimensional array, assuming it was
created with makeMultidimensionalArray and the same allocator was used.

Params:
T = element type of an element of the multidimensional array
alloc = the allocator used for getting memory
array = the multidimensional array that is to be deallocated
*/
void disposeMultidimensionalArray(Allocator, T)(auto ref Allocator alloc, T[] array)
{
static if (isArray!T)
{
foreach (ref e; array)
disposeMultidimensionalArray(alloc, e);
}

dispose(alloc, array);
}

///
unittest
{
struct TestAllocator
{
import std.experimental.allocator.common : platformAlignment;
import std.experimental.allocator.mallocator : Mallocator;

alias allocator = Mallocator.instance;

private static struct ByteRange
{
void* ptr;
size_t length;
}

private ByteRange[] _allocations;

enum uint alignment = platformAlignment;

void[] allocate(size_t numBytes)
{
auto ret = allocator.allocate(numBytes);
_allocations ~= ByteRange(ret.ptr, ret.length);
return ret;
}

bool deallocate(void[] bytes)
{
import std.algorithm.mutation : remove;
import std.algorithm.searching : canFind;

bool pred(ByteRange other)
{ return other.ptr == bytes.ptr && other.length == bytes.length; }

assert(_allocations.canFind!pred);

_allocations = _allocations.remove!pred;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI: there is countUntil which allows to the search only once, but of course it doesn't matter for this simple test.

return allocator.deallocate(bytes);
}

~this()
{
assert(!_allocations.length);
}
}

TestAllocator allocator;

size_t[5] a = [2, 3, 6, 7, 2];
auto mArray = allocator.makeMultidimensionalArray!(a.length, int)(a);

allocator.disposeMultidimensionalArray(mArray);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about doing the same test with something that has a destructor and thus verifying that the destructor is called for all elements? e.g.

static instances = 0;
struct Foo
{

~this()
{
   instances = 0;
}

// allocate
assert(instances == 100);
// dispose
assert(instances == 0);


/**

Returns a dynamically-typed $(D CAllocator) built around a given statically-
Expand Down