git-svn-id: svn://10.65.10.50/branches/R_10_00@23164 c028cbd2-c16b-5b4b-a496-9718f37d4682

This commit is contained in:
guy 2015-12-21 11:22:35 +00:00
parent 501a4cf167
commit 367940dd97
7 changed files with 391 additions and 33 deletions

View File

@ -42,7 +42,7 @@ THash_object* TAssoc_array::_lookup(
const word hv = key.hash() % HASH_SIZE;
TArray& arr = bucket(hv);
THash_object* o = NULL;
isnew = FALSE;
isnew = false;
int i;
for (i = 0; i < arr.items(); i++)
@ -62,7 +62,7 @@ THash_object* TAssoc_array::_lookup(
arr.insert(o,i);
_cnt++;
}
isnew = TRUE;
isnew = true;
}
return o;
@ -190,10 +190,7 @@ bool TAssoc_array::add(
o->_obj = obj;
}
else
{
NFCHECK("deleting duplicate hash object");
delete obj;
}
return true;
}
o->_obj = obj;
@ -212,19 +209,18 @@ bool TAssoc_array::add(const char* key, const TObject& obj, bool force)
*/
bool isnew = false;
THash_object* o = _lookup(key, isnew, true);
if (!isnew)
if (isnew)
{
if (force)
{
if (o->_obj != NULL)
delete o->_obj;
o->_obj = obj.dup();
}
return true;
o->_obj = obj.dup();
return false;
}
o->_obj = obj.dup();
return false;
if (force)
{
if (o->_obj != NULL)
delete o->_obj;
o->_obj = obj.dup();
}
return true;
}
// @doc EXTERNAL

View File

