RFC on range design for D2
Andrei Alexandrescu
SeeWebsiteForEmail at erdani.org
Tue Sep 9 21:24:34 PDT 2008
Benji Smith wrote:
> bearophile wrote:
>> 5) The source code of the current algorithm module of D2 is already
>> very complex to follow, it smells of over-generalization here and
>> there. Sometimes it's better to reduce the generality of things, even
>> if that reduces their power a little, to reduce complexity, etc. Tango
>> code too isn't perfect, but it often looks more human. While you have
>> created the algorithm module I too have created something similar, but
>> based on different grounds.
>
> Along these same lines, while D is still young, the documentation is
> often thin, and code examples are scarce.
>
> I've been doing a lot of programming lately with Tango, and despite the
> growing documentation, I've had to refer directly to the Tango source
> code on more occasions than I can count. Luckily, the Tango sources are
> well-written and pretty easy to read and understand, and I've had very
> few problems figuring out how to use the library.
>
> I hope the range implementation makes readability a high priority.
Speaking of examples and readability, and to tie this with the
discussion on array reallocation, I was curious on an array appender
built on the output range interface. I've seen a quite complicated array
builder in digitalmars.d. I wanted a simpler appender that should not do
worse than the built-in ~= and that works with algorithm2 whenever data
is written out.
It turned out quite simple and it improved performance of a large-scale
data preprocessing task of mine (which involved reading and parsing
about 1M lines of integers) by 15%. I'd be curious how it fares with
other tests that you guys may have.
The idea is very simple: just use D's native append operation, but cache
the capacity to avoid too many lookups (I understand that that's the
bottleneck).
I paste the code below, I'd be indebted if you guys grabbed it and
tested it.
Andrei
struct ArrayAppender(T)
{
private T* _buffer;
private size_t _length;
private size_t _capacity;
this(T[] array)
{
_buffer = array.ptr;
_length = array.length;
if (_buffer) _capacity = .capacity(array.ptr) / T.sizeof;
}
size_t capacity() const { return _capacity; }
void putNext(T item)
{
invariant desiredLength = _length + 1;
if (desiredLength <= _capacity)
{
// Should do in-place construction here
_buffer[_length] = item;
}
else
{
// Time to reallocate, do it and cache capacity
auto tmp = _buffer[0 .. _length];
tmp ~= item;
_buffer = tmp.ptr;
_capacity = .capacity(_buffer) / T.sizeof;
}
_length = desiredLength;
}
T[] release()
{
// Shrink-to-fit
auto result = cast(T[]) realloc(_buffer, _length * T.sizeof);
// Relinquish state
_buffer = null;
_length = _capacity = 0;
return result;
}
}
unittest
{
auto app = arrayAppender(new char[0]);
string b = "abcdefg";
foreach (char c; b) app.putNext(c);
assert(app.release == "abcdefg");
}
More information about the Digitalmars-d-announce
mailing list