digitalmars.D.learn - Stack-based nogc dynamic array
- Marco de Wild (86/86) May 16 2019 Hey all,
- Adam D. Ruppe (9/9) May 16 2019 I think you have overcomplicated something quite simple.
- Marco de Wild (4/13) May 16 2019 Thanks. It's really a lot simpler than I thought. It's slightly
- Kagamin (2/2) May 16 2019 Try mach.d https://github.com/pineapplemachine/mach.d it uses
- Marco de Wild (6/8) May 16 2019 Thank you. I've looked into it, and it appears to be quite a big
- Kagamin (3/8) May 17 2019 You use your array with math.range, but without alias this, it
- Mike Franklin (55/56) May 17 2019 I took a stab at it:
Hey all,
I want to create a small collection of items to store
intermediate results of a calculation. It runs on a background
thread, so it does not need to be the most efficient
implementation. However, I want to prevent my background thread
introducing a stop-the-world garbage collection.
In my program (rules and an AI for a mahjong game), the
collection size is at most 14 (tiles in hand). I figured it would
be the most simple to just keep it stack based. MY first attempt
looks like:
```
struct NoGcArray(size_t maxSize, T)
{
private T[maxSize] _buffer;
private size_t _length;
size_t length() pure const nogc nothrow
{
return _length;
}
void opOpAssign(string op)(T element) pure nogc nothrow
in(_length < maxSize, "Cannot append if the buffer is fully
filled.")
{
static if(op == "~")
{
_buffer[_length] = element;
++_length;
}
else
{
static assert(false, "Only concatenation supported");
}
}
T opIndex(size_t index)
in(index < _length, "Cannot access index greater than length")
{
return _buffer[index];
}
auto range() pure const nogc nothrow
{
return Range(this);
}
alias range this;
static struct Range
{
this(NoGcArray src)
{
_src = src;
}
private NoGcArray _src;
private size_t _index;
T front() pure nogc nothrow
{
return _src[_index];
}
void popFront() pure nogc nothrow
{
_index++;
}
bool empty() pure nogc nothrow
{
return _src._length <= _index;
}
}
}
```
However,
```
unittest
{
import std.algorithm : sum, map;
import fluent.asserts;
NoGcArray!(4, int) array;
array ~= 420;
array ~= 42;
array.map!(x => x*2).sum.should.equal(924);
}
```
fails. The test will run in an infinite loop. After some digging,
I realise that the `alias this` is foiling with my plan rather
than helping it. Is there a recommended way to achieve
- std.algorithm functions should Just Work (tm)
- appending as if it were a dynamic array
- preferably index-based access and .length should also work.
Is there a dub package that achieves this? Or are there any tips
to roll my own implementation?
May 16 2019
I think you have overcomplicated something quite simple. int[4] buffer; int bufferLength; buffer[bufferLength++] = item_to_append; buffer[bufferLength++] = item_to_append; int[] slice = buffer[0 .. bufferLength]; // you can use slice to any std.algorithm calls etc // just remember it is on the stack so don't store it beyond a function call
May 16 2019
On Thursday, 16 May 2019 at 12:45:03 UTC, Adam D. Ruppe wrote:I think you have overcomplicated something quite simple. int[4] buffer; int bufferLength; buffer[bufferLength++] = item_to_append; buffer[bufferLength++] = item_to_append; int[] slice = buffer[0 .. bufferLength]; // you can use slice to any std.algorithm calls etc // just remember it is on the stack so don't store it beyond a function callThanks. It's really a lot simpler than I thought. It's slightly error prone (i.e., the code doesn't work if I use ++bufferLength), but its simplicity might be worth the trade-off.
May 16 2019
Try mach.d https://github.com/pineapplemachine/mach.d it uses explicit range accessors for iteration.
May 16 2019
Thank you both for the quick replies. On Thursday, 16 May 2019 at 12:55:34 UTC, Kagamin wrote:Try mach.d https://github.com/pineapplemachine/mach.d it uses explicit range accessors for iteration.Thank you. I've looked into it, and it appears to be quite a big library. I've looked into mach.collect and mach.range, but I didn't manage to find what I was looking for (a simple array data structure). Do you recommend to look into any specific module?
May 16 2019
On Friday, 17 May 2019 at 06:58:54 UTC, Marco de Wild wrote:Thank you. I've looked into it, and it appears to be quite a big library. I've looked into mach.collect and mach.range, but I didn't manage to find what I was looking for (a simple array data structure). Do you recommend to look into any specific module?You use your array with math.range, but without alias this, it uses explicit accessor `asrange` for iteration.
May 17 2019
On Thursday, 16 May 2019 at 12:16:26 UTC, Marco de Wild wrote:Or are there any tips to roll my own implementation?I took a stab at it: --- nogc: nothrow: pure: struct NoGcArray(size_t maxSize, T) { private T[maxSize] _buffer; private T[] _slice; private size_t _frontIndex; size_t length() const { return _slice.length; } void opOpAssign(string op)(T element) { static if(op == "~") { _buffer[_frontIndex + length] = element; _slice = _buffer[_frontIndex..(length + 1)]; } else { static assert(false, "Only concatenation supported"); } } T opIndex(size_t index) const { return _slice[index]; } T front() const { return _slice[0]; } void popFront() { _frontIndex++; _slice = _slice[1..$]; } bool empty() const { return _slice.length == 0; } } void main() { import std.algorithm : sum, map; NoGcArray!(4, int) array; array ~= 420; array ~= 42; assert(array.map!(x => x*2).sum == 924); } --- Mike
May 17 2019









Marco de Wild <mdwild sogyo.nl> 