@ -15,9 +15,7 @@
//
// @base public | TObject
class THash_object : public TObject
// @author:(INTERNAL) Guido
// @author:(INTERNAL) Villa
{
// @cfriend TAssoc_array
friend class TAssoc_array;
@ -55,7 +53,7 @@ public:
// @base public |TObject
class TAssoc_array : public TContainer
// @author:(INTERNAL) Guido
// @author:(INTERNAL) Villa
//@access:(INTERNAL) Private Member
{

279
include/hashtable.cpp Normal file
View File

@ -0,0 +1,279 @@
#include <hashtable.h>
#define STRICT
#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
#include <windows.h>
#include <cassert>
struct THash_table::THashEntry
{
char* key;
unsigned int hash;
TObject* value;
THashEntry* next;
THashEntry(const char* key, unsigned int hash, TObject* value);
~THashEntry()
{
if (key) free(key);
if (value) delete value;
}
};
///////////////////////////////////////////////////////////
// Utilities
///////////////////////////////////////////////////////////
static inline unsigned int ELFHash(const char* str)
{
unsigned int hash = 0;
unsigned int x = 0;
for(const char* c = str; *c; c++)
{
hash = (hash << 4) + *c;
x = hash & 0xF0000000L;
if (x != 0)
{
hash ^= (x >> 24);
hash &= ~x;
}
}
return (hash & 0x7FFFFFFF);
}
static inline size_t calculateIndex(unsigned int bucketCount, unsigned int hash)
{ return ((size_t)hash) & (bucketCount - 1); }
///////////////////////////////////////////////////////////
// THash_table
///////////////////////////////////////////////////////////
void THash_table::expand_if_needed()
{
// If the load factor exceeds 0.5...
if (_size > (_bucketCount / 2))
{
const size_t newBucketCount = _bucketCount * 2;
THashEntry** newBuckets = (THashEntry**)calloc(newBucketCount, sizeof(THashEntry*));
if (newBuckets)
{
// Move over existing entries.
for (size_t i = 0; i < _bucketCount; i++)
{
THashEntry* entry = _buckets[i];
while (entry != NULL)
{
THash_table::THashEntry* next = entry->next;
const size_t index = ::calculateIndex(newBucketCount, entry->hash);
entry->next = newBuckets[index];
newBuckets[index] = entry;
entry = next;
}
}
// Copy over internals: _size remains untouched
free(_buckets);
_buckets = newBuckets;
_bucketCount = newBucketCount;
}
}
}
void THash_table::Lock()
{
while (::InterlockedCompareExchange(&_lock, 1, 0))
::Sleep(0);
}
void THash_table::Unlock()
{
::InterlockedDecrement(&_lock);
}
THash_table::~THash_table()
{
Lock();
for (size_t i = 0; i < _bucketCount; i++)
{
THashEntry* entry = _buckets[i];
while (entry != NULL)
{
THash_table::THashEntry* next = entry->next;
delete entry;
entry = next;
}
}
::free(_buckets);
}
THash_table::THashEntry::THashEntry(const char* str, unsigned int h, TObject* val)
{
CHECK(str && *str, "NULL hash key");
key = _strdup(str);
hash = h;
value = val;
next = NULL;
}
THash_table::THashEntry* THash_table::lookup_ex(const char* key, unsigned int& hash, size_t& index) const
{
hash = ELFHash(key);
index = calculateIndex(_bucketCount, hash);
THashEntry* entry = _buckets[index];
for (; entry; entry = entry->next)
{
if (entry->hash == hash && strcmp(entry->key, key)==0)
break;
}
return entry;
}
THash_table::THashEntry* THash_table::lookup(const char* key) const
{
unsigned int hash;
size_t index;
return lookup_ex(key, hash, index);
}
bool THash_table::add(const char* key, TObject* value, bool force)
{
Lock();
unsigned int hash;
size_t index;
THashEntry* current = lookup_ex(key, hash, index);
if (current)
{
if (force)
{
delete current->value;
current->value = value;
}
else
delete value;
}
else
{
THashEntry* new_entry = new THashEntry(key, hash, value);
new_entry->next = _buckets[index];
_buckets[index] = new_entry;
_size++;
}
Unlock();
return current != NULL;
}
bool THash_table::add(const char* key, const TObject& value, bool force)
{
Lock();
unsigned int hash;
size_t index;
THashEntry* current = lookup_ex(key, hash, index);
if (current)
{
if (force)
{
delete current->value;
current->value = value.dup();
}
}
else
{
THashEntry* new_entry = new THashEntry(key, hash, value.dup());
new_entry->next = _buckets[index];
_buckets[index] = new_entry;
_size++;
}
Unlock();
return current != NULL;
}
TObject* THash_table::get(const char* key)
{
THashEntry* entry = lookup(key);
return entry ? entry->value : NULL;
}
TObject* THash_table::remove(const char* key)
{
Lock();
unsigned int hash;
size_t index;
THash_table::THashEntry* e = lookup_ex(key, hash, index);
if (e)
{
TObject* value = NULL;
// Pointer to the current THashEntry.
THashEntry** p = &(_buckets[index]);
THashEntry* current;
while ((current = *p) != NULL)
{
if (current == e)
{
value = current->value;
current->value = NULL;
p = &current->next;
delete current;
_size--;
break;
}
p = &current->next;
}
}
Unlock();
return e ? e->value : NULL;
}
bool THash_table::destroy(const char* key)
{
TObject* o = remove(key);
if (o) delete o;
return o != NULL;
}
THash_table::THash_table(size_t initialCapacity)
{
_bucketCount = 8;
// Bucket count must be power of 2.
while (_bucketCount <= initialCapacity)
_bucketCount *= 2;
_buckets = (THashEntry**)calloc(_bucketCount, sizeof(THashEntry*));
assert(_buckets != NULL);
_size = 0;
_lock = 0;
_curr_bucket = 0;
_curr_entry = NULL;
}
TObject* THash_table::succ_item()
{
for (;;)
{
while (_curr_entry)
{
TObject* obj = _curr_entry->value;
_curr_entry = _curr_entry->next;
if (obj)
return obj;
}
if (++_curr_bucket >= _bucketCount)
break;
_curr_entry = _buckets[_curr_bucket];
}
return NULL;
}
TObject* THash_table::first_item()
{
_curr_bucket = -1;
_curr_entry = NULL;
return succ_item();
}
TObject* THash_table::last_item()
{ return first_item(); }
TObject* THash_table::pred_item()
{ return succ_item(); }

47
include/hashtable.h Normal file
View File

@ -0,0 +1,47 @@
#pragma once
#ifndef __HASHTABLE_H__
#define __HASHTABLE_H__
#ifndef __ARRAY_H__
#include <array.h>
#endif
class THash_table : public TContainer
{
struct THashEntry;
THashEntry** _buckets;
size_t _bucketCount, _size;
volatile unsigned int _lock;
// container iterator
size_t _curr_bucket;
THashEntry* _curr_entry;
protected:
THashEntry* lookup_ex(const char* key, unsigned int& hash, size_t& index) const;
THashEntry* lookup(const char* key) const;
void expand_if_needed();
void Lock();
void Unlock();
public: // Container interface
virtual TObject* first_item();
virtual TObject* last_item();
virtual TObject* succ_item();
virtual TObject* pred_item();
virtual long objects() const { return _size; }
public:
bool add(const char* key, TObject* value, bool force = false);
bool add(const char* key, const TObject& value, bool force = false);
bool is_key(const char* key) const { return lookup(key) != NULL; }
TObject* get(const char* key);
TObject* remove(const char* key);
bool destroy(const char* key);
size_t items() const { return _size; }
THash_table(size_t sz = 0);
~THash_table();
};
#endif

View File

@ -1003,9 +1003,46 @@ void TRelation_application::edit_cancel()
}
}
short TRelation_application::mask_field_dirty() const
{
short id = 0;
if (_mask)
{
const int mode = _mask->mode();
if (mode == MODE_QUERY)
{
FOR_EACH_MASK_FIELD(*_mask, i, f)
{
if (f->dirty() && f->active())
{
id = f->dlg();
break;
}
}
}
else
{
FOR_EACH_MASK_FIELD(*_mask, i, f)
{
if (f->dirty() && f->active() && f->field())
{
if (id == 0)
id = f->dlg();
if (f->dirty() > 1) // error on field content
{
id = f->dlg();
break;
}
}
}
}
}
return id;
}
bool TRelation_application::save(bool check_dirty)
{
static bool was_dirty = FALSE;
static bool was_dirty = false;
int pos = _mask->id2pos(DLG_SAVEREC);
if (pos < 0 || !_mask->fld(pos).active())
@ -1018,7 +1055,7 @@ bool TRelation_application::save(bool check_dirty)
const int mode = _mask->mode();
if (check_dirty)
{
const short dirty = _mask->dirty();
const short dirty = mask_field_dirty();
if (mode == MODE_QUERY)
{
@ -1090,26 +1127,26 @@ bool TRelation_application::save(bool check_dirty)
if (!ff.on_key(K_TAB))
{
_mask->first_focus(-ff.dlg());
was_dirty = TRUE;
return FALSE;
was_dirty = true;
return false;
}
}
if (!_mask->check_fields()) // Exit with ESC didn't check values
if (!_mask->check_fields()) // Exit with ESC didn't check values
{
// check_fields sets the focus on the blocking field
_mask->first_focus(-_mask->focus_field().dlg());
was_dirty = TRUE;
return FALSE;
was_dirty = true;
return false;
}
}
}
was_dirty = FALSE;
was_dirty = false;
TWait_cursor hourglass;
if (mode == MODE_INS)
{
bool changed = TRUE;
bool changed_key = FALSE;
bool changed = true;
bool changed_key = false;
while (changed)
{

View File

@ -110,6 +110,7 @@ private:
// @cmember:(INTERNAL) Sistema il bottone ricerca se necessario
void set_find_button();
short mask_field_dirty() const;
// @access Protected Member
protected: // TApplication

View File

@ -132,11 +132,11 @@ public: // TObject
void replacef(TLocalisamfile* f, int lognum = 0,const char * relexprs="",int key=1);
// @cmember Aggiunge il record corrente
virtual int write (bool force = TRUE);
virtual int write (bool force = true);
// @cmember Riscrive il record corrente
virtual int rewrite (bool force = TRUE);
virtual int rewrite (bool force = true);
// @cmember Elimina il record corrente
virtual int remove ();
virtual int remove();
// @cmember Controlla se e' stata raggiunta la fine del file
// (se <p logicnum> = 0 dell'intera relazione, altrimenti del file indicato )