compiled Community.CsharpSqlite.dll for target AnyCPU, added source code
This commit is contained in:
1 parent
5b87c37e3a
commit
b4d155a5a3
93 files changed
+121260
-2
No files matched your search
@@ -0,0 +1,363 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
|
||||
using u8 = System.Byte;
|
||||
using u32 = System.UInt32;
|
||||
|
||||
namespace Community.CsharpSqlite
|
||||
{
|
||||
public partial class Sqlite3
|
||||
{
|
||||
/*
|
||||
** 2001 September 22
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** This is the implementation of generic hash-tables
|
||||
** used in SQLite.
|
||||
*************************************************************************
|
||||
** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
|
||||
** C#-SQLite is an independent reimplementation of the SQLite software library
|
||||
**
|
||||
** SQLITE_SOURCE_ID: 2010-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3
|
||||
**
|
||||
*************************************************************************
|
||||
*/
|
||||
//#include "sqliteInt.h"
|
||||
//#include <assert.h>
|
||||
|
||||
/* Turn bulk memory into a hash table object by initializing the
|
||||
** fields of the Hash structure.
|
||||
**
|
||||
** "pNew" is a pointer to the hash table that is to be initialized.
|
||||
*/
|
||||
static void sqlite3HashInit( Hash pNew )
|
||||
{
|
||||
Debug.Assert( pNew != null );
|
||||
pNew.first = null;
|
||||
pNew.count = 0;
|
||||
pNew.htsize = 0;
|
||||
pNew.ht = null;
|
||||
}
|
||||
|
||||
/* Remove all entries from a hash table. Reclaim all memory.
|
||||
** Call this routine to delete a hash table or to reset a hash table
|
||||
** to the empty state.
|
||||
*/
|
||||
static void sqlite3HashClear( Hash pH )
|
||||
{
|
||||
HashElem elem; /* For looping over all elements of the table */
|
||||
|
||||
Debug.Assert( pH != null );
|
||||
elem = pH.first;
|
||||
pH.first = null;
|
||||
//sqlite3_free( ref pH.ht );
|
||||
pH.ht = null;
|
||||
pH.htsize = 0;
|
||||
while ( elem != null )
|
||||
{
|
||||
HashElem next_elem = elem.next;
|
||||
////sqlite3_free(ref elem );
|
||||
elem = next_elem;
|
||||
}
|
||||
pH.count = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** The hashing function.
|
||||
*/
|
||||
static u32 strHash( string z, int nKey )
|
||||
{
|
||||
int h = 0;
|
||||
Debug.Assert( nKey >= 0 );
|
||||
int _z = 0;
|
||||
while ( nKey > 0 )
|
||||
{
|
||||
h = ( h << 3 ) ^ h ^ ( ( _z < z.Length ) ? (int)sqlite3UpperToLower[(byte)z[_z++]] : 0 );
|
||||
nKey--;
|
||||
}
|
||||
return (u32)h;
|
||||
}
|
||||
|
||||
/* Link pNew element into the hash table pH. If pEntry!=0 then also
|
||||
** insert pNew into the pEntry hash bucket.
|
||||
*/
|
||||
static void insertElement(
|
||||
Hash pH, /* The complete hash table */
|
||||
_ht pEntry, /* The entry into which pNew is inserted */
|
||||
HashElem pNew /* The element to be inserted */
|
||||
)
|
||||
{
|
||||
HashElem pHead; /* First element already in pEntry */
|
||||
if ( pEntry != null )
|
||||
{
|
||||
pHead = pEntry.count != 0 ? pEntry.chain : null;
|
||||
pEntry.count++;
|
||||
pEntry.chain = pNew;
|
||||
}
|
||||
else
|
||||
{
|
||||
pHead = null;
|
||||
}
|
||||
if ( pHead != null )
|
||||
{
|
||||
pNew.next = pHead;
|
||||
pNew.prev = pHead.prev;
|
||||
if ( pHead.prev != null )
|
||||
{
|
||||
pHead.prev.next = pNew;
|
||||
}
|
||||
else
|
||||
{
|
||||
pH.first = pNew;
|
||||
}
|
||||
pHead.prev = pNew;
|
||||
}
|
||||
else
|
||||
{
|
||||
pNew.next = pH.first;
|
||||
if ( pH.first != null )
|
||||
{
|
||||
pH.first.prev = pNew;
|
||||
}
|
||||
pNew.prev = null;
|
||||
pH.first = pNew;
|
||||
}
|
||||
}
|
||||
|
||||
/* Resize the hash table so that it cantains "new_size" buckets.
|
||||
**
|
||||
** The hash table might fail to resize if sqlite3_malloc() fails or
|
||||
** if the new size is the same as the prior size.
|
||||
** Return TRUE if the resize occurs and false if not.
|
||||
*/
|
||||
static bool rehash( ref Hash pH, u32 new_size )
|
||||
{
|
||||
_ht[] new_ht; /* The new hash table */
|
||||
HashElem elem;
|
||||
HashElem next_elem; /* For looping over existing elements */
|
||||
|
||||
#if SQLITE_MALLOC_SOFT_LIMIT
|
||||
if( new_size*sizeof(struct _ht)>SQLITE_MALLOC_SOFT_LIMIT ){
|
||||
new_size = SQLITE_MALLOC_SOFT_LIMIT/sizeof(struct _ht);
|
||||
}
|
||||
if( new_size==pH->htsize ) return false;
|
||||
#endif
|
||||
|
||||
/* There is a call to sqlite3Malloc() inside rehash(). If there is
|
||||
** already an allocation at pH.ht, then if this malloc() fails it
|
||||
** is benign (since failing to resize a hash table is a performance
|
||||
** hit only, not a fatal error).
|
||||
*/
|
||||
sqlite3BeginBenignMalloc();
|
||||
new_ht = new _ht[new_size]; //(struct _ht )sqlite3Malloc( new_size*sizeof(struct _ht) );
|
||||
for ( int i = 0; i < new_size; i++ )
|
||||
new_ht[i] = new _ht();
|
||||
sqlite3EndBenignMalloc();
|
||||
|
||||
if ( new_ht == null )
|
||||
return false;
|
||||
//sqlite3_free( ref pH.ht );
|
||||
pH.ht = new_ht;
|
||||
// pH.htsize = new_size = sqlite3MallocSize(new_ht)/sizeof(struct _ht);
|
||||
//memset(new_ht, 0, new_size*sizeof(struct _ht));
|
||||
pH.htsize = new_size;
|
||||
|
||||
for ( elem = pH.first, pH.first = null; elem != null; elem = next_elem )
|
||||
{
|
||||
u32 h = strHash( elem.pKey, elem.nKey ) % new_size;
|
||||
next_elem = elem.next;
|
||||
insertElement( pH, new_ht[h], elem );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* This function (for internal use only) locates an element in an
|
||||
** hash table that matches the given key. The hash for this key has
|
||||
** already been computed and is passed as the 4th parameter.
|
||||
*/
|
||||
static HashElem findElementGivenHash(
|
||||
Hash pH, /* The pH to be searched */
|
||||
string pKey, /* The key we are searching for */
|
||||
int nKey, /* Bytes in key (not counting zero terminator) */
|
||||
u32 h /* The hash for this key. */
|
||||
)
|
||||
{
|
||||
HashElem elem; /* Used to loop thru the element list */
|
||||
int count; /* Number of elements left to test */
|
||||
|
||||
if ( pH.ht != null && pH.ht[h] != null )
|
||||
{
|
||||
_ht pEntry = pH.ht[h];
|
||||
elem = pEntry.chain;
|
||||
count = (int)pEntry.count;
|
||||
}
|
||||
else
|
||||
{
|
||||
elem = pH.first;
|
||||
count = (int)pH.count;
|
||||
}
|
||||
while ( count-- > 0 && ALWAYS( elem ) )
|
||||
{
|
||||
if ( elem.nKey == nKey && elem.pKey.Equals( pKey, StringComparison.InvariantCultureIgnoreCase ) )
|
||||
{
|
||||
return elem;
|
||||
}
|
||||
elem = elem.next;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* Remove a single entry from the hash table given a pointer to that
|
||||
** element and a hash on the element's key.
|
||||
*/
|
||||
static void removeElementGivenHash(
|
||||
Hash pH, /* The pH containing "elem" */
|
||||
ref HashElem elem, /* The element to be removed from the pH */
|
||||
u32 h /* Hash value for the element */
|
||||
)
|
||||
{
|
||||
_ht pEntry;
|
||||
if ( elem.prev != null )
|
||||
{
|
||||
elem.prev.next = elem.next;
|
||||
}
|
||||
else
|
||||
{
|
||||
pH.first = elem.next;
|
||||
}
|
||||
if ( elem.next != null )
|
||||
{
|
||||
elem.next.prev = elem.prev;
|
||||
}
|
||||
if ( pH.ht != null && pH.ht[h] != null )
|
||||
{
|
||||
pEntry = pH.ht[h];
|
||||
if ( pEntry.chain == elem )
|
||||
{
|
||||
pEntry.chain = elem.next;
|
||||
}
|
||||
pEntry.count--;
|
||||
Debug.Assert( pEntry.count >= 0 );
|
||||
}
|
||||
//sqlite3_free( ref elem );
|
||||
pH.count--;
|
||||
if ( pH.count <= 0 )
|
||||
{
|
||||
Debug.Assert( pH.first == null );
|
||||
Debug.Assert( pH.count == 0 );
|
||||
sqlite3HashClear( pH );
|
||||
}
|
||||
}
|
||||
|
||||
/* Attempt to locate an element of the hash table pH with a key
|
||||
** that matches pKey,nKey. Return the data for this element if it is
|
||||
** found, or NULL if there is no match.
|
||||
*/
|
||||
static T sqlite3HashFind<T>( Hash pH, string pKey, int nKey, T nullType ) where T : class
|
||||
{
|
||||
HashElem elem; /* The element that matches key */
|
||||
u32 h; /* A hash on key */
|
||||
|
||||
Debug.Assert( pH != null );
|
||||
Debug.Assert( pKey != null );
|
||||
Debug.Assert( nKey >= 0 );
|
||||
if ( pH.ht != null )
|
||||
{
|
||||
h = strHash( pKey, nKey ) % pH.htsize;
|
||||
}
|
||||
else
|
||||
{
|
||||
h = 0;
|
||||
}
|
||||
elem = findElementGivenHash( pH, pKey, nKey, h );
|
||||
return elem != null ? (T)elem.data : nullType;
|
||||
}
|
||||
|
||||
/* Insert an element into the hash table pH. The key is pKey,nKey
|
||||
** and the data is "data".
|
||||
**
|
||||
** If no element exists with a matching key, then a new
|
||||
** element is created and NULL is returned.
|
||||
**
|
||||
** If another element already exists with the same key, then the
|
||||
** new data replaces the old data and the old data is returned.
|
||||
** The key is not copied in this instance. If a malloc fails, then
|
||||
** the new data is returned and the hash table is unchanged.
|
||||
**
|
||||
** If the "data" parameter to this function is NULL, then the
|
||||
** element corresponding to "key" is removed from the hash table.
|
||||
*/
|
||||
static T sqlite3HashInsert<T>( ref Hash pH, string pKey, int nKey, T data ) where T : class
|
||||
{
|
||||
u32 h; /* the hash of the key modulo hash table size */
|
||||
|
||||
HashElem elem; /* Used to loop thru the element list */
|
||||
HashElem new_elem; /* New element added to the pH */
|
||||
|
||||
Debug.Assert( pH != null );
|
||||
Debug.Assert( pKey != null );
|
||||
Debug.Assert( nKey >= 0 );
|
||||
|
||||
if ( pH.htsize != 0 )
|
||||
{
|
||||
h = strHash( pKey, nKey ) % pH.htsize;
|
||||
}
|
||||
else
|
||||
{
|
||||
h = 0;
|
||||
}
|
||||
elem = findElementGivenHash( pH, pKey, nKey, h );
|
||||
if ( elem != null )
|
||||
{
|
||||
T old_data = (T)elem.data;
|
||||
if ( data == null )
|
||||
{
|
||||
removeElementGivenHash( pH, ref elem, h );
|
||||
}
|
||||
else
|
||||
{
|
||||
elem.data = data;
|
||||
elem.pKey = pKey;
|
||||
Debug.Assert( nKey == elem.nKey );
|
||||
}
|
||||
return old_data;
|
||||
}
|
||||
if ( data == null )
|
||||
return data;
|
||||
new_elem = new HashElem();//(HashElem)sqlite3Malloc( sizeof(HashElem) );
|
||||
if ( new_elem == null )
|
||||
return data;
|
||||
new_elem.pKey = pKey;
|
||||
new_elem.nKey = nKey;
|
||||
new_elem.data = data;
|
||||
pH.count++;
|
||||
if ( pH.count >= 10 && pH.count > 2 * pH.htsize )
|
||||
{
|
||||
if ( rehash( ref pH, pH.count * 2 ) )
|
||||
{
|
||||
Debug.Assert( pH.htsize > 0 );
|
||||
h = strHash( pKey, nKey ) % pH.htsize;
|
||||
}
|
||||
}
|
||||
if ( pH.ht != null )
|
||||
{
|
||||
insertElement( pH, pH.ht[h], new_elem );
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
insertElement( pH, null, new_elem );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user