diff --git a/DHT/dht.c b/DHT/dht.c index 90103df1a..7c0fc8b26 100644 --- a/DHT/dht.c +++ b/DHT/dht.c @@ -396,14 +396,14 @@ static InternHsElement *stepDirTable(dirEnumerate *enumeration) typedef struct { - dhtHashValue (*Hash)(dhtConstValue); - int (*Equal)(dhtConstValue, dhtConstValue); - dhtConstValue (*DupKey)(dhtConstValue); - dhtConstValue (*DupData)(dhtConstValue); - void (*FreeKey)(dhtValue); + dhtHashValue (*Hash)(dhtKey); + int (*Equal)(dhtKey, dhtKey); + int (*DupKeyValue)(dhtValue, dhtValue *); + int (*DupData)(dhtValue, dhtValue *); + void (*FreeKeyValue)(dhtValue); void (*FreeData)(dhtValue); - void (*DumpData)(dhtConstValue,FILE *); - void (*DumpKey)(dhtConstValue,FILE *); + void (*DumpData)(dhtValue,FILE *); + void (*DumpKeyValue)(dhtValue,FILE *); } Procedures; typedef struct dht { @@ -436,7 +436,7 @@ typedef struct dht { #define ActualLoadFactor(h) (((h)->KeyCount*100)/(h)->DirTab.count) #endif /*OVERFLOW_SAVE*/ -unsigned long dhtKeyCount(dht *h) +unsigned long dhtKeyCount(dht const *h) { return h->KeyCount; } @@ -508,17 +508,17 @@ dht *dhtCreate(dhtValueType KeyType, dhtValuePolicy KeyPolicy, ht->procs.Hash= dhtProcedures[KeyType]->Hash; ht->procs.Equal= dhtProcedures[KeyType]->Equal; ht->procs.DumpData= dhtProcedures[DtaType]->Dump; - ht->procs.DumpKey= dhtProcedures[KeyType]->Dump; + ht->procs.DumpKeyValue= dhtProcedures[KeyType]->Dump; if (KeyPolicy==dhtNoCopy) { - ht->procs.DupKey= dhtProcedures[dhtSimpleValue]->Dup; - ht->procs.FreeKey= dhtProcedures[dhtSimpleValue]->Free; + ht->procs.DupKeyValue= dhtProcedures[dhtSimpleValue]->Dup; + ht->procs.FreeKeyValue= dhtProcedures[dhtSimpleValue]->Free; } else if (KeyPolicy==dhtCopy) { - ht->procs.DupKey= dhtProcedures[KeyType]->Dup; - ht->procs.FreeKey= dhtProcedures[KeyType]->Free; + ht->procs.DupKeyValue= dhtProcedures[KeyType]->Dup; + ht->procs.FreeKeyValue= dhtProcedures[KeyType]->Free; } if (DataPolicy==dhtNoCopy) @@ -559,8 +559,8 @@ void dhtDestroy(HashTable *ht) while (b) { InternHsElement *tmp= b; - (ht->procs.FreeKey)((dhtValue)b->HsEl.Key); - (ht->procs.FreeData)((dhtValue)b->HsEl.Data); + (ht->procs.FreeKeyValue)(b->HsEl.Key.value); + (ht->procs.FreeData)(b->HsEl.Data); b= b->Next; FreeInternHsElement(tmp); } @@ -599,7 +599,7 @@ void dhtDumpIndented(int ind, HashTable *ht, FILE *f) while (b) { fprintf(f, "%*s ", ind, ""); - (ht->procs.DumpKey)(b->HsEl.Key, f); + (ht->procs.DumpKeyValue)(b->HsEl.Key.value, f); fputs("->", f); (ht->procs.DumpData)(b->HsEl.Data, f); b= b->Next; @@ -796,14 +796,18 @@ LOCAL void ShrinkHashTable(HashTable *ht) shrinkDirTable(&ht->DirTab); } -LOCAL InternHsElement **LookupInternHsElement(HashTable *ht, dhtConstValue key) +LOCAL InternHsElement **LookupInternHsElement(HashTable *ht, dhtKey key) { uLong h; InternHsElement **phe; TraceFunctionEntry(__func__); TraceFunctionParam("%p",(void *)ht); - TraceFunctionParam("%p",(void const *)key); +#if (defined(__cplusplus) && (__cplusplus >= 201103L)) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) + TraceFunctionParam("%jx",key.value.unsigned_integer); +#else + TraceFunctionParam("%lx",(unsigned long)key.value.unsigned_integer); +#endif TraceFunctionParamListEnd(); h = DynamicHash(ht->p, ht->maxp, (ht->procs.Hash)(key)); @@ -827,14 +831,18 @@ LOCAL InternHsElement **LookupInternHsElement(HashTable *ht, dhtConstValue key) return phe; } -void dhtRemoveElement(HashTable *ht, dhtConstValue key) +void dhtRemoveElement(HashTable *ht, dhtKey key) { MYNAME(dhtRemoveElement) InternHsElement **phe, *he; TraceFunctionEntry(__func__); TraceFunctionParam("%p",(void *)ht); - TraceFunctionParam("%p",(void const *)key); +#if (defined(__cplusplus) && (__cplusplus >= 201103L)) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) + TraceFunctionParam("%jx",key.value.unsigned_integer); +#else + TraceFunctionParam("%lx",(unsigned long)key.value.unsigned_integer); +#endif TraceFunctionParamListEnd(); phe= LookupInternHsElement(ht, key); @@ -849,8 +857,8 @@ void dhtRemoveElement(HashTable *ht, dhtConstValue key) ht->NextStep= ht->NextStep->Next; *phe= he->Next; - (ht->procs.FreeData)((dhtValue)he->HsEl.Data); - (ht->procs.FreeKey)((dhtValue)he->HsEl.Key); + (ht->procs.FreeData)(he->HsEl.Data); + (ht->procs.FreeKeyValue)(he->HsEl.Key.value); FreeInternHsElement(he); ht->KeyCount--; if (ActualLoadFactor(ht) < ht->MinLoadFactor) @@ -877,21 +885,26 @@ void dhtRemoveElement(HashTable *ht, dhtConstValue key) TraceFunctionResultEnd(); } -dhtElement *dhtEnterElement(HashTable *ht, dhtConstValue key, dhtConstValue data) +dhtElement *dhtEnterElement(HashTable *ht, dhtKey key, dhtValue data) { InternHsElement **phe, *he; - dhtConstValue KeyV; - dhtConstValue DataV; + dhtKey KeyV; + dhtValue DataV; TraceFunctionEntry(__func__); TraceFunctionParam("%p",(void *)ht); - TraceFunctionParam("%p",(void const *)key); - TraceFunctionParam("%p",(void const *)data); +#if (defined(__cplusplus) && (__cplusplus >= 201103L)) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) + TraceFunctionParam("%jx",key.value.unsigned_integer); + TraceFunctionParam("%jx",data.unsigned_integer); +#else + TraceFunctionParam("%lx",(unsigned long)key.value.unsigned_integer); + TraceFunctionParam("%lx",(unsigned long)data.unsigned_integer); +#endif TraceFunctionParamListEnd(); - assert(key!=0); - KeyV = (ht->procs.DupKey)(key); - if (KeyV==0) + assert(key.value.object_pointer!=0); /* TODO: This assert assumes that object_pointer is the active member. + Is there a more generic test we could do? Do we need one? */ + if ((ht->procs.DupKeyValue)(key.value, &KeyV.value)) { TraceText("key duplication failed\n"); TraceFunctionExit(__func__); @@ -900,10 +913,9 @@ dhtElement *dhtEnterElement(HashTable *ht, dhtConstValue key, dhtConstValue data return dhtNilElement; } - DataV = data==0 ? 0 : (ht->procs.DupData)(data); - if (data!=0 && DataV==0) + if ((ht->procs.DupData)(data, &DataV)) { - (ht->procs.FreeKey)((dhtValue)KeyV); + (ht->procs.FreeKeyValue)(KeyV.value); TraceText("data duplication failed\n"); TraceFunctionExit(__func__); TraceFunctionResult("%p",(void *)dhtNilElement); @@ -923,8 +935,8 @@ dhtElement *dhtEnterElement(HashTable *ht, dhtConstValue key, dhtConstValue data TraceEOL(); if (he==0) { - (ht->procs.FreeKey)((dhtValue)KeyV); - (ht->procs.FreeData)((dhtValue)DataV); + (ht->procs.FreeKeyValue)(KeyV.value); + (ht->procs.FreeData)(DataV); TraceText("allocation of new intern Hs element failed\n"); TraceFunctionExit(__func__); TraceFunctionResult("%p",(void *)dhtNilElement); @@ -941,9 +953,9 @@ dhtElement *dhtEnterElement(HashTable *ht, dhtConstValue key, dhtConstValue data else { if (ht->DtaPolicy == dhtCopy) - (ht->procs.FreeData)((dhtValue)he->HsEl.Data); + (ht->procs.FreeData)(he->HsEl.Data); if (ht->KeyPolicy == dhtCopy) - (ht->procs.FreeKey)((dhtValue)he->HsEl.Key); + (ht->procs.FreeKeyValue)(he->HsEl.Key.value); } he->HsEl.Key = KeyV; @@ -975,7 +987,7 @@ dhtElement *dhtEnterElement(HashTable *ht, dhtConstValue key, dhtConstValue data return &he->HsEl; } -dhtElement *dhtLookupElement(HashTable *ht, dhtConstValue key) +dhtElement *dhtLookupElement(HashTable *ht, dhtKey key) { InternHsElement **phe; dhtElement *result; diff --git a/DHT/dht.h b/DHT/dht.h index a2a50c07b..da48e683d 100644 --- a/DHT/dht.h +++ b/DHT/dht.h @@ -6,7 +6,7 @@ * Institut fuer Informatik, TU Muenchen, Germany * bartel@informatik.tu-muenchen.de * You may use this code as you wish, as long as this - * comment with the above copyright notice is keept intact + * comment with the above copyright notice is kept intact * and in place. */ typedef enum { @@ -15,28 +15,28 @@ typedef enum { /* Now finally this is the HashElement */ typedef struct { - dhtConstValue Key; - dhtConstValue Data; + dhtKey Key; + dhtValue Data; } dhtElement; -#define dhtNilElement ((dhtElement *)0) +#define dhtNilElement ((dhtElement *)0) struct dht; -#define dhtNilHashTable ((struct dht *)0) +#define dhtNilHashTable ((struct dht *)0) /* procedures */ -struct dht *dhtCreate(dhtValueType KeyType, dhtValuePolicy KeyPolicy, - dhtValueType DtaType, dhtValuePolicy DataPolicy); -dhtElement *dhtEnterElement(struct dht *, dhtConstValue key, dhtConstValue data); -unsigned int dhtBucketStat (struct dht *, unsigned int *counter, unsigned int n); -void dhtDestroy (struct dht *); -void dhtDump (struct dht *, FILE *); -void dhtDumpIndented (int i, struct dht *, FILE *); -void dhtRemoveElement (struct dht *, dhtConstValue key); -dhtElement *dhtLookupElement (struct dht *, dhtConstValue key); -dhtElement *dhtGetFirstElement(struct dht *); -dhtElement *dhtGetNextElement (struct dht *); -unsigned long dhtKeyCount (struct dht *); -char const *dhtErrorMsg (void); +struct dht *dhtCreate(dhtValueType KeyType, dhtValuePolicy KeyPolicy, + dhtValueType DtaType, dhtValuePolicy DataPolicy); +dhtElement *dhtEnterElement(struct dht *, dhtKey key, dhtValue data); +unsigned int dhtBucketStat(struct dht *, unsigned int *counter, unsigned int n); +void dhtDestroy(struct dht *); +void dhtDump(struct dht *, FILE *); +void dhtDumpIndented(int ind, struct dht *, FILE *); +void dhtRemoveElement(struct dht *, dhtKey key); +dhtElement *dhtLookupElement(struct dht *, dhtKey key); +dhtElement *dhtGetFirstElement(struct dht *); +dhtElement *dhtGetNextElement(struct dht *); +unsigned long dhtKeyCount(struct dht const *); +char const *dhtErrorMsg(void); extern char dhtError[]; diff --git a/DHT/dhtbcmem.c b/DHT/dhtbcmem.c index 54c474c91..dede2285e 100644 --- a/DHT/dhtbcmem.c +++ b/DHT/dhtbcmem.c @@ -4,33 +4,41 @@ * Institut fuer Informatik, TU Muenchen, Germany * bartel@informatik.tu-muenchen.de * You may use this code as you wish, as long as this - * comment with the above copyright notice is keept intact + * comment with the above copyright notice is kept intact * and in place. */ -#include "debugging/assert.h" #include #include #include #include +#include #if defined(__BORLANDC__) #include #endif /*__BORLANDC__*/ +#include "debugging/assert.h" #include "dhtvalue.h" #include "dhtbcmem.h" #include "dht.h" -static dhtHashValue ConvertBCMemValue(dhtConstValue m) +enum { + ENSURE_SIZE_OF_ELEMENT_IS_ONE = 1/(1 == sizeof ((BCMemValue const *)NULL)->Data[0]) +}; + +static dhtHashValue ConvertBCMemValue(dhtKey m) { - BCMemValue const * const toBeConverted = (BCMemValue const *)m; - unsigned int leng = toBeConverted->Leng; - unsigned char const *s = toBeConverted->Data; + BCMemValue const * const toBeConverted = (BCMemValue const *)m.value.object_pointer; + unsigned short leng; + unsigned char const *s; + assert(!!toBeConverted); + leng = toBeConverted->Leng; + s = toBeConverted->Data; dhtHashValue hash = 0; - unsigned int i; - for (i=0; iData + value1->Leng; - - return memcmp(value1,value2,size)==0; + BCMemValue const * const value1 = (BCMemValue const *)v1.value.object_pointer; + BCMemValue const * const value2 = (BCMemValue const *)v2.value.object_pointer; + unsigned short length; + unsigned char const *data1; + unsigned char const *data2; + assert(value1 && value2); + length = value1->Leng; + + if (length != value2->Leng) + return 0; + + data1 = value1->Data; + data2 = value2->Data; + while (length > ((size_t)-1)) + { + if (memcmp(data1, data2, ((size_t)-1))) + return 0; + data1 += ((size_t)-1); + data2 += ((size_t)-1); + length -= ((size_t)-1); + } + return !memcmp(data1, data2, length); } -static dhtConstValue DupBCMemValue(dhtConstValue v) +static int DupBCMemValue(dhtValue kv, dhtValue *output) { - BCMemValue const * const original = (BCMemValue const *)v; - size_t const size = (sizeof *original - - sizeof original->Data - + original->Leng); + BCMemValue const *original = (BCMemValue const *)kv.object_pointer; + size_t const num_bytes_in_Data = ((sizeof *original) - offsetof(BCMemValue, Data)); + BCMemValue *result; + unsigned short length; + size_t size = sizeof *original; + + assert(!!output); + if (!original) + { + output->object_pointer = NULL; + return 0; + } - BCMemValue * const result = fxfAlloc(size); - if (result!=0) - memcpy(result,original,size); + length = original->Leng; + if (length > num_bytes_in_Data) + { + if (length > (((size_t)-1) - size + num_bytes_in_Data)) + return 1; + size += (length - num_bytes_in_Data); + } + + result = (BCMemValue *)fxfAlloc(size); + if (result) + { + result->Leng = length; + memcpy(result->Data,original->Data,length); + output->object_pointer = result; + return 0; + } - return (dhtConstValue)result; + return 1; } -static void FreeBCMemVal(dhtValue v) +static void FreeBCMemValue(dhtValue kv) { - BCMemValue * const freed = (BCMemValue *)v; - size_t const size = sizeof *freed - sizeof freed->Data + freed->Leng; - fxfFree(freed,size); + BCMemValue *freed = (BCMemValue *)kv.object_pointer; + size_t const num_bytes_in_Data = ((sizeof *freed) - offsetof(BCMemValue, Data)); + if (freed) + { + size_t size = sizeof *freed; + unsigned short length = freed->Leng; + if (length > num_bytes_in_Data) + { + assert(length <= (((size_t)-1) - size + num_bytes_in_Data)); + size += (length - num_bytes_in_Data); + } + fxfFree(freed,size); + } } -static void DumpBCMemValue(dhtConstValue v, FILE *f) +static void DumpBCMemValue(dhtValue kv, FILE *f) { - BCMemValue const * const toBeDumped = (BCMemValue const *)v; - unsigned int const length = toBeDumped->Leng; - unsigned int i; + BCMemValue const *toBeDumped = (BCMemValue const *)kv.object_pointer; + unsigned short length; + unsigned short i; + + assert(toBeDumped && f); - fprintf(f, "(%d)", toBeDumped->Leng); + length = toBeDumped->Leng; + fprintf(f, "(%u)", length); for (i=0; iData[i] & 0xff); + fprintf(f, "%02x", (toBeDumped->Data[i] & 0xffU)); } dhtValueProcedures dhtBCMemoryProcs = @@ -90,6 +149,6 @@ dhtValueProcedures dhtBCMemoryProcs = ConvertBCMemValue, EqualBCMemValue, DupBCMemValue, - FreeBCMemVal, + FreeBCMemValue, DumpBCMemValue }; diff --git a/DHT/dhtbcmem.h b/DHT/dhtbcmem.h index 30f015648..55bd635f3 100644 --- a/DHT/dhtbcmem.h +++ b/DHT/dhtbcmem.h @@ -6,7 +6,7 @@ * Institut fuer Informatik, TU Muenchen, Germany * bartel@informatik.tu-muenchen.de * You may use this code as you wish, as long as this - * comment with the above copyright notice is keept + * comment with the above copyright notice is kept * intact and in place. */ @@ -16,8 +16,8 @@ */ typedef struct BCMemValue { - unsigned char Leng; - unsigned char Data[1]; + unsigned short Leng; + unsigned char Data[1]; } BCMemValue; #endif /*DHTBCMEM_INCLUDED*/ diff --git a/DHT/dhtcmem.c b/DHT/dhtcmem.c index 9353418ca..a6a486403 100644 --- a/DHT/dhtcmem.c +++ b/DHT/dhtcmem.c @@ -4,13 +4,15 @@ * Institut fuer Informatik, TU Muenchen, Germany * bartel@informatik.tu-muenchen.de * You may use this code as you wish, as long as this - * comment with the above copyright notice is keept intact + * comment with the above copyright notice is kept intact * and in place. */ #include #include #include +#include +#include "debugging/assert.h" #include "dhtvalue.h" #include "dhtcmem.h" #include "dht.h" @@ -22,13 +24,21 @@ typedef unsigned long uLong; typedef unsigned char uChar; -static dhtHashValue ConvertCompactMemoryValue(dhtConstValue m) +enum { + ENSURE_SIZE_OF_ELEMENT_IS_ONE = 1/(1 == sizeof NilCompactMemVal->Data[0]) +}; + +static dhtHashValue ConvertCompactMemoryValue(dhtKey m) { - uLong leng= ((CompactMemVal const *)m)->Leng; - uChar const *s= ((CompactMemVal const *)m)->Data; + CompactMemVal const * const toBeConverted = (CompactMemVal const *)m.value.object_pointer; + uLong leng; + uChar const *s; + assert(!!toBeConverted); + leng= toBeConverted->Leng; + s= toBeConverted->Data; dhtHashValue hash= 0; uLong i; - for (i=0; i> 6; @@ -39,39 +49,90 @@ static dhtHashValue ConvertCompactMemoryValue(dhtConstValue m) return hash; } -static int EqualCompactMemoryValue(dhtConstValue v1, dhtConstValue v2) +static int EqualCompactMemoryValue(dhtKey v1, dhtKey v2) { - if (((CompactMemVal const *)v1)->Leng != ((CompactMemVal const *)v2)->Leng) + CompactMemVal const * const value1 = (CompactMemVal const *)v1.value.object_pointer; + CompactMemVal const * const value2 = (CompactMemVal const *)v2.value.object_pointer; + uLong length; + unsigned char const *data1; + unsigned char const *data2; + assert(value1 && value2); + length = value1->Leng; + if (length != value2->Leng) return 0; - if (memcmp(((CompactMemVal const *)v1)->Data, - ((CompactMemVal const *)v2)->Data, ((CompactMemVal const *)v1)->Leng)) - return 0; - else - return 1; + data1 = value1->Data; + data2 = value2->Data; + while (length > ((size_t)-1)) + { + if (memcmp(data1, data2, ((size_t)-1))) + return 0; + data1 += ((size_t)-1); + data2 += ((size_t)-1); + length -= ((size_t)-1); + } + return !memcmp(data1, data2, length); } -static dhtConstValue DupCompactMemoryValue(dhtConstValue v) +static int DupCompactMemoryValue(dhtValue kv, dhtValue *output) { - CompactMemVal *cm= NewCompactMemVal(((CompactMemVal const *)v)->Leng); - if (cm) { - cm->Leng= ((CompactMemVal const *)v)->Leng; - memcpy(cm->Data, ((CompactMemVal const *)v)->Data, cm->Leng); - return (dhtValue)cm; + CompactMemVal const *v = (CompactMemVal const *)kv.object_pointer; + size_t const num_bytes_in_Data = ((sizeof *v) - offsetof(CompactMemVal, Data)); + size_t size = sizeof *v; + CompactMemVal *result; + uLong length; + + assert(!!output); + if (!v) + { + output->object_pointer = NilCompactMemVal; + return 0; } - return (dhtValue)cm; + + length = v->Leng; + if (length > num_bytes_in_Data) + { + if (length > (((size_t)-1) - size + num_bytes_in_Data)) + return 1; + size += (length - num_bytes_in_Data); + } + + result = (CompactMemVal *)fxfAlloc(size); + if (result) + { + result->Leng = length; + memcpy(result->Data,v->Data,length); + output->object_pointer = result; + return 0; + } + + return 1; } -static void FreeCompactMemoryValue(dhtValue v) +static void FreeCompactMemoryValue(dhtValue kv) { - FreeCompactMemVal(v); + CompactMemVal *v = (CompactMemVal *)kv.object_pointer; + size_t const num_bytes_in_Data = ((sizeof *v) - offsetof(CompactMemVal, Data)); + if (v) + { + size_t size = sizeof *v; + uLong length = v->Leng; + if (length > num_bytes_in_Data) + { + assert(length <= (((size_t)-1) - size + num_bytes_in_Data)); + size += (length - num_bytes_in_Data); + } + fxfFree(v,size); + } } -static void DumpCompactMemoryValue(dhtConstValue v, FILE *f) +static void DumpCompactMemoryValue(dhtValue kv, FILE *f) { + CompactMemVal const *v = (CompactMemVal const *)kv.object_pointer; uLong i; - fprintf(f, "(%lu)", ((CompactMemVal const *)v)->Leng); - for (i=0; i<((CompactMemVal const *)v)->Leng; i++) - fprintf(f, "%02x", ((CompactMemVal const *)v)->Data[i] & 0xff); + assert(v && f); + fprintf(f, "(%lu)", v->Leng); + for (i=0; iLeng; i++) + fprintf(f, "%02x", (v->Data[i] & 0xffU)); } dhtValueProcedures dhtCompactMemoryProcs = { diff --git a/DHT/dhtcmem.h b/DHT/dhtcmem.h index 7e1a6c85d..85b24a1c4 100644 --- a/DHT/dhtcmem.h +++ b/DHT/dhtcmem.h @@ -6,7 +6,7 @@ * Institut fuer Informatik, TU Muenchen, Germany * bartel@informatik.tu-muenchen.de * You may use this code as you wish, as long as this - * comment with the above copyright notice is keept + * comment with the above copyright notice is kept * intact and in place. */ @@ -14,10 +14,10 @@ * It is allocated via one malloc call. */ typedef struct CompactMemVal { - unsigned long Leng; - unsigned char Data[1]; + unsigned long Leng; + unsigned char Data[1]; } CompactMemVal; -#define NilCompactMemVal (CompactMemVal *)0 -#define NewCompactMemVal(n) (CompactMemVal *)fxfAlloc(sizeof(CompactMemVal)+(n)*sizeof(uChar)) +#define NilCompactMemVal ((CompactMemVal *)0) +#define NewCompactMemVal(n) ((CompactMemVal *)fxfAlloc(sizeof(CompactMemVal)+(n)*sizeof(uChar))) #define FreeCompactMemVal(v) fxfFree(v, sizeof(CompactMemVal)+((CompactMemVal const *)(v))->Leng*sizeof(uChar)) #endif /*DHTCMEM_INCLUDED*/ diff --git a/DHT/dhtexam1.c b/DHT/dhtexam1.c index 7fb3e9adf..5c0cc27b1 100644 --- a/DHT/dhtexam1.c +++ b/DHT/dhtexam1.c @@ -4,7 +4,7 @@ * Institut fuer Informatik, TU Muenchen, Germany * bartel@informatik.tu-muenchen.de * You may use this code as you wish, as long as this - * comment with the above copyright notice is keept intact + * comment with the above copyright notice is kept intact * and in place. */ @@ -62,7 +62,7 @@ uLong inet_addr(char *cp) { return addr; } -struct hostent *gethent(char *file) +struct hostent *gethent(char const *file) { static struct hostent host; char *p; @@ -115,6 +115,8 @@ int main(int argc, char *argv[]) { struct hostent *host; int i; char *hostsfile; + dhtKey k; + dhtValue v; if (argc > 1) { @@ -194,14 +196,18 @@ int main(int argc, char *argv[]) { */ InetAddr= *(uLong *)h; - if (dhtLookupElement(NameToInet, (dhtValue)HostName)) { + k.value.object_pointer = HostName; + if (dhtLookupElement(NameToInet, k)) { fprintf(stderr, "Hostname %s already entered\n", host->h_name); } - dhtEnterElement(NameToInet, (dhtValue)HostName, (dhtValue)InetAddr); - if (dhtLookupElement(InetToName, (dhtValue)InetAddr)) { + v.unsigned_integer = InetAddr; + dhtEnterElement(NameToInet, k, v); + k.value.unsigned_integer = InetAddr; + if (dhtLookupElement(InetToName, k)) { fprintf(stderr, "InetAddr 0x%08lx already entered\n", InetAddr); } - dhtEnterElement(InetToName, (dhtValue)InetAddr, (dhtValue)HostName); + v.object_pointer = HostName; + dhtEnterElement(InetToName, k, v); } #if defined(FXF) fputs("fxf-Info after filling the hash tables\n",stderr); @@ -219,7 +225,7 @@ int main(int argc, char *argv[]) { fDumpMallinfo(stderr); */ - fputs("Testing if we get alle entries from NameToInet via GetFirst and GetNext...\n",stderr); + fputs("Testing if we get all entries from NameToInet via GetFirst and GetNext...\n",stderr); he= dhtGetFirstElement(NameToInet); i= 0; while (he) { @@ -239,33 +245,35 @@ int main(int argc, char *argv[]) { he= dhtGetFirstElement(NameToInet); while (he) { - uLong adr= (uLong)he->Data; + uLong adr= (uLong)he->Data.unsigned_integer; char *Name; #if defined(USE_MEMVAL) strncpy(str, - (char *)((MemVal *)he->Key)->Data, - ((MemVal *)he->Key)->Leng); - str[((MemVal *)he->Key)->Leng]='\0'; + (char *)((MemVal *)he->Key.value.object_pointer)->Data, + ((MemVal *)he->Key.value.object_pointer)->Leng); + str[((MemVal *)he->Key.value.object_pointer)->Leng]='\0'; Name= str; #else - Name= (char *)he->Key; + Name= (char *)he->Key.value.object_pointer; #endif /*USE_MEMVAL*/ printf("%3u.%3u.%3u.%3u = %s ", BYT(adr), BYT(adr>>8), BYT(adr>>16), BYT(adr>>24), Name); dhtRemoveElement(NameToInet, he->Key); - dhtRemoveElement(InetToName, he->Data); + k.value = he->Data; + dhtRemoveElement(InetToName, k); printf(" Deleting and checking consistency (Load=%lu... ", dhtKeyCount(NameToInet)); i=0; hhe= dhtGetFirstElement(NameToInet); fputs(" ", stdout); fflush(stdout); while (hhe) { - dhtElement *he1= dhtLookupElement(InetToName, hhe->Data); - if (strcmp((char *)he1->Data, (char *)hhe->Key) != 0) { + k.value = hhe->Data; + dhtElement *he1= dhtLookupElement(InetToName, k); + if (strcmp((char const *)he1->Data.object_pointer, (char const *)hhe->Key.value.object_pointer) != 0) { puts("\nSorry, Mismatch"); exit(1); } - if (he1->Key != hhe->Data) { + if (he1->Key.value.unsigned_integer != hhe->Data.unsigned_integer) { puts("\nSorry, Mismatch"); exit(2); } diff --git a/DHT/dhtexam2.c b/DHT/dhtexam2.c index 58a9229e8..4f3f6dbf2 100644 --- a/DHT/dhtexam2.c +++ b/DHT/dhtexam2.c @@ -4,7 +4,7 @@ * Institut fuer Informatik, TU Muenchen, Germany * bartel@informatik.tu-muenchen.de * You may use this code as you wish, as long as this - * comment with the above copyright notice is keept intact + * comment with the above copyright notice is kept intact * and in place. */ @@ -23,6 +23,8 @@ int main(int argc, char *argv[]) { int cnt, EntryCnt= 0; long int tmp; + dhtKey k; + dhtValue v; struct dummy { long l1; @@ -82,7 +84,9 @@ int main(int argc, char *argv[]) { for (cnt=0; cntage= Age; info_to_enter->room= Room; /* the string will be duplicated the info not */ - dhtEnterElement(OurTable, - (dhtValue)string_to_enter, (dhtValue)info_to_enter); + k.value.object_pointer = string_to_enter; + v.object_pointer = info_to_enter; + dhtEnterElement(OurTable, k, v); } /* access table */ while (scanf("%127s", name_to_find) != EOF) { - he= dhtLookupElement(OurTable, (dhtValue)name_to_find); + k.value.object_pointer = name_to_find; + he= dhtLookupElement(OurTable, k); if (he != dhtNilElement) { /* if item is in the table */ (void)printf("found %s, age = %d, room = %d\n", - (char *)he->Key, - ((struct info *)he->Data)->age, - ((struct info *)he->Data)->room); + (char *)he->Key.value.object_pointer, + ((struct info *)he->Data.object_pointer)->age, + ((struct info *)he->Data.object_pointer)->room); } else { (void)printf("no such employee %s\n", name_to_find); } @@ -79,7 +83,7 @@ int main( ) /* now delete all struct info in the table */ he= dhtGetFirstElement(OurTable); while (he) { - free((dhtValue)he->Data); + free(he->Data.object_pointer); he= dhtGetNextElement(OurTable); } /* now destroy the whole table */ diff --git a/DHT/dhtmem.c b/DHT/dhtmem.c index 7f573748f..92ee47333 100644 --- a/DHT/dhtmem.c +++ b/DHT/dhtmem.c @@ -4,7 +4,7 @@ * Institut fuer Informatik, TU Muenchen, Germany * bartel@informatik.tu-muenchen.de * You may use this code as you wish, as long as this - * comment with the above copyright notice is keept intact + * comment with the above copyright notice is kept intact * and in place. */ @@ -16,6 +16,7 @@ # include #endif /*__BORLANDC__*/ +#include "debugging/assert.h" #include "dhtvalue.h" #include "dhtmem.h" #include "dht.h" @@ -23,59 +24,112 @@ typedef unsigned long uLong; typedef unsigned char uChar; -static dhtHashValue HashMemoryValue(dhtConstValue v) +enum { + ENSURE_SIZE_OF_ELEMENT_IS_ONE = 1/(1 == sizeof NilMemVal->Data[0]) +}; + +static dhtHashValue HashMemoryValue(dhtKey k) { - uLong leng= ((MemVal const *)v)->Leng; - uChar const *s= ((MemVal const *)v)->Data; + MemVal const * toBeHashed = (MemVal const *)k.value.object_pointer; + assert(!!toBeHashed); + assert(toBeHashed->Data || !toBeHashed->Leng); + uLong leng= toBeHashed->Leng; + uChar const *s= toBeHashed->Data; dhtHashValue hash= 0; uLong i; - for (i=0; i> 6; + for (i=0; i> 6; } hash+= hash << 3; hash^= hash >> 11; hash+= hash << 15; return hash; } -static int EqualMemoryValue(dhtConstValue v1, dhtConstValue v2) +static int EqualMemoryValue(dhtKey v1, dhtKey v2) { - if (((MemVal const *)v1)->Leng != ((MemVal const *)v2)->Leng) - return 0; - if (memcmp(((MemVal const *)v1)->Data, ((MemVal const *)v2)->Data, ((MemVal const *)v1)->Leng)) + MemVal const * value1 = (MemVal const *)v1.value.object_pointer; + MemVal const * value2 = (MemVal const *)v2.value.object_pointer; + uLong length; + uChar const *data1; + uChar const *data2; + + assert(value1 && value2); + length = value1->Leng; + data1 = value1->Data; + assert(data1 || !length); + data2 = value2->Data; + assert(data2 || !value2->Leng); + + if (length != value2->Leng) return 0; - else + if (!length) // We'll check this here to avoid (maybe) passing NULL as an argument to memcmp. return 1; + while (length > ((size_t)-1)) + { + if (memcmp(data1, data2, ((size_t)-1))) + return 0; + data1+= ((size_t)-1); + data2+= ((size_t)-1); + length-= ((size_t)-1); + } + return !memcmp(data1, data2, length); } - -static dhtConstValue DupMemoryValue(dhtConstValue v) +static int DupMemoryValue(dhtValue kv, dhtValue *output) { + MemVal const *v= (MemVal const *)kv.object_pointer; + uChar const *data; + uLong length; MemVal *mv; - + assert(!!output); + if (!v) { + output->object_pointer = NilMemVal; + return 0; + } + length= v->Leng; + data= v->Data; + assert(data || !length); + if (length > ((size_t)-1)) + return 1; mv= NewMemVal; if (mv) { - mv->Data= (unsigned char *)fxfAlloc(((MemVal const *)v)->Leng); - if (mv->Data) { - mv->Leng= ((MemVal const *)v)->Leng; - memcpy(mv->Data, ((MemVal const *)v)->Data, mv->Leng); - return (dhtValue)mv; + mv->Leng= length; + if (length) { + void *newBuffer= fxfAlloc(length); + if (newBuffer) { + memcpy(newBuffer, data, length); + mv->Data = (uChar *)newBuffer; + output->object_pointer = mv; + return 0; + } else { + FreeMemVal(mv); + return 1; + } } else { - FreeMemVal(mv); - mv = NilMemVal; + mv->Data= NULL; // NULL is a valid pointer if Leng == 0 + output->object_pointer= mv; + return 0; } } - return (dhtValue)mv; + return 1; } -static void FreeMemoryValue(dhtValue v) +static void FreeMemoryValue(dhtValue kv) { - DeleteMemVal(v); + MemVal *v= (MemVal *)kv.object_pointer; + if (v) { + fxfFree(v->Data, v->Leng); + fxfFree(v, sizeof *v); + } } -static void DumpMemoryValue(dhtConstValue v, FILE *f) { +static void DumpMemoryValue(dhtValue kv, FILE *f) { + MemVal const * v= (MemVal *)kv.object_pointer; uLong i; - fprintf(f, "(%lu)", ((MemVal const *)v)->Leng); - for (i=0; i<((MemVal const *)v)->Leng; i++) - fprintf(f, "%02x", ((MemVal const *)v)->Data[i] & 0xff); + assert(v && f); + assert(v->Data || !v->Leng); + fprintf(f, "(%lu)", v->Leng); + for (i=0; iLeng; i++) + fprintf(f, "%02x", (v->Data[i] & 0xffU)); } dhtValueProcedures dhtMemoryProcs = { diff --git a/DHT/dhtmem.h b/DHT/dhtmem.h index 57774b353..c7640bfa7 100644 --- a/DHT/dhtmem.h +++ b/DHT/dhtmem.h @@ -6,7 +6,7 @@ * Institut fuer Informatik, TU Muenchen, Germany * bartel@informatik.tu-muenchen.de * You may use this code as you wish, as long as this - * comment with the above copyright notice is keept intact + * comment with the above copyright notice is kept intact * and in place. */ @@ -16,12 +16,12 @@ * hash-table is needed. */ typedef struct MemVal { - unsigned long Leng; - unsigned char *Data; + unsigned long Leng; + unsigned char *Data; } MemVal; -#define NilMemVal (MemVal *)0 -#define NewMemVal (MemVal *)fxfAlloc(sizeof(MemVal)) +#define NilMemVal ((MemVal *)0) +#define NewMemVal ((MemVal *)fxfAlloc(sizeof(MemVal))) #define FreeMemVal(v) fxfFree(v, sizeof(MemVal)) -#define DeleteMemVal(v) if (((MemVal const *)(v))!=NilMemVal) fxfFree(((MemVal const *)(v))->Data, ((MemVal const *)(v))->Leng), FreeMemVal(v) +#define DeleteMemVal(v) do {if (((MemVal const *)(v))!=NilMemVal) fxfFree(((MemVal const *)(v))->Data, ((MemVal const *)(v))->Leng), FreeMemVal(v);} while (0) #endif /*DHTMEM_INCLUDED*/ diff --git a/DHT/dhtsimpl.c b/DHT/dhtsimpl.c index 7ee2c4aba..15289d8e0 100644 --- a/DHT/dhtsimpl.c +++ b/DHT/dhtsimpl.c @@ -4,9 +4,10 @@ * Institut fuer Informatik, TU Muenchen, Germany * bartel@informatik.tu-muenchen.de * You may use this code as you wish, as long as this - * comment with the above copyright notice is keept intact + * comment with the above copyright notice is kept intact * and in place. */ +#include "debugging/assert.h" #include "dhtvalue.h" #if defined(ARCH64) @@ -30,52 +31,69 @@ b -= c; b -= a; b ^= (a<<18); \ c -= a; c -= b; c ^= (b>>22); \ } -static unsigned long ConvertSimpleValue(dhtConstValue v) +static unsigned long ConvertSimpleValue(dhtKey k) { +# if (defined(__cplusplus) && (__cplusplus >= 201103L)) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) + unsigned long long a, b, c; + c = 0x9e3779b97f4a7c13LLU; +# else +# if !((((-1LU) >> 31) >> 31) >> 1) +# error "ERROR: unable to build dhtsimpl.c due to lack of a sufficiently-large integer type." +# endif unsigned long a, b, c; - c = 0x9e3779b97f4a7c13LL; - a = v<<1; - b = v; + c = 0x9e3779b97f4a7c13LU; +# endif + a = k.value.unsigned_integer<<1; + b = k.value.unsigned_integer; mix(a,b,c); - return c; + return (unsigned long)c; } #else -static unsigned long ConvertSimpleValue(dhtConstValue v) +static unsigned long ConvertSimpleValue(dhtKey k) { - size_t c = (size_t)v; - size_t a = 0; - size_t b = 0x9e3779b9; + unsigned long c = k.value.unsigned_integer; + unsigned long a = 0; + unsigned long b = 0x9e3779b9U; a -= c; a ^= c >> 13; - b -= c; b -= a; b ^= a << 8; - c -= a; c -= b; c ^= b >> 13; - a -= b; a -= c; a ^= c >> 12; - b -= c; b -= a; b ^= a << 16; - c -= a; c -= b; c ^= b >> 5; - a -= b; a -= c; a ^= c >> 3; - b -= c; b -= a; b ^= a << 10; - c -= a; c -= b; c ^= b >> 15; - return (unsigned long)c; + b -= c; b -= a; b ^= (a << 8); + c -= a; c -= b; c ^= (b >> 13); + a -= b; a -= c; a ^= (c >> 12); + b -= c; b -= a; b ^= (a << 16); + c -= a; c -= b; c ^= (b >> 5); + a -= b; a -= c; a ^= (c >> 3); + b -= c; b -= a; b ^= (a << 10); + c -= a; c -= b; c ^= (b >> 15); + return c; } #endif /*ARCH64*/ -static int EqualSimpleValue(dhtConstValue v1, dhtConstValue v2) +static int EqualSimpleValue(dhtKey k1, dhtKey k2) { - return v1 == v2; + return (k1.value.unsigned_integer == k2.value.unsigned_integer); } -static dhtConstValue DupSimpleValue(dhtConstValue v) +static int DupSimpleValue(dhtValue kv, dhtValue *output) { - return v; + assert(!!output); + *output = kv; + return 0; } -static void FreeSimpleValue(dhtValue v) +static void FreeSimpleValue(dhtValue kv) { + (void)kv; } -static void DumpSimpleValue(dhtConstValue v, FILE *f) +static void DumpSimpleValue(dhtValue kv, FILE *f) { - fprintf(f, "%08lx", (unsigned long)(size_t)v); + assert(!!f); +#if (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) + fprintf(f, "%08jx", kv.unsigned_integer); +#else + fprintf(f, "%08lx", kv.unsigned_integer); +#endif } dhtValueProcedures dhtSimpleProcs = diff --git a/DHT/dhtstrng.c b/DHT/dhtstrng.c index 24d643105..1f79b28c7 100644 --- a/DHT/dhtstrng.c +++ b/DHT/dhtstrng.c @@ -4,64 +4,91 @@ * Institut fuer Informatik, TU Muenchen, Germany * bartel@informatik.tu-muenchen.de * You may use this code as you wish, as long as this - * comment with the above copyright notice is keept intact + * comment with the above copyright notice is kept intact * and in place. */ #include #include #include +#include "debugging/assert.h" #include "dhtvalue.h" #include "dht.h" -static unsigned long ConvertString(dhtConstValue v) +static dhtHashValue ConvertString(dhtKey k) { - /* I found this hash function on - * http://ourworld.compuserve.com/homepages/bob_jenkins/doobs.htm - * There are other functions, but this one is has some advantages: - * - its small - * - independant from word sizes - * - needs no initialisation - */ - unsigned char const *s= (unsigned char const *)v; - unsigned long hash= 0; - while (*s) { - hash+= *s++; - hash+= hash << 10; - hash^= hash >> 6; - } - hash+= hash << 3; - hash^= hash >> 11; - hash+= hash << 15; - return hash; + /* I found this hash function on + * http://ourworld.compuserve.com/homepages/bob_jenkins/doobs.htm + * There are other functions, but this one has some advantages: + * - it's small + * - independent from word sizes + * - needs no initialisation + */ + unsigned char const *s= (unsigned char const *)k.value.object_pointer; + unsigned long hash; + unsigned char tmp; + assert(!!s); + hash= 0; + while ((tmp= *s)) { + hash+= tmp; + hash+= hash << 10; + hash^= hash >> 6; + ++s; + } + hash+= hash << 3; + hash^= hash >> 11; + hash+= hash << 15; + return (dhtHashValue)hash; } -static int EqualString(dhtConstValue v1, dhtConstValue v2) +static int EqualString(dhtKey v1, dhtKey v2) { - if (strcmp((char const *)v1, (char const *)v2)) - return 0; - else - return 1; + char const *s1= (char const *)v1.value.object_pointer; + char const *s2= (char const *)v2.value.object_pointer; + assert(s1 && s2); + return !strcmp(s1, s2); } -static dhtConstValue DupString(dhtConstValue v) +static int DupString(dhtValue v, dhtValue *output) { char *nv; - nv= (char *)fxfAlloc(strlen((char const *)v)+1); - if (nv!=0) - strcpy(nv, (char const *)v); - return (dhtConstValue)nv; + size_t len; + char const *original= (char const *)v.object_pointer; + assert(!!output); + if (!original) { + output->object_pointer= NULL; + return 0; + } + len= strlen(original); + if ((len < ((size_t)-1)) && !original[len]) { + ++len; + nv= (char *)fxfAlloc(len); + if (nv) { + memcpy(nv, original, len); + output->object_pointer= nv; + return 0; + } + } + return 1; } static void FreeString(dhtValue v) { - fxfFree(v, strlen((char const *)v)+1); + char *s= (char *)v.object_pointer; + if (s) + { + size_t const len= strlen(s); + assert((len < ((size_t)-1)) && !s[len]); + fxfFree(s, len+1); + } } -static void DumpString(dhtConstValue v, FILE *f) +static void DumpString(dhtValue v, FILE *f) { - fputs((char const *)v,f); + char const *s= (char const *)v.object_pointer; + assert(s && f); + fputs(s,f); } -dhtValueProcedures dhtStringProcs = { +dhtValueProcedures dhtStringProcs= { ConvertString, EqualString, DupString, diff --git a/DHT/dhtvalue.c b/DHT/dhtvalue.c index ef5761d59..321a08f8f 100644 --- a/DHT/dhtvalue.c +++ b/DHT/dhtvalue.c @@ -4,7 +4,7 @@ * Institut fuer Informatik, TU Muenchen, Germany * bartel@informatik.tu-muenchen.de * You may use this code as you wish, as long as this - * comment with the above copyright notice is keept intact + * comment with the above copyright notice is kept intact * and in place. */ #include "dhtvalue.h" diff --git a/DHT/dhtvalue.h b/DHT/dhtvalue.h index befd63b4d..cc389da97 100644 --- a/DHT/dhtvalue.h +++ b/DHT/dhtvalue.h @@ -7,15 +7,31 @@ * Institut fuer Informatik, TU Muenchen, Germany * bartel@informatik.tu-muenchen.de * You may use this code as you wish, as long as this - * comment with the above copyright notice is keept intact + * comment with the above copyright notice is kept intact * and in place. */ #include +#ifdef __cplusplus +# if __cplusplus >= 201103L +# include +# else +# include +# endif +# include +#elif defined(__STDC_VERSION__) +# if __STDC_VERSION__ >= 199901L +# include +# else +# include +# endif +# include +#endif #if defined(FXF) #include "fxf.h" #else -#define fxfAlloc(x) malloc(x) +#include +#define fxfAlloc(x) malloc(x) /* TODO: Should we track allocations to ensure that we never allocate more than some chosen number (e.g., hashtable_kilos*1024) of total byte(s)? */ #define fxfFree(x,n) free(x) #endif /*FXF*/ @@ -52,19 +68,63 @@ typedef enum { extern char const *dhtValueTypeToString[dhtValueTypeCnt]; -typedef void *dhtValue; -typedef void const *dhtConstValue; +typedef union { +#ifdef __cplusplus +# if __cplusplus >= 201103L + ::std::uintmax_t unsigned_integer; + ::std::intmax_t signed_integer; +# elif defined(LLONG_MAX) + unsigned long long int unsigned_integer; + long long int signed_integer; +# else + unsigned long int unsigned_integer; + long int signed_integer; +# endif + bool boolean; + ::std::sig_atomic_t atomic_integer; +#else +# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) + uintmax_t unsigned_integer; + intmax_t signed_integer; + _Bool boolean; +# else +# if defined(LLONG_MAX) + unsigned long long int unsigned_integer; + long long int signed_integer; +# else + unsigned long int unsigned_integer; + long int signed_integer; +# endif + int boolean; // What else? +# endif + sig_atomic_t atomic_integer; +#endif + const volatile void * object_pointer; + char character; + void (*function_pointer)(void); +#ifdef DHTVALUE_NEEDS_FLOATING_POINT + long double floating_point; +#endif + unsigned char buffer[1]; /* treat as having sizeof(dhtValue) elements */ +} dhtValue; + +typedef struct { + dhtValue value; +} dhtKey; + typedef unsigned long dhtHashValue; typedef struct { - dhtHashValue (*Hash)(dhtConstValue); - int (*Equal)(dhtConstValue, dhtConstValue); - dhtConstValue (*Dup)(dhtConstValue); - void (*Free)(dhtValue); - void (*Dump)(dhtConstValue, FILE *); + dhtHashValue (*Hash)(dhtKey); + int (*Equal)(dhtKey, dhtKey); + int (*Dup)(dhtValue, dhtValue *); // should return 0 on success (and store the copied value at the second argument) and nonzero on error + void (*Free)(dhtValue); + void (*Dump)(dhtValue, FILE *); } dhtValueProcedures; #if defined(REGISTER_SIMPLE) +/* dhtSimple verifies equality by comparing unsigned_integer members; + keys should be stored to unsigned_integer members, cast if needed */ extern dhtValueProcedures dhtSimpleProcs; #endif /*REGISTER_SIMPLE*/ #if defined(REGISTER_STRING) diff --git a/DHT/fxf.c b/DHT/fxf.c index 7c7e285c3..2bd484fd9 100644 --- a/DHT/fxf.c +++ b/DHT/fxf.c @@ -3,7 +3,7 @@ #include "debugging/assert.h" #include #include -#include +#include #if defined(__TURBOC__) # include @@ -18,27 +18,65 @@ #if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || /* >= C99 -- We have printf ptrdiff_t/size_t specifiers. */ \ (defined(__cplusplus) && (__cplusplus >= 201103L)) /* >= C++11 -- We have printf ptrdiff_t/size_t specifiers. */ -# include +# include typedef ptrdiff_t ptrdiff_t_printf_type; typedef size_t size_t_printf_type; +# define MAX_POINTER_DIFFERENCE PTRDIFF_MAX +# if defined(UINTPTR_MAX) + typedef uintptr_t convert_pointer_to_int_type; +# else + typedef uintmax_t convert_pointer_to_int_type; +# endif # define PTRDIFF_T_PRINTF_SPECIFIER "td" # define SIZE_T_PRINTF_SPECIFIER "zu" -#elif defined(LLONG_MAX) /* We have long long integer types. */ +#else +# define MAX_POINTER_DIFFERENCE (((size_t)-1)>>1) /* just a guess */ +# if defined(LLONG_MAX) /* We have long long integer types. */ typedef long long int ptrdiff_t_printf_type; typedef unsigned long long int size_t_printf_type; -# define PTRDIFF_T_PRINTF_SPECIFIER "lld" -# define SIZE_T_PRINTF_SPECIFIER "llu" -#else /* We don't have long long integer types. */ + typedef unsigned long long int convert_pointer_to_int_type; +# define PTRDIFF_T_PRINTF_SPECIFIER "lld" +# define SIZE_T_PRINTF_SPECIFIER "llu" +# else /* We don't have long long integer types. */ typedef long int ptrdiff_t_printf_type; typedef unsigned long int size_t_printf_type; -# define PTRDIFF_T_PRINTF_SPECIFIER "ld" -# define SIZE_T_PRINTF_SPECIFIER "lu" + typedef unsigned long int convert_pointer_to_int_type; +# define PTRDIFF_T_PRINTF_SPECIFIER "ld" +# define SIZE_T_PRINTF_SPECIFIER "lu" +# endif +#endif + +#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) +# define MAX_ALIGNMENT _Alignof(max_align_t) +#elif (defined(__cplusplus) && (__cplusplus >= 201103L)) +# define MAX_ALIGNMENT alignof(max_align_t) +#else +# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# include +# endif +struct GET_MAX_ALIGNMENT_TYPE { + unsigned char c; + union { +# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) + uintmax_t unsigned_integer; +# elif defined(LLONG_MAX) /* We have long long integer types. */ + unsigned long long int unsigned_integer; +# else + unsigned long int unsigned_integer; +# endif + const volatile void * object_pointer; + void (*function_pointer)(void); + long double floating_point; + } max_aligned_union; +}; +# define MAX_ALIGNMENT offsetof(struct GET_MAX_ALIGNMENT_TYPE, max_aligned_union) #endif -#if !defined(Nil) && !defined(New) && !defined(nNew) /* TODO: Is this the correct check for all of the below lines? */ +#if !defined(Nil) && !defined(New) && !defined(nNewUntyped) && !defined(nNewCallocUntyped) /* TODO: Is this the correct check for all of the below lines? */ # define Nil(type) ((type *)0) # define New(type) ((type *)malloc(sizeof(type))) -# define nNew(n, type) ((type *)nNewImpl(n,sizeof(type))) +# define nNewUntyped(n, type) nNewImpl(n,sizeof(type)) +# define nNewCallocUntyped(n, type) calloc(n,sizeof(type)) static inline void * nNewImpl(size_t const nmemb, size_t const size) { return ((size && (nmemb > (((size_t)-1)/size))) ? Nil(void) : malloc(nmemb*size)); } @@ -68,7 +106,7 @@ static inline void * nNewImpl(size_t const nmemb, size_t const size) { /* FiXed and Fast malloc, free * As the name tells: this code implements on top of traditional * malloc/realloc/free a fast version, that relies on a lot of - * allocation/delallocation of fixed sized blocks of memory. For + * allocation/deallocation of fixed sized blocks of memory. For * each size of memory we keep a head pointer and all freed chunks * of memory is threaded on this list. If memory of this size * is requested, we drag it from the list, otherwise we carve it @@ -80,13 +118,15 @@ static inline void * nNewImpl(size_t const nmemb, size_t const size) { typedef struct { unsigned long MallocCount; unsigned long FreeCount; - char * FreeHead; + void * FreeHead; } SizeHead; +#define CLIP_TO_MAX_POINTER_DIFFERENCE(x) (((x) > MAX_POINTER_DIFFERENCE) ? MAX_POINTER_DIFFERENCE : (x)) + #if defined(DOS) /* MSDOS 16 Bit support (maxmemory <= 1 MB) */ #define SEGMENTED -#define ARENA_SEG_SIZE 32000 +#define ARENA_SEG_SIZE (CLIP_TO_MAX_POINTER_DIFFERENCE(32000) & ~(MAX_ALIGNMENT - 1U)) #define ARENA_SEG_COUNT ((1024*1024)/ARENA_SEG_SIZE) #define OSNAME "MSDOS" #define OSMAXMEM "1 MB" @@ -94,40 +134,64 @@ typedef struct { /* Win95/Win98/WinME can only allocate chunks up to 255 MB */ /* maxmemory <= 768 MB */ #define SEGMENTED -#define ARENA_SEG_SIZE 1000000 +#define ARENA_SEG_SIZE (CLIP_TO_MAX_POINTER_DIFFERENCE(1000000) & ~(MAX_ALIGNMENT - 1U)) #define ARENA_SEG_COUNT ((768*1024*1024)/ARENA_SEG_SIZE) #define OSNAME "Win95/Win98/WinME" #define OSMAXMEM "768 MB" #endif /* The maximum size an fxfAlloc can handle */ +/* TODO: Do the macros really accurately determine the maximum we need (apparently 1024 or 2048)? + Can we instead compute the needed value(s) with expressions involving, say, sizeof(void *) + and any other system properties we have access to? +*/ +enum +{ + fxfMINSIZE = sizeof(void *), /* Different size of fxfMINSIZE for 32-/64/Bit compilation */ + fxfMAXSIZE = #if defined(SEGMENTED) || defined(__TURBOC__) -#define fxfMAXSIZE ((size_t)1024) +# if defined(ARENA_SEG_SIZE) + ((((1024 > ARENA_SEG_SIZE) ? ARENA_SEG_SIZE : ((size_t)1024)) +# else + ((((size_t)1024) +# endif #else -#define fxfMAXSIZE ((size_t)2048) /* this is needed only when sizeof(void*)==8 */ + ((((size_t)2048) /* This is needed only when sizeof(void*)==8. */ #endif + + (MAX_ALIGNMENT - 1U)) & ~(MAX_ALIGNMENT - 1U)) /* Round up if necessary. */ +}; -/* Different size of fxfMINSIZE for 32-/64/Bit compilation */ -enum -{ - fxfMINSIZE = sizeof(size_t) +enum { + ENSURE_FXFMINSIZE_GT_0 = 1/(fxfMINSIZE > 0), + ENSURE_FXFMAXSIZE_GE_FXFMINSIZE = 1/(fxfMAXSIZE >= fxfMINSIZE) }; -static SizeHead SizeData[fxfMAXSIZE+1]; +#define BOTTOM_BIT_OF_FXFMINSIZE ((size_t)fxfMINSIZE & -(size_t)fxfMINSIZE) +#define MIN_ALIGNMENT_UNDERESTIMATE ((BOTTOM_BIT_OF_FXFMINSIZE > MAX_ALIGNMENT) ? MAX_ALIGNMENT : BOTTOM_BIT_OF_FXFMINSIZE) /* We'd prefer the top bit, but we'll compute that during fxfInit. + (Of course, they're probably the same.) + TODO: Can we compute what we want at compile time and just use it? */ +static size_t min_alignment= 0; /* for now */ + +static SizeHead SizeData[1 + ((fxfMAXSIZE - fxfMINSIZE)/MIN_ALIGNMENT_UNDERESTIMATE)]; /* Minimum allocation is (fxfMINSIZE + (MIN_ALIGNMENT_UNDERESTIMATE - 1U)) & ~(MIN_ALIGNMENT_UNDERESTIMATE - 1U). + Maximum allocation is fxfMAXSIZE. + All allocations will be multiples of MIN_ALIGNMENT_UNDERESTIMATE. */ +#define SIZEDATA_SIZE_TO_INDEX(s) (((s) - fxfMINSIZE)/MIN_ALIGNMENT_UNDERESTIMATE) +#define SIZEDATA_INDEX_TO_SIZE(x) ((size_t)(((x) * MIN_ALIGNMENT_UNDERESTIMATE) + \ + ((fxfMINSIZE + (MIN_ALIGNMENT_UNDERESTIMATE - 1U)) & ~(MIN_ALIGNMENT_UNDERESTIMATE - 1U)))) #if defined(SEGMENTED) /* #define ARENA_SEG_SIZE 32000 */ /* #define ARENA_SEG_COUNT ((1024*1024)/ARENA_SEG_SIZE) */ -static char *Arena[ARENA_SEG_COUNT] = { Nil(char) }; +static void *Arena[ARENA_SEG_COUNT]= { Nil(void) }; static int ArenaSegCnt= 0; static int CurrentSeg= 0; #else -static char *Arena= Nil(char); +static void *Arena= Nil(void); #endif /*SEGMENTED*/ static size_t GlobalSize; -static char *BotFreePtr; -static char *TopFreePtr; +static void *BotFreePtr; +static void *TopFreePtr; #undef FREEMAP @@ -215,26 +279,38 @@ void PrintFreeMap(FILE *f) { fputc('?', f); } } -#else -static void SetRange(size_t x, size_t l) { (void) x; (void) l; } -static void ClrRange(size_t x, size_t l) { (void) x; (void) l; } #endif /*FREEMAP, !SEGMENTED*/ +static inline ptrdiff_t pointerDifference(void const *ptr1, void const *ptr2) { + assert(ptr1 && ptr2); + return (((char const *)ptr1) - ((char const *)ptr2)); +} + +static inline void * stepPointer(void *ptr, ptrdiff_t step) { + assert(!!ptr); + return (void *)(((char *)ptr) + step); +} + +size_t fxfMaxAllocation(void) { + return fxfMAXSIZE; +} + size_t fxfInit(size_t Size) { #if defined(LOG) static char const * const myname= "fxfInit"; #endif #if defined(SEGMENTED) - size_t maxSegCnt= (Size ? (1 + ((Size - 1) / ARENA_SEG_SIZE)) : 0); + size_t maxSegCnt= (Size / ARENA_SEG_SIZE); if (maxSegCnt > ARENA_SEG_COUNT) maxSegCnt= ARENA_SEG_COUNT; while (ArenaSegCnt > maxSegCnt) { --ArenaSegCnt; free(Arena[ArenaSegCnt]); - Arena[ArenaSegCnt]= Nil(char); + Arena[ArenaSegCnt]= Nil(void); } while (ArenaSegCnt < maxSegCnt) { - if ((Arena[ArenaSegCnt]= nNew(ARENA_SEG_SIZE, char)) == Nil(char)) + Arena[ArenaSegCnt]= nNewUntyped(ARENA_SEG_SIZE, char); + if (!Arena[ArenaSegCnt]) break; ++ArenaSegCnt; } @@ -242,28 +318,35 @@ size_t fxfInit(size_t Size) { BotFreePtr= Arena[CurrentSeg]; TopFreePtr= Arena[CurrentSeg]; if (TopFreePtr) - TopFreePtr+= ARENA_SEG_SIZE; + TopFreePtr= stepPointer(TopFreePtr, ARENA_SEG_SIZE); GlobalSize= ArenaSegCnt*ARENA_SEG_SIZE; #else #if defined(FREEMAP) if (FreeMap) { free(FreeMap); - FreeMap = Nil(FreeMapType); + FreeMap= Nil(FreeMapType); } +#endif +#if defined(LOG) + size_t const orig_Size= Size; #endif if (Arena) free(Arena); - if ((Arena=nNew(Size, char)) == Nil(char)) { - ERROR_LOG2("%s: Sorry, cannot allocate arena of %" SIZE_T_PRINTF_SPECIFIER " bytes\n", - myname, (size_t_printf_type) Size); + if (Size > MAX_POINTER_DIFFERENCE) + Size= MAX_POINTER_DIFFERENCE; + Size&= ~(MAX_ALIGNMENT - 1U); + Arena= nNewUntyped(Size, char); + if (!Arena) { + ERROR_LOG3("%s: Sorry, cannot allocate arena of %" SIZE_T_PRINTF_SPECIFIER " <= %" SIZE_T_PRINTF_SPECIFIER " bytes\n", + myname, (size_t_printf_type)Size, (size_t_printf_type)orig_Size); BotFreePtr= Arena; TopFreePtr= Arena; GlobalSize= 0; return GlobalSize; } BotFreePtr= Arena; - TopFreePtr= Arena+Size; + TopFreePtr= stepPointer(Arena, (ptrdiff_t)Size); GlobalSize= Size; #if defined(FREEMAP) @@ -277,15 +360,23 @@ size_t fxfInit(size_t Size) { Size = ((Size+31)>>5); } - FreeMap= nNew(Size, FreeMapType); /* TODO: Can/Should we replace this allocation+memset with a call to calloc? */ - if (FreeMap) - { - memset(FreeMap, '\0', Size*(sizeof *FreeMap)); - } + FreeMap= (FreeMapType *)nNewCallocUntyped(Size, FreeMapType); #endif /*FREEMAP*/ #endif /*SEGMENTED*/ - memset(SizeData, '\0', sizeof(SizeData)); + for (Size= 0; Size < ((sizeof SizeData)/(sizeof *SizeData)); ++Size) + { + SizeData[Size].MallocCount= 0; + SizeData[Size].FreeCount= 0; + SizeData[Size].FreeHead= Nil(void); + } + + if (!min_alignment) + { + min_alignment= MAX_ALIGNMENT; + while (min_alignment > fxfMINSIZE) + min_alignment>>= 1; + } return GlobalSize; } @@ -297,29 +388,37 @@ void fxfTeardown(void) { --ArenaSegCnt; free(Arena[ArenaSegCnt]); - Arena[ArenaSegCnt] = Nil(char); + Arena[ArenaSegCnt]= Nil(void); } CurrentSeg= 0; #else #if defined(FREEMAP) free(FreeMap); - FreeMap= Nil(unsigned int); + FreeMap= Nil(FreeMapType); #endif /*FREEMAP*/ free(Arena); - Arena= Nil(char); + Arena= Nil(void); #endif /*SEGMENTED*/ - memset(SizeData, '\0', sizeof(SizeData)); + { + size_t i; + for (i= 0; i < ((sizeof SizeData)/(sizeof *SizeData)); ++i) + { + SizeData[i].MallocCount= 0; + SizeData[i].FreeCount= 0; + SizeData[i].FreeHead= Nil(void); + } + } GlobalSize= 0; - TopFreePtr= Nil(char); - BotFreePtr= Nil(char); + TopFreePtr= Nil(void); + BotFreePtr= Nil(void); } int fxfInitialised(void) { #if defined(SEGMENTED) - return Arena[0]!=0; + return !!Arena[0]; #else - return Arena!=0; + return !!Arena; #endif } @@ -330,12 +429,12 @@ void fxfReset(void) BotFreePtr= Arena[CurrentSeg]; TopFreePtr= Arena[CurrentSeg]; if (TopFreePtr) - TopFreePtr+= ARENA_SEG_SIZE; + TopFreePtr= stepPointer(TopFreePtr, ARENA_SEG_SIZE); #else BotFreePtr= Arena; TopFreePtr= Arena; if (TopFreePtr) - TopFreePtr+= GlobalSize; + TopFreePtr= stepPointer(TopFreePtr, (ptrdiff_t)GlobalSize); #if defined(FREEMAP) if (FreeMap) @@ -345,13 +444,21 @@ void fxfReset(void) #if !defined(NDEBUG) { - unsigned int i; - for (i = 1; i<=50; ++i) + size_t i; + for (i = 0; i<((sizeof SizeData)/(sizeof *SizeData)); ++i) assert(SizeData[i].MallocCount==0); } #endif - memset(SizeData, '\0', sizeof SizeData); + { + size_t i; + for (i= 0; i < ((sizeof SizeData)/(sizeof *SizeData)); ++i) + { + SizeData[i].MallocCount= 0; + SizeData[i].FreeCount= 0; + SizeData[i].FreeHead= Nil(void); + } + } } /* we have to define the following, since some architectures cannot @@ -360,12 +467,8 @@ void fxfReset(void) * SPARC, HPPA, MIPS. We wouldn't need this when running on an * Intel *86 type of CPU, but also there, aligned access is faster. */ -#define PTRMASK (sizeof(char *)-1) -#define ALIGNED_MINSIZE (sizeof(char *)+PTRMASK) -#define ALIGN(ptr) (((size_t)ptr+PTRMASK) & (~PTRMASK)) - -#define GetNextPtr(ptr) (*(char **)ALIGN(ptr)) -#define PutNextPtr(dst, ptr) *(char **)ALIGN(dst)= ptr +#define PTRMASK (MAX_ALIGNMENT-1U) +#define ALIGN_TO_MINIMUM(s) (((s) + (min_alignment - 1U)) & ~(min_alignment - 1U)) #define TMDBG(x) if (0) x @@ -374,13 +477,16 @@ void *fxfAlloc(size_t size) { static char const * const myname= "fxfAlloc"; #endif SizeHead *sh; - char *ptr; + void *ptr= Nil(void); TMDBG(printf("fxfAlloc - size:%" SIZE_T_PRINTF_SPECIFIER,(size_t_printf_type)size)); DBG((stderr, "%s(%" SIZE_T_PRINTF_SPECIFIER ") =", myname, (size_t_printf_type)size)); + if (!size) + return Nil(void); + if (sizefxfMAXSIZE) { @@ -388,114 +494,261 @@ void *fxfAlloc(size_t size) { myname, (size_t_printf_type) size, (size_t_printf_type) fxfMAXSIZE); - return Nil(char); + return Nil(void); } - if ( (size&PTRMASK) && sizeFreeHead) { +#if defined(SEGMENTED) + int ptrSegment; + ptrdiff_t ptrIndex; +#endif ptr= sh->FreeHead; - sh->FreeHead= GetNextPtr(ptr); + if (size < sizeof sh->FreeHead) + sh->FreeHead= Nil(void); + else + memcpy(&sh->FreeHead, ptr, sizeof sh->FreeHead); sh->FreeCount--; sh->MallocCount++; - ClrRange((char *)ptr-Arena, size); -#if !defined(SEGMENTED) /* TODO: What should we output in the SEGMENTED case? */ - TMDBG(printf(" FreeCount:%lu ptr-Arena:%" PTRDIFF_T_PRINTF_SPECIFIER " MallocCount:%lu\n",sh->FreeCount,(ptrdiff_t_printf_type)(ptr-Arena),sh->MallocCount)); +#if defined(SEGMENTED) + ptrSegment= CurrentSeg; + if (CurrentSeg) { + convert_pointer_to_int_type tmp= (convert_pointer_to_int_type)ptr; + do { + convert_pointer_to_int_type segment_begin= (convert_pointer_to_int_type)Arena[ptrSegment]; + if ((tmp >= segment_begin) && ((tmp - segment_begin) < ARENA_SEG_SIZE)) { + ptrIndex= (tmp - segment_begin); + goto FOUND_PUTATIVE_SEGMENT; + } + } while (0 <= --ptrSegment); + ptrIndex= -1; + } else + ptrIndex= pointerDifference(ptr, Arena[0]); +FOUND_PUTATIVE_SEGMENT: + TMDBG(printf(" FreeCount:%lu ptr-Arena[%d]:%" PTRDIFF_T_PRINTF_SPECIFIER " MallocCount:%lu\n",sh->FreeCount,ptrSegment,(ptrdiff_t_printf_type)ptrIndex,sh->MallocCount)); +#else +# if defined(FREEMAP) + ClrRange(pointerDifference(ptr, Arena), size); +# endif + TMDBG(printf(" FreeCount:%lu ptr-Arena:%" PTRDIFF_T_PRINTF_SPECIFIER " MallocCount:%lu\n",sh->FreeCount,(ptrdiff_t_printf_type)pointerDifference(ptr, Arena),sh->MallocCount)); #endif } else { /* we have to allocate a new piece */ - size_t const sizeCurrentSeg = (size_t)(TopFreePtr-BotFreePtr); + size_t sizeCurrentSeg; +#if defined(SEGMENTED) +START_LOOKING_FOR_CHUNK: +#endif + sizeCurrentSeg = (size_t)pointerDifference(TopFreePtr,BotFreePtr); TMDBG(printf(" sizeCurrentSeg:%" SIZE_T_PRINTF_SPECIFIER,(size_t_printf_type)sizeCurrentSeg)); if (sizeCurrentSeg>=size) { if (size&PTRMASK) { - /* not aligned */ + /* not fully aligned */ + size_t curBottomIndex; + size_t needed_alignment_mask= PTRMASK; + while (needed_alignment_mask >= size) + needed_alignment_mask>>= 1; +#if defined(SEGMENTED) + curBottomIndex= (size_t)pointerDifference(BotFreePtr,Arena[CurrentSeg]); +#else + curBottomIndex= (size_t)pointerDifference(BotFreePtr,Arena); +#endif + if (curBottomIndex & needed_alignment_mask) { + size_t const numBytesToAdd= (needed_alignment_mask - (curBottomIndex & needed_alignment_mask)) + 1U; + if (numBytesToAdd > (sizeCurrentSeg-size)) + goto NEXT_SEGMENT; + do { + size_t const cur_alignment= (curBottomIndex & -curBottomIndex); +#if defined(FREEMAP) && !defined(SEGMENTED) + SetRange(curBottomIndex,cur_alignment); +#endif + if (cur_alignment >= fxfMINSIZE) { + SizeHead *cur_sh= &SizeData[SIZEDATA_SIZE_TO_INDEX(cur_alignment)]; + if ((cur_alignment >= sizeof cur_sh->FreeHead) || !cur_sh->FreeCount) { + if (cur_alignment >= sizeof cur_sh->FreeHead) + memcpy(BotFreePtr, &cur_sh->FreeHead, sizeof cur_sh->FreeHead); + cur_sh->FreeHead= BotFreePtr; + ++cur_sh->FreeCount; + TMDBG(printf(" FreeCount:%lu",cur_sh->FreeCount)); + } + } + BotFreePtr= stepPointer(BotFreePtr, (ptrdiff_t)cur_alignment); + curBottomIndex+= cur_alignment; + } while (curBottomIndex & needed_alignment_mask); + } ptr= BotFreePtr; - BotFreePtr+= size; + BotFreePtr= stepPointer(BotFreePtr, (ptrdiff_t)size); } else { - /* aligned */ - ptr= TopFreePtr-= size; + /* fully aligned */ + ptr= (TopFreePtr= stepPointer(TopFreePtr, -(ptrdiff_t)size)); } sh->MallocCount++; -#if !defined(SEGMENTED) /* TODO: What should we output in the SEGMENTED case? */ - TMDBG(printf(" current seg ptr-Arena:%" PTRDIFF_T_PRINTF_SPECIFIER " MallocCount:%lu\n",(ptrdiff_t_printf_type)(ptr-Arena),sh->MallocCount)); +#if defined(SEGMENTED) + TMDBG(printf(" current seg ptr-Arena[%d]:%" PTRDIFF_T_PRINTF_SPECIFIER " MallocCount:%lu\n",CurrentSeg,(ptrdiff_t_printf_type)pointerDifference(ptr, Arena[CurrentSeg]),sh->MallocCount)); +#else + TMDBG(printf(" current seg ptr-Arena:%" PTRDIFF_T_PRINTF_SPECIFIER " MallocCount:%lu\n",(ptrdiff_t_printf_type)pointerDifference(ptr,Arena),sh->MallocCount)); #endif } else { +NEXT_SEGMENT: #if defined(SEGMENTED) - if ((CurrentSeg+1) < ArenaSegCnt) { + if (CurrentSeg < (ArenaSegCnt-1)) { + size_t curBottomIndex= (BotFreePtr - Arena[CurrentSeg]); + while (curBottomIndex & PTRMASK) { + size_t const cur_alignment= (curBottomIndex & -curBottomIndex); + if (cur_alignment >= fxfMINSIZE) { + SizeHead *cur_sh= &SizeData[SIZEDATA_SIZE_TO_INDEX(cur_alignment)]; + if ((cur_alignment >= sizeof cur_sh->FreeHead) || !cur_sh->FreeCount) { + if (cur_alignment >= sizeof cur_sh->FreeHead) + memcpy(BotFreePtr, &cur_sh->FreeHead, sizeof cur_sh->FreeHead); + cur_sh->FreeHead= BotFreePtr; + ++cur_sh->FreeCount; + TMDBG(printf(" FreeCount:%lu",cur_sh->FreeCount)); + } + } + BotFreePtr= stepPointer(BotFreePtr, cur_alignment); + curBottomIndex+= cur_alignment; + } + curBottomIndex= (size_t)(TopFreePtr-BotFreePtr); + if (curBottomIndex >= fxfMINSIZE) { + SizeHead *cur_sh= &SizeData[SIZEDATA_SIZE_TO_INDEX(curBottomIndex)]; + if ((curBottomIndex >= sizeof cur_sh->FreeHead) || !cur_sh->FreeCount) { + if (curBottomIndex >= sizeof cur_sh->FreeHead) + memcpy(BotFreePtr, &cur_sh->FreeHead, sizeof cur_sh->FreeHead); + cur_sh->FreeHead= BotFreePtr; + ++cur_sh->FreeCount; + TMDBG(printf(" FreeCount:%lu",cur_sh->FreeCount)); + } + } TMDBG(fputs(" next seg", stdout)); ++CurrentSeg; BotFreePtr= Arena[CurrentSeg]; - TopFreePtr= Arena[CurrentSeg]+ARENA_SEG_SIZE; - ptr= fxfAlloc(size); + TopFreePtr= stepPointer(Arena[CurrentSeg], ARENA_SEG_SIZE); + goto START_LOOKING_FOR_CHUNK; } else - ptr= Nil(char); + ptr= Nil(void); #else /*SEGMENTED*/ - ptr= Nil(char); + ptr= Nil(void); #endif /*!SEGMENTED*/ - TMDBG(printf(" ptr:%p\n",(void *)ptr)); + TMDBG(printf(" ptr:%p\n", ptr)); } } - DBG((df, "%p\n", (void *) ptr)); + DBG((df, "%p\n", ptr)); return ptr; } void fxfFree(void *ptr, size_t size) { +#if defined(LOG) || defined(DEBUG) static char const * const myname= "fxfFree"; +#endif SizeHead *sh; -#if !defined(SEGMENTED) /* TODO: What should we output in the SEGMENTED case? */ - TMDBG(printf("fxfFree - ptr-Arena:%" PTRDIFF_T_PRINTF_SPECIFIER " size:%" SIZE_T_PRINTF_SPECIFIER,(ptrdiff_t_printf_type)(((char const*)ptr)-Arena),(size_t_printf_type)size)); + ptrdiff_t ptrIndex; +#if defined(SEGMENTED) + int ptrSegment; #endif - DBG((df, "%s(%p, %" SIZE_T_PRINTF_SPECIFIER ")\n", myname, (void *) ptr, (size_t_printf_type) size)); - if (size > fxfMAXSIZE) { - fprintf(stderr, "%s: size=%" SIZE_T_PRINTF_SPECIFIER " >= %" SIZE_T_PRINTF_SPECIFIER "\n", - myname, (size_t_printf_type) size, (size_t_printf_type) fxfMAXSIZE); - exit(-5); + if (!ptr) + return; + assert(!!size); +#if defined(SEGMENTED) + ptrSegment= CurrentSeg; + if (CurrentSeg) { + convert_pointer_to_int_type tmp= (convert_pointer_to_int_type)ptr; + do { + convert_pointer_to_int_type segment_begin= (convert_pointer_to_int_type)Arena[ptrSegment]; + if (tmp >= segment_begin) { + ptrIndex= (tmp - segment_begin); + if (ptrIndex < ARENA_SEG_SIZE) + goto FOUND_PUTATIVE_SEGMENT; + } + } while (0 <= --ptrSegment); + ptrIndex= -1; + } else { + ptrIndex= pointerDifference(ptr,Arena[0]); + assert((ptrIndex >= 0) && (ptrIndex < ARENA_SEG_SIZE)); } +FOUND_PUTATIVE_SEGMENT: + TMDBG(printf("fxfFree - ptr-Arena[%d]:%" PTRDIFF_T_PRINTF_SPECIFIER " size:%" SIZE_T_PRINTF_SPECIFIER,ptrSegment,(ptrdiff_t_printf_type)ptrIndex,(size_t_printf_type)size)); +#else + ptrIndex= pointerDifference(ptr,Arena); + assert((ptrIndex >= 0) && (ptrIndex < GlobalSize)); + TMDBG(printf("fxfFree - ptr-Arena:%" PTRDIFF_T_PRINTF_SPECIFIER " size:%" SIZE_T_PRINTF_SPECIFIER,(ptrdiff_t_printf_type)ptrIndex,(size_t_printf_type)size)); +#endif + DBG((df, "%s(%p, %" SIZE_T_PRINTF_SPECIFIER ")\n", myname, (void *)ptr, (size_t_printf_type) size)); if (size < fxfMINSIZE) size= fxfMINSIZE; - if ((size&PTRMASK) && size= TopFreePtr)); +# else + { + assert(size <= (GlobalSize - ptrIndex)); + assert(((ptrIndex + size) <= pointerDifference(BotFreePtr,Arena)) || (ptr >= TopFreePtr)); +#endif + if (ptrIndex > 0) + { + size_t needed_alignment= MAX_ALIGNMENT; + while (needed_alignment > size) + needed_alignment>>= 1; + assert(!(((size_t)ptrIndex) & (needed_alignment - 1U))); + } + } +#endif + sh= &SizeData[SIZEDATA_SIZE_TO_INDEX(size)]; if (size&PTRMASK) { - /* unaligned size */ - TMDBG(printf(" BotFreePtr-ptr:%" PTRDIFF_T_PRINTF_SPECIFIER,(ptrdiff_t_printf_type)(BotFreePtr-(char const*)ptr))); - if ((char *)ptr+size == BotFreePtr) { - BotFreePtr-= size; - TMDBG(printf(" BotFreePtr sizeCurrentSeg:%" PTRDIFF_T_PRINTF_SPECIFIER,(ptrdiff_t_printf_type)(TopFreePtr-BotFreePtr))); + /* not fully aligned size */ + TMDBG(printf(" BotFreePtr-ptr:%" PTRDIFF_T_PRINTF_SPECIFIER,(ptrdiff_t_printf_type)pointerDifference(BotFreePtr,ptr))); + if (stepPointer(ptr, (ptrdiff_t)size) == BotFreePtr) { + BotFreePtr= ptr; + TMDBG(printf(" BotFreePtr sizeCurrentSeg:%" PTRDIFF_T_PRINTF_SPECIFIER,(ptrdiff_t_printf_type)pointerDifference(TopFreePtr,BotFreePtr))); --sh->MallocCount; } else { - SetRange((char *)ptr-Arena,size); - *(char **)ALIGN(ptr)= sh->FreeHead; - sh->FreeHead= ptr; - ++sh->FreeCount; - --sh->MallocCount; - TMDBG(printf(" FreeCount:%lu",sh->FreeCount)); +#if defined(FREEMAP) && !defined(SEGMENTED) + SetRange((pointerDifference(ptr,Arena),size); +#endif + if ((size >= sizeof sh->FreeHead) || !sh->FreeHead) { + if (size >= sizeof sh->FreeHead) + memcpy(ptr, &sh->FreeHead, sizeof sh->FreeHead); + sh->FreeHead= ptr; + ++sh->FreeCount; + --sh->MallocCount; + TMDBG(printf(" FreeCount:%lu",sh->FreeCount)); + } } } else { - /* aligned size */ - TMDBG(printf(" ptr-TopFreePtr:%" PTRDIFF_T_PRINTF_SPECIFIER,(ptrdiff_t_printf_type)(((char const*)ptr)-TopFreePtr))); - if ((char *)ptr == TopFreePtr) { - TopFreePtr+= size; - TMDBG(printf(" TopFreePtr sizeCurrentSeg:%" PTRDIFF_T_PRINTF_SPECIFIER,(ptrdiff_t_printf_type)(TopFreePtr-BotFreePtr))); + /* fully aligned size */ + TMDBG(printf(" ptr-TopFreePtr:%" PTRDIFF_T_PRINTF_SPECIFIER,(ptrdiff_t_printf_type)pointerDifference(ptr,TopFreePtr))); + if (ptr == TopFreePtr) { + TopFreePtr= stepPointer(TopFreePtr, (ptrdiff_t)size); + TMDBG(printf(" TopFreePtr sizeCurrentSeg:%" PTRDIFF_T_PRINTF_SPECIFIER,(ptrdiff_t_printf_type)pointerDifference(TopFreePtr,BotFreePtr))); --sh->MallocCount; } else { - SetRange((char *)ptr-Arena,size); - *(char **)ptr= sh->FreeHead; - sh->FreeHead= ptr; - ++sh->FreeCount; - --sh->MallocCount; - TMDBG(printf(" FreeCount:%lu",sh->FreeCount)); +#if defined(FREEMAP) && !defined(SEGMENTED) + SetRange(pointerDifference(ptr,Arena),size); +#endif + if ((size >= sizeof sh->FreeHead) || !sh->FreeCount) { + if (size >= sizeof sh->FreeHead) + memcpy(ptr, &sh->FreeHead, sizeof sh->FreeHead); + sh->FreeHead= ptr; + ++sh->FreeCount; + --sh->MallocCount; + TMDBG(printf(" FreeCount:%lu",sh->FreeCount)); + } } } TMDBG(printf(" MallocCount:%lu",sh->MallocCount)); @@ -505,11 +758,58 @@ void fxfFree(void *ptr, size_t size) void *fxfReAlloc(void *ptr, size_t OldSize, size_t NewSize) { void *nptr; if (!ptr) + { + assert(!OldSize); return fxfAlloc(NewSize); + } +#if !defined(NDEBUG) +# if defined(SEGMENTED) + if (!CurrentSeg) /* Otherwise we'd be relying on converting to convert_pointer_to_int_type, + and such calculations aren't guaranteed to provide exactly what we need. */ + { + ptrdiff_t const ptrIndex= pointerDifference(ptr,Arena[0]); + assert(ptrIndex < ARENA_SEG_SIZE); +# else + { + ptrdiff_t const ptrIndex= pointerDifference(ptr,Arena); + assert(ptrIndex < GlobalSize); +# endif + assert(ptrIndex >= 0); + if (ptrIndex > 0) + { + size_t allocatedSize= OldSize; + size_t needed_alignment; + if (allocatedSize < fxfMINSIZE) + allocatedSize= fxfMINSIZE; + assert(allocatedSize <= fxfMAXSIZE); + allocatedSize= ALIGN_TO_MINIMUM(allocatedSize); +# if defined(SEGMENTED) + assert(allocatedSize <= (ARENA_SEG_SIZE - ptrIndex)); +# else + assert(allocatedSize <= (GlobalSize - ptrIndex)); +# endif + needed_alignment= MAX_ALIGNMENT; + while (needed_alignment > allocatedSize) + needed_alignment>>= 1; + assert(!(((size_t)ptrIndex) & (needed_alignment - 1U))); + } + } +#endif if (!NewSize) + { fxfFree(ptr, OldSize); + return Nil(void); + } + /* TODO: It may be worth trying to return ptr if ALIGN_TO_MINIMUM(OldSize) >= NewSize. + To go along with this, we'd have to carefully add any excess to the free store. + In the !defined(SEGMENTED) case this is likely easy, but in the defined(SEGMENTED) + case it may be difficult. Regardless, the computations to set this up -- or even + determine if it's possible -- are kind of annoying, and they'd only be worthwhile + if we hit this possibility frequently (and if the alternative below is expensive + or proves impossible). This all would need to be investigated. + */ nptr= fxfAlloc(NewSize); - if (NewSize && nptr) + if (nptr) { memcpy(nptr, ptr, ((NewSize < OldSize) ? NewSize : OldSize)); fxfFree(ptr, OldSize); @@ -522,11 +822,11 @@ size_t fxfTotal(void) { size_t UsedBytes = 0; size_t FreeBytes = 0; - unsigned int i; - for (i=0; i<=fxfMAXSIZE; i++,hd++) { + size_t i; + for (i=0; i<((sizeof SizeData)/(sizeof *SizeData)); i++,hd++) { if (hd->MallocCount+hd->FreeCount>0) { - UsedBytes+= hd->MallocCount*i; - FreeBytes+= hd->FreeCount*i; + UsedBytes+= hd->MallocCount*SIZEDATA_INDEX_TO_SIZE(i); + FreeBytes+= hd->FreeCount*SIZEDATA_INDEX_TO_SIZE(i); } } @@ -535,7 +835,7 @@ size_t fxfTotal(void) { void fxfInfo(FILE *f) { size_t const one_kilo = 1<<10; - size_t const sizeCurrentSeg = (size_t)(TopFreePtr-BotFreePtr); + size_t const sizeCurrentSeg = (size_t)pointerDifference(TopFreePtr,BotFreePtr); size_t const sizeArenaUsed = GlobalSize-sizeCurrentSeg #if defined(SEGMENTED) @@ -557,15 +857,15 @@ void fxfInfo(FILE *f) { size_t UsedBytes = 0; size_t FreeBytes = 0; - unsigned int i; + size_t i; fprintf(f, "%12s %10s%10s\n", "Size", "MallocCnt", "FreeCnt"); - for (i=0; i<=fxfMAXSIZE; i++,hd++) { + for (i=0; i<((sizeof SizeData)/(sizeof *SizeData)); i++,hd++) { if (hd->MallocCount+hd->FreeCount>0) { - fprintf(f, "%12u %10lu%10lu\n", i, hd->MallocCount, hd->FreeCount); + fprintf(f, "%12zu %10lu%10lu\n", SIZEDATA_INDEX_TO_SIZE(i), hd->MallocCount, hd->FreeCount); nrUsed+= hd->MallocCount; - UsedBytes+= hd->MallocCount*i; + UsedBytes+= hd->MallocCount*(i+1U); nrFree+= hd->FreeCount; - FreeBytes+= hd->FreeCount*i; + FreeBytes+= hd->FreeCount*(i+1U); } } fprintf(f, "%12s %10lu%10lu\n", "Total:", nrUsed, nrFree); @@ -577,4 +877,8 @@ void fxfInfo(FILE *f) { } } +#else /*FXF*/ + +extern unsigned char FXF_C_NONEMPTY_TRANSLATION_UNIT; + #endif /*FXF*/ diff --git a/DHT/fxf.h b/DHT/fxf.h index 401dfc5df..d56cbcfb3 100644 --- a/DHT/fxf.h +++ b/DHT/fxf.h @@ -2,14 +2,16 @@ #define FXF_H #include +#include -size_t fxfInit(size_t GlobalSize); /* returns the number of bytes actually allocated */ +size_t fxfInit(size_t Size); /* returns the number of bytes actually allocated */ int fxfInitialised(void); void *fxfAlloc(size_t size); void *fxfReAlloc(void *ptr, size_t OldSize, size_t NewSize); void fxfFree(void *ptr, size_t size); void fxfInfo(FILE *); size_t fxfTotal(void); +size_t fxfMaxAllocation(void); /* Reset the internal data structures to the state that was reached * after the latest call to fxfInit() */ diff --git a/debugging/trace.c b/debugging/trace.c index e24e42e4c..f6c9c9607 100644 --- a/debugging/trace.c +++ b/debugging/trace.c @@ -473,7 +473,7 @@ void TraceCurrentHashBuffer(void) HashBuffer const *hb = &hashBuffers[nbply]; unsigned int i; - printf(" #%lu nbply:%u Leng:%u ",level,nbply,hb->cmv.Leng); + printf(" #%lu nbply:%u Leng:%hu ",level,nbply,hb->cmv.Leng); for (i = 0; icmv.Leng; ++i) printf("%02x ",(unsigned int)hb->cmv.Data[i]); putchar('\n'); @@ -521,7 +521,7 @@ static void trace_link(char const *prefix, slice_index si, char const *suffix) static char const context_shortcuts[] = { 'I', 'A', 'D', 'H', 'M', 'T', 'N' }; static char const level_shortcuts[] = { 'T', 'S', 'N' }; -static void trace_common(slice_index si, stip_structure_traversal *st) +static void trace_common(slice_index si, stip_structure_traversal const *st) { if (do_trace) { diff --git a/optimisations/hash.c b/optimisations/hash.c index bc2f1f519..5ee65beaf 100644 --- a/optimisations/hash.c +++ b/optimisations/hash.c @@ -42,7 +42,7 @@ ** for more details. Two procedures are used: ** dhtLookupElement: This procedure delivers ** a nil pointer, when the given position is not in the hashtable, - ** or a pointer to a hashelement. + ** or a pointer to a hashElement. ** dhtEnterElement: This procedure enters an encoded position ** with its values into the hashtable. ** @@ -56,7 +56,7 @@ ** in 5 moves", since the former can be recomputed faster. For the other ** type of information ("solvable") the comparison is the other way round. ** The compression of the table is an expensive operation, in a lot - ** of exeperiments it has shown to be quite effective in keeping the + ** of experiments it has shown to be quite effective in keeping the ** most valuable information, and speeds up the computation time ** considerably. But to be of any use, there must be enough memory to ** to store more than 800 positions. @@ -64,7 +64,7 @@ ** There seems to be no real penalty in using hashing, even if the ** hit ratio is very small and only about 5%, it speeds up the ** computation time by 30%. - ** I changed the output of hashstat, since its really informative + ** I changed the output of hashstat, since it's really informative ** to see the hit rate. ** ** inithash() @@ -120,6 +120,10 @@ #include "platform/timer.h" #endif +enum { + ENSURE_MAX_LENGTH_FITS_IN_UNSIGNED_SHORT = 1/(MAX_LENGTH_OF_ENCODING <= USHRT_MAX) +}; + unsigned long hash_max_number_storable_positions = ULONG_MAX; typedef unsigned int hash_value_type; @@ -148,6 +152,11 @@ static hash_value_type minimalElementValueAfterCompression; static unsigned int nr_hash_slices; static slice_index hash_slices[max_nr_slices]; +enum +{ + NUM_ELEMENTS_IN_HASHBUFFER = ((sizeof(HashBuffer) - offsetof(BCMemValue, Data))/sizeof(byte)), + ENSURE_HASHBUFFER_DATA_HAS_AT_LEAST_NR_ROWS_ON_BOARD_ENTRIES = 1/(NUM_ELEMENTS_IN_HASHBUFFER >= nr_rows_on_board) +}; HashBuffer hashBuffers[maxply+1]; @@ -246,26 +255,6 @@ static void (*encode)(stip_length_type min_length, typedef unsigned int data_type; -/* hash table element type defining the data member as we use it in - * this module - */ -typedef struct -{ - dhtValue Key; - data_type data; -} element_t; - -/* Grand union of "element" type and the generic one used by the hash - * table implementation. - * Using this union type rather than casting frm dhtElement * to - * element_t * avoids aliasing issues. - */ -typedef union -{ - dhtElement d; - element_t e; -} hashElement_union_t; - /* Hashing properties of stipulation slices */ typedef struct @@ -372,7 +361,7 @@ static void slice_property_offset_shifter(slice_index si, * @param delta indicates how much to shift the value offsets */ static void shift_offsets(slice_index si, - stip_structure_traversal *st, + stip_structure_traversal const *st, unsigned int delta) { unsigned int i; @@ -651,17 +640,17 @@ static void init_slice_properties(slice_index si) /* Pseudo hash table element - template for fast initialization of * newly created actual table elements */ -static hashElement_union_t template_element; +static dhtElement template_element; -static void set_value_attack_nosuccess(hashElement_union_t *hue, +static void set_value_attack_nosuccess(dhtElement *e, slice_index si, hash_value_type val) { unsigned int const offset = slice_properties[si].u.d.offsetNoSucc; unsigned int const bits = ((offset < (CHAR_BIT * (sizeof val))) ? (val << offset) : 0); unsigned int const mask = slice_properties[si].u.d.maskNoSucc; - element_t * const e = &hue->e; + data_type tmp; TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceFunctionParam("%u",val); @@ -669,27 +658,29 @@ static void set_value_attack_nosuccess(hashElement_union_t *hue, TraceValue("%u",slice_properties[si].size); TraceValue("%u",offset); TraceValue("%08x ",mask); - TraceValue("%p",(void *)&e->data); - TraceValue("pre:%08x ",e->data); + TraceValue("%p",(void *)&e->Data.unsigned_integer); + TraceValue("pre:%08x ",(unsigned int)(data_type)e->Data.unsigned_integer); TraceValue("%08x",bits); TraceEOL(); assert((bits&mask)==bits); - e->data &= ~mask; - e->data |= bits; - TraceValue("post:%08x",e->data); + tmp = (data_type)e->Data.unsigned_integer; + tmp &= ~mask; + tmp |= bits; + e->Data.unsigned_integer = tmp; + TraceValue("post:%08x",(unsigned int)(data_type)e->Data.unsigned_integer); TraceEOL(); TraceFunctionExit(__func__); TraceFunctionResultEnd(); } -static void set_value_attack_success(hashElement_union_t *hue, +static void set_value_attack_success(dhtElement *e, slice_index si, hash_value_type val) { unsigned int const offset = slice_properties[si].u.d.offsetSucc; unsigned int const bits = ((offset < (CHAR_BIT * (sizeof val))) ? (val << offset) : 0); unsigned int const mask = slice_properties[si].u.d.maskSucc; - element_t * const e = &hue->e; + data_type tmp; TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); @@ -699,28 +690,30 @@ static void set_value_attack_success(hashElement_union_t *hue, TraceValue("%u",slice_properties[si].size); TraceValue("%u",offset); TraceValue("%08x ",mask); - TraceValue("%p",(void *)&e->data); - TraceValue("pre:%08x ",e->data); + TraceValue("%p",(void *)&e->Data.unsigned_integer); + TraceValue("pre:%08x ",(unsigned int)(data_type)e->Data.unsigned_integer); TraceValue("%08x",bits); TraceEOL(); assert((bits&mask)==bits); - e->data &= ~mask; - e->data |= bits; - TraceValue("post:%08x",e->data); + tmp = (data_type)e->Data.unsigned_integer; + tmp &= ~mask; + tmp |= bits; + e->Data.unsigned_integer = tmp; + TraceValue("post:%08x",(unsigned int)(data_type)e->Data.unsigned_integer); TraceEOL(); TraceFunctionExit(__func__); TraceFunctionResultEnd(); } -static void set_value_help(hashElement_union_t *hue, +static void set_value_help(dhtElement *e, slice_index si, hash_value_type val) { unsigned int const offset = slice_properties[si].u.h.offsetNoSucc; unsigned int const bits = val << offset; unsigned int const mask = slice_properties[si].u.h.maskNoSucc; - element_t * const e = &hue->e; + data_type tmp; TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceFunctionParam("%u",val); @@ -728,31 +721,32 @@ static void set_value_help(hashElement_union_t *hue, TraceValue("%u",slice_properties[si].size); TraceValue("%u",offset); TraceValue("0x%08x ",mask); - TraceValue("%p ",(void *)&e->data); - TraceValue("pre:0x%08x ",e->data); + TraceValue("%p ",(void *)&e->Data.unsigned_integer); + TraceValue("pre:0x%08x ",(unsigned int)(data_type)e->Data.unsigned_integer); TraceValue("0x%08x",bits); TraceEOL(); assert((bits&mask)==bits); - e->data &= ~mask; - e->data |= bits; - TraceValue("post:0x%08x",e->data); + tmp = (data_type)e->Data.unsigned_integer; + tmp &= ~mask; + tmp |= bits; + e->Data.unsigned_integer = tmp; + TraceValue("post:0x%08x",(unsigned int)(data_type)e->Data.unsigned_integer); TraceEOL(); TraceFunctionExit(__func__); TraceFunctionResultEnd(); } -static hash_value_type get_value_attack_success(hashElement_union_t const *hue, +static hash_value_type get_value_attack_success(dhtElement const *e, slice_index si) { unsigned int const offset = slice_properties[si].u.d.offsetSucc; unsigned int const mask = slice_properties[si].u.d.maskSucc; - element_t const * const e = &hue->e; - data_type const result = (e->data & mask) >> offset; + data_type const result = (((data_type)e->Data.unsigned_integer) & mask) >> offset; TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceValue("%08x ",mask); - TraceValue("%p",(void *)&e->data); - TraceValue("%08x",e->data); + TraceValue("%p",(void const *)&e->Data.unsigned_integer); + TraceValue("%08x",(unsigned int)(data_type)e->Data.unsigned_integer); TraceEOL(); TraceFunctionExit(__func__); @@ -761,18 +755,17 @@ static hash_value_type get_value_attack_success(hashElement_union_t const *hue, return result; } -static hash_value_type get_value_attack_nosuccess(hashElement_union_t const *hue, +static hash_value_type get_value_attack_nosuccess(dhtElement const *e, slice_index si) { unsigned int const offset = slice_properties[si].u.d.offsetNoSucc; unsigned int const mask = slice_properties[si].u.d.maskNoSucc; - element_t const * const e = &hue->e; - data_type const result = (e->data & mask) >> offset; + data_type const result = (((data_type)e->Data.unsigned_integer) & mask) >> offset; TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceValue("%08x ",mask); - TraceValue("%p",(void *)&e->data); - TraceValue("%08x",e->data); + TraceValue("%p",(void const *)&e->Data.unsigned_integer); + TraceValue("%08x",(unsigned int)(data_type)e->Data.unsigned_integer); TraceEOL(); TraceFunctionExit(__func__); @@ -781,19 +774,18 @@ static hash_value_type get_value_attack_nosuccess(hashElement_union_t const *hue return result; } -static hash_value_type get_value_help(hashElement_union_t const *hue, +static hash_value_type get_value_help(dhtElement const *e, slice_index si) { unsigned int const offset = slice_properties[si].u.h.offsetNoSucc; unsigned int const mask = slice_properties[si].u.h.maskNoSucc; - element_t const * const e = &hue->e; - data_type const result = (e->data & mask) >> offset; + data_type const result = (((data_type)e->Data.unsigned_integer) & mask) >> offset; TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceValue("%u",offset); TraceValue("0x%08x ",mask); - TraceValue("%p ",(void *)&e->data); - TraceValue("0x%08x",e->data); + TraceValue("%p ",(void const *)&e->Data.unsigned_integer); + TraceValue("0x%08x",(unsigned int)(data_type)e->Data.unsigned_integer); TraceEOL(); TraceFunctionExit(__func__); @@ -808,7 +800,7 @@ static hash_value_type get_value_help(hashElement_union_t const *hue, * @param si slice index of slice * @return value of contribution of slice si to *he's value */ -static hash_value_type own_value_of_data_solve(hashElement_union_t const *hue, +static hash_value_type own_value_of_data_solve(dhtElement const *hue, slice_index si) { stip_length_type const length = SLICE_U(si).branch.length; @@ -818,7 +810,7 @@ static hash_value_type own_value_of_data_solve(hashElement_union_t const *hue, hash_value_type success_neg; TraceFunctionEntry(__func__); - TraceFunctionParam("%p",hue); + TraceFunctionParam("%p",(void const *)hue); TraceFunctionParam("%u",si); TraceFunctionParamListEnd(); @@ -842,14 +834,14 @@ static hash_value_type own_value_of_data_solve(hashElement_union_t const *hue, * @param si slice index of help slice * @return value of contribution of slice si to *he's value */ -static hash_value_type own_value_of_data_help(hashElement_union_t const *hue, +static hash_value_type own_value_of_data_help(dhtElement const *hue, slice_index si) { unsigned int const parity = slice_properties[si].u.h.parity; hash_value_type result; TraceFunctionEntry(__func__); - TraceFunctionParam("%p",hue); + TraceFunctionParam("%p",(void const *)hue); TraceFunctionParam("%u",si); TraceFunctionParamListEnd(); @@ -869,14 +861,14 @@ static hash_value_type own_value_of_data_help(hashElement_union_t const *hue, * @param si slice index * @return value of contribuation of the slice to *he's value */ -static hash_value_type value_of_data_from_slice(hashElement_union_t const *hue, +static hash_value_type value_of_data_from_slice(dhtElement const *hue, slice_index si) { hash_value_type result; unsigned int const offset = slice_properties[si].valueOffset; TraceFunctionEntry(__func__); - TraceFunctionParam("%p",hue); + TraceFunctionParam("%p",(void const *)hue); TraceFunctionParam("%u",si); TraceFunctionParamListEnd(); @@ -912,13 +904,13 @@ static hash_value_type value_of_data_from_slice(hashElement_union_t const *hue, * @param he address of hash table element to determine value of * @return value of *he */ -static hash_value_type value_of_data(hashElement_union_t const *hue) +static hash_value_type value_of_data(dhtElement const *hue) { hash_value_type result = 0; unsigned int i; TraceFunctionEntry(__func__); - TraceFunctionParam("%p",hue); + TraceFunctionParam("%p",(void const *)hue); TraceFunctionParamListEnd(); for (i = 0; iKey); #if defined(TESTHASH) if (nrElementsRemovedInCompression + dhtKeyCount(pyhash) != nrElementsAtStartOfCompression) @@ -1206,6 +1194,145 @@ static void ProofLargeEncodePiece(byte **bp, ++*bp; } +static byte *SmallEncodePiece(byte *bp, + int row, int col, + piece_walk_type pienam, Flags pspec) +{ + *bp++= (byte)((row<<(CHAR_BIT/2))+col); + if (one_byte_hash) + *bp++ = (byte)pspec + (piece_nbr[pienam] << (CHAR_BIT/2)); + else + { + unsigned int i; + *bp++ = pienam; + for (i = 0; i>(CHAR_BIT*i)) & ByteMask); + } + + return bp; +} + +static byte *CommonEncode(byte *bp, + stip_length_type min_length, + stip_length_type validity_value) +{ + if (CondFlag[messigny]) + { + move_effect_journal_index_type const base = move_effect_journal_base[nbply]; + move_effect_journal_index_type const movement = base+move_effect_journal_index_offset_movement; + if (move_effect_journal[movement].type==move_effect_piece_exchange + && move_effect_journal[movement].reason==move_effect_reason_messigny_exchange) + { + *bp++ = (byte)(move_effect_journal[movement].u.piece_exchange.to - square_a1); + *bp++ = (byte)(move_effect_journal[movement].u.piece_exchange.from - square_a1); + } + else + *bp++ = (byte)UCHAR_MAX; + } + + if (CondFlag[duellist]) + { + *bp++ = (byte)(duellists[White] - square_a1); + *bp++ = (byte)(duellists[Black] - square_a1); + } + + if (CondFlag[blfollow] || CondFlag[whfollow] || CondFlag[champursue]) + { + square const sq_departure = move_effect_journal_get_departure_square(nbply); + if (sq_departure==initsquare) + *bp++ = (byte)UCHAR_MAX; + else + *bp++ = (byte)(sq_departure-square_a1); + } + + if (CondFlag[blacksynchron] || CondFlag[whitesynchron] + || CondFlag[blackantisynchron] || CondFlag[whiteantisynchron]) + { + square const sq_departure = move_effect_journal_get_departure_square(nbply); + if (sq_departure==initsquare) + *bp++ = (byte)UCHAR_MAX; + else + { + move_effect_journal_index_type const base = move_effect_journal_base[nbply]; + move_effect_journal_index_type const movement = base+move_effect_journal_index_offset_movement; + square const sq_arrival = move_effect_journal[movement].u.piece_movement.to; + enum { nr_squares = nr_rows_on_board*nr_files_on_board }; + *bp++= (byte)(sq_num(sq_departure)-sq_num(sq_arrival)+nr_squares); + } + } + + if (CondFlag[imitators]) + { + unsigned int imi_idx; + + /* The number of imitators has to be coded too to avoid + * ambiguities. + */ + *bp++ = (byte)being_solved.number_of_imitators; + for (imi_idx = 0; imi_idx>CHAR_BIT); + *bp++ = (byte)(removedspec&ByteMask); + } + } + else + *bp++ = (byte)0; + } + + assert(validity_value<=(1<slack_length+1) + *bp++ = (byte)(validity_value); + + { + unsigned int i; + + assert((en_passant_top[nbply]-en_passant_top[nbply-1])<=MAX_EN_PASSANT_TOP_DIFFERENCE); + for (i = en_passant_top[nbply-1]+1; i<=en_passant_top[nbply]; ++i) + *bp++ = (byte)(en_passant_multistep_over[i] - square_a1); + } + + *bp++ = being_solved.castling_rights; /* Castling_Flag */ + + if (CondFlag[BGL]) { + memcpy(bp, &BGL_values[White], sizeof BGL_values[White]); + bp += sizeof BGL_values[White]; + memcpy(bp, &BGL_values[Black], sizeof BGL_values[Black]); + bp += sizeof BGL_values[Black]; + } + + if (CondFlag[disparate]) + { + move_effect_journal_index_type const top = move_effect_journal_base[nbply]; + move_effect_journal_index_type const movement = top+move_effect_journal_index_offset_movement; + *bp++ = (byte)move_effect_journal[movement].u.piece_movement.moving; + *bp++ = trait[nbply]; + } + + return bp; +} /* CommonEncode */ + static void ProofEncode(stip_length_type min_length, stip_length_type validity_value) { HashBuffer *hb = &hashBuffers[nbply]; @@ -1213,7 +1340,7 @@ static void ProofEncode(stip_length_type min_length, stip_length_type validity_v byte *bp = position+nr_rows_on_board; /* clear the bits for storing the position of pieces */ - memset(position, 0, nr_rows_on_board); + memset(position, 0, nr_rows_on_board * sizeof *position); { boolean even = false; @@ -1260,8 +1387,8 @@ static void ProofEncode(stip_length_type min_length, stip_length_type validity_v /* Now the rest of the party */ bp = CommonEncode(bp,min_length,validity_value); - assert(bp-hb->cmv.Data<=UCHAR_MAX); - hb->cmv.Leng = (unsigned char)(bp-hb->cmv.Data); + assert((bp - hb->cmv.Data) <= MAX_LENGTH_OF_ENCODING); + hb->cmv.Leng = (bp - hb->cmv.Data); } static unsigned int TellCommonEncodePosLeng(unsigned int len, @@ -1380,126 +1507,6 @@ static unsigned int TellSmallEncodePosLeng(void) return result; } /* TellSmallEncodePosLeng */ -byte *CommonEncode(byte *bp, - stip_length_type min_length, - stip_length_type validity_value) -{ - if (CondFlag[messigny]) - { - move_effect_journal_index_type const base = move_effect_journal_base[nbply]; - move_effect_journal_index_type const movement = base+move_effect_journal_index_offset_movement; - if (move_effect_journal[movement].type==move_effect_piece_exchange - && move_effect_journal[movement].reason==move_effect_reason_messigny_exchange) - { - *bp++ = (byte)(move_effect_journal[movement].u.piece_exchange.to - square_a1); - *bp++ = (byte)(move_effect_journal[movement].u.piece_exchange.from - square_a1); - } - else - *bp++ = (byte)UCHAR_MAX; - } - - if (CondFlag[duellist]) - { - *bp++ = (byte)(duellists[White] - square_a1); - *bp++ = (byte)(duellists[Black] - square_a1); - } - - if (CondFlag[blfollow] || CondFlag[whfollow] || CondFlag[champursue]) - { - square const sq_departure = move_effect_journal_get_departure_square(nbply); - if (sq_departure==initsquare) - *bp++ = (byte)UCHAR_MAX; - else - *bp++ = (byte)(sq_departure-square_a1); - } - - if (CondFlag[blacksynchron] || CondFlag[whitesynchron] - || CondFlag[blackantisynchron] || CondFlag[whiteantisynchron]) - { - square const sq_departure = move_effect_journal_get_departure_square(nbply); - if (sq_departure==initsquare) - *bp++ = (byte)UCHAR_MAX; - else - { - move_effect_journal_index_type const base = move_effect_journal_base[nbply]; - move_effect_journal_index_type const movement = base+move_effect_journal_index_offset_movement; - square const sq_arrival = move_effect_journal[movement].u.piece_movement.to; - enum { nr_squares = nr_rows_on_board*nr_files_on_board }; - *bp++= (byte)(sq_num(sq_departure)-sq_num(sq_arrival)+nr_squares); - } - } - - if (CondFlag[imitators]) - { - unsigned int imi_idx; - - /* The number of imitators has to be coded too to avoid - * ambiguities. - */ - *bp++ = (byte)being_solved.number_of_imitators; - for (imi_idx = 0; imi_idx>CHAR_BIT); - *bp++ = (byte)(removedspec&ByteMask); - } - } - else - *bp++ = (byte)0; - } - - assert(validity_value<=(1<slack_length+1) - *bp++ = (byte)(validity_value); - - { - unsigned int i; - - for (i = en_passant_top[nbply-1]+1; i<=en_passant_top[nbply]; ++i) - *bp++ = (byte)(en_passant_multistep_over[i] - square_a1); - } - - *bp++ = being_solved.castling_rights; /* Castling_Flag */ - - if (CondFlag[BGL]) { - memcpy(bp, &BGL_values[White], sizeof BGL_values[White]); - bp += sizeof BGL_values[White]; - memcpy(bp, &BGL_values[Black], sizeof BGL_values[Black]); - bp += sizeof BGL_values[Black]; - } - - if (CondFlag[disparate]) - { - move_effect_journal_index_type const top = move_effect_journal_base[nbply]; - move_effect_journal_index_type const movement = top+move_effect_journal_index_offset_movement; - *bp++ = (byte)move_effect_journal[movement].u.piece_movement.moving; - *bp++ = trait[nbply]; - } - - return bp; -} /* CommonEncode */ - static byte *LargeEncodePiece(byte *bp, byte *position, int row, int col, piece_walk_type pienam, Flags pspec) @@ -1533,7 +1540,7 @@ static void LargeEncode(stip_length_type min_length, TraceFunctionParamListEnd(); /* clear the bits for storing the position of pieces */ - memset(position,0,nr_rows_on_board); + memset(position,0,nr_rows_on_board * sizeof *position); for (row=0; rowcmv.Data<=UCHAR_MAX); - hb->cmv.Leng = (unsigned char)(bp-hb->cmv.Data); + assert((bp - hb->cmv.Data) <= MAX_LENGTH_OF_ENCODING); + hb->cmv.Leng = (bp - hb->cmv.Data); TraceFunctionExit(__func__); TraceFunctionResultEnd(); } /* LargeEncode */ -byte *SmallEncodePiece(byte *bp, - int row, int col, - piece_walk_type pienam, Flags pspec) -{ - *bp++= (byte)((row<<(CHAR_BIT/2))+col); - if (one_byte_hash) - *bp++ = (byte)pspec + (piece_nbr[pienam] << (CHAR_BIT/2)); - else - { - unsigned int i; - *bp++ = pienam; - for (i = 0; i>(CHAR_BIT*i)) & ByteMask); - } - - return bp; -} - static void SmallEncode(stip_length_type min_length, stip_length_type validity_value) { @@ -1625,8 +1614,8 @@ static void SmallEncode(stip_length_type min_length, /* Now the rest of the party */ bp = CommonEncode(bp,min_length,validity_value); - assert(bp-hb->cmv.Data<=UCHAR_MAX); - hb->cmv.Leng = (unsigned char)(bp-hb->cmv.Data); + assert((bp - hb->cmv.Data) <= MAX_LENGTH_OF_ENCODING); + hb->cmv.Leng = (bp - hb->cmv.Data); TraceFunctionExit(__func__); TraceFunctionResultEnd(); @@ -1636,7 +1625,7 @@ static void SmallEncode(stip_length_type min_length, * element's data field with null values * @param he address of hash table element */ -static void init_elements(hashElement_union_t *hue) +static void init_elements(dhtElement *hue) { unsigned int i; @@ -1677,9 +1666,9 @@ static void init_elements(hashElement_union_t *hue) * @param hb has value (basis for calculation of key) * @return address of element */ -static dhtElement *allocDHTelement(dhtConstValue hb) +static dhtElement *allocDHTelement(dhtKey hb) { - dhtElement *result = dhtEnterElement(pyhash,hb,template_element.d.Data); + dhtElement *result = dhtEnterElement(pyhash,hb,template_element.Data); while (result==dhtNilElement) { unsigned long const nrKeysBeforeCompression = dhtKeyCount(pyhash); @@ -1696,11 +1685,11 @@ static dhtElement *allocDHTelement(dhtConstValue hb) fprintf(stderr, "\nOUT OF SPACE: Unable to create hash table in %s in %s -- aborting.\n", __func__, __FILE__); exit(2); /* TODO: Do we have to exit here? */ } - result = dhtEnterElement(pyhash,hb,template_element.d.Data); + result = dhtEnterElement(pyhash,hb,template_element.Data); break; } else - result = dhtEnterElement(pyhash,hb,template_element.d.Data); + result = dhtEnterElement(pyhash,hb,template_element.Data); } if (result==dhtNilElement) @@ -1790,7 +1779,12 @@ static boolean is_proofgame(slice_index si) */ boolean is_hashtable_allocated(void) { - return fxfInitialised(); +#if defined(FXF) + return !!fxfInitialised(); /* !! just in case fxfInitialised returns a nonzero value other than 1 + and boolean is some type that won't automatically convert it to 1. */ +#else + return hashtable_kilos>0; +#endif } /* Initialise the hashing machinery for the current stipulation @@ -1814,7 +1808,7 @@ static void inithash(slice_index si) init_slice_properties(si); - template_element.d.Data = 0; + template_element.Data.unsigned_integer = 0; init_elements(&template_element); is_table_uncompressed = true; /* V3.60 TLi */ @@ -2202,7 +2196,7 @@ static void addtohash_battle_nosuccess(slice_index si, stip_length_type n, stip_length_type min_length_adjusted) { - HashBuffer const * const hb = &hashBuffers[nbply]; + dhtKey hb; hash_value_type const val = (n+1-min_length_adjusted)/2; dhtElement *he; @@ -2211,17 +2205,17 @@ static void addtohash_battle_nosuccess(slice_index si, TraceFunctionParam("%u",min_length_adjusted); TraceFunctionParamListEnd(); + hb.value.object_pointer = &hashBuffers[nbply]; he = dhtLookupElement(pyhash,hb); if (he==dhtNilElement) { - hashElement_union_t * const hue = (hashElement_union_t *)allocDHTelement(hb); - set_value_attack_nosuccess(hue,si,val); + he = allocDHTelement(hb); + set_value_attack_nosuccess(he,si,val); } else { - hashElement_union_t * const hue = (hashElement_union_t *)he; - if (get_value_attack_nosuccess(hue,si)val) - set_value_attack_success(hue,si,val); + if (get_value_attack_success(he,si)>val) + set_value_attack_success(he,si,val); } TraceFunctionExit(__func__); @@ -2317,6 +2310,7 @@ stip_length_type delegate_can_attack_in_n(slice_index si, void attack_hashed_tester_solve(slice_index si) { dhtElement const *he; + dhtKey k; slice_index const base = SLICE_U(si).derived_pipe.base; stip_length_type const min_length = SLICE_U(base).branch.min_length; stip_length_type const played = SLICE_U(base).branch.length-solve_nr_remaining; @@ -2334,23 +2328,23 @@ void attack_hashed_tester_solve(slice_index si) (*encode)(min_length,validity_value); - he = dhtLookupElement(pyhash,&hashBuffers[nbply]); + k.value.object_pointer = &hashBuffers[nbply]; + he = dhtLookupElement(pyhash,k); if (he==dhtNilElement) solve_result = delegate_can_attack_in_n(si,min_length_adjusted); else { - hashElement_union_t const * const hue = (hashElement_union_t const *)he; stip_length_type const parity = (solve_nr_remaining-min_length_adjusted)%2; /* It is more likely that a position has no solution. */ /* Therefore let's check for "no solution" first. TLi */ - hash_value_type const val_nosuccess = get_value_attack_nosuccess(hue,base); + hash_value_type const val_nosuccess = get_value_attack_nosuccess(he,base); stip_length_type const n_nosuccess = 2*val_nosuccess + min_length_adjusted-parity; if (n_nosuccess>=MOVE_HAS_SOLVED_LENGTH()) solve_result = MOVE_HAS_NOT_SOLVED_LENGTH(); else { - hash_value_type const val_success = get_value_attack_success(hue,base); + hash_value_type const val_success = get_value_attack_success(he,base); stip_length_type const n_success = 2*val_success + min_length_adjusted+2-parity; if (n_success<=MOVE_HAS_SOLVED_LENGTH()) solve_result = n_success; @@ -2385,7 +2379,7 @@ void attack_hashed_tester_solve(slice_index si) static boolean inhash_help(slice_index si) { boolean result; - HashBuffer *hb = &hashBuffers[nbply]; + dhtKey hb; dhtElement const *he; stip_length_type const validity_value = (solve_nr_remaining-1)/2+1; @@ -2404,10 +2398,11 @@ static boolean inhash_help(slice_index si) ifHASHRATE(use_all++); + hb.value.object_pointer = &hashBuffers[nbply]; he = dhtLookupElement(pyhash,hb); if (he==dhtNilElement) result = false; - else if (get_value_help((hashElement_union_t const *)he,si)==1) + else if (get_value_help(he,si)==1) { ifHASHRATE(use_pos++); result = true; @@ -2427,21 +2422,19 @@ static boolean inhash_help(slice_index si) */ static void addtohash_help(slice_index si) { - HashBuffer const * const hb = &hashBuffers[nbply]; + dhtKey hb; dhtElement *he; - hashElement_union_t * hue; TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceFunctionParamListEnd(); + hb.value.object_pointer = &hashBuffers[nbply]; he = dhtLookupElement(pyhash,hb); if (he==dhtNilElement) - hue = (hashElement_union_t *)allocDHTelement(hb); - else - hue = (hashElement_union_t *)he; + he = allocDHTelement(hb); - set_value_help(hue,si,1); + set_value_help(he,si,1); TraceFunctionExit(__func__); TraceFunctionResultEnd(); @@ -2577,14 +2570,11 @@ void hash_opener_solve(slice_index si) TraceFunctionResultEnd(); } -/* assert()s below this line must remain active even in "productive" - * executables. */ -#undef NDEBUG -#include - /* Check assumptions made in the hashing module. Abort if one of them * isn't met. * This is called from checkGlobalAssumptions() once at program start. + * NOTE: Currently these are all compile-time checks, but we reserve + * the right to add run-time checks in the future. */ void check_hash_assumptions(void) { diff --git a/optimisations/hash.h b/optimisations/hash.h index 2e977a546..256c41154 100644 --- a/optimisations/hash.h +++ b/optimisations/hash.h @@ -12,7 +12,11 @@ #include "DHT/dhtbcmem.h" #include "pieces/pieces.h" #include "solving/machinery/solve.h" +#include "position/underworld.h" +#include "position/position.h" +#include "position/board.h" #include "solving/ply.h" +#include "conditions/bgl.h" #if defined(TESTHASH) # if !defined(HASHRATE) @@ -23,9 +27,114 @@ /* typedefs */ typedef unsigned char byte; +/* Time for some math -- let's figure out the maximum number of bytes a position encoding may take up. + If it's a proofgame then ProofEncode will be used. Otherwise, SmallEncode or LargeEncode will be chosen, + the former if TellSmallEncodePosLeng <= TellLargeEncodePosLeng, the latter otherwise. + - ProofEncode <= nr_rows_on_board + + "num nonempty squares (found by looping over nr_rows_on_board and nr_files_on_board)" * max(ProofLargeEncodePiece, ProofSmallEncodePiece) + + 1 + + nr_ghosts * SmallEncodePiece + + CommonEncode + - LargeEncode = nr_rows_on_board + + "num nonempty squares (found by looping over nr_rows_on_board and nr_files_on_board)" * LargeEncodePiece + + nr_ghosts * LargeEncodePiece + + CommonEncode + - SmallEncode = "num nonempty squares (found by looping over nr_rows_on_board and nr_files_on_board)" * SmallEncodePiece + + nr_ghosts * SmallEncodePiece + + CommonEncode + TellLargeEncodePosLeng = 8 + + "num nonempty squares (found by looping boardnum until 0 is found)" * bytes_per_piece + + (sizeof BGL_values[White] + sizeof BGL_values[Black]) * !!CondFlag[BGL] + + nr_ghosts*bytes_per_piece + + TellCommonEncodePosLeng + TellSmallEncodePosLeng = "num nonempty squares (found by looping boardnum until 0 is found)" * (1 + bytes_per_piece) + + nr_ghosts*bytes_per_piece + + TellCommonEncodePosLeng + SmallEncode will therefore be chosen iff "num nonempty squares" <= (8 + sizeof BGL_values[White] + sizeof BGL_values[Black]) * !!CondFlag[BGL], + hence: + - If SmallEncode is chosen then "num nonempty squares" <= min((nr_rows_on_board * nr_files_on_board), (8 + sizeof BGL_values[White] + sizeof BGL_values[Black])). + - If LargeEncode is chosen then 8 < "num nonempty squares" <= (nr_rows_on_board * nr_files_on_board). + Substituting we find that + - SmallEncode <= min((nr_rows_on_board * nr_files_on_board), (8 + sizeof BGL_values[White] + sizeof BGL_values[Black])) * SmallEncodePiece + + nr_ghosts*bytes_per_piece + + CommonEncode + - LargeEncode <= nr_rows_on_board + + (nr_rows_on_board * nr_files_on_board) * LargeEncodePiece + + nr_ghosts * LargeEncodePiece + + CommonEncode + - ProofEncode <= nr_rows_on_board + + (nr_rows_on_board * nr_files_on_board) * max(ProofLargeEncodePiece, ProofSmallEncodePiece) + + 1 + + nr_ghosts * SmallEncodePiece + + CommonEncode + Meanwhile, inspection reveals that: + - ProofLargeEncodePiece = 2 + - ProofSmallEncodePiece <= 1 + - SmallEncodePiece <= 1 + 1 + bytes_per_spec + - LargeEncodePiece = 1 + bytes_per_spec + - CommonEncode <= 2 + 2 + 1 + 1 + 1 + + being_solved.number_of_imitators + + 1 + 1 + 3 + 1 + + en_passant_top[nbply] - en_passant_top[nbply-1] + + 1 + sizeof BGL_values[White] + sizeof BGL_values[Black] + + 2 + = 16 + sizeof BGL_values[White] + sizeof BGL_values[Black] + + being_solved.number_of_imitators + + en_passant_top[nbply] - en_passant_top[nbply-1] + Substituting yields: + - SmallEncode <= min((nr_rows_on_board * nr_files_on_board), (8 + sizeof BGL_values[White] + sizeof BGL_values[Black])) * (2 + bytes_per_spec) + + nr_ghosts*(2 + bytes_per_spec) + + CommonEncode + - LargeEncode <= nr_rows_on_board + + (nr_rows_on_board * nr_files_on_board) * (1 + bytes_per_spec) + + nr_ghosts * (1 + bytes_per_spec) + + CommonEncode + - ProofEncode <= nr_rows_on_board + + (nr_rows_on_board * nr_files_on_board) * 2 + + 1 + + nr_ghosts * (2 + bytes_per_spec) + + CommonEncode + We need to bound the remaining non-constants. We have + - nr_ghosts <= underworld_capacity + - bytes_per_spec <= 4 + - being_solved.number_of_imitators <= maxinum + en_passant_top[nbply] - en_passant_top[nbply-1] requires a bit more thought. It should be an upper + bound on the number of en passant squares stored per ply. For now we'll assume that + - en_passant_top[nbply] - en_passant_top[nbply-1] <= nr_rows_on_board - 2 + as (nr_rows_on_board - 2) is the number of squares that a pawn jumping from the first rank to the + last rank would skip over. + With all of the above, we can determine the maximum bytes that an encoding should take up. We'll + let the compiler perform the arithmetic. +*/ + +enum { + MAX_EN_PASSANT_TOP_DIFFERENCE = nr_rows_on_board - 2, /* TODO: Is this a safe maximum? Can we get away with a smaller value? */ + COMMONENCODE_MAX = 16 + + sizeof BGL_values[White] + sizeof BGL_values[Black] + + maxinum + + MAX_EN_PASSANT_TOP_DIFFERENCE, + NUM_NONEMPTY_SMALL_FIRST = (nr_rows_on_board * nr_files_on_board), + NUM_NONEMPTY_SMALL_SECOND = ((8 + sizeof BGL_values[White] + sizeof BGL_values[Black]) * (2 + 4)), + NUM_NONEMPTY_SMALL = ((NUM_NONEMPTY_SMALL_FIRST < NUM_NONEMPTY_SMALL_SECOND) ? NUM_NONEMPTY_SMALL_FIRST : NUM_NONEMPTY_SMALL_SECOND), + SMALLENCODE_MAX = (NUM_NONEMPTY_SMALL * (2 + 4)) + + (underworld_capacity * (2 + 4)) + + COMMONENCODE_MAX, + LARGEENCODE_MAX = nr_rows_on_board + + ((nr_rows_on_board * nr_files_on_board) * (1 + 4)) + + (underworld_capacity * (1 + 4)) + + COMMONENCODE_MAX, + PROOFENCODE_MAX = nr_rows_on_board + + ((nr_rows_on_board * nr_files_on_board) * 2) + + 1 + + (underworld_capacity * (2 + 4)) + + COMMONENCODE_MAX +}; + enum { - hashbuf_length = 256 + MAX_LENGTH_OF_ENCODING = ((SMALLENCODE_MAX > LARGEENCODE_MAX) ? ((SMALLENCODE_MAX > PROOFENCODE_MAX) ? SMALLENCODE_MAX : PROOFENCODE_MAX) + : ((LARGEENCODE_MAX > PROOFENCODE_MAX) ? LARGEENCODE_MAX : PROOFENCODE_MAX)), + hashbuf_length = (MAX_LENGTH_OF_ENCODING * sizeof(byte)) + offsetof(BCMemValue, Data) }; typedef union @@ -59,14 +168,6 @@ void HashStats(unsigned int level, char const *trailer); void IncHashRateLevel(void); void DecHashRateLevel(void); -byte *CommonEncode(byte *bp, - stip_length_type min_length, - stip_length_type validity_value); - -byte *SmallEncodePiece(byte *bp, - int row, int col, - piece_walk_type p, Flags pspec); - /* Try to solve in solve_nr_remaining half-moves. * @param si slice index * @note assigns solve_result the length of solution found and written, i.e.: diff --git a/position/pieceid.h b/position/pieceid.h index e402f0ddd..bd770ed4c 100644 --- a/position/pieceid.h +++ b/position/pieceid.h @@ -8,7 +8,7 @@ enum { NullPieceId = 0, MinPieceId = 1, - MaxPieceId = 63 + MaxPieceId = 64 }; typedef unsigned long PieceIdType; @@ -21,6 +21,11 @@ typedef unsigned long PieceIdType; #define GetPieceId(spec) ((spec) >> PieceIdOffset) #define ClearPieceId(spec) SetPieceId(spec,NullPieceId) +enum +{ + ENSURE_PIECEIDWIDTH_IS_LARGE_ENOUGH=1/!((MaxPieceId>>(PieceIdWidth-1u))>>1) +}; + extern square PiecePositionsInDiagram[MaxPieceId+1]; #define GetPositionInDiagram(spec) PiecePositionsInDiagram[GetPieceId(spec)]