Last update June 4, 2007

Daniel Keep /
snippets



Just some random bits of code. Everything in this page is public domain; if you do use something, a quick "thanks" in the ol' inbox would be appreciated.

CTFE string functions

Here are some functions designed to be used at compile-time.

ctfe_rcsStrip

Strips off the cruft from a single RCS keyword expansion. You know, things like "$Rev: 145 $" and "$Author: foo $" in source files. It strips out everything apart from the content in the middle, and even trims any superfluous whitespace out.

private enum RcsStripState { FindDollar, FindColon, FindClose }

char[] ctfe_rcsStrip(char[] keyword)
{
    auto state = RcsStripState.FindDollar;
    size_t indStart, indEnd;
    foreach( i,c ; keyword )
    {
        if( state == RcsStripState.FindDollar )
        {
            if( c == '$' )
                state = RcsStripState.FindColon;
        }
        else if( state == RcsStripState.FindColon )
        {
            if( c == ':' )
            {
                indStart = i+1;
                state = RcsStripState.FindClose;
            }
        }
        else if( state == RcsStripState.FindClose )
        {
            if( c == '$' )
                return ctfe_strip(keyword[indStart..i]);
        }
        else
            assert(false);
    }

    return keyword;
}

ctfe_strip

This function just strips off whitespace; but at compile time! Basically, it just walks the string forward to the first non-whitespace character, and then walks it backwards, returning the slice in the middle.

char[] ctfe_strip(char[] str)
{
    char[] next;

    foreach( i,c ; str )
    {
        if( !(c == ' ' || c == '\t' || c == '\v'
                   || c == '\r' || c == '\n') )
        {
            next = str[i..$];
            break;
        }
    }

    if( next.length == 0 )
        return next;

    foreach_reverse( i,c ; next )
    {
        if( !(c == ' ' || c == '\t' || c == '\v'
                    || c == '\r' || c == '\n') )
            return next[0..i+1];
    }

    // If we got here... well, we *shouldn't* have.
    assert(false);
}

Buffer

This is a very simple structure designed to allow you to explicitly control how much space is reserved for an array. To do this, it adds a "reserved" property. Unlike regular arrays, setting the length to zero doesn't deallocate the array; only setting reserved to zero does that.

import std.string : format;

struct buff(T : T[])
{
    private
    {
        alias buff!(T[]) thisT;
        T[] storage;
        size_t used;
    }

    static thisT opCall(size_t length)
    {
        return thisT(length, length);
    }

    static thisT opCall(size_t length, size_t reserved)
    {
        thisT result;
        result.storage = new T[reserved];
        result.used = length;
        return result;
    }

    static thisT opCall(T[] arr)
    {
        return thisT(arr, arr.length);
    }

    static thisT opCall(T[] arr, size_t length)
    {
        thisT result;
        result.storage = arr;
        result.used = length;
        return result;
    }

    T[] arr()
    {
        return storage[0..used];
    }

    thisT dup()
    {
        return thisT(storage.dup, used);
    }

    T* ptr()
    {
        return storage.ptr;
    }

    size_t length()
    {
        return used;
    }

    size_t length(size_t v)
    {
        if( reserved < v )
            reserved = v;
        return (used = v);
    }

    size_t reserved()
    {
        return storage.length;
    }

    size_t reserved(size_t v)
    {
        if( v < length )
            throw new Exception("attempt to reserve less space than used");
        
        else if( v == 0 )
        {
            delete storage;
            return 0;
        }
        else
            return (storage.length = v);
    }

    char[] toString()
    {
        return format("%s", arr);
    }

    thisT opCat(thisT rhs)
    {
        return thisT(this.arr ~ rhs.arr);
    }

    thisT opCat(T[] rhs)
    {
        return thisT(this.arr ~ rhs);
    }

    thisT opCat_r(T[] lhs)
    {
        return thisT(lhs ~ this.arr);
    }

    thisT opCatAssign(thisT rhs)
    {
        this.length = this.length + rhs.length;
        this.arr[$-rhs.length..$] = rhs[];
        return rhs;
    }

    T opCatAssign(T rhs)
    {
        this.length = this.length + 1;
        this.arr[$-1] = rhs;
        return rhs;
    }

    T[] opCatAssign(T[] rhs)
    {
        this.length = this.length + rhs.length;
        this.arr[$-rhs.length..$] = rhs[];
        return rhs;
    }

    T opIndex(size_t i)
    in
    {
        assert( i < length );
    }
    body
    {
        return storage[i];
    }

    T opIndexAssign(T v, size_t i)
    in
    {
        assert( i < length );
    }
    body
    {
        return (storage[i] = v);
    }

    T[] opSlice()
    {
        return arr;
    }

    T[] opSlice(size_t a, size_t b)
    in
    {
        assert( a <= b );
        assert( b <= length );
    }
    body
    {
        return storage[a..b];
    }

    T opSliceAssign(T v)
    {
        storage[0..used] = v;
        return v;
    }

    T[] opSliceAssign(T[] v)
    in
    {
        assert( v.length == length );
    }
    body
    {
        return (storage[0..used] = v[]);
    }

    thisT opSliceAssign(thisT v)
    in
    {
        assert( v.length == length );
    }
    body
    {
        storage[0..used] = v[];
        return v;
    }

    T opSliceAssign(T v, size_t a, size_t b)
    in
    {
        assert( a <= b );
        assert( b <= length );
    }
    body
    {
        storage[a..b] = v;
        return v;
    }

    T[] opSliceAssign(T[] v, size_t a, size_t b)
    in
    {
        assert( a <= b );
        assert( b <= length );
        assert( v.length == (b-a) );
    }
    body
    {
        return (storage[a..b] = v[]);
    }

    thisT opSliceAssign(thisT v, size_t a, size_t b)
    in
    {
        assert( a <= b );
        assert( b <= length );
        assert( v.length == (b-a) );
    }
    body
    {
        storage[a..b] = v[];
        return v;
    }
}

And here's a little demo on how to use it.

import std.stdio;

void main()
{
    auto a = buff!(int[])(0,10);

    void a_stats()
    {
        writefln("a.ptr = %08x, a.length = %2s, a.reserved = %2s; %s",
                a.ptr, a.length, a.reserved, a);
    }

    a_stats;

    a.length = 5;
    a[0..5] = [1,2,3,4,5];
    a_stats;

    a ~= 6;
    a_stats;

    a ~= [7,8,9,10];
    a_stats;

    a ~= 11;
    a_stats;

    a.length = 0;
    a_stats;

    a ~= [21,22,23,24,25];
    a_stats;

    a.length = 0;
    a.reserved = 0;
    a_stats;

    a.length = 3;
    a_stats;
}


FrontPage | News | TestPage | MessageBoard | Search | Contributors | Folders | Index | Help | Preferences | Edit

Edit text of this page (date of last change: June 4, 2007 13:47 (diff))