//
// $Id: Vector.m,v 1.40 2005/05/18 06:46:54 will_mason Exp $
//
// vi: set ft=objc:

/*
 * ObjectiveLib - a library of containers and algorithms for Objective-C
 *
 * Copyright (c) 2004
 * Will Mason
 *
 * Portions:
 *
 * Copyright (c) 1994
 * Hewlett-Packard Company
 *
 * Copyright (c) 1996,1997
 * Silicon Graphics Computer Systems, Inc.
 *
 * Copyright (c) 1997
 * Moscow Center for SPARC Technology
 *
 * Copyright (c) 1999 
 * Boris Fomitchev
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * You may contact the author at will_mason@users.sourceforge.net.
 */

#import "VectorPackage.h"
#import "Constants.h"
#import "ContainerCoder.h"
#import <Foundation/NSValue.h>
#import <Foundation/NSCoder.h>
#import <Foundation/NSString.h>
#import <Foundation/NSData.h>
#import <string.h>
#import <limits.h>

#define OL_WORD_BIT ((unsigned)(CHAR_BIT * sizeof(uint32_t)))

static NSNumber* OL_BOOL_YES = nil;
static NSNumber* OL_BOOL_NO = nil;

static void __advanceBitIterBase(OLBitIteratorBase* b, int count)
{
    int n = count + b->offset;

    b->chunk += n / OL_WORD_BIT;
    n = n % OL_WORD_BIT;
    if (n < 0)
    {
        b->offset = n + OL_WORD_BIT;
        b->chunk--;
    }
    else
    {
        b->offset = n;
    }
}

static void __assignBitIterBase(OLBitIteratorBase* b, BOOL val)
{
    uint32_t mask = 1U << b->offset;

    if (val)
        *b->chunk |= mask;
    else
        *b->chunk &= ~mask;
}

static void __bumpDownBitIterBase(OLBitIteratorBase* b)
{
    if (b->offset-- == 0)
    {
        b->offset = OL_WORD_BIT - 1;
        b->chunk--;
    }
}

static void __bumpUpBitIterBase(OLBitIteratorBase* b)
{
    if (b->offset++ == OL_WORD_BIT -1)
    {
        b->offset = 0;
        b->chunk++;
    }
}

static BOOL __dereferenceBitIterBase(OLBitIteratorBase* b)
{
    return (*b->chunk & (1U << b->offset)) ? YES : NO;
}

static BOOL __isEqualBitIterBase(OLBitIteratorBase* b1, OLBitIteratorBase* b2)
{
    return (b1->chunk == b2->chunk && b1->offset == b2->offset) ? YES : NO;
}

static OLBitIteratorBase __copyBackwardBitIterBase(OLBitIteratorBase first,
                                                   OLBitIteratorBase last,
                                                   OLBitIteratorBase dest)
{
    while (!__isEqualBitIterBase(&last, &first))
    {
        __bumpDownBitIterBase(&last);
        __bumpDownBitIterBase(&dest);
        __assignBitIterBase(&dest, __dereferenceBitIterBase(&last));
    }
    return dest;
}

static OLBitIteratorBase __copyBitIterBase(OLBitIteratorBase first,
                                           OLBitIteratorBase last,
                                           OLBitIteratorBase dest)
{
    for ( ;
         !__isEqualBitIterBase(&first, &last);
         __bumpUpBitIterBase(&first), __bumpUpBitIterBase(&dest))
    {
        __assignBitIterBase(&dest, __dereferenceBitIterBase(&first));
    }
    return dest;
}

static int __differenceBitIterBase(OLBitIteratorBase* b1, OLBitIteratorBase* b2)
{
    return OL_WORD_BIT * (b1->chunk - b2->chunk) +
        b1->offset - b2->offset;
}

static void __fillBitIterBase(OLBitIteratorBase first, OLBitIteratorBase last, BOOL val)
{
    for ( ;
         !__isEqualBitIterBase(&first, &last);
         __bumpUpBitIterBase(&first))
    {
        __assignBitIterBase(&first, val);
    }
}

static void __fillNBitIterBase(OLBitIteratorBase first, unsigned count, BOOL val)
{
    unsigned cur;

    for (cur = 0; cur < count; cur++, __bumpUpBitIterBase(&first))
        __assignBitIterBase(&first, val);
}

@interface OLVector (PrivateMethods)

- (OLArrayIterator*) eraseImplFrom: (OLArrayIterator*)first to: (OLArrayIterator*)last needItor: (BOOL)needItor;

@end

@interface OLArrayIterator (PrivateMethods)

- (id*) pointer;

@end

@interface OLBitIterator (PrivateMethods)

- (id) initWithChunk: (uint32_t*)ch offset: (uint8_t)off;
- (OLBitIteratorBase*) base;

@end

@interface OLBoolVector (PrivateMethods)

- (uint32_t*) bitAlloc: (unsigned)bitCount;
- (OLBitIteratorBase) eraseImplFrom: (OLBitIteratorBase*)first to: (OLBitIteratorBase*)last;
- (void) insertImplAt: (OLBitIteratorBase*)where count: (unsigned)num filledWith: (BOOL)value;
- (void) insertImplAt: (OLBitIteratorBase*)where from: (OLForwardIterator*)first to: (OLForwardIterator*)last;
- (OLBitIteratorBase) insertImplAt: (OLBitIteratorBase*)where value: (BOOL)val;
- (void) initialize: (unsigned)bitCount setEnd: (BOOL)setEnd;

