On Sunday, 29 July 2012 at 06:27:32 UTC, Dmitry Olshansky wrote:
OK. Now back to the biggest question:
Slices use references (sometimes) to previous bitarray. Since it's a slice (like an array) this could be expected.

The "sometimes" part is not god enough! The problem is that small string optimization (or small array optimization) doesn't work with reference semantics. You may dig up discussion on proposal for small string optimization for char[] and string that was shot down on these grounds.

Bulit-in like semantics call for simple ptr/ptr+length struct and you can't get that can you?.>
E.g.

void mess_with(BitArray ba)
{
ba ~= true;
ba ~= false;
 //does it change anything outside this function? *maybe*

If it was a previous slice, then it never chances outside and appending would automatically allocate new memory.

ba[0] ^= true;
ba[1] ^= true;
auto x = ba; //even if used ref BitArray ba, x *maybe* references ba
//is x now a reference or a copy? *maybe*

Thus BitArray either becomes value type (that may come as unexpected, see your option c/d). Or it becomes full reference type as in option a (though it sucks).

Sorry but b is no go, as it makes code unpredictable I'd rather take my idea with separate ranges then b.

Solutions:
a) Drop the union, make all functions @safe (compared to @trusted), and they are all ref/slices b) Leave as sometimes ref, sometimes not; Use .dup when you NEED to ensure different unique copies. c) Apply COW (Copy-On-Write) where a known slice type (canExpand is false) when a change would apply, it replaces the present slice into it's own unique array. d) All slices become new dup'ed allocated arrays (Most expensive of them all)

Agreed, B is a bad choice. I'm going to suggest c myself, as changes would only propagate to a new true copy, otherwise it's read-only as a slice.

Because of d, I proposed that slices be separate type that is always a reference to original. Then only coping arrays themselves involves dup.

 Mmmm... i think you're right...

No it doesn't. bitfields are used to handle the beginning/ending offsets, equaling a total of 14 bits. It's the most confusing part (aside from [offset + sliceoffset + i] formulas). canExpand and isCompact fill the other two bits.

OK, finally I think I understand how your current version works. It's clever but leaves you in half-way value-reference state.

I didn't want to originally use the 1-byte per startBit/endingBit, but it does actually work when you have the functions working.

To point out few problems with unification of slice type and BitArray:

- Every time a small slice is taken say [1..30] it becomes a small array(?) thus it is a value type and doesn't affect original array

No, slices of compact arrays remain compact arrays. slices of larger arrays are reference until length is set, dupped, or appended to (forcing a resize/dup)

- No idea if a = b make a copy will make programmers nervous, esp if one is writing a library function as in this case there is no assumption that fits all

If it's compact, it's an auto separate copy/valuetype. If it's not compact, it's a reference to the original.

- Same thing but more, does this work?
        auto c = ba; //if ba is compact
        ba ~= true;

 ba may or may not be a normal/compact at this point

        assert(c.length = ba.length-1);
//c should remain with the same length unaffected (at least like built in arrays)

Most likely it would be compact afterwards (Even if it allocated memory).

I guess after going this over, two things need to happen. First it needs to be non-reference type, I don't want to go option d route, so I'll go for c instead. On a copy I'll add a postblit that makes the 'copy' now a slice which will create a new array when it changes in any way. Only question is when you pass the BitArray to a function as you showed, it would still think it's the original, unless the postblit/opAssign (or similar) can handle that. Hmmm time for some testing.

Reply via email to