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;
} |
|
|