@end

@implementation OLVector

+ (id) vector
{
    OL_BEGIN_AUTO_CTOR(OLVector)
        init
    OL_END_AUTO_CTOR;
}

+ (id) vectorFrom: (OLForwardIterator*)first to: (OLForwardIterator*)last
{
    OL_BEGIN_AUTO_CTOR(OLVector)
        initFrom: first to: last
    OL_END_AUTO_CTOR;
}

+ (id) vectorWithCapacity: (unsigned)capacity
{
    OL_BEGIN_AUTO_CTOR(OLVector)
        initWithCapacity: capacity
    OL_END_AUTO_CTOR;
}

+ (id) vectorWithSize: (unsigned)size filledWith: (id)value
{
    OL_BEGIN_AUTO_CTOR(OLVector)
        initWithSize: size filledWith: value
    OL_END_AUTO_CTOR;
}

+ (id) vectorWithVector: (OLVector*)right
{
    OL_BEGIN_AUTO_CTOR(OLVector)
        initWithVector: right
    OL_END_AUTO_CTOR;
}

- (id) init
{
    return [self initWithAllocator: [OLAllocator defaultAllocator]];
}

- (id) initFrom: (OLForwardIterator*)first to: (OLForwardIterator*)last
{
    return [self initFrom: first to: last allocator: [OLAllocator defaultAllocator]];
}

- (id) initFrom: (OLForwardIterator*)first to: (OLForwardIterator*)last allocator: (OLAllocator*)alloc
{
    [super init];
    [self initWithAllocator: alloc];
    [self assignFrom: first to: last];
    return self;
}

- (id) initWithAllocator: (OLAllocator*)alloc
{
    [super init];
    allocator = OBJ_RETAIN(alloc);
    begin = end = endOfCapacity = NULL;
    return self;
}

- (id) initWithCapacity: (unsigned)capacity
{
    [super init];
    allocator = OBJ_RETAIN([OLAllocator defaultAllocator]);
    begin = end = [allocator allocateBytes: capacity * sizeof(id)];
    endOfCapacity = begin + capacity;
    return self;
}

- (id) initWithCoder: (NSCoder*)decoder
{
    unsigned count;

    [super init];
    allocator = OBJ_RETAIN([OLContainerCoder decodeAllocatorWithCoder: decoder]);
    begin = [OLContainerCoder decodeWithCoder: decoder allocator: allocator
        returnedCount: &count];
    endOfCapacity = begin + count;
    for (end = begin; end != endOfCapacity; end++)
        OBJ_RETAIN(*end);
    return self;
}

- (id) initWithSize: (unsigned)size filledWith: (id)value
{
    return [self initWithSize: size filledWith: value allocator: [OLAllocator defaultAllocator]];
}

- (id) initWithSize: (unsigned)size filledWith: (id)value allocator: (OLAllocator*)alloc
{
    [super init];
    allocator = OBJ_RETAIN(alloc);
    begin = [allocator allocateBytes: size * sizeof(id)];
    endOfCapacity = begin + size;
    for (end = begin; end != endOfCapacity; end++)
        *end = OBJ_RETAIN(value);
    return self;
}

- (id) initWithVector: (OLVector*)vector
{
    id* other;

    [super init];
    allocator = OBJ_RETAIN(vector->allocator);
    begin = [allocator allocateBytes: [vector size] * sizeof(id)];
    for (end = begin, other = vector->begin; other != vector->end; other++, end++)
        *end = OBJ_RETAIN(*other);
    endOfCapacity = end;
    return self;
}

- (void) dealloc
{
    if (begin != NULL)
    {
        [self clear];
        [allocator deallocateBytes: begin];
    }
    OBJ_RELEASE(allocator);
    [super dealloc];
}

- (void) assign: (unsigned)count filledWith: (id)value
{
    [self clear];
    [self reserve: count];
    for ( ; end != (begin + count); end++)
        *end = OBJ_RETAIN(value);
}

- (void) assignAt: (unsigned)index value: (id)object
{
    id target = begin[index];

    if (target != object)
    {
        OBJ_RELEASE(target);
        begin[index] = OBJ_RETAIN(object);
    }
}

- (void) assignFrom: (OLForwardIterator*)first to: (OLForwardIterator*)last
{
    OLForwardIterator* itor;
    unsigned distance = [OLIterator distanceFrom: first to: last allocator: allocator];

    [self clear];
    [self reserve: distance];
    for (itor = [first copyWithAllocator: allocator];
         ![itor isEqual: last];
         [itor advance], end++)
    {
        *end = OBJ_RETAIN([itor dereference]);
    }
    [allocator deallocateObject: itor];
}

- (id) at: (unsigned)index
{
    return begin[index];
}

- (id) back
{
    return begin[(end - begin) - 1];
}

- (OLArrayIterator*) begin
{
    return OBJ_COND_AUTORELEASE([self beginImpl]);
}

- (unsigned) capacity
{
    return endOfCapacity - begin;
}

