On 2017-08-29 19:35, Moritz Maxeiner wrote:
On Tuesday, 29 August 2017 at 09:59:30 UTC, Jacob Carlborg wrote:
[...]
But if I keep the range internal, can't I just do the allocation
inside the range and only use "formattedWrite"? Instead of using both
formattedWrite and sformat and go through the data twice. Then of
course the final size is not known before allocating.
Certainly, that's what dynamic arrays (aka vectors, e.g. std::vector in
C++ STL) are for:
---
import core.exception;
import std.stdio;
import std.experimental.allocator;
import std.algorithm;
struct PoorMansVector(T)
{
private:
T[] store;
size_t length;
IAllocator alloc;
public:
@disable this(this);
this(IAllocator alloc)
{
this.alloc = alloc;
}
~this()
{
if (store)
{
alloc.dispose(store);
store = null;
}
}
void put(T t)
{
if (!store)
{
// Allocate only once for "small" vectors
store = alloc.makeArray!T(8);
if (!store) onOutOfMemoryError();
}
else if (length == store.length)
{
// Growth factor of 1.5
auto expanded = alloc.expandArray!char(store, store.length
/ 2);
if (!expanded) onOutOfMemoryError();
}
assert (length < store.length);
moveEmplace(t, store[length++]);
}
char[] release()
{
auto elements = store[0..length];
store = null;
return elements;
}
}
char[] sanitize(string value, IAllocator alloc)
{
import std.format : formattedWrite, sformat;
auto r = PoorMansVector!char(alloc);
(&r).formattedWrite!"'%s'"(value); // do not copy the range
return r.release();
}
void main()
{
auto s = sanitize("foo", theAllocator);
scope (exit) theAllocator.dispose(s);
writeln(s);
}
---
Do be aware that the above vector is named "poor man's vector" for a
reason, that's a hasty write down from memory and is sure to contain bugs.
For better vector implementations you can use at collection libraries
such as EMSI containers; my own attempt at a DbI vector container can be
found here [1]
[1]
https://github.com/Calrama/libds/blob/6a1fc347e1f742b8f67513e25a9fdbf79f007417/src/ds/vector.d
Thanks.
--
/Jacob Carlborg