#include "tkIntSet.h"
#include "tkBitField.h"
#include "tkAlloc.h"
#if !(__STDC_VERSION__ >= 199901L || (defined(_MSC_VER) && _MSC_VER >= 1900))
# define _TK_NEED_IMPLEMENTATION
# include "tkIntSetPriv.h"
#endif
#include <string.h>
#include <assert.h>
#ifndef MIN
# define MIN(a,b) (((int) a) < ((int) b) ? a : b)
#endif
#ifndef MAX
# define MAX(a,b) (((int) a) < ((int) b) ? b : a)
#endif
#if TK_CHECK_ALLOCS
# define DEBUG_ALLOC(expr) expr
#else
# define DEBUG_ALLOC(expr)
#endif
#define TestIfEqual TkIntSetIsEqual__
#define SET_SIZE(size) ((unsigned) (Tk_Offset(TkIntSet, buf) + (size)*sizeof(TkIntSetType)))
DEBUG_ALLOC(unsigned tkIntSetCountNew = 0);
DEBUG_ALLOC(unsigned tkIntSetCountDestroy = 0);
static bool IsPowerOf2(unsigned n) { return !(n & (n - 1)); }
static unsigned
NextPowerOf2(
unsigned n)
{
--n;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
#if !(UINT_MAX <= 4294967295u)
n |= n >> 32;
#endif
return ++n;
}
bool
TkIntSetIsEqual__(
const TkIntSetType *set1, const TkIntSetType *end1,
const TkIntSetType *set2, const TkIntSetType *end2)
{
if (end1 - set1 != end2 - set2) {
return false;
}
for ( ; set1 < end1; ++set1, ++set2) {
if (*set1 != *set2) {
return false;
}
}
return true;
}
#if !TK_TEXT_DONT_USE_BITFIELDS
unsigned
TkIntSetFindFirstInIntersection(
const TkIntSet *set,
const TkBitField *bf)
{
unsigned size, i;
assert(set);
assert(bf);
if (!TkBitNone(bf)) {
size = TkIntSetSize(set);
for (i = 0; i < size; ++i) {
TkIntSetType value = TkIntSetAccess(set, i);
if (TkBitTest(bf, value)) {
return value;
}
}
}
return TK_SET_NPOS;
}
#endif
TkIntSetType *
TkIntSetLowerBound(
TkIntSetType *first,
TkIntSetType *last,
TkIntSetType value)
{
while (first != last) {
TkIntSetType *mid = first + (last - first)/2;
if (*mid < value) {
first = mid + 1;
} else {
last = mid;
}
}
return first;
}
TkIntSet *
TkIntSetNew()
{
TkIntSet *set = malloc(SET_SIZE(0));
set->end = set->buf;
set->refCount = 0;
set->isSetFlag = true;
DEBUG_ALLOC(tkIntSetCountNew++);
return set;
}
#if !TK_TEXT_DONT_USE_BITFIELDS
TkIntSet *
TkIntSetFromBits(
const TkBitField *bf)
{
unsigned size;
TkIntSet *set;
unsigned index = 0, i;
size = TkBitCount(bf);
set = malloc(SET_SIZE(NextPowerOf2(size)));
set->end = set->buf + size;
set->refCount = 1;
set->isSetFlag = true;
DEBUG_ALLOC(tkIntSetCountNew++);
for (i = TkBitFindFirst(bf); i != TK_BIT_NPOS; i = TkBitFindNext(bf, i)) {
set->buf[index++] = i;
}
return set;
}
#endif
void
TkIntSetDestroy(
TkIntSet **setPtr)
{
assert(setPtr);
if (*setPtr) {
free(*setPtr);
*setPtr = NULL;
DEBUG_ALLOC(tkIntSetCountDestroy++);
}
}
TkIntSet *
TkIntSetCopy(
const TkIntSet *set)
{
TkIntSet *newSet;
unsigned size;
assert(set);
size = TkIntSetSize(set);
newSet = malloc(SET_SIZE(NextPowerOf2(size)));
newSet->end = newSet->buf + size;
newSet->refCount = 1;
newSet->isSetFlag = true;
memcpy(newSet->buf, set->buf, size*sizeof(TkIntSetType));
DEBUG_ALLOC(tkIntSetCountNew++);
return newSet;
}
static TkIntSetType *
Join(
TkIntSetType *dst,
const TkIntSetType *src, const TkIntSetType *srcEnd,
const TkIntSetType *add, const TkIntSetType *addEnd)
{
unsigned size;
while (src < srcEnd && add < addEnd) {
if (*src < *add) {
*dst++ = *src++;
} else {
if (*src == *add) {
++src;
}
*dst++ = *add++;
}
}
if ((size = srcEnd - src) > 0) {
memcpy(dst, src, size*sizeof(TkIntSetType));
dst += size;
} else if ((size = addEnd - add) > 0) {
memcpy(dst, add, size*sizeof(TkIntSetType));
dst += size;
}
return dst;
}
TkIntSet *
TkIntSetJoin(
TkIntSet *dst,
const TkIntSet *src)
{
TkIntSet *set;
unsigned capacity1, capacity2;
unsigned size;
assert(src);
assert(dst);
assert(TkIntSetRefCount(dst) > 0);
capacity1 = NextPowerOf2(TkIntSetSize(dst) + TkIntSetSize(src));
set = malloc(SET_SIZE(capacity1));
set->end = Join(set->buf, dst->buf, dst->end, src->buf, src->end);
size = set->end - set->buf;
capacity2 = NextPowerOf2(size);
assert(capacity2 <= capacity1);
DEBUG_ALLOC(tkIntSetCountNew++);
if (capacity2 < capacity1) {
set = realloc(set, SET_SIZE(capacity2));
set->end = set->buf + size;
}
if (--dst->refCount == 0) {
free(dst);
DEBUG_ALLOC(tkIntSetCountDestroy++);
}
set->refCount = 1;
set->isSetFlag = true;
return set;
}
static TkIntSetType *
JoinBits(
TkIntSetType *dst,
const TkIntSetType *src, const TkIntSetType *srcEnd,
const TkBitField *bf)
{
unsigned size, i;
i = TkBitFindFirst(bf);
while (src < srcEnd && i != TK_BIT_NPOS) {
if (*src < i) {
*dst++ = *src++;
} else {
if (*src == i) {
++src;
}
*dst++ = i;
i = TkBitFindNext(bf, i);
}
}
if ((size = srcEnd - src) > 0) {
memcpy(dst, src, size*sizeof(TkIntSetType));
dst += size;
} else {
for ( ; i != TK_BIT_NPOS; i = TkBitFindNext(bf, i)) {
*dst++ = i;
}
}
return dst;
}
#if !TK_TEXT_DONT_USE_BITFIELDS
TkIntSet *
TkIntSetJoinBits(
TkIntSet *dst,
const TkBitField *src)
{
TkIntSet *set;
assert(src);
assert(dst);
assert(TkIntSetRefCount(dst) > 0);
if (dst->buf == dst->end) {
set = TkIntSetNew();
} else {
unsigned capacity1, capacity2, size;
capacity1 = NextPowerOf2(TkIntSetSize(dst) + TkBitSize(src));
set = malloc(SET_SIZE(capacity1));
set->end = JoinBits(set->buf, dst->buf, dst->end, src);
size = set->end - set->buf;
capacity2 = NextPowerOf2(size);
assert(capacity2 <= capacity1);
DEBUG_ALLOC(tkIntSetCountNew++);
if (capacity2 < capacity1) {
set = realloc(set, SET_SIZE(capacity2));
set->end = set->buf + size;
}
}
if (--dst->refCount == 0) {
free(dst);
DEBUG_ALLOC(tkIntSetCountDestroy++);
}
set->refCount = 1;
set->isSetFlag = true;
return set;
}
#endif
static TkIntSetType *
Join2(
TkIntSetType *dst,
const TkIntSetType *src, const TkIntSetType *srcEnd,
const TkIntSetType *set1, const TkIntSetType *set1End,
const TkIntSetType *set2, const TkIntSetType *set2End)
{
unsigned size;
while (src < srcEnd && set1 < set1End && set2 < set2End) {
if (*set1 < *set2) {
if (*src < *set1) {
*dst++ = *src++;
} else {
if (*src == *set1) {
src++;
}
*dst++ = *set1++;
}
} else {
if (*src < *set2) {
*dst++ = *src++;
} else {
if (*src == *set2) {
src++;
}
if (*set1 == *set2)
set1++;
*dst++ = *set2++;
}
}
}
if (src == srcEnd) {
dst = Join(dst, set1, set1End, set2, set2End);
} else if (set1 < set1End) {
dst = Join(dst, src, srcEnd, set1, set1End);
} else if (set2 < set2End) {
dst = Join(dst, src, srcEnd, set2, set2End);
} else if ((size = srcEnd - src) > 0) {
memcpy(dst, src, size*sizeof(TkIntSetType));
dst += size;
}
return dst;
}
TkIntSet *
TkIntSetJoin2(
TkIntSet *dst,
const TkIntSet *set1,
const TkIntSet *set2)
{
TkIntSet *set;
unsigned capacity1, capacity2;
unsigned size;
assert(dst);
assert(set1);
assert(set2);
assert(TkIntSetRefCount(dst) > 0);
capacity1 = NextPowerOf2(TkIntSetSize(dst) + TkIntSetSize(set1) + TkIntSetSize(set2));
set = malloc(SET_SIZE(capacity1));
set->end = Join2(set->buf, dst->buf, dst->end, set1->buf, set1->end, set2->buf, set2->end);
size = set->end - set->buf;
capacity2 = NextPowerOf2(size);
assert(capacity2 <= capacity1);
DEBUG_ALLOC(tkIntSetCountNew++);
if (capacity2 < capacity1) {
set = realloc(set, SET_SIZE(capacity2));
set->end = set->buf + size;
}
if (--dst->refCount == 0) {
free(dst);
DEBUG_ALLOC(tkIntSetCountDestroy++);
}
set->refCount = 1;
set->isSetFlag = true;
return set;
}
static TkIntSetType *
Intersect(
TkIntSetType *dst,
const TkIntSetType *src, const TkIntSetType *srcEnd,
const TkIntSetType *isc, const TkIntSetType *iscEnd)
{
while (src < srcEnd && isc < iscEnd) {
if (*src < *isc) {
++src;
} else {
if (*src == *isc) {
*dst++ = *src++;
}
++isc;
}
}
return dst;
}
TkIntSet *
TkIntSetIntersect(
TkIntSet *dst,
const TkIntSet *src)
{
TkIntSet *set;
unsigned size;
unsigned capacity1, capacity2;
assert(src);
assert(dst);
assert(TkIntSetRefCount(dst) > 0);
size = MIN(TkIntSetSize(src), TkIntSetSize(dst));
capacity1 = NextPowerOf2(size);
set = malloc(SET_SIZE(capacity1));
set->end = Intersect(set->buf, dst->buf, dst->end, src->buf, src->end);
size = set->end - set->buf;
capacity2 = NextPowerOf2(size);
assert(capacity2 <= capacity1);
DEBUG_ALLOC(tkIntSetCountNew++);
if (capacity2 < capacity1) {
set = realloc(set, SET_SIZE(capacity2));
set->end = set->buf + size;
}
if (--dst->refCount == 0) {
free(dst);
DEBUG_ALLOC(tkIntSetCountDestroy++);
}
set->refCount = 1;
set->isSetFlag = true;
return set;
}
static TkIntSetType *
IntersectBits(
TkIntSetType *dst,
const TkIntSetType *src, const TkIntSetType *srcEnd,
const TkBitField *isc)
{
unsigned size = TkBitSize(isc);
for ( ; src < srcEnd; ++src) {
if (*src >= size) {
break;
}
if (TkBitTest(isc, *src)) {
*dst++ = *src;
}
}
return dst;
}
#if !TK_TEXT_DONT_USE_BITFIELDS
TkIntSet *
TkIntSetIntersectBits(
TkIntSet *dst,
const TkBitField *src)
{
TkIntSet *set;
unsigned size;
unsigned capacity1, capacity2;
assert(src);
assert(dst);
assert(TkIntSetRefCount(dst) > 0);
size = TkBitCount(src);
size = MIN(TkIntSetSize(dst), TkBitCount(src));
capacity1 = NextPowerOf2(size);
set = malloc(SET_SIZE(capacity1));
set->end = IntersectBits(set->buf, dst->buf, dst->end, src);
size = set->end - set->buf;
capacity2 = NextPowerOf2(size);
assert(capacity2 <= capacity1);
DEBUG_ALLOC(tkIntSetCountNew++);
if (capacity2 < capacity1) {
set = realloc(set, SET_SIZE(capacity2));
set->end = set->buf + size;
}
if (--dst->refCount == 0) {
free(dst);
DEBUG_ALLOC(tkIntSetCountDestroy++);
}
set->refCount = 1;
set->isSetFlag = true;
return set;
}
#endif
static TkIntSetType *
Remove(
TkIntSetType *dst,
const TkIntSetType *src, const TkIntSetType *srcEnd,
const TkIntSetType *sub, const TkIntSetType *subEnd)
{
while (src < srcEnd && sub < subEnd) {
if (*src < *sub) {
*dst++ = *src++;
} else {
if (*src == *sub) {
++src;
}
++sub;
}
}
if (src < srcEnd) {
unsigned size = srcEnd - src;
memcpy(dst, src, size*sizeof(TkIntSetType));
dst += size;
}
return dst;
}
TkIntSet *
TkIntSetRemove(
TkIntSet *dst,
const TkIntSet *src)
{
TkIntSet *set;
unsigned capacity1, capacity2;
unsigned size;
assert(src);
assert(dst);
assert(TkIntSetRefCount(dst) > 0);
capacity1 = NextPowerOf2(TkIntSetSize(dst));
set = malloc(SET_SIZE(capacity1));
set->end = Remove(set->buf, dst->buf, dst->end, src->buf, src->end);
size = set->end - set->buf;
capacity2 = NextPowerOf2(size);
assert(capacity2 <= capacity1);
DEBUG_ALLOC(tkIntSetCountNew++);
if (capacity2 < capacity1) {
set = realloc(set, SET_SIZE(capacity2));
set->end = set->buf + size;
}
if (--dst->refCount == 0) {
free(dst);
DEBUG_ALLOC(tkIntSetCountDestroy++);
}
set->refCount = 1;
set->isSetFlag = true;
return set;
}
static TkIntSetType *
RemoveBits(
TkIntSetType *dst,
const TkIntSetType *src, const TkIntSetType *srcEnd,
const TkBitField *sub)
{
unsigned size = TkBitSize(sub);
for ( ; src < srcEnd; ++src) {
if (*src >= size) {
break;
}
if (!TkBitTest(sub, *src)) {
*dst++ = *src;
}
}
if ((size = srcEnd - src) > 0) {
memcpy(dst, src, size*sizeof(TkIntSetType));
dst += size;
}
return dst;
}
#if !TK_TEXT_DONT_USE_BITFIELDS
TkIntSet *
TkIntSetRemoveBits(
TkIntSet *dst,
const TkBitField *src)
{
TkIntSet *set;
unsigned capacity1, capacity2;
unsigned size;
assert(src);
assert(dst);
assert(TkIntSetRefCount(dst) > 0);
capacity1 = NextPowerOf2(TkIntSetSize(dst));
set = malloc(SET_SIZE(capacity1));
set->end = RemoveBits(set->buf, dst->buf, dst->end, src);
size = set->end - set->buf;
capacity2 = NextPowerOf2(size);
assert(capacity2 <= capacity1);
DEBUG_ALLOC(tkIntSetCountNew++);
if (capacity2 < capacity1) {
set = realloc(set, SET_SIZE(capacity2));
set->end = set->buf + size;
}
if (--dst->refCount == 0) {
free(dst);
DEBUG_ALLOC(tkIntSetCountDestroy++);
}
set->refCount = 1;
set->isSetFlag = true;
return set;
}
#endif
static TkIntSetType *
ComplementTo(
TkIntSetType *dst,
const TkIntSetType *sub, const TkIntSetType *subEnd,
const TkIntSetType *src, const TkIntSetType *srcEnd)
{
return Remove(dst, src, srcEnd, sub, subEnd);
}
TkIntSet *
TkIntSetComplementTo(
TkIntSet *dst,
const TkIntSet *src)
{
TkIntSet *set;
unsigned capacity1, capacity2;
unsigned size;
assert(src);
assert(dst);
assert(TkIntSetRefCount(dst) > 0);
capacity1 = NextPowerOf2(TkIntSetSize(src));
set = malloc(SET_SIZE(capacity1));
set->end = ComplementTo(set->buf, dst->buf, dst->end, src->buf, src->end);
size = set->end - set->buf;
capacity2 = NextPowerOf2(size);
assert(capacity2 <= capacity1);
DEBUG_ALLOC(tkIntSetCountNew++);
if (capacity2 < capacity1) {
set = realloc(set, SET_SIZE(capacity2));
set->end = set->buf + size;
}
if (--dst->refCount == 0) {
free(dst);
DEBUG_ALLOC(tkIntSetCountDestroy++);
}
set->refCount = 1;
set->isSetFlag = true;
return set;
}
static TkIntSetType *
ComplementToBits(
TkIntSetType *dst,
const TkIntSetType *sub, const TkIntSetType *subEnd,
const TkBitField *src)
{
unsigned i = TkBitFindFirst(src);
while (sub < subEnd && i != TK_BIT_NPOS) {
if (*sub < i) {
++sub;
} else {
if (i < *sub) {
*dst++ = i;
} else {
++sub;
}
i = TkBitFindNext(src, i);
}
}
for ( ; i != TK_BIT_NPOS; i = TkBitFindNext(src, i)) {
*dst++ = i;
}
return dst;
}
#if !TK_TEXT_DONT_USE_BITFIELDS
TkIntSet *
TkIntSetComplementToBits(
TkIntSet *dst,
const TkBitField *src)
{
TkIntSet *set;
unsigned capacity1, capacity2;
unsigned size;
assert(src);
assert(dst);
assert(TkIntSetRefCount(dst) > 0);
capacity1 = NextPowerOf2(TkBitSize(src));
set = malloc(SET_SIZE(capacity1));
set->end = ComplementToBits(set->buf, dst->buf, dst->end, src);
size = set->end - set->buf;
capacity2 = NextPowerOf2(size);
assert(capacity2 <= capacity1);
DEBUG_ALLOC(tkIntSetCountNew++);
if (capacity2 < capacity1) {
set = realloc(set, SET_SIZE(capacity2));
set->end = set->buf + size;
}
if (--dst->refCount == 0) {
free(dst);
DEBUG_ALLOC(tkIntSetCountDestroy++);
}
set->refCount = 1;
set->isSetFlag = true;
return set;
}
#endif
static TkIntSetType *
JoinComplementTo(
TkIntSetType *dst,
const TkIntSetType *src, const TkIntSetType *srcEnd,
const TkIntSetType *set1, const TkIntSetType *set1End,
const TkIntSetType *set2, const TkIntSetType *set2End)
{
while (src < srcEnd && set1 < set1End && set2 < set2End) {
if (*set2 < *set1) {
if (*src < *set2) {
*dst++ = *src++;
} else if (*src == *set2) {
*dst++ = *src++;
set2++;
} else {
if (*src == *set2) {
++src;
}
*dst++ = *set2++;
}
} else if (*src < *set1) {
*dst++ = *src++;
} else {
if (*set2 == *set1) {
set2++;
}
if (*src == *set1) {
*dst++ = *src++;
}
set1++;
}
}
if (src == srcEnd) {
dst = ComplementTo(dst, set1, set1End, set2, set2End);
} else if (set2 < set2End) {
dst = Join(dst, src, srcEnd, set2, set2End);
} else {
unsigned size = srcEnd - src;
memcpy(dst, src, size*sizeof(TkIntSetType));
dst += size;
}
return dst;
}
TkIntSet *
TkIntSetJoinComplementTo(
TkIntSet *dst,
const TkIntSet *set1,
const TkIntSet *set2)
{
TkIntSet *set;
unsigned capacity1, capacity2;
unsigned size;
assert(dst);
assert(set1);
assert(set2);
assert(TkIntSetRefCount(dst) > 0);
capacity1 = NextPowerOf2(TkIntSetSize(dst) + TkIntSetSize(set1));
set = malloc(SET_SIZE(capacity1));
set->end = JoinComplementTo(
set->buf, dst->buf, dst->end, set1->buf, set1->end, set2->buf, set2->end);
size = set->end - set->buf;
capacity2 = NextPowerOf2(size);
assert(capacity2 <= capacity1);
DEBUG_ALLOC(tkIntSetCountNew++);
if (capacity2 < capacity1) {
set = realloc(set, SET_SIZE(capacity2));
set->end = set->buf + size;
}
if (--dst->refCount == 0) {
free(dst);
DEBUG_ALLOC(tkIntSetCountDestroy++);
}
set->refCount = 1;
set->isSetFlag = true;
return set;
}
static TkIntSetType *
JoinNonIntersection(
TkIntSetType *dst,
const TkIntSetType *src, const TkIntSetType *srcEnd,
const TkIntSetType *set1, const TkIntSetType *set1End,
const TkIntSetType *set2, const TkIntSetType *set2End)
{
unsigned size;
while (src != srcEnd && set1 != set1End && set2 != set2End) {
if (*set1 < *set2) {
if (*set1 < *src) {
*dst++ = *set1++;
} else {
if (*src == *set1) {
++set1;
}
*dst++ = *src++;
}
} else if (*set2 < *set1) {
if (*set2 < *src) {
*dst++ = *set2++;
} else {
if (*src == *set2) {
++set2;
}
*dst++ = *src++;
}
} else {
++set1;
++set2;
}
}
if (src == srcEnd) {
while (set1 != set1End && set2 != set2End) {
if (*set1 < *set2) {
*dst++ = *set1++;
} else if (*set2 < *set1) {
*dst++ = *set2++;
} else {
++set1;
++set2;
}
}
if (set1 == set1End) {
set1 = set2;
set1End = set2End;
}
if ((size = set1End - set1)) {
memcpy(dst, set1, size*sizeof(TkIntSetType));
dst += size;
}
} else {
if (set1 == set1End) {
set1 = set2;
set1End = set2End;
}
dst = Join(dst, src, srcEnd, set1, set1End);
}
return dst;
}
TkIntSet *
TkIntSetJoinNonIntersection(
TkIntSet *dst,
const TkIntSet *set1,
const TkIntSet *set2)
{
TkIntSet *set;
unsigned capacity1, capacity2;
unsigned size;
assert(dst);
assert(set1);
assert(set2);
assert(TkIntSetRefCount(dst) > 0);
capacity1 = NextPowerOf2(TkIntSetSize(dst) + TkIntSetSize(set1) + TkIntSetSize(set2));
set = malloc(SET_SIZE(capacity1));
set->end = JoinNonIntersection(
set->buf, dst->buf, dst->end, set1->buf, set1->end, set2->buf, set2->end);
size = set->end - set->buf;
capacity2 = NextPowerOf2(size);
assert(capacity2 <= capacity1);
DEBUG_ALLOC(tkIntSetCountNew++);
if (capacity2 < capacity1) {
set = realloc(set, SET_SIZE(capacity2));
set->end = set->buf + size;
}
if (--dst->refCount == 0) {
free(dst);
DEBUG_ALLOC(tkIntSetCountDestroy++);
}
set->refCount = 1;
set->isSetFlag = true;
return set;
}
TkIntSet *
TkIntSetJoin2ComplementToIntersection(
TkIntSet *dst,
const TkIntSet *add,
const TkIntSet *set1,
const TkIntSet *set2)
{
TkIntSet *set;
const TkIntSetType *set1P;
const TkIntSetType *set2P;
const TkIntSetType *set1End;
const TkIntSetType *set2End;
TkIntSetType *res1, *res2, *res3, *res1End, *res2End, *res3End;
TkIntSetType buffer[512];
unsigned capacity1, capacity2;
unsigned size, size1, size2;
assert(dst);
assert(add);
assert(set1);
assert(set2);
assert(TkIntSetRefCount(dst) > 0);
set1P = set1->buf;
set2P = set2->buf;
set1End = set1->end;
set2End = set2->end;
size1 = TkIntSetSize(set1) + TkIntSetSize(set2);
size2 = MIN(TkIntSetSize(set1), TkIntSetSize(set2));
size = size1 + 2*size2;
res1 = size <= sizeof(buffer)/sizeof(buffer[0]) ? buffer : malloc(size*sizeof(TkIntSetType));
res2 = res1 + size1;
res3 = res2 + size2;
res1End = Join(res1, set1P, set1End, set2P, set2End);
res2End = Intersect(res2, set1P, set1End, set2P, set2End);
res3End = ComplementTo(res3, res1, res1End, res2, res2End);
capacity1 = NextPowerOf2(TkIntSetSize(dst) + TkIntSetSize(add) + (res3End - res3));
set = malloc(SET_SIZE(capacity1));
set->end = Join2(set->buf, dst->buf, dst->end, add->buf, add->end, res3, res3End);
size = set->end - set->buf;
capacity2 = NextPowerOf2(size);
assert(capacity2 <= capacity1);
DEBUG_ALLOC(tkIntSetCountNew++);
if (capacity2 < capacity1) {
set = realloc(set, SET_SIZE(capacity2));
set->end = set->buf + size;
}
if (--dst->refCount == 0) {
free(dst);
DEBUG_ALLOC(tkIntSetCountDestroy++);
}
if (res1 != buffer) {
free(res1);
}
set->refCount = 1;
set->isSetFlag = true;
return set;
}
TkIntSet *
TkIntSetJoinOfDifferences(
TkIntSet *dst,
const TkIntSet *set1,
const TkIntSet *set2)
{
TkIntSet *set;
TkIntSetType *buf1, *buf2, *end1, *end2;
unsigned capacity1, capacity2;
unsigned size;
assert(dst);
assert(set1);
assert(set2);
assert(TkIntSetRefCount(dst) > 0);
capacity2 = TkIntSetSize(dst) + TkIntSetSize(set1);
capacity1 = NextPowerOf2(2*capacity2);
set = malloc(SET_SIZE(capacity1));
buf1 = set->buf + capacity2;
buf2 = buf1 + TkIntSetSize(dst);
end1 = Remove(buf1, dst->buf, dst->end, set1->buf, set1->end);
end2 = Remove(buf2, set1->buf, set1->end, set2->buf, set2->end);
set->end = Join(set->buf, buf1, end1, buf2, end2);
size = set->end - set->buf;
capacity2 = NextPowerOf2(size);
assert(capacity2 <= capacity1);
DEBUG_ALLOC(tkIntSetCountNew++);
if (capacity2 < capacity1) {
set = realloc(set, SET_SIZE(capacity2));
set->end = set->buf + size;
}
if (--dst->refCount == 0) {
free(dst);
DEBUG_ALLOC(tkIntSetCountDestroy++);
}
set->refCount = 1;
set->isSetFlag = true;
return set;
}
bool
TkIntSetDisjunctive__(
const TkIntSetType *set1, const TkIntSetType *end1,
const TkIntSetType *set2, const TkIntSetType *end2)
{
while (set1 != end1 && set2 != end2) {
if (*set1 == *set2) {
return false;
}
if (*set1 < *set2) {
++set1;
} else {
++set2;
}
}
return true;
}
bool
TkIntSetContains__(
const TkIntSetType *set1, const TkIntSetType *end1,
const TkIntSetType *set2, const TkIntSetType *end2)
{
if (end1 - set1 < end2 - set2) {
return false;
}
while (set1 != end1 && set2 != end2) {
if (*set2 < *set1) {
return false;
} else if (*set1 == *set2) {
++set2;
}
++set1;
}
return set2 == end2;
}
bool
TkIntSetIsContainedBits(
const TkIntSet *set,
const TkBitField *bf)
{
unsigned setSize, bitSize, i;
assert(bf);
assert(set);
setSize = TkIntSetSize(set);
bitSize = TkBitSize(bf);
for (i = 0; i < setSize; ++i) {
TkIntSetType value = set->buf[i];
if (value >= bitSize || !TkBitTest(bf, value)) {
return false;
}
}
return true;
}
#if !TK_TEXT_DONT_USE_BITFIELDS
bool
TkIntSetIntersectionIsEqual(
const TkIntSet *set1,
const TkIntSet *set2,
const TkBitField *del)
{
const TkIntSetType *s1;
const TkIntSetType *e1;
const TkIntSetType *s2;
const TkIntSetType *e2;
assert(set1);
assert(set2);
assert(del);
assert(TkIntSetMax(set1) < TkBitSize(del));
assert(TkIntSetMax(set2) < TkBitSize(del));
if (set1 == set2) {
return true;
}
s1 = set1->buf; e1 = set1->end;
s2 = set2->buf; e2 = set2->end;
while (s1 != e1 && s2 != e2) {
if (*s1 == *s2) {
++s1;
++s2;
} else if (*s1 < *s2) {
if (!TkBitTest(del, *s1)) {
return false;
}
++s1;
} else {
if (!TkBitTest(del, *s2)) {
return false;
}
++s2;
}
}
for ( ; s1 != e1; ++s1) {
if (!TkBitTest(del, *s1)) {
return false;
}
}
for ( ; s2 != e2; ++s2) {
if (!TkBitTest(del, *s2)) {
return false;
}
}
return true;
}
bool
TkIntSetIntersectionIsEqualBits(
const TkIntSet *set,
const TkBitField *bf,
const TkBitField *del)
{
TkBitField *cp = TkBitCopy(del, -1);
bool test;
assert(set);
assert(bf);
assert(del);
assert(TkIntSetMax(set) < TkBitSize(del));
assert(TkBitSize(bf) <= TkBitSize(del));
TkBitIntersect(cp, bf);
test = TkIntSetIsEqualBits(set, cp);
TkBitDestroy(&cp);
return test;
}
#endif
static TkIntSet *
Add(
TkIntSet *set,
TkIntSetType *pos,
unsigned n)
{
unsigned size = set->end - set->buf;
if (IsPowerOf2(size)) {
TkIntSet *newSet = malloc(SET_SIZE(MAX(2*size, 1)));
unsigned offs = pos - set->buf;
assert(offs <= size);
memcpy(newSet->buf, set->buf, offs*sizeof(TkIntSetType));
memcpy(newSet->buf + offs + 1, pos, (size - offs)*sizeof(TkIntSetType));
newSet->end = newSet->buf + size + 1;
newSet->refCount = 1;
newSet->isSetFlag = true;
DEBUG_ALLOC(tkIntSetCountNew++);
if (--set->refCount == 0) {
free(set);
DEBUG_ALLOC(tkIntSetCountDestroy++);
}
set = newSet;
pos = set->buf + offs;
} else {
memmove(pos + 1, pos, (set->end - pos)*sizeof(TkIntSetType));
set->end += 1;
}
*pos = n;
return set;
}
TkIntSet *
TkIntSetAdd(
TkIntSet *set,
unsigned n)
{
TkIntSetType *pos;
assert(set);
assert(TkIntSetRefCount(set) > 0);
pos = TkIntSetLowerBound(set->buf, set->end, n);
if (pos < set->end && *pos == n) {
return set;
}
return Add(set, pos, n);
}
static TkIntSet *
Erase(
TkIntSet *set,
TkIntSetType *pos,
unsigned n)
{
unsigned size = set->end - set->buf - 1;
if (IsPowerOf2(size)) {
TkIntSet *newSet = malloc(SET_SIZE(size));
unsigned offs = pos - set->buf;
memcpy(newSet->buf, set->buf, offs*sizeof(TkIntSetType));
memcpy(newSet->buf + offs, pos + 1, (size - offs)*sizeof(TkIntSetType));
newSet->end = newSet->buf + size;
newSet->refCount = 1;
newSet->isSetFlag = true;
DEBUG_ALLOC(tkIntSetCountNew++);
if (--set->refCount == 0) {
free(set);
DEBUG_ALLOC(tkIntSetCountDestroy++);
}
set = newSet;
} else {
memmove(pos, pos + 1, (set->end - pos - 1)*sizeof(TkIntSetType));
set->end -= 1;
}
return set;
}
TkIntSet *
TkIntSetErase(
TkIntSet *set,
unsigned n)
{
TkIntSetType *pos;
assert(set);
assert(TkIntSetRefCount(set) > 0);
pos = TkIntSetLowerBound(set->buf, set->end, n);
if (pos == set->end || *pos != n) {
return set;
}
return Erase(set, pos, n);
}
TkIntSet *
TkIntSetTestAndSet(
TkIntSet *set,
unsigned n)
{
TkIntSetType *pos;
assert(set);
assert(TkIntSetRefCount(set) > 0);
pos = TkIntSetLowerBound(set->buf, set->end, n);
if (pos < set->end && *pos == n) {
return NULL;
}
return Add(set, pos, n);
}
TkIntSet *
TkIntSetTestAndUnset(
TkIntSet *set,
unsigned n)
{
TkIntSetType *pos;
assert(set);
assert(TkIntSetRefCount(set) > 0);
pos = TkIntSetLowerBound(set->buf, set->end, n);
if (pos == set->end || *pos != n) {
return NULL;
}
return Erase(set, pos, n);
}
TkIntSet *
TkIntSetClear(
TkIntSet *set)
{
TkIntSet *newSet;
assert(set);
assert(TkIntSetRefCount(set) > 0);
if (set->buf == set->end) {
return set;
}
newSet = malloc(SET_SIZE(0));
newSet->end = newSet->buf;
newSet->refCount = 1;
newSet->isSetFlag = true;
DEBUG_ALLOC(tkIntSetCountNew++);
if (--set->refCount == 0) {
free(set);
DEBUG_ALLOC(tkIntSetCountDestroy++);
}
return newSet;
}
#if !TK_TEXT_DONT_USE_BITFIELDS
bool
TkIntSetIsEqualBits(
const TkIntSet *set,
const TkBitField *bf)
{
unsigned sizeSet, sizeBf, i;
assert(set);
assert(bf);
sizeSet = TkIntSetSize(set);
if (sizeSet != TkBitCount(bf)) {
return false;
}
sizeBf = TkBitSize(bf);
for (i = 0; i < sizeSet; ++i) {
TkIntSetType value = set->buf[i];
if (value >= sizeBf || !TkBitTest(bf, value)) {
return false;
}
}
return true;
}
bool
TkIntSetContainsBits(
const TkIntSet *set,
const TkBitField *bf)
{
unsigned sizeSet, sizeBf, i;
unsigned count = 0;
assert(set);
assert(bf);
sizeSet = TkIntSetSize(set);
sizeBf = TkBitSize(bf);
for (i = 0; i < sizeSet; ++i) {
TkIntSetType value = set->buf[i];
if (value >= sizeBf) {
break;
}
if (TkBitTest(bf, value)) {
count += 1;
}
}
return count == TkBitCount(bf);
}
bool
TkIntSetDisjunctiveBits(
const TkIntSet *set,
const TkBitField *bf)
{
unsigned sizeSet, sizeBf, i;
assert(set);
assert(bf);
sizeSet = TkIntSetSize(set);
sizeBf = TkBitSize(bf);
for (i = 0; i < sizeSet; ++i) {
TkIntSetType value = set->buf[i];
if (value >= sizeBf) {
return true;
}
if (TkBitTest(bf, value)) {
return false;
}
}
return true;
}
#endif
#if !NDEBUG
# include <stdio.h>
void
TkIntSetPrint(
const TkIntSet *set)
{
unsigned i, n;
const char *comma = "";
assert(set);
n = TkIntSetSize(set);
printf("%d:{ ", n);
for (i = 0; i < n; ++i) {
printf("%s%d", comma, set->buf[i]);
comma = ", ";
}
printf(" }\n");
}
#endif
#if TK_UNUSED_INTSET_FUNCTIONS
static TkIntSetType *
InnerJoinDifference(
TkIntSetType *dst,
const TkIntSetType *src, const TkIntSetType *srcEnd,
const TkIntSetType *add, const TkIntSetType *addEnd,
const TkIntSetType *sub, const TkIntSetType *subEnd)
{
while (src != srcEnd && add != addEnd) {
if (*src < *add) {
++src;
} else {
if (*src == *add) {
*dst++ = *add;
++src;
} else {
for ( ; sub != subEnd && *sub < *add; ++sub) {
}
if (sub == subEnd) {
break;
}
if (*add != *sub) {
*dst++ = *add;
}
}
++add;
}
}
if (sub == subEnd) {
unsigned size = addEnd - add;
memcpy(dst, add, size*sizeof(TkIntSetType));
dst += size;
} else if (src == srcEnd) {
dst = Remove(dst, add, addEnd, sub, subEnd);
} else {
}
return dst;
}
TkIntSet *
TkIntSetInnerJoinDifference(
TkIntSet *dst,
const TkIntSet *add,
const TkIntSet *sub)
{
TkIntSet *set;
unsigned capacity1, capacity2;
unsigned size;
assert(dst);
assert(add);
assert(sub);
assert(TkIntSetRefCount(dst) > 0);
capacity1 = NextPowerOf2(TkIntSetSize(dst) + TkIntSetSize(add));
set = malloc(SET_SIZE(capacity1));
set->end = InnerJoinDifference(set->buf, dst->buf, dst->end, add->buf, add->end, sub->buf, sub->end);
size = set->end - set->buf;
capacity2 = NextPowerOf2(size);
assert(capacity2 <= capacity1);
DEBUG_ALLOC(tkIntSetCountNew++);
if (capacity2 < capacity1) {
set = realloc(set, SET_SIZE(capacity2));
set->end = set->buf + size;
}
if (--dst->refCount == 0) {
free(dst);
DEBUG_ALLOC(tkIntSetCountDestroy++);
}
set->refCount = 1;
set->isSetFlag = true;
return set;
}
bool
TkIntSetInnerJoinDifferenceIsEmpty(
const TkIntSet *set,
const TkIntSet *add,
const TkIntSet *sub)
{
const TkIntSetType *setP, *setEnd;
const TkIntSetType *addP, *addEnd;
const TkIntSetType *subP, *subEnd;
assert(set);
assert(add);
assert(sub);
if (add->buf == add->end) {
return true;
}
if (add == set) {
return TkIntSetIsEmpty(add);
}
setP = set->buf; setEnd = set->end;
addP = add->buf; addEnd = add->end;
while (setP != setEnd && addP < addEnd) {
if (*setP == *addP) {
return false;
} else if (*setP < *addP) {
++setP;
} else {
++addP;
}
}
addP = add->buf; addEnd = add->end;
subP = sub->buf; subEnd = sub->end;
while (addP != addEnd && subP != subEnd) {
if (*addP < *subP) {
return false;
} else if (*addP == *subP) {
++addP;
}
++subP;
}
return addP == addEnd;
}
static bool
DifferenceIsEmpty(
const TkIntSetType *set, const TkIntSetType *setEnd,
const TkIntSetType *sub, const TkIntSetType *subEnd)
{
while (set != setEnd && sub != subEnd) {
if (*set < *sub) {
return false;
} else {
if (*set == *sub) {
++set;
}
++sub;
}
}
return set == setEnd;
}
bool
TkIntSetIsEqualToDifference(
const TkIntSet *set1,
const TkIntSet *set2,
const TkIntSet *sub2)
{
const TkIntSetType *set1P, *set1End;
const TkIntSetType *set2P, *set2End;
const TkIntSetType *sub2P, *sub2End;
assert(set1);
assert(set2);
assert(sub2);
if (set2->buf == set2->end) {
return set1->buf == set1->end;
}
set1P = set1->buf; set1End = set1->end;
set2P = set2->buf; set2End = set2->end;
sub2P = sub2->buf; sub2End = sub2->end;
if (set1P == set1End) {
return DifferenceIsEmpty(set2P, set2End, sub2P, sub2End);
}
while (set1P != set1End && set2P != set2End) {
if (*set1P < *set2P) {
return false;
}
for ( ; sub2P != sub2End && *sub2P < *set2P; ++sub2P) {
}
if (sub2P == sub2End) {
break;
}
if (*set1P == *set2P) {
if (*set2P == *sub2P) {
return false;
}
++set1P;
} else {
if (*set2P != *sub2P) {
return false;
}
}
++set2P;
}
if (set2P == set2End) {
return set1P == set1End;
}
if (sub2P == sub2End) {
return TestIfEqual(set1P, set1End, set2P, set2End);
}
assert(set1P == set1End);
return DifferenceIsEmpty(set2P, set2End, sub2P, sub2End);
}
bool
TkIntSetIsEqualToInnerJoin(
const TkIntSet *set1,
const TkIntSet *set2,
const TkIntSet *add2)
{
const TkIntSetType *set1P, *set1End;
const TkIntSetType *set2P, *set2End;
const TkIntSetType *add2P, *add2End;
assert(set1);
assert(set2);
assert(add2);
if (set1 == set2) {
return true;
}
set1P = set1->buf; set1End = set1->end;
set2P = set2->buf; set2End = set2->end;
if (set2P == set2End) {
return set1P == set1End;
}
if (set2 == add2) {
return TestIfEqual(set1P, set1End, set2P, set2End);
}
add2P = add2->buf; add2End = add2->end;
while (set1P != set1End && set2P != set2End && add2P != add2End) {
if (*set2P < *set1P) {
return false;
} else if (*set1P == *set2P) {
++set1P;
++set2P;
} else if (*add2P < *set2P) {
++add2P;
} else if (*set2P < *add2P) {
++set2P;
} else {
return false;
}
}
if (add2P == add2End) {
return TestIfEqual(set1P, set1End, set2P, set2End);
}
if (set1P == set1End) {
return set2P == set2End;
}
return set1P == set1End;
}
static bool
EqualToJoin(
const TkIntSetType *src, const TkIntSetType *send,
const TkIntSetType *set1, const TkIntSetType *end1,
const TkIntSetType *set2, const TkIntSetType *end2)
{
assert(src != send);
while (set1 != end1 && set2 != end2) {
if (*src == *set1) {
if (*src == *set2) {
++set2;
}
++set1;
} else if (*src == *set2) {
++set2;
} else {
return false;
}
if (++src == send) {
return set1 == end1 && set2 == end2;
}
}
if (set1 == end1) {
set1 = set2;
end1 = end2;
}
return TestIfEqual(src, send, set1, end1);
}
bool
TkIntSetIsEqualToInnerJoinDifference(
const TkIntSet *set1,
const TkIntSet *set2,
const TkIntSet *add2,
const TkIntSet *sub2)
{
TkIntSetType buf1[100];
TkIntSetType buf2[100];
TkIntSetType *inscBuf;
TkIntSetType *diffBuf;
TkIntSetType *inscP, *inscEnd;
TkIntSetType *diffP, *diffEnd;
unsigned inscSize;
unsigned diffSize;
bool isEqual;
assert(set1);
assert(set2);
assert(add2);
assert(sub2);
if (add2->buf == add2->end) {
return TkIntSetIsEmpty(set1);
}
if (sub2->buf == sub2->end) {
return TkIntSetIsEqualToInnerJoin(set1, add2, set2);
}
if (set1->buf == set1->end) {
return TkIntSetDisjunctive(set2, add2)
&& DifferenceIsEmpty(add2->buf, add2->end, sub2->buf, sub2->end);
}
diffSize = TkIntSetSize(add2);
inscSize = MIN(TkIntSetSize(set2), diffSize);
inscBuf = inscSize <= sizeof(buf1)/sizeof(buf1[0]) ? buf1 : malloc(inscSize*sizeof(buf1[0]));
inscEnd = Intersect(inscP = inscBuf, set2->buf, set2->end, add2->buf, add2->end);
if (inscP == inscEnd) {
isEqual = TkIntSetIsEqualToDifference(set1, add2, sub2);
} else {
diffBuf = diffSize <= sizeof(buf2)/sizeof(buf2[0]) ? buf2 : malloc(diffSize*sizeof(buf2[0]));
diffEnd = Remove(diffP = diffBuf, add2->buf, add2->end, sub2->buf, sub2->end);
if (diffP == diffEnd) {
isEqual = TestIfEqual(set1->buf, set1->end, inscP, inscEnd);
} else {
isEqual = EqualToJoin(set1->buf, set1->end, inscP, inscEnd, diffP, diffEnd);
}
if (diffBuf != buf2) { free(diffBuf); }
}
if (inscBuf != buf1) { free(inscBuf); }
return isEqual;
}
static bool
InnerJoinDifferenceIsEqual(
const TkIntSetType *set, const TkIntSetType *setEnd,
const TkIntSetType *add, const TkIntSetType *addEnd,
const TkIntSetType *sub, const TkIntSetType *subEnd)
{
if (add != addEnd) {
while (set != setEnd && sub != subEnd) {
if (*set == *sub) {
while (*add < *set) {
if (++add == addEnd) {
return true;
}
}
if (*add == *set) {
return false;
}
++set;
++sub;
} else if (*set < *sub) {
++set;
} else {
++sub;
}
}
}
return true;
}
bool
TkIntSetInnerJoinDifferenceIsEqual(
const TkIntSet *set1,
const TkIntSet *set2,
const TkIntSet *add,
const TkIntSet *sub)
{
const TkIntSetType *set1P, *set1End;
const TkIntSetType *set2P, *set2End;
const TkIntSetType *addP, *addEnd;
const TkIntSetType *subP, *subEnd;
if (add->buf == add->end) {
return true;
}
set1P = set1->buf; set1End = set1->end;
set2P = set2->buf; set2End = set2->end;
addP = add->buf; addEnd = add->end;
subP = sub->buf; subEnd = sub->end;
if (set1P == set1End) {
return InnerJoinDifferenceIsEqual(set2P, set2End, addP, addEnd, subP, subEnd);
}
if (set2P == set2End) {
return InnerJoinDifferenceIsEqual(set1P, set1End, addP, addEnd, subP, subEnd);
}
while (addP != addEnd && subP != subEnd) {
if (*addP < *subP) {
++addP;
} else {
if (*addP == *subP) {
for ( ; set1P != set1End && *set1P < *addP; ++set1P) {
}
if (set1P == set1End) {
return InnerJoinDifferenceIsEqual(set2P, set2End, addP, addEnd, subP, subEnd);
}
for ( ; set2P != set2End && *set2P < *addP; ++set2P) {
}
if (set2P == set2End) {
return InnerJoinDifferenceIsEqual(set1P, set1End, addP, addEnd, subP, subEnd);
}
if (*addP == *set1P) {
if (*addP != *set2P) {
return false;
}
++set1P;
++set2P;
} else if (*addP == *set2P) {
return false;
}
++addP;
}
++subP;
}
}
return true;
}
#endif
#if __STDC_VERSION__ >= 199901L || (defined(_MSC_VER) && _MSC_VER >= 1900)
#define inline extern
inline unsigned TkIntSetByteSize(const TkIntSet *set);
inline const unsigned char *TkIntSetData(const TkIntSet *set);
inline bool TkIntSetIsEmpty(const TkIntSet *set);
inline unsigned TkIntSetSize(const TkIntSet *set);
inline unsigned TkIntSetMax(const TkIntSet *set);
inline unsigned TkIntSetRefCount(const TkIntSet *set);
inline void TkIntSetIncrRefCount(TkIntSet *set);
inline unsigned TkIntSetDecrRefCount(TkIntSet *set);
inline TkIntSetType TkIntSetAccess(const TkIntSet *set, unsigned index);
inline bool TkIntSetTest(const TkIntSet *set, unsigned n);
inline bool TkIntSetNone(const TkIntSet *set);
inline bool TkIntSetAny(const TkIntSet *set);
inline bool TkIntSetIsEqual(const TkIntSet *set1, const TkIntSet *set2);
inline bool TkIntSetContains(const TkIntSet *set1, const TkIntSet *set2);
inline bool TkIntSetDisjunctive(const TkIntSet *set1, const TkIntSet *set2);
inline bool TkIntSetIntersects(const TkIntSet *set1, const TkIntSet *set2);
inline unsigned TkIntSetFindFirst(const TkIntSet *set);
inline unsigned TkIntSetFindNext(const TkIntSet *set);
inline TkIntSet *TkIntSetAddOrErase(TkIntSet *set, unsigned n, bool add);
#endif