- (void) clear
{
    id* current;

    for (current = begin; current != end; current++)
        OBJ_RELEASE(*current);
    end = begin;
}

- (id) copyWithAllocator: (OLAllocator*)allocatr
{
    return [[allocatr allocateObject: [OLVector class]]
        initWithVector: self];
}

- (id) copyWithZone: (NSZone*)zone
{
    return [[OLVector allocWithZone: zone] initWithVector: self];
}

- (BOOL) empty
{
    return begin == end;
}

- (void) encodeWithCoder: (NSCoder*)encoder
{
    OLArrayIterator* first = [self beginImpl];

    [OLContainerCoder encodeAllocator: allocator withCoder: encoder];
    [OLContainerCoder encodeFrom: first count: end - begin
        withCoder: encoder allocator: allocator];
    [allocator deallocateObject: first];
}

- (OLArrayIterator*) end
{
    return OBJ_COND_AUTORELEASE([self endImpl]);
}

- (OLArrayIterator*) erase: (OLArrayIterator*)where
{
    id* after = [where pointer] + 1;

    OBJ_RELEASE([where dereference]);
    if (after != end)
        memmove([where pointer], after, (end - after) * sizeof(id));
    end--;
    return OBJ_COND_AUTORELEASE([[allocator allocateObject: [OLArrayIterator class]]
        initWithPointer: [where pointer]]);
}

- (OLArrayIterator*) eraseFrom: (OLArrayIterator*)first to: (OLArrayIterator*)last
{
    return OBJ_COND_AUTORELEASE([self eraseImplFrom: first to: last needItor: YES]);
}

- (id) front
{
    return *begin;
}

- (OLAllocator*) allocator
{
    return allocator;
}

- (OLArrayIterator*) insertAt: (OLArrayIterator*)where value: (id)object
{
    unsigned offset = [where pointer] - begin;
    BOOL atEnd = [where pointer] == end;
    id* newWhere;

    [self reserve: [self size] + 1];
    newWhere = begin + offset;
    if (!atEnd)
        memmove(newWhere + 1, newWhere, (end - newWhere) * sizeof(id));
    *newWhere = OBJ_RETAIN(object);
    end++;
    return OBJ_COND_AUTORELEASE([[allocator allocateObject: [OLArrayIterator class]]
        initWithPointer: newWhere]);
}

- (void) insertAt: (OLArrayIterator*)where count: (unsigned)num filledWith: (id)value
{
    unsigned offset = [where pointer] - begin;
    BOOL atEnd = [where pointer] == end;
    id* newWhere;
    int i;

    [self reserve: [self size] + num];
    newWhere = begin + offset;
    if (!atEnd)
        memmove(newWhere + num, newWhere, (end - newWhere) * sizeof(id));
    for (i = 0; i < num; i++)
        newWhere[i] = OBJ_RETAIN(value);
    end += num;
}

- (void) insertAt: (OLArrayIterator*)where from: (OLForwardIterator*)first to: (OLForwardIterator*)last
{
    OLForwardIterator* firstCopy = [first copyWithAllocator: allocator];
    unsigned distance = 0;
    unsigned offset = [where pointer] - begin;
    BOOL atEnd = [where pointer] == end;
    id* newWhere;
    id* counter;

    for ( ; ![firstCopy isEqual: last]; [firstCopy advance])
        distance++;
    [allocator deallocateObject: firstCopy];
    [self reserve: [self size] + distance];
    newWhere = begin + offset;
    if (!atEnd)
        memmove(newWhere + distance, newWhere, (end - newWhere) * sizeof(id));
    firstCopy = [first copyWithAllocator: allocator];
    counter = newWhere;
    for ( ; ![firstCopy isEqual: last]; [firstCopy advance], counter++)
        *counter = OBJ_RETAIN([firstCopy dereference]);
    [allocator deallocateObject: firstCopy];
    end += distance;
}

- (BOOL) isEqual: (id)object
{
    id* current;
    OLVector* other;
    id* otherCurrent;

    if (![object isKindOfClass: [OLVector class]])
        return NO;
    other = (OLVector*)object;
    if ([other size] != [self size])
        return NO;
    for (current = begin, otherCurrent = other->begin; current != end; current++, otherCurrent++)
    {
        if (![*current isEqual: *otherCurrent])
            return NO;
    }
    return YES;
}

- (unsigned) maxSize
{
    return UINT_MAX / sizeof(id);
}

- (void) popBack
{
    OBJ_RELEASE(*(end - 1));
    end--;
}

- (void) pushBack: (id)object
{
    [self reserve: [self size] + 1];
    *end = OBJ_RETAIN(object);
    end++;
}

- (OLReverseRandomIterator*) rbegin
{
    OLArrayIterator* itor = [self endImpl];
    OLReverseRandomIterator* rc = OBJ_COND_AUTORELEASE([[allocator allocateObject:
        [OLReverseRandomIterator class]] initWithIterator: itor]);

    [allocator deallocateObject: itor];
    return rc;
}

- (OLReverseRandomIterator*) rend
{
    OLArrayIterator* itor = [self beginImpl];
    OLReverseRandomIterator* rc = OBJ_COND_AUTORELEASE([[allocator allocateObject:
        [OLReverseRandomIterator class]] initWithIterator: itor]);

    [allocator deallocateObject: itor];
    return rc;
}

