diff --git a/DHT/dht.c b/DHT/dht.c index 90103df1a..eba59a2c8 100644 --- a/DHT/dht.c +++ b/DHT/dht.c @@ -50,11 +50,11 @@ void set_dhtDebug(int const d) {dhtDebug = d;} #endif /*DEBUG_DHT*/ #if !defined(New) /* TODO: Is this the correct check for all of the below lines? */ -# define New(type) ((type *)fxfAlloc(sizeof(type))) -# define nNew(n,type) ((type *)nNewImpl(n,sizeof(type))) +# define New(type) fxfAlloc(sizeof(type), type) +# define nNew(n,type) ((type *)nNewImpl(n,sizeof(type),ALIGNMENT_OF_TYPE(type))) # define Nil(type) ((type *)0) -static inline void * nNewImpl(size_t const nmemb, size_t const size) { - return ((size && (nmemb > (((size_t)-1)/size))) ? Nil(void) : fxfAlloc(nmemb*size)); +static inline void * nNewImpl(size_t const nmemb, size_t const size, size_t desired_alignment) { + return ((size && (nmemb > (((size_t)-1)/size))) ? Nil(void) : fxfAllocRaw(nmemb*size, desired_alignment)); } #endif /*New*/ @@ -197,7 +197,7 @@ static boolean appendDirTable_recursive(dirTable *dt, TraceFunctionEntry(__func__); TraceFunctionParam("%p",(void *)dt); TraceFunctionParam("%p",elmt_to_append); - TraceFunctionParam("%d",elmt_depth); + TraceFunctionParam("%u",elmt_depth); TraceFunctionParamListEnd(); if (elmt_depth>dt->level) @@ -263,7 +263,7 @@ static boolean appendDirTable_recursive(dirTable *dt, } TraceFunctionExit(__func__); - TraceFunctionResult("%d",result); + TraceFunctionResult("%d",(int)result); TraceFunctionResultEnd(); return result; } @@ -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 { @@ -423,7 +423,7 @@ typedef struct dht { #if !defined(HashTable) #define HashTable struct dht #endif -#define NewHashTable ((HashTable *)fxfAlloc(sizeof(dht))) +#define NewHashTable fxfAlloc(sizeof(dht), HashTable) #define FreeHashTable(h) fxfFree(h, sizeof(dht)) #define OVERFLOW_SAVE 1 #if defined(OVERFLOW_SAVE) @@ -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.FreeData)(b->HsEl.Data); + (ht->procs.FreeKeyValue)(b->HsEl.Key.value); 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,25 @@ 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 (ht->KeyPolicy==dhtNoCopy) + { +#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 + } + else + { + TraceFunctionParam("%p",(void const *)key.value.object_pointer); // TODO: something more generic here? + } TraceFunctionParamListEnd(); h = DynamicHash(ht->p, ht->maxp, (ht->procs.Hash)(key)); @@ -827,14 +838,25 @@ 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 (ht->KeyPolicy==dhtNoCopy) + { +#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 + } + else + { + TraceFunctionParam("%p",(void const *)key.value.object_pointer); // TODO: something more generic here? + } TraceFunctionParamListEnd(); phe= LookupInternHsElement(ht, key); @@ -849,8 +871,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,40 +899,52 @@ void dhtRemoveElement(HashTable *ht, dhtConstValue key) TraceFunctionResultEnd(); } -dhtElement *dhtEnterElement(HashTable *ht, dhtConstValue key, dhtConstValue data) +/* dhtEnterElement adds the key, data pair. If an equivalent key already exists + then the data will be updated and the existing key will be replaced by the + provided key. (The latter can matter if keys contain data that doesn't affect + the equivalence check.) + This function allocates copies before freeing any old data, allowing us to bail + on failure while leaving the old data intact. This isn't ideal from a memory- + usage perspective, so if this "strong exception guarantee" is unnecessary then + the code can likely be simplified and improved. */ +dhtElement *dhtEnterElement(HashTable *ht, dhtKey key, dhtValue data) { InternHsElement **phe, *he; - dhtConstValue KeyV; - dhtConstValue DataV; + dhtKey KeyV; + dhtValue DataV; + dhtValue *KeyVPtr; + dhtValue *DataVPtr; TraceFunctionEntry(__func__); TraceFunctionParam("%p",(void *)ht); - TraceFunctionParam("%p",(void const *)key); - TraceFunctionParam("%p",(void const *)data); - TraceFunctionParamListEnd(); - - assert(key!=0); - KeyV = (ht->procs.DupKey)(key); - if (KeyV==0) + if (ht->KeyPolicy==dhtNoCopy) { - TraceText("key duplication failed\n"); - TraceFunctionExit(__func__); - TraceFunctionResult("%p",(void *)dhtNilElement); - TraceFunctionResultEnd(); - return dhtNilElement; +#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 } - - DataV = data==0 ? 0 : (ht->procs.DupData)(data); - if (data!=0 && DataV==0) + else { - (ht->procs.FreeKey)((dhtValue)KeyV); - TraceText("data duplication failed\n"); - TraceFunctionExit(__func__); - TraceFunctionResult("%p",(void *)dhtNilElement); - TraceFunctionResultEnd(); - return dhtNilElement; + TraceFunctionParam("%p",(void const *)key.value.object_pointer); // TODO: something more generic here? + } + if (ht->DtaPolicy==dhtNoCopy) + { +#if (defined(__cplusplus) && (__cplusplus >= 201103L)) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) + TraceFunctionParam("%jx",data.unsigned_integer); +#else + TraceFunctionParam("%lx",(unsigned long)data.unsigned_integer); +#endif + } + else + { + TraceFunctionParam("%p",(void const *)data.object_pointer); // TODO: something more generic here? } + 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? */ + phe = LookupInternHsElement(ht,key); TraceValue("%p",(void *)phe); he = *phe; @@ -923,50 +957,78 @@ dhtElement *dhtEnterElement(HashTable *ht, dhtConstValue key, dhtConstValue data TraceEOL(); if (he==0) { - (ht->procs.FreeKey)((dhtValue)KeyV); - (ht->procs.FreeData)((dhtValue)DataV); TraceText("allocation of new intern Hs element failed\n"); TraceFunctionExit(__func__); TraceFunctionResult("%p",(void *)dhtNilElement); TraceFunctionResultEnd(); return dhtNilElement; } - else - { - *phe = he; - he->Next = NilInternHsElement; - ht->KeyCount++; - } + KeyVPtr = &he->HsEl.Key.value; + DataVPtr = &he->HsEl.Data; } else + { + KeyVPtr = &KeyV.value; + DataVPtr = &DataV; + } + if ((ht->procs.DupKeyValue)(key.value, KeyVPtr)) + { + if (!*phe) + FreeInternHsElement(he); + TraceText("key duplication failed\n"); + TraceFunctionExit(__func__); + TraceFunctionResult("%p",(void *)dhtNilElement); + TraceFunctionResultEnd(); + return dhtNilElement; + } + if ((ht->procs.DupData)(data, DataVPtr)) + { + (ht->procs.FreeKeyValue)(*KeyVPtr); + if (!*phe) + FreeInternHsElement(he); + TraceText("data duplication failed\n"); + TraceFunctionExit(__func__); + TraceFunctionResult("%p",(void *)dhtNilElement); + TraceFunctionResultEnd(); + return dhtNilElement; + } + if (*phe) { 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; + he->HsEl.Data = DataV; + } + else + { + *phe = he; + he->Next = NilInternHsElement; + ht->KeyCount++; } - - he->HsEl.Key = KeyV; - he->HsEl.Data = DataV; if (ActualLoadFactor(ht)>ht->MaxLoadFactor) { - /* +#if 0 fputs("Dumping Hash-Table before expansion\n",stderr); fDumpHashTable(ht, stderr); - */ +#endif if (ExpandHashTable(ht)!=dhtOkStatus) { + /* TODO: It seems strange to return dhtNilElement AFTER we've added a new entry + or overwritten an old one. Should we return something else here? Should + we check and deal with this issue BEFORE creating or overwriting an entry? */ TraceText("expansion failed\n"); TraceFunctionExit(__func__); TraceFunctionResult("%p",(void *)dhtNilElement); TraceFunctionResultEnd(); return dhtNilElement; } - /* +#if 0 fputs("Dumping Hash-Table after expansion\n",stderr); fDumpHashTable(ht, stderr); - */ +#endif } TraceFunctionExit(__func__); @@ -975,7 +1037,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..541424c79 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,36 @@ 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); + +/* dhtEnterElement adds the key, data pair. If an equivalent key already exists + then the data will be updated and the existing key will be replaced by the + provided key. (The latter can matter if keys contain data that doesn't affect + the equivalence check.) + TODO: Is the "equivalent key" behavior what we need/want? Otherwise it's + pessimization in comparison to just leaving the original key intact. */ +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..2d0f7cb1e 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 = fxfAlloc(size, BCMemValue); + 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..2eaddfe1c 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 = fxfAlloc(size, CompactMemVal); + 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..5b69994dd 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) fxfAlloc(sizeof(CompactMemVal)+(n)*sizeof(uChar), CompactMemVal) #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..11390b456 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) { + uChar *newBuffer= fxfAlloc(length, uChar); + if (newBuffer) { + memcpy(newBuffer, data, length); + mv->Data = 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..126ed8c72 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 fxfAlloc(sizeof(MemVal), 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..ab8011d5d 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= fxfAlloc(len, char); + 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..b5df6c1ce 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,type) ((type *) 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..460ed876a 100644 --- a/DHT/fxf.c +++ b/DHT/fxf.c @@ -1,9 +1,9 @@ -#if defined (FXF) +#if defined(FXF) #include "debugging/assert.h" #include #include -#include +#include #if defined(__TURBOC__) # include @@ -18,27 +18,75 @@ #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; + typedef uintmax_t largest_integer_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 +# 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; + typedef unsigned long long int largest_integer_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; + typedef unsigned long int largest_integer_type; +# define PTRDIFF_T_PRINTF_SPECIFIER "ld" +# define SIZE_T_PRINTF_SPECIFIER "lu" +# endif +# define MAX_POINTER_DIFFERENCE ((ptrdiff_t_printf_type)(((size_t)-1)>>1)) /* just a guess */ +enum +{ + ENSURE_MAX_POINTER_DIFFERENCE_POSITIVE = 1/(MAX_POINTER_DIFFERENCE > 0) /* I'm not sure what would happen if this fails, + but it likely wouldn't be pretty. */ +}; #endif -#if !defined(Nil) && !defined(New) && !defined(nNew) /* TODO: Is this the correct check for all of the below lines? */ +#define BOTTOM_BIT(s) (((size_t) (s)) & -(size_t) (s)) + +#if defined(FXF_MAX_ALIGNMENT_TYPE) +# define MAX_ALIGNMENT ALIGNMENT_OF_TYPE(FXF_MAX_ALIGNMENT_TYPE) +#else /*FXF_MAX_ALIGNMENT_TYPE*/ +# 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 +# define MAX_ALIGNMENT ALIGNMENT_OF_TYPE(union {largest_integer_type unsigned_integer; \ + const volatile void * object_pointer; \ + void (*function_pointer)(void); \ + long double floating_point;}) +# endif +#endif /*!FXF_MAX_ALIGNMENT_TYPE*/ + +#if defined(FXF_NOT_MULTIPLE_ALIGNMENT_TYPE) +# define NOT_MULTIPLE_ALIGNMENT ((ALIGNMENT_OF_TYPE(FXF_NOT_MULTIPLE_ALIGNMENT_TYPE) > MAX_ALIGNMENT) ? \ + MAX_ALIGNMENT : \ + ALIGNMENT_OF_TYPE(FXF_NOT_MULTIPLE_ALIGNMENT_TYPE)) +#else /*FXF_NOT_MULTIPLE_ALIGNMENT_TYPE*/ +# define NOT_MULTIPLE_ALIGNMENT MAX_ALIGNMENT +#endif /*!FXF_NOT_MULTIPLE_ALIGNMENT_TYPE*/ + +#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 +116,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 +128,18 @@ 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)) +#define ROUND_DOWN_TO_ALIGNMENT(s, a) (((size_t) (s)) & ~(((size_t) (a)) - 1U)) +#define ROUND_UP_TO_ALIGNMENT(s, a) ROUND_DOWN_TO_ALIGNMENT((((size_t) (a)) - 1U) + (size_t) (s), a) +#define CLEAR_BOTTOM_BIT(s) ((((size_t) (s)) - 1U) & (size_t) (s)) + #if defined(DOS) /* MSDOS 16 Bit support (maxmemory <= 1 MB) */ #define SEGMENTED -#define ARENA_SEG_SIZE 32000 +#define ARENA_SEG_SIZE ROUND_DOWN_TO_ALIGNMENT(CLIP_TO_MAX_POINTER_DIFFERENCE(32000), MAX_ALIGNMENT) #define ARENA_SEG_COUNT ((1024*1024)/ARENA_SEG_SIZE) #define OSNAME "MSDOS" #define OSMAXMEM "1 MB" @@ -94,40 +147,67 @@ 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 ROUND_DOWN_TO_ALIGNMENT(CLIP_TO_MAX_POINTER_DIFFERENCE(1000000), MAX_ALIGNMENT) #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 */ -#if defined(SEGMENTED) || defined(__TURBOC__) -#define fxfMAXSIZE ((size_t)1024) -#else -#define fxfMAXSIZE ((size_t)2048) /* this is needed only when sizeof(void*)==8 */ +#if !defined(FXF_DESIRED_MAX_ALLOC) +# define FXF_DESIRED_MAX_ALLOC (256U * sizeof(void *)) +/* TODO: Is the above a good default, sufficiently large for all of our needs without being excessive? */ #endif -/* Different size of fxfMINSIZE for 32-/64/Bit compilation */ +#define DESIRED_MAX_ALLOC_ALIGNMENT ((FXF_DESIRED_MAX_ALLOC < MAX_ALIGNMENT) ? NOT_MULTIPLE_ALIGNMENT : MAX_ALIGNMENT) +#define ROUNDED_DESIRED_MAXIMUM_ALLOC ROUND_UP_TO_ALIGNMENT(FXF_DESIRED_MAX_ALLOC, DESIRED_MAX_ALLOC_ALIGNMENT) enum { - fxfMINSIZE = sizeof(size_t) + fxfMINSIZE = sizeof(void *), /* Different size of fxfMINSIZE for 32-/64/Bit compilation */ +#if defined(SEGMENTED) + fxfMAXSIZE = ((ROUNDED_DESIRED_MAXIMUM_ALLOC > ARENA_SEG_SIZE) ? ARENA_SEG_SIZE : ROUNDED_DESIRED_MAXIMUM_ALLOC) +#else + fxfMAXSIZE = ROUNDED_DESIRED_MAXIMUM_ALLOC +#endif +}; + +enum { + ENSURE_FXFMINSIZE_GT_0 = 1/(fxfMINSIZE > 0), + ENSURE_FXFMAXSIZE_GE_FXFMINSIZE = 1/(fxfMAXSIZE >= fxfMINSIZE), +#if defined(SEGMENT) + ENSURE_SEGMENTS_ALIGNED = 1/!((ARENA_SEG_SIZE & (((ARENA_SEG_SIZE < MAX_ALIGNMENT) ? NOT_MULTIPLE_ALIGNMENT : MAX_ALIGNMENT) - 1U)) && + (ARENA_SEG_SIZE & (ARENA_SEG_SIZE - 1U))), +#endif + ENSURE_FXFMAXSIZE_ALIGNED = 1/((!CLEAR_BOTTOM_BIT(fxfMAXSIZE)) || + ((fxfMAXSIZE < MAX_ALIGNMENT) && !(fxfMAXSIZE & (NOT_MULTIPLE_ALIGNMENT - 1U))) || + !(fxfMAXSIZE & (MAX_ALIGNMENT - 1U))), + ENSURE_ALIGNMENT_ORDERED = 1/((NOT_MULTIPLE_ALIGNMENT > 0) && (NOT_MULTIPLE_ALIGNMENT <= MAX_ALIGNMENT)), + ENSURE_ALIGNMENTS_POWERS_OF_2 = 1/!(CLEAR_BOTTOM_BIT(NOT_MULTIPLE_ALIGNMENT) || CLEAR_BOTTOM_BIT(MAX_ALIGNMENT)) }; -static SizeHead SizeData[fxfMAXSIZE+1]; +#define MIN_ALIGNMENT_UNDERESTIMATE (((NOT_MULTIPLE_ALIGNMENT>>1) < fxfMINSIZE) ? NOT_MULTIPLE_ALIGNMENT : \ + (CLEAR_BOTTOM_BIT(fxfMINSIZE) ? (BOTTOM_BIT(fxfMINSIZE)<<2) : \ + fxfMINSIZE)) +static size_t min_alignment= NOT_MULTIPLE_ALIGNMENT; /* for now */ + +#define ROUNDED_MIN_SIZE_UNDERESTIMATE ROUND_UP_TO_ALIGNMENT(fxfMINSIZE, MIN_ALIGNMENT_UNDERESTIMATE) +#define SIZEDATA_SIZE_TO_INDEX(s) (((s) - ROUNDED_MIN_SIZE_UNDERESTIMATE)/MIN_ALIGNMENT_UNDERESTIMATE) +#define SIZEDATA_INDEX_TO_SIZE(x) ((size_t)(((x) * MIN_ALIGNMENT_UNDERESTIMATE) + ROUNDED_MIN_SIZE_UNDERESTIMATE)) +static SizeHead SizeData[1 + SIZEDATA_SIZE_TO_INDEX(fxfMAXSIZE)]; #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 +295,40 @@ 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; +} + +#define ALIGN_TO_MINIMUM(s) ROUND_UP_TO_ALIGNMENT(s, min_alignment) + size_t fxfInit(size_t Size) { -#if defined(LOG) +#if defined(LOG) && !defined(SEGMENTED) 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) { + while (maxSegCnt < (size_t)ArenaSegCnt) { --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)) + while (maxSegCnt > (size_t)ArenaSegCnt) { + Arena[ArenaSegCnt]= nNewUntyped(ARENA_SEG_SIZE, char); + if (!Arena[ArenaSegCnt]) break; ++ArenaSegCnt; } @@ -242,28 +336,41 @@ size_t fxfInit(size_t Size) { BotFreePtr= Arena[CurrentSeg]; TopFreePtr= Arena[CurrentSeg]; if (TopFreePtr) - TopFreePtr+= ARENA_SEG_SIZE; - GlobalSize= ArenaSegCnt*ARENA_SEG_SIZE; + TopFreePtr= stepPointer(TopFreePtr, ARENA_SEG_SIZE); + GlobalSize= ARENA_SEG_SIZE*(size_t)ArenaSegCnt; #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; + if (Size < NOT_MULTIPLE_ALIGNMENT) + while (CLEAR_BOTTOM_BIT(Size)) + Size= CLEAR_BOTTOM_BIT(Size); + else if (Size < MAX_ALIGNMENT) + Size= ROUND_DOWN_TO_ALIGNMENT(Size, NOT_MULTIPLE_ALIGNMENT); + else + Size= ROUND_DOWN_TO_ALIGNMENT(Size, MAX_ALIGNMENT); + 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 +384,20 @@ 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 ((NOT_MULTIPLE_ALIGNMENT>>1) >= fxfMINSIZE) /* compile-time check */ + while (min_alignment >= (((size_t)fxfMINSIZE)<<1)) + min_alignment>>= 1; return GlobalSize; } @@ -297,29 +409,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 +450,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 +465,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,156 +488,411 @@ 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) + +#if defined(FXF_ENABLE_TMDBG) +# define TMDBG(x) do {x;} while (0) +#else /*FXF_ENABLE_TMDBG*/ +# define TMDBG(x) do {;} while (0) +#endif /*!FXF_ENABLE_TMDBG*/ + +static int pushOntoFreeStore(void * const ptr, size_t const size) { + SizeHead *cur_sh; + assert((size >= ROUNDED_MIN_SIZE_UNDERESTIMATE) && + (size <= fxfMAXSIZE) && + !(size & (min_alignment - 1U))); + cur_sh= &SizeData[SIZEDATA_SIZE_TO_INDEX(size)]; + assert((!cur_sh->FreeHead) == (!cur_sh->FreeCount)); + if ((ROUNDED_MIN_SIZE_UNDERESTIMATE < sizeof cur_sh->FreeHead) /* compile-time check */ && + (size < sizeof cur_sh->FreeHead) && + cur_sh->FreeHead) + TMDBG(printf(" leaking %" SIZE_T_PRINTF_SPECIFIER " byte(s) instead of freeing them\n", (size_t_printf_type)size)); + else + { + if ((ROUNDED_MIN_SIZE_UNDERESTIMATE >= sizeof cur_sh->FreeHead) /* compile-time check */ || + (size >= sizeof cur_sh->FreeHead)) + memcpy(ptr, &cur_sh->FreeHead, sizeof cur_sh->FreeHead); + cur_sh->FreeHead= ptr; + cur_sh->FreeCount++; + TMDBG(printf(" FreeCount:%lu",cur_sh->FreeCount)); +#if defined(FREEMAP) && !defined(SEGMENTED) + SetRange(pointerDifference(ptr, Arena), size); +#endif + return 1; + } + return 0; +} -#define TMDBG(x) if (0) x +static void * popOffFreeStore(size_t const size) +{ + SizeHead *cur_sh; + void *ptr; + assert((size >= ROUNDED_MIN_SIZE_UNDERESTIMATE) && + (size <= fxfMAXSIZE) && + !(size & (min_alignment - 1U))); + cur_sh= &SizeData[SIZEDATA_SIZE_TO_INDEX(size)]; + ptr= cur_sh->FreeHead; + assert((!ptr) == (!cur_sh->FreeCount)); + if (ptr) { + cur_sh->FreeCount--; + if ((ROUNDED_MIN_SIZE_UNDERESTIMATE < sizeof cur_sh->FreeHead) /* compile-time check */ && + (size < sizeof cur_sh->FreeHead)) + cur_sh->FreeHead= Nil(void); + else + memcpy(&cur_sh->FreeHead, ptr, sizeof cur_sh->FreeHead); +# if defined(FREEMAP) && !defined(SEGMENTED) + ClrRange(pointerDifference(ptr, Arena), size); +# endif + } + return ptr; +} -void *fxfAlloc(size_t size) { +void *fxfAllocRaw(size_t size, size_t desired_alignment) { #if defined(LOG) || defined(DEBUG) - static char const * const myname= "fxfAlloc"; + static char const * const myname= "fxfAllocRaw"; #endif - SizeHead *sh; - char *ptr; + void *ptr= Nil(void); - TMDBG(printf("fxfAlloc - size:%" SIZE_T_PRINTF_SPECIFIER,(size_t_printf_type)size)); + TMDBG(printf("fxfAllocRaw - size:%" SIZE_T_PRINTF_SPECIFIER,(size_t_printf_type)size)); DBG((stderr, "%s(%" SIZE_T_PRINTF_SPECIFIER ") =", myname, (size_t_printf_type)size)); + assert(desired_alignment && !CLEAR_BOTTOM_BIT(desired_alignment)); - if (sizefxfMAXSIZE) + assert(desired_alignment <= size); + if (sizefxfMAXSIZE) { ERROR_LOG3("%s: size=%" SIZE_T_PRINTF_SPECIFIER " > %" SIZE_T_PRINTF_SPECIFIER "\n", myname, (size_t_printf_type) size, (size_t_printf_type) fxfMAXSIZE); - return Nil(char); + return Nil(void); } - if ( (size&PTRMASK) && sizeFreeHead) { - ptr= sh->FreeHead; - sh->FreeHead= GetNextPtr(ptr); - 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)); + // Round up to a multiple of min_alignment + size= ALIGN_TO_MINIMUM(size); + +#if defined(NDEBUG) + (void) desired_alignment; /* Ensure we "use" alignment. */ +#else /*NDEBUG*/ + /* Check our alignment assumptions, purely for informational purposes. */ + if (size&PTRMASK) { + if (desired_alignment > NOT_MULTIPLE_ALIGNMENT) + fprintf(stderr, "WARNING: Not fully aligned allocation of size %" SIZE_T_PRINTF_SPECIFIER "needs %" SIZE_T_PRINTF_SPECIFIER "-byte allocation, > the %" SIZE_T_PRINTF_SPECIFIER " byte(s) that FXF will guarantee\n", + (size_t_printf_type) size, + (size_t_printf_type) desired_alignment, + (size_t_printf_type) NOT_MULTIPLE_ALIGNMENT); + } + else { + if (desired_alignment > MAX_ALIGNMENT) + fprintf(stderr, "WARNING: fully aligned allocation of size %" SIZE_T_PRINTF_SPECIFIER " needs %" SIZE_T_PRINTF_SPECIFIER "-byte allocation, > the %" SIZE_T_PRINTF_SPECIFIER " byte(s) that FXF will guarantee\n", + (size_t_printf_type) size, + (size_t_printf_type) desired_alignment, + (size_t_printf_type) NOT_MULTIPLE_ALIGNMENT); + } +#endif /*!NDEBUG*/ + + ptr= popOffFreeStore(size); + + if (ptr) { + SizeHead *const sh= &SizeData[SIZEDATA_SIZE_TO_INDEX(size)]; +#if defined(SEGMENTED) && defined(FXF_ENABLE_TMDBG) + ptrdiff_t ptrIndex; + int ptrSegment= CurrentSeg; #endif + sh->MallocCount++; +#if defined(SEGMENTED) +# if defined(FXF_ENABLE_TMDBG) + 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)); +# endif /*FXF_ENABLE_TMDBG*/ +#else /*SEGMENTED*/ + 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 /*!SEGMENTED*/ } 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) { + SizeHead *sh; if (size&PTRMASK) { - /* not aligned */ + /* not fully aligned */ + size_t curBottomIndex= +#if defined(SEGMENTED) + (size_t)pointerDifference(BotFreePtr,Arena[CurrentSeg]); +#else + (size_t)pointerDifference(BotFreePtr,Arena); +#endif + size_t needed_alignment_mask= (NOT_MULTIPLE_ALIGNMENT-1U); + while (needed_alignment_mask >= size) + needed_alignment_mask>>= 1; + curBottomIndex&= needed_alignment_mask; + if (curBottomIndex) { + if ((needed_alignment_mask - curBottomIndex) >= (sizeCurrentSeg - size)) + goto NEXT_SEGMENT; + do { + size_t const cur_alignment= BOTTOM_BIT(curBottomIndex); + pushOntoFreeStore(BotFreePtr, cur_alignment); + 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 */ + TopFreePtr= stepPointer(TopFreePtr, -(ptrdiff_t)size); + ptr= TopFreePtr; } + sh= &SizeData[SIZEDATA_SIZE_TO_INDEX(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) { + size_t curBottomIndex= (size_t)pointerDifference(BotFreePtr,Arena[CurrentSeg]); + while (curBottomIndex & (NOT_MULTIPLE_ALIGNMENT-1U)) + { + size_t const cur_alignment= BOTTOM_BIT(curBottomIndex); + pushOntoFreeStore(BotFreePtr, cur_alignment); + BotFreePtr= stepPointer(BotFreePtr, (ptrdiff_t)cur_alignment); + curBottomIndex+= cur_alignment; + } + curBottomIndex= (size_t)pointerDifference(TopFreePtr,BotFreePtr); + if (curBottomIndex >= fxfMINSIZE) + { + assert(!(curBottomIndex & (NOT_MULTIPLE_ALIGNMENT - 1U))); + pushOntoFreeStore(BotFreePtr, curBottomIndex); + } + else if (curBottomIndex) + TMDBG(printf(" leaking %" SIZE_T_PRINTF_SPECIFIER " byte(s) moving from segment %d to segment %d\n", (size_t_printf_type)curBottomIndex, CurrentSeg, CurrentSeg+1)); 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); -#else /*SEGMENTED*/ - ptr= Nil(char); -#endif /*!SEGMENTED*/ - TMDBG(printf(" ptr:%p\n",(void *)ptr)); +#endif /*SEGMENTED*/ + { + ptr= Nil(void); + /* TODO: Should we try to break apart a larger chunk? */ + } + 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(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)); +#if defined(FXF_ENABLE_TMDBG) || !defined(NDEBUG) + ptrdiff_t ptrIndex; +#endif +#if defined(SEGMENTED) && (defined(FXF_ENABLE_TMDBG) || !defined(NDEBUG)) + 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) +# if defined(FXF_ENABLE_TMDBG) || !defined(NDEBUG) + 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= (ptrdiff_t)(tmp - segment_begin); + if (ARENA_SEG_SIZE > (size_t)ptrIndex) + goto FOUND_PUTATIVE_SEGMENT; + } + } while (0 <= --ptrSegment); + ptrIndex= -1; + } else { + ptrIndex= pointerDifference(ptr,Arena[0]); + assert((ptrIndex >= 0) && (ARENA_SEG_SIZE > (size_t)ptrIndex)); } +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)); +# endif /*FXF_ENABLE_TMDBG*/ +#else /*SEGMENTED*/ +# if defined(FXF_ENABLE_TMDBG) || !defined(NDEBUG) + ptrIndex= pointerDifference(ptr,Arena); +# endif + assert((ptrIndex >= 0) && (GlobalSize > (size_t)ptrIndex)); + 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 /*!SEGMENTED*/ + 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 - (size_t)ptrIndex)); + assert(((size + (size_t)ptrIndex) <= (size_t)pointerDifference(BotFreePtr,Arena)) || (ptr >= TopFreePtr)); +#endif + if (ptrIndex > 0) + { + size_t needed_alignment; + if (size&PTRMASK) + { + needed_alignment= NOT_MULTIPLE_ALIGNMENT; + while (needed_alignment > size) + needed_alignment>>= 1; + } + else + needed_alignment= MAX_ALIGNMENT; + assert(!(((size_t)ptrIndex) & (needed_alignment - 1U))); + } + } +#endif 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))); - --sh->MallocCount; + /* 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))); } else { - SetRange((char *)ptr-Arena,size); - *(char **)ALIGN(ptr)= sh->FreeHead; - sh->FreeHead= ptr; - ++sh->FreeCount; - --sh->MallocCount; - TMDBG(printf(" FreeCount:%lu",sh->FreeCount)); + pushOntoFreeStore(ptr, size); } } 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))); - --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)); + /* 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))); } + else + pushOntoFreeStore(ptr, size); } + sh= &SizeData[SIZEDATA_SIZE_TO_INDEX(size)]; + sh->MallocCount--; TMDBG(printf(" MallocCount:%lu",sh->MallocCount)); TMDBG(putchar('\n')); } -void *fxfReAlloc(void *ptr, size_t OldSize, size_t NewSize) { +void *fxfReAllocRaw(void *ptr, size_t OldSize, size_t NewSize, size_t desired_alignment) { void *nptr; + size_t original_allocation; if (!ptr) - return fxfAlloc(NewSize); + { + assert(!OldSize); + return fxfAllocRaw(NewSize, desired_alignment); + } + assert(OldSize && (OldSize <= fxfMAXSIZE)); +#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(ARENA_SEG_SIZE > (size_t)ptrIndex); +# else + { + ptrdiff_t const ptrIndex= pointerDifference(ptr,Arena); + assert(GlobalSize > (size_t)ptrIndex); +# endif + assert(ptrIndex >= 0); + if (ptrIndex > 0) + { + size_t allocatedSize= OldSize; + size_t needed_alignment; + if (allocatedSize < fxfMINSIZE) + allocatedSize= fxfMINSIZE; + else + { + assert(allocatedSize <= fxfMAXSIZE); + } + allocatedSize= ALIGN_TO_MINIMUM(allocatedSize); +# if defined(SEGMENTED) + assert(allocatedSize <= (ARENA_SEG_SIZE - (size_t)ptrIndex)); +# else + assert(allocatedSize <= (GlobalSize - (size_t)ptrIndex)); +# endif + if (allocatedSize&PTRMASK) + { + needed_alignment= NOT_MULTIPLE_ALIGNMENT; + while (needed_alignment > allocatedSize) + needed_alignment>>= 1; + } + else + needed_alignment= MAX_ALIGNMENT; + assert(!(((size_t)ptrIndex) & (needed_alignment - 1U))); + } + } +#endif + assert(desired_alignment && !CLEAR_BOTTOM_BIT(desired_alignment)); + assert(desired_alignment <= OldSize); if (!NewSize) + { fxfFree(ptr, OldSize); - nptr= fxfAlloc(NewSize); - if (NewSize && nptr) + return Nil(void); + } + assert(desired_alignment <= NewSize); + original_allocation= OldSize; + if (original_allocation < fxfMINSIZE) + original_allocation= fxfMINSIZE; + original_allocation= ALIGN_TO_MINIMUM(original_allocation); + if (NewSize <= original_allocation) + { + size_t needed_allocation= NewSize; + if (needed_allocation < fxfMINSIZE) + needed_allocation= fxfMINSIZE; + needed_allocation= ALIGN_TO_MINIMUM(needed_allocation); + if (needed_allocation == original_allocation) + return ptr; + /* TODO: Should we try to break apart this chunk? */ + } + nptr= fxfAllocRaw(NewSize, desired_alignment); + if (nptr) { memcpy(nptr, ptr, ((NewSize < OldSize) ? NewSize : OldSize)); fxfFree(ptr, OldSize); @@ -522,12 +905,11 @@ size_t fxfTotal(void) { size_t UsedBytes = 0; size_t FreeBytes = 0; - unsigned int i; - for (i=0; i<=fxfMAXSIZE; i++,hd++) { - if (hd->MallocCount+hd->FreeCount>0) { - UsedBytes+= hd->MallocCount*i; - FreeBytes+= hd->FreeCount*i; - } + size_t i; + for (i=0; i<((sizeof SizeData)/(sizeof *SizeData)); i++,hd++) { + size_t const cur_size= SIZEDATA_INDEX_TO_SIZE(i); + UsedBytes+= hd->MallocCount*cur_size; + FreeBytes+= hd->FreeCount*cur_size; } return UsedBytes+FreeBytes; @@ -535,11 +917,11 @@ 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) - - (ArenaSegCnt-CurrentSeg-1)*ARENA_SEG_SIZE + - ARENA_SEG_SIZE*(size_t)(ArenaSegCnt-CurrentSeg-1) #endif /*SEGMENTED*/ ; assert(GlobalSize/one_kilo<=ULONG_MAX); @@ -557,15 +939,16 @@ 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++) { - if (hd->MallocCount+hd->FreeCount>0) { - fprintf(f, "%12u %10lu%10lu\n", i, hd->MallocCount, hd->FreeCount); + for (i=0; i<((sizeof SizeData)/(sizeof *SizeData)); i++,hd++) { + if (hd->MallocCount || hd->FreeCount) { + size_t const cur_size= SIZEDATA_INDEX_TO_SIZE(i); + fprintf(f, "%12" SIZE_T_PRINTF_SPECIFIER " %10lu%10lu\n", (size_t_printf_type)cur_size, hd->MallocCount, hd->FreeCount); nrUsed+= hd->MallocCount; - UsedBytes+= hd->MallocCount*i; + UsedBytes+= hd->MallocCount*cur_size; nrFree+= hd->FreeCount; - FreeBytes+= hd->FreeCount*i; + FreeBytes+= hd->FreeCount*cur_size; } } fprintf(f, "%12s %10lu%10lu\n", "Total:", nrUsed, nrFree); @@ -577,4 +960,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..da27ceeda 100644 --- a/DHT/fxf.h +++ b/DHT/fxf.h @@ -2,14 +2,30 @@ #define FXF_H #include +#include -size_t fxfInit(size_t GlobalSize); /* returns the number of bytes actually allocated */ +#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) +# define ALIGNMENT_OF_TYPE(type) _Alignof(type) +#elif (defined(__cplusplus) && (__cplusplus >= 201103L)) +# define ALIGNMENT_OF_TYPE(type) alignof(type) +#else + /* This technique for getting a type's alignment is taken from Steve Jessop's comment at + https://stackoverflow.com/a/228015/1019990. + We take the bottom bit in case the calculated value is some multiple of the correct alignment; + this should at least be closer to the correct value. */ +# define ALIGNMENT_OF_TYPE(type) (offsetof(struct {unsigned char c; type t;}, t) & -offsetof(struct {unsigned char c; type t;}, t)) +#endif + +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 *fxfAllocRaw(size_t size, size_t desired_alignment); +void *fxfReAllocRaw(void *ptr, size_t OldSize, size_t NewSize, size_t desired_alignment); +#define fxfAlloc(size, type) ((type *) fxfAllocRaw(size, ALIGNMENT_OF_TYPE(type))) +#define fxfReAlloc(ptr, OldSize, NewSize, type) ((type *) fxfReAllocRaw(ptr, OldSize, NewSize, ALIGNMENT_OF_TYPE(type))) 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/makefile.defaults b/makefile.defaults index 9e104697b..f76fad3a6 100644 --- a/makefile.defaults +++ b/makefile.defaults @@ -102,12 +102,14 @@ VERSION=4.90 # Other # ----- -DEFS=$(DEFINEMACRO)SIGNALS $(DEFINEMACRO)MSG_IN_MEM $(DEFINEMACRO)FXF $(DEFINEMACRO)DOMEASURE +DEFS=$(DEFINEMACRO)SIGNALS $(DEFINEMACRO)MSG_IN_MEM $(DEFINEMACRO)FXF $(DEFINEMACRO)DOMEASURE $(DEFINEMACRO)FXF_MAX_ALIGNMENT_TYPE=void* $(DEFINEMACRO)FXF_NOT_MULTIPLE_ALIGNMENT_TYPE=short # $(DEFINEMACRO)DOMEASURE # $(DEFINEMACRO)TESTHASH # $(DEFINEMACRO)NDEBUG # $(DEFINEMACRO)DOTRACE # $(DEFINEMACRO)DOTRACECALLSTACK +# $(DEFINEMACRO)FXF_MAX_ALIGNMENT_TYPE=void* +# $(DEFINEMACRO)FXF_NOT_MULTIPLE_ALIGNMENT_TYPE=short # diff --git a/optimisations/hash.c b/optimisations/hash.c index a16fa2b10..87c59e1e7 100644 --- a/optimisations/hash.c +++ b/optimisations/hash.c @@ -42,11 +42,11 @@ ** 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. ** - ** When there is no more memory, or more than hash_max_number_storable_positions positions + ** When there is no more memory, or more than hash_max_kilo_storable_positions*1000 positions ** are stored in the hash-table, then some positions are removed ** from the table. This is done in the compress procedure. ** This procedure uses a little improved scheme introduced by Torsten. @@ -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() @@ -121,6 +121,10 @@ #include "platform/timer.h" #endif +enum { + ENSURE_MAX_LENGTH_FITS_IN_UNSIGNED_SHORT = 1/(MAX_LENGTH_OF_ENCODING <= USHRT_MAX) +}; + #if defined(FXF) unsigned long hash_max_kilo_storable_positions = ULONG_MAX; #endif @@ -151,6 +155,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]; @@ -249,26 +258,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 @@ -375,7 +364,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; @@ -654,17 +643,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); @@ -672,27 +661,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); @@ -702,28 +693,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); @@ -731,31 +724,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__); @@ -764,18 +758,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__); @@ -784,19 +777,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__); @@ -811,7 +803,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; @@ -821,7 +813,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(); @@ -845,14 +837,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(); @@ -872,14 +864,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(); @@ -915,13 +907,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) @@ -1340,7 +1326,8 @@ static byte *CommonEncode(byte *bp, if (min_length>slack_length+1) { - assert(validity_value<=(1<<2*CHAR_BIT)); + assert((((validity_value>>(CHAR_BIT-1))>>(CHAR_BIT-1))>>2)<2); /* Equivalent to assert(validity_value<=(1<<2*CHAR_BIT) but we don't have to worry about the shift overflowing. + TODO: Is this the right assertion? validity_value == 0x10000 would pass. */ *bp++ = (byte)(validity_value); *bp++ = (byte)(validity_value>>CHAR_BIT); } @@ -1348,6 +1335,7 @@ static byte *CommonEncode(byte *bp, { 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); } @@ -1416,7 +1404,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; @@ -1463,8 +1451,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, @@ -1625,7 +1613,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(); @@ -1706,8 +1694,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(); @@ -1717,7 +1705,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; @@ -1762,9 +1750,9 @@ static unsigned long allocCounter = 0; * @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); @@ -1781,11 +1769,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 defined(FXF) @@ -1888,7 +1876,8 @@ static boolean is_proofgame(slice_index si) boolean is_hashtable_allocated(void) { #if defined(FXF) - return fxfInitialised(); + 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 @@ -1915,7 +1904,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 */ @@ -1990,7 +1979,7 @@ static void inithash(slice_index si) if (hashtable_kilos>0 && hash_max_kilo_storable_positions==ULONG_MAX) hash_max_kilo_storable_positions= hashtable_kilos/(Large+sizeof(char *)+1); #endif - } + } } #if defined(FXF) @@ -2316,7 +2305,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; @@ -2325,18 +2314,16 @@ static void addtohash_battle_nosuccess(slice_index si, TraceFunctionParam("%u",min_length_adjusted); TraceFunctionParamListEnd(); + hb.value.object_pointer = &hashBuffers[nbply].cmv; 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__); TraceFunctionResultEnd(); @@ -2431,6 +2415,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; @@ -2448,23 +2433,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].cmv; + 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; @@ -2489,20 +2474,21 @@ void attack_hashed_tester_solve(slice_index si) TraceFunctionResultEnd(); } -static hashElement_union_t *find_or_add_help_elmt(HashBuffer const *hb) +static dhtElement *find_or_add_help_elmt(HashBuffer const *hb) { TraceFunctionEntry(__func__); TraceFunctionParam("%p",hb); TraceFunctionParamListEnd(); { - dhtElement * const he = dhtLookupElement(pyhash,hb); - hashElement_union_t * const result = (hashElement_union_t *)(he==dhtNilElement - ? allocDHTelement(hb) - : he); - + dhtKey k; + dhtElement *result; + k.value.object_pointer = &hb->cmv; + result = dhtLookupElement(pyhash,k); + if (result==dhtNilElement) + result = allocDHTelement(k); TraceFunctionExit(__func__); - TraceFunctionResult("%p",result); + TraceFunctionResult("%p",(void const *)result); TraceFunctionResultEnd(); return result; } @@ -2579,7 +2565,7 @@ static void addtohash_help_solved(slice_index si) #endif /*HASHRATE*/ } -static hashElement_union_t const *find_help_elmt_solved(HashBuffer *hb) +static dhtElement const *find_help_elmt_solved(HashBuffer *hb) { TraceFunctionEntry(__func__); TraceFunctionParam("%p",hb); @@ -2590,10 +2576,10 @@ static hashElement_union_t const *find_help_elmt_solved(HashBuffer *hb) hb->cmv.Data[hb->cmv.Leng-1] += (byte)2; { - dhtElement const * const he = dhtLookupElement(pyhash,hb); - hashElement_union_t const * const result = (he==dhtNilElement - ? 0 - : (hashElement_union_t const *)he); + dhtKey k; + dhtElement const *result; + k.value.object_pointer = &hb->cmv; + result = dhtLookupElement(pyhash,k); hb->cmv.Data[hb->cmv.Leng-1] -= (byte)2; @@ -2607,7 +2593,7 @@ static hashElement_union_t const *find_help_elmt_solved(HashBuffer *hb) static boolean is_position_known_to_be_solved(HashBuffer *hb, slice_index si) { boolean result; - hashElement_union_t const *hue_solved; + dhtElement const *hue_solved; TraceFunctionEntry(__func__); TraceFunctionParam("%p",hb); @@ -2660,20 +2646,19 @@ static void addtohash_help_not_solved(slice_index si) #endif /*HASHRATE*/ } -static hashElement_union_t const *find_help_elmt_not_solved(HashBuffer *hb) +static dhtElement const *find_help_elmt_not_solved(HashBuffer *hb) { TraceFunctionEntry(__func__); TraceFunctionParam("%p",hb); TraceFunctionParamListEnd(); { - dhtElement const *he = dhtLookupElement(pyhash,hb); - hashElement_union_t const * const result = (he==dhtNilElement - ? 0 - : (hashElement_union_t const *)he); - + dhtKey k; + dhtElement const *result; + k.value.object_pointer = &hb->cmv; + result = dhtLookupElement(pyhash,k); TraceFunctionExit(__func__); - TraceFunctionResult("%p",result); + TraceFunctionResult("%p",(void const *)result); TraceFunctionResultEnd(); return result; } @@ -2682,7 +2667,7 @@ static hashElement_union_t const *find_help_elmt_not_solved(HashBuffer *hb) static boolean is_position_known_not_to_be_solved(HashBuffer *hb, slice_index si) { boolean result; - hashElement_union_t const *hue_not_solved; + dhtElement const *hue_not_solved; TraceFunctionEntry(__func__); TraceFunctionParam("%p",hb); @@ -2715,7 +2700,7 @@ static boolean is_position_known_not_to_be_solved(HashBuffer *hb, slice_index si static boolean inhash_help(slice_index si) { boolean result; - HashBuffer * const hb = &hashBuffers[nbply]; + HashBuffer *hb; stip_length_type const validity_value = (solve_nr_remaining-1)/2+1; stip_length_type const min_length = SLICE_U(si).branch.min_length; @@ -2729,9 +2714,9 @@ static boolean inhash_help(slice_index si) /* Create a difference between odd and even numbers of moves. * A solution for h#n isn't necessarily a solution for h#n.5 */ - assert(hb->cmv.Lengcmv.Data[hashBuffers[nbply].cmv.Leng] = (byte)(min_length%2); - ++hb->cmv.Leng; + hb = &hashBuffers[nbply]; + assert(hb->cmv.Lengcmv.Data[hb->cmv.Leng++] = (byte)(min_length%2); ifHASHRATE(use_all++); @@ -2882,6 +2867,8 @@ void hash_opener_solve(slice_index si) /* 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 d370c87e0..238d434c1 100644 --- a/optimisations/hash.h +++ b/optimisations/hash.h @@ -12,7 +12,12 @@ #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" +#include "conditions/fuddled_men.h" #if defined(TESTHASH) # if !defined(HASHRATE) @@ -23,9 +28,129 @@ /* 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 * (2 + bytes_per_spec) + + CommonEncode + - SmallEncode = "num nonempty squares (found by looping over nr_rows_on_board and nr_files_on_board)" * SmallEncodePiece + + nr_ghosts * SmallEncodePiece + + CommonEncode + - TellLargeEncodePosLeng = TellCommonEncodePosLeng(len, nbr_p) + with + len = 8 + + "num nonempty squares (found by looping boardnum until 0 is found)" * bytes_per_piece + + !!CondFlag[BGL] * (sizeof BGL_values[White] + sizeof BGL_values[Black]) + + nr_ghosts * bytes_per_piece + nbr_p = "num nonempty squares (found by looping boardnum until 0 is found)" + - TellSmallEncodePosLeng = TellCommonEncodePosLeng(len, nbr_p) + with + len = "num nonempty squares (found by looping boardnum until 0 is found)" * (1 + bytes_per_piece) + + nr_ghosts * bytes_per_piece + nbr_p = "num nonempty squares (found by looping boardnum until 0 is found)" + TellCommonEncodePosLeng(len, np) is a strictly increasing function of len. SmallEncode will therefore be chosen iff + "num nonempty squares" <= 8 + !!CondFlag[BGL] * (sizeof BGL_values[White] + sizeof BGL_values[Black]). + Therefore: + - 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 when chosen: + - SmallEncode <= min((nr_rows_on_board * nr_files_on_board), (8 + sizeof BGL_values[White] + sizeof BGL_values[Black])) * SmallEncodePiece + + nr_ghosts * SmallEncodePiece + + CommonEncode + - LargeEncode <= nr_rows_on_board + + (nr_rows_on_board * nr_files_on_board) * LargeEncodePiece + + nr_ghosts * (2 + bytes_per_spec) + + 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 + + bytes_per_spec + + 1 + 2 + + en_passant_top[nbply] - en_passant_top[nbply-1] + + 1 + + sizeof BGL_values[White] + sizeof BGL_values[Black] + + 2 + + sizeof fuddled + Substituting yields: + - SmallEncode <= min((nr_rows_on_board * nr_files_on_board), (8 + sizeof BGL_values[White] + sizeof BGL_values[Black])) * (1 + 1 + bytes_per_spec) + + nr_ghosts * (1 + 1 + bytes_per_spec) + + CommonEncode + - LargeEncode <= nr_rows_on_board + + (nr_rows_on_board * nr_files_on_board) * (1 + bytes_per_spec) + + nr_ghosts * (2 + 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_NR_GHOSTS = underworld_capacity, + MAX_BYTES_PER_SPEC = 4, + MAX_NUMBER_OF_IMITATORS = maxinum, + 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 = 2 + 2 + 1 + 1 + 1 + + MAX_NUMBER_OF_IMITATORS + + 1 + 1 + 3 + 1 + + MAX_BYTES_PER_SPEC + + 1 + 2 + + MAX_EN_PASSANT_TOP_DIFFERENCE + + 1 + + sizeof BGL_values[White] + sizeof BGL_values[Black] + + 2 + + sizeof fuddled, + 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]), + NUM_NONEMPTY_SMALL = ((NUM_NONEMPTY_SMALL_FIRST < NUM_NONEMPTY_SMALL_SECOND) ? NUM_NONEMPTY_SMALL_FIRST : NUM_NONEMPTY_SMALL_SECOND), + SMALLENCODE_MAX = (NUM_NONEMPTY_SMALL * (1 + 1 + MAX_BYTES_PER_SPEC)) + + (MAX_NR_GHOSTS * (1 + 1 + MAX_BYTES_PER_SPEC)) + + COMMONENCODE_MAX, + LARGEENCODE_MAX = nr_rows_on_board + + ((nr_rows_on_board * nr_files_on_board) * (1 + MAX_BYTES_PER_SPEC)) + + (MAX_NR_GHOSTS * (1 + 1 + MAX_BYTES_PER_SPEC)) + + COMMONENCODE_MAX, + PROOFENCODE_MAX = nr_rows_on_board + + ((nr_rows_on_board * nr_files_on_board) * 2) + + 1 + + (MAX_NR_GHOSTS * (1 + 1 + MAX_BYTES_PER_SPEC)) + + 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 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)]