module gcc.support;

struct Array
{
    int length;
    void *ptr;
}

/* Type 'chunk' and associated values must match bitArrayElemType
   in the compiler. Also see internal/gc/gc.d: bit and *b functions */

//private const ubyte chunk;
//private const uint chunk_shift = 3;
//private const uint chunk_mask = 7;

/* Using 32-bit uint because:
   1. That's what DMD uses.
   2. Gcx.fullcollect assumes it.

   Hopefully, nothing depends on little endianess...
*/
private alias uint chunk;
private const uint chunk_shift = 5;
private const uint chunk_mask = 31;

private bit[] unaligned_slice(bit * source, uint low, uint high)
{
    Array a;
    uint di = 0;
    bit* pdst = new bit[high-low];
    a.length = high - low;

    while (low < high)
	pdst[di++] = source[low++];

    a.ptr = pdst;
    return * (bit[]*) & a;
}

extern (C):

// %% These need bounds checks and optimization
bit[] _d_gnu_bitarrayslicep(bit * source, uint low, uint high) {
    if ( (low & chunk_mask) /*|| (high & chunk_mask)*/ ) {
	return unaligned_slice(source, low, high);
    } else {
	Array a;
	a.length = high - low;
	a.ptr = ((chunk *) source) + (low >> chunk_shift);
	return * (bit[]*) & a;
    }
}

bit[] _d_gnu_bitarrayslice(bit[] source, uint low, uint high)
in {
    assert(low <= high);
    assert(high <= source.length);
}
body {
    if ( (low & chunk_mask) /*|| (high & chunk_mask)*/ ) {
	return unaligned_slice((bit *) source, low, high);
    } else {
	Array a;
	a.length = high - low;
	a.ptr = ((chunk *)source) + (low >> chunk_shift);
	return * (bit[]*) & a;
    }
}

// dst is not bound checked; compiler needs to do that
bit[] _d_gnu_copytobitarrayslice(bit * dst, uint low, uint high, bit[] src)
in {
    assert(low <= high);
    assert(high <= src.length);
}
body {
    bit *psrc = src;
    uint si = 0;
    uint di = low;
    while (di < high) {
	dst[di++] = psrc[si++];
    }
    return dst[low..high];
}