- (void) reserve: (unsigned)count
{
    id* newBegin;
    unsigned newCapacity;
    unsigned myCapacity = endOfCapacity - begin;
    unsigned mySize;

    if (count > myCapacity)
    {
        newCapacity = MAX(count, myCapacity * 2);
        newBegin = [allocator allocateBytes: newCapacity * sizeof(id)];
        mySize = end - begin;
        if (begin != NULL)
        {
            memcpy(newBegin, begin, mySize * sizeof(id));
            [allocator deallocateBytes: begin];
        }
        begin = newBegin;
        end = begin + mySize;
        endOfCapacity = begin + newCapacity;
    }
}

- (void) resize: (unsigned)newsize filledWith: (id)value
{
    unsigned mySize = [self size];
    id* newEnd;
    OLArrayIterator* first;
    OLArrayIterator* endItor;

    if (newsize > mySize)
    {
        [self reserve: newsize];
        newEnd = begin + newsize;
        for ( ; end < newEnd; end++)
            *end = OBJ_RETAIN(value);
    }
    else if (newsize < mySize)
    {
        first = [[allocator allocateObject: [OLArrayIterator class]]
            initWithPointer: begin + newsize];
        endItor = [self endImpl];
        [self eraseImplFrom: first to: endItor needItor: NO];
        [allocator deallocateObject: first];
        [allocator deallocateObject: endItor];
    }
}

- (unsigned) size
{
    return end - begin;
}

- (void) swap: (OLVector*)right
{
    OL_PREPARE_SLOW_SWAP;
    OLArrayIterator* itorBegin;
    OLArrayIterator* itorEnd;
    OLVector* copy;

    if (self != right)
    {
        if ([allocator isEqual: right->allocator])
        {
            OL_SLOW_SWAP(begin, right->begin);
            OL_SLOW_SWAP(end, right->end);
            OL_SLOW_SWAP(endOfCapacity, right->endOfCapacity);
        }
        else
        {
            itorBegin = [self beginImpl];
            itorEnd = [self endImpl];
            copy = [[allocator allocateObject: [OLVector class]]
                initFrom: itorBegin to: itorEnd allocator: allocator];
            [allocator deallocateObject: itorBegin];
            [allocator deallocateObject: itorEnd];
            itorBegin = [right beginImpl];
            itorEnd = [right endImpl];
            [self assignFrom: itorBegin to: itorEnd];
            [allocator deallocateObject: itorBegin];
            [allocator deallocateObject: itorEnd];
            itorBegin = [copy beginImpl];
            itorEnd = [copy endImpl];
            [right assignFrom: itorBegin to: itorEnd];
            [allocator deallocateObject: itorBegin];
            [allocator deallocateObject: itorEnd];
            [allocator deallocateObject: copy];
        }
    }
}

@end

@implementation OLVector (PackageMethods)

- (OLArrayIterator*) beginImpl
{
    return [[allocator allocateObject: [OLArrayIterator class]] initWithPointer: begin];
}

- (OLArrayIterator*) endImpl
{
    return [[allocator allocateObject: [OLArrayIterator class]] initWithPointer: end];
}

@end

@implementation OLVector (PrivateMethods)

- (OLArrayIterator*) eraseImplFrom: (OLArrayIterator*)first to: (OLArrayIterator*)last needItor: (BOOL)needItor
{
    id* current;
    id* firstPtr = [first pointer];
    id* lastPtr = [last pointer];
    unsigned span = lastPtr - firstPtr;

    for (current = firstPtr; current != lastPtr; current++)
        OBJ_RELEASE(*current);
    if (lastPtr != end)
        memmove(firstPtr, lastPtr, span * sizeof(id));
    end -= span;
    return needItor ?
        [[allocator allocateObject: [OLArrayIterator class]] initWithPointer: [first pointer]] :
        nil;
}

@end

@implementation OLArrayIterator (PrivateMethods)

- (id*) pointer
{
    return current;
}

@end

@implementation OLBitIterator

- (id) advance
{
    __bumpUpBitIterBase(&base);
    return self;
}

- (id) advanceBy: (int)count
{
    __advanceBitIterBase(&base, count);
    return self;
}

- (id) assign: (id)object
{
    __assignBitIterBase(&base, [object boolValue]);
    return self;
}

- (id) copyWithAllocator: (OLAllocator*)alloc
{
    return [[alloc allocateObject: [OLBitIterator class]]
        initWithChunk: base.chunk offset: base.offset];
}

- (id) copyWithZone: (NSZone*)zone
{
    return [[OLBitIterator allocWithZone: zone]
        initWithChunk: base.chunk offset: base.offset];
}

- (id) dereference
{
    return __dereferenceBitIterBase(&base) ? OL_BOOL_YES : OL_BOOL_NO;
}

- (int) difference: (OLRandomAccessIterator*)other
{
    int diff = 0;

    if ([other isMemberOfClass: [OLBitIterator class]])
        diff = __differenceBitIterBase(&base, &((OLBitIterator*)other)->base);
    return diff;
}

- (BOOL) isEqual: (id)object
{
    return [super isEqual: object] &&
           __isEqualBitIterBase(&base, &((OLBitIterator*)object)->base);
}

- (id) reverse
{
    __bumpDownBitIterBase(&base);
    return self;
}

@end

@implementation OLBitIterator (PrivateMethods)

- (id) initWithChunk: (uint32_t*)ch offset: (uint8_t)off
{
    [super init];
    if (OL_BOOL_YES == nil)
    {
        OL_BOOL_YES = [[NSNumber alloc] initWithBool: YES];
        OL_BOOL_NO = [[NSNumber alloc] initWithBool: NO];
    }
    base.chunk = ch;
    base.offset = off;
    return self;
}

- (OLBitIteratorBase*) base
{
    return &base;
}

@end

@implementation OLBoolVector

+ (id) boolVector
{
    OL_BEGIN_AUTO_CTOR(OLBoolVector)
        init
    OL_END_AUTO_CTOR;
}

+ (id) boolVectorFrom: (OLForwardIterator*)first to: (OLForwardIterator*)last
{
    OL_BEGIN_AUTO_CTOR(OLBoolVector)
        initFrom: first to: last
    OL_END_AUTO_CTOR;
}

+ (id) boolVectorWithBoolVector: (OLBoolVector*)right
{
    OL_BEGIN_AUTO_CTOR(OLBoolVector)
        initWithBoolVector: right
    OL_END_AUTO_CTOR;
}

+ (id) boolVectorWithCapacity: (unsigned)capacity
{
    OL_BEGIN_AUTO_CTOR(OLBoolVector)
        initWithCapacity: capacity
    OL_END_AUTO_CTOR;
}

+ (id) boolVectorWithSize: (unsigned)size filledWithBool: (BOOL)value
{
    OL_BEGIN_AUTO_CTOR(OLBoolVector)
        initWithSize: size filledWithBool: value
    OL_END_AUTO_CTOR;
}

- (id) init
{
    return [self initWithAllocator: [OLAllocator defaultAllocator]];
}

- (id) initFrom: (OLForwardIterator*)first to: (OLForwardIterator*)last
{
    return [self initFrom: first to: last allocator: [OLAllocator defaultAllocator]];
}

- (id) initFrom: (OLForwardIterator*)first to: (OLForwardIterator*)last allocator: (OLAllocator*)alloc
{
    OLForwardIterator* f;

    [self initWithAllocator: alloc];
    [self initialize: [OLIterator distanceFrom: first to: last allocator: alloc] setEnd: NO];
    for (f = [first copyWithAllocator: alloc]; ![f isEqual: last]; [f advance])
        [self pushBack: [[f dereference] boolValue]];
    [alloc deallocateObject: f];
    return self;
}

- (id) initWithAllocator: (OLAllocator*)alloc
{
    [super init];
    allocator = OBJ_RETAIN(alloc);
    begin.chunk = end.chunk = endOfCapacity = NULL;
    begin.offset = end.offset = 0;
    return self;
}

- (id) initWithBoolVector: (OLBoolVector*)bvector
{
    [self initWithAllocator: bvector->allocator];
    [self initialize: [bvector size] setEnd: YES];
    __copyBitIterBase(bvector->begin, bvector->end, begin);
    return self;
}

- (id) initWithCapacity: (unsigned)capacity
{
    [self init];
    [self initialize: capacity setEnd: NO];
    return self;
}

- (id) initWithCoder: (NSCoder*)decoder
{
    uint32_t length;

    [super init];
    allocator = OBJ_RETAIN([OLContainerCoder decodeAllocatorWithCoder: decoder]);
    if ([decoder respondsToSelector: @selector(allowsKeyedCoding)] &&
        [decoder allowsKeyedCoding])
    {
        length = [decoder decodeIntForKey: LENGTH_KEY];
        if (length != 0)
        {
            begin.offset = [decoder decodeIntForKey: BEGIN_OFFSET_KEY];
            end.offset = [decoder decodeIntForKey: END_OFFSET_KEY];
        }
    }
    else
    {
        [decoder decodeValueOfObjCType: @encode(uint32_t) at: &length];
        if (length != 0)
        {
            [decoder decodeValueOfObjCType: @encode(uint8_t) at: &begin.offset];
            [decoder decodeValueOfObjCType: @encode(uint8_t) at: &end.offset];
        }
    }
    if (length == 0)
    {
        begin.chunk = end.chunk = endOfCapacity = NULL;
        begin.offset = end.offset = 0;
    }
    else
    {
        begin.chunk = [allocator allocateBytes: length * sizeof(uint32_t)];
        endOfCapacity = begin.chunk + length;
        end.chunk = endOfCapacity - 1;
        [decoder decodeArrayOfObjCType: @encode(uint32_t) count: length at: begin.chunk];
    }
    return self;
}

- (id) initWithSize: (unsigned)size filledWithBool: (BOOL)value
{
    return [self initWithSize: size filledWithBool: value
        allocator: [OLAllocator defaultAllocator]];
}

- (id) initWithSize: (unsigned)size filledWithBool: (BOOL)value allocator: (OLAllocator*)alloc
{
    uint32_t* cur;
    uint32_t fill = value ? ~0 : 0;

    [self initWithAllocator: alloc];
    [self initialize: size setEnd: YES];
    for (cur = begin.chunk; cur != endOfCapacity; cur++)
        *cur = fill;
    return self;
}

- (void) dealloc
{
    if (begin.chunk != NULL)
        [allocator deallocateBytes: begin.chunk];
    OBJ_RELEASE(allocator);
    [super dealloc];
}

- (void) assign: (unsigned)count filledWith: (BOOL)value
{
    OLBitIteratorBase tmp;
    uint32_t* cur;
    uint32_t fill = value ? ~0 : 0;
    unsigned mySize = [self size];

    if (count > mySize)
    {
        for (cur = begin.chunk; cur < endOfCapacity; cur++)
            *cur = fill;
        [self insertImplAt: &end count: count - mySize filledWith: value];
    }
    else
    {
        tmp = begin;
        __advanceBitIterBase(&tmp, count);
        [self eraseImplFrom: &tmp to: &end];
        for (cur = begin.chunk; cur < endOfCapacity; cur++)
            *cur = fill;
    }
}

- (void) assignAt: (unsigned)index value: (BOOL)val
{
    OLBitIteratorBase pos = begin;

    __advanceBitIterBase(&pos, index);
    __assignBitIterBase(&pos, val);
}

- (void) assignFrom: (OLForwardIterator*)first to: (OLForwardIterator*)last
{
    OLBitIteratorBase cur = begin;
    OLForwardIterator* f = [first copyWithAllocator: allocator];

    for ( ;
         ![f isEqual: last] && !__isEqualBitIterBase(&cur, &end);
         [f advance], __bumpUpBitIterBase(&cur))
    {
        __assignBitIterBase(&cur, [[f dereference] boolValue]);
    }
    if ([f isEqual: last])
        [self eraseImplFrom: &cur to: &end];
    else
        [self insertImplAt: &end from: f to: last];
    [allocator deallocateObject: f];
}

- (BOOL) at: (unsigned)index
{
    OLBitIteratorBase i = begin;

    __advanceBitIterBase(&i, index);
    return __dereferenceBitIterBase(&i);
}

- (BOOL) back
{
    OLBitIteratorBase i = end;

    __bumpDownBitIterBase(&i);
    return __dereferenceBitIterBase(&i);
}

- (OLBitIterator*) begin
{
    return OBJ_COND_AUTORELEASE([[allocator allocateObject: [OLBitIterator class]]
        initWithChunk: begin.chunk offset: begin.offset]);
}

- (unsigned) capacity
{
    OLBitIteratorBase top = { endOfCapacity, 0 };

    return __differenceBitIterBase(&top, &begin);
}

- (void) clear
{
    [self eraseImplFrom: &begin to: &end];
}

- (id) copyWithAllocator: (OLAllocator*)alloc
{
    return [[alloc allocateObject: [OLBoolVector class]]
        initWithBoolVector: self];
}

- (id) copyWithZone: (NSZone*)zone
{
    return [[OLBoolVector allocWithZone: zone] initWithBoolVector: self];
}

- (BOOL) empty
{
    return __isEqualBitIterBase(&begin, &end);
}

- (void) encodeWithCoder: (NSCoder*)encoder
{
    uint32_t count = ([self size] + OL_WORD_BIT - 1) / OL_WORD_BIT;

    [OLContainerCoder encodeAllocator: allocator withCoder: encoder];
    if ([encoder respondsToSelector: @selector(allowsKeyedCoding)] &&
        [encoder allowsKeyedCoding])
    {
        [encoder encodeInt: count forKey: LENGTH_KEY];
        if (count != 0)
        {
            [encoder encodeInt: begin.offset forKey: BEGIN_OFFSET_KEY];
            [encoder encodeInt: end.offset forKey: END_OFFSET_KEY];
        }
    }
    else
    {
        [encoder encodeValueOfObjCType: @encode(uint32_t) at: &count];
        if (count != 0)
        {
            [encoder encodeValueOfObjCType: @encode(uint8_t) at: &begin.offset];
            [encoder encodeValueOfObjCType: @encode(uint8_t) at: &end.offset];
        }
    }
    if (count != 0)
        [encoder encodeArrayOfObjCType: @encode(uint32_t) count: count at: begin.chunk];
}

- (OLBitIterator*) end
{
    return OBJ_COND_AUTORELEASE([[allocator allocateObject: [OLBitIterator class]]
        initWithChunk: end.chunk offset: end.offset]);
}

- (OLBitIterator*) erase: (OLBitIterator*)where
{
    OLBitIteratorBase pos = *[where base];
    OLBitIteratorBase posPlus = pos;

    __bumpUpBitIterBase(&posPlus);
    if (!__isEqualBitIterBase(&posPlus, &end))
        __copyBitIterBase(posPlus, end, pos);
    __bumpDownBitIterBase(&end);
    return OBJ_COND_AUTORELEASE([[allocator allocateObject: [OLBitIterator class]]
        initWithChunk: pos.chunk offset: pos.offset]);
}

- (OLBitIterator*) eraseFrom: (OLBitIterator*)first to: (OLBitIterator*)last
{
    OLBitIteratorBase r = [self eraseImplFrom: [first base] to: [last base]];

    return OBJ_COND_AUTORELEASE([[allocator allocateObject: [OLBitIterator class]]
        initWithChunk: r.chunk offset: r.offset]);
}

- (BOOL) front
{
    return __dereferenceBitIterBase(&begin);
}

- (OLAllocator*) allocator
{
    return allocator;
}

- (void) insertAt: (OLBitIterator*)where count: (unsigned)num filledWith: (BOOL)value
{
    [self insertImplAt: [where base] count: num filledWith: value];
}

- (void) insertAt: (OLBitIterator*)where from: (OLForwardIterator*)first to: (OLForwardIterator*)last
{
    [self insertImplAt: [where base] from: first to: last];
}

- (OLBitIterator*) insertAt: (OLBitIterator*)where value: (BOOL)val
{
    OLBitIteratorBase r = [self insertImplAt: [where base] value: val];

    return OBJ_COND_AUTORELEASE([[allocator allocateObject: [OLBitIterator class]]
        initWithChunk: r.chunk offset: r.offset]);
}

- (BOOL) isEqual: (id)object
{
    OLBitIteratorBase cur;
    OLBitIteratorBase itsCur;
    OLBoolVector* other;

    if (![object isKindOfClass: [OLBoolVector class]])
        return NO;
    other = (OLBoolVector*)object;
    if ([other size] != [self size])
        return NO;
    for (cur = begin, itsCur = other->begin;
         !__isEqualBitIterBase(&cur, &end);
         __bumpUpBitIterBase(&cur), __bumpUpBitIterBase(&itsCur))
    {
        if (__dereferenceBitIterBase(&cur) != __dereferenceBitIterBase(&itsCur))
            return NO;
    }
    return YES;
}

- (unsigned) maxSize
{
    return UINT_MAX;
}

- (void) popBack
{
    __bumpDownBitIterBase(&end);
}

- (void) pushBack: (BOOL)value
{
    if (end.chunk != endOfCapacity)
    {
        __assignBitIterBase(&end, value);
        __bumpUpBitIterBase(&end);
    }
    else
    {
        [self insertImplAt: &end value: value];
    }
}

- (OLReverseRandomIterator*) rbegin
{
    OLBitIterator* e = [[allocator allocateObject: [OLBitIterator class]]
        initWithChunk: end.chunk offset: end.offset];
    OLReverseRandomIterator* r = [[allocator allocateObject: [OLReverseRandomIterator class]]
        initWithIterator: e];

    [allocator deallocateObject: e];
    return OBJ_COND_AUTORELEASE(r);
}

- (OLReverseRandomIterator*) rend
{
    OLBitIterator* b = [[allocator allocateObject: [OLBitIterator class]]
        initWithChunk: begin.chunk offset: begin.offset];
    OLReverseRandomIterator* r = [[allocator allocateObject: [OLReverseRandomIterator class]]
        initWithIterator: b];

    [allocator deallocateObject: b];
    return OBJ_COND_AUTORELEASE(r);
}

- (void) reserve: (unsigned)count
{
    OLBitIteratorBase tmp;

    if ([self capacity] < count)
    {
        tmp.chunk = [self bitAlloc: count];
        tmp.offset = 0;
        end = __copyBitIterBase(begin, end, tmp);
        if (begin.chunk != NULL)
            [allocator deallocateBytes: begin.chunk];
        endOfCapacity = tmp.chunk + (count + OL_WORD_BIT - 1) / OL_WORD_BIT;
        begin = tmp;
    }
}

- (void) resize: (unsigned)newsize filledWith: (BOOL)value
{
    OLBitIteratorBase first;

    if (newsize < [self size])
    {
        first = begin;
        __advanceBitIterBase(&first, newsize);
        [self eraseImplFrom: &first to: &end];
    }
    else
    {
        [self insertImplAt: &end count: newsize - [self size] filledWith: value];
    }
}

- (unsigned) size
{
    return __differenceBitIterBase(&end, &begin);
}

- (void) swap: (OLBoolVector*)right
{
    OL_PREPARE_SLOW_SWAP;
    OLBoolVector* copy;
    OLBitIterator* first;
    OLBitIterator* last;

    if (self != right)
    {
        if ([allocator isEqual: right->allocator])
        {
            OL_SLOW_SWAP(begin.chunk, right->begin.chunk);
            OL_FAST_SWAP(begin.offset, right->begin.offset);
            OL_SLOW_SWAP(end.chunk, right->end.chunk);
            OL_FAST_SWAP(end.offset, right->end.offset);
            OL_SLOW_SWAP(endOfCapacity, right->endOfCapacity);
        }
        else
        {
            copy = [self copyWithAllocator: allocator];
            first = [[allocator allocateObject: [OLBitIterator class]]
                initWithChunk: right->begin.chunk offset: right->begin.offset];
            last = [[allocator allocateObject: [OLBitIterator class]]
                initWithChunk: right->end.chunk offset: right->end.offset];
            [self assignFrom: first to: last];
            [allocator deallocateObject: first];
            [allocator deallocateObject: last];
            first = [[allocator allocateObject: [OLBitIterator class]]
                initWithChunk: copy->begin.chunk offset: copy->begin.offset];
            last = [[allocator allocateObject: [OLBitIterator class]]
                initWithChunk: copy->end.chunk offset: copy->end.offset];
            [right assignFrom: first to: last];
            [allocator deallocateObject: first];
            [allocator deallocateObject: last];
            [allocator deallocateObject: copy];
        }
    }
}

@end

@implementation OLBoolVector (PrivateMethods)

- (uint32_t*) bitAlloc: (unsigned)bitCount
{
    return [allocator allocateBytes:
        ((bitCount + OL_WORD_BIT - 1) / OL_WORD_BIT) * sizeof(uint32_t)];
}

- (OLBitIteratorBase) eraseImplFrom: (OLBitIteratorBase*)first to: (OLBitIteratorBase*)last
{
    end = __copyBitIterBase(*last, end, *first);
    return *first;
}

- (void) insertImplAt: (OLBitIteratorBase*)where count: (unsigned)num filledWith: (BOOL)value
{
    OLBitIteratorBase dest;
    OLBitIteratorBase i;
    OLBitIteratorBase tmp;
    unsigned len;

    if (num != 0)
    {
        if ([self capacity] - [self size] >= num)
        {
            dest = end;
            __advanceBitIterBase(&dest, num);
            __copyBackwardBitIterBase(*where, end, dest);
            dest = *where;
            __advanceBitIterBase(&dest, num);
            __fillBitIterBase(*where, dest, value);
            __advanceBitIterBase(&end, num);
        }
        else
        {
            len = [self size] + MAX([self size], num);
            tmp.chunk = [self bitAlloc: len];
            tmp.offset = 0;
            i = __copyBitIterBase(begin, *where, tmp);
            __fillNBitIterBase(i, num, value);
            __advanceBitIterBase(&i, num);
            end = __copyBitIterBase(*where, end, i);
            if (begin.chunk != NULL)
                [allocator deallocateBytes: begin.chunk];
            endOfCapacity = tmp.chunk + (len + OL_WORD_BIT - 1) / OL_WORD_BIT;
            begin = tmp;
        }
    }
}

- (void) insertImplAt: (OLBitIteratorBase*)where from: (OLForwardIterator*)first to: (OLForwardIterator*)last
{
    OLBitIteratorBase dest;
    OLBitIteratorBase tmp;
    OLBitIteratorBase i;
    OLForwardIterator* cur;
    unsigned len;
    unsigned n;

    if (![first isEqual: last])
    {
        len = [OLIterator distanceFrom: first to: last allocator: allocator];
        if ([self capacity] - [self size] >= len)
        {
            dest = end;
            __advanceBitIterBase(&dest, len);
            __copyBackwardBitIterBase(*where, end, dest);
            for (cur = [first copyWithAllocator: allocator], dest = *where;
                 ![cur isEqual: last];
                 [cur advance], __bumpUpBitIterBase(&dest))
            {
                __assignBitIterBase(&dest, [[cur dereference] boolValue]);
            }
            [allocator deallocateObject: cur];
            __advanceBitIterBase(&end, len);
        }
        else
        {
            n = [self size] + MAX([self size], len);
            tmp.chunk = [self bitAlloc: len];
            tmp.offset = 0;
            i = __copyBitIterBase(begin, *where, tmp);
            for (cur = [first copyWithAllocator: allocator];
                 ![cur isEqual: last];
                 [cur advance], __bumpUpBitIterBase(&i))
            {
                __assignBitIterBase(&i, [[cur dereference] boolValue]);
            }
            [allocator deallocateObject: cur];
            end = __copyBitIterBase(*where, end, i);
            if (begin.chunk != NULL)
                [allocator deallocateBytes: begin.chunk];
            endOfCapacity = tmp.chunk + (len + OL_WORD_BIT - 1) / OL_WORD_BIT;
            begin = tmp;
        }
    }
}

- (OLBitIteratorBase) insertImplAt: (OLBitIteratorBase*)where value: (BOOL)val
{
    OLBitIteratorBase dest;
    OLBitIteratorBase tmp;
    OLBitIteratorBase i;
    OLBitIteratorBase r;
    unsigned len;
    int diff;

    diff = __differenceBitIterBase(where, &begin);
    if (end.chunk != endOfCapacity)
    {
        dest = end;
        __bumpUpBitIterBase(&dest);
        __copyBackwardBitIterBase(*where, end, dest);
        __assignBitIterBase(where, val);
        __bumpUpBitIterBase(&end);
    }
    else
    {
        len = [self size] ? 2 * [self size] : OL_WORD_BIT;
        tmp.chunk = [self bitAlloc: len];
        tmp.offset = 0;
        i = __copyBitIterBase(begin, *where, tmp);
        __assignBitIterBase(&i, val);
        __bumpUpBitIterBase(&i);
        end = __copyBitIterBase(*where, end, i);
        if (begin.chunk != NULL)
            [allocator deallocateBytes: begin.chunk];
        endOfCapacity = tmp.chunk + (len + OL_WORD_BIT - 1) / OL_WORD_BIT;
        begin = tmp;
    }
    r = begin;
    __advanceBitIterBase(&r, diff);
    return r;
}

- (void) initialize: (unsigned)bitCount setEnd: (BOOL)setEnd
{
    begin.chunk = end.chunk = [self bitAlloc: bitCount];
    begin.offset = end.offset = 0;
    endOfCapacity = begin.chunk + (bitCount + OL_WORD_BIT - 1) / OL_WORD_BIT;
    if (setEnd)
        __advanceBitIterBase(&end, bitCount);
}

@end


