|
Packit |
8f70b4 |
/*
|
|
Packit |
8f70b4 |
* lftp - file transfer program
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* Copyright (c) 1996-2016 by Alexander V. Lukyanov (lav@yars.free.net)
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
8f70b4 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
8f70b4 |
* the Free Software Foundation; either version 3 of the License, or
|
|
Packit |
8f70b4 |
* (at your option) any later version.
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
8f70b4 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
8f70b4 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
8f70b4 |
* GNU General Public License for more details.
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
8f70b4 |
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
8f70b4 |
*/
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include <config.h>
|
|
Packit |
8f70b4 |
#include <assert.h>
|
|
Packit |
8f70b4 |
#include "xmap.h"
|
|
Packit |
8f70b4 |
#include <stdio.h>
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void _xmap::new_map()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
map.get_space(hash_size,1);
|
|
Packit |
8f70b4 |
map.set_length(hash_size);
|
|
Packit |
8f70b4 |
for(int i=0; i
|
|
Packit |
8f70b4 |
map[i]=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
_xmap::_xmap(int vs)
|
|
Packit |
8f70b4 |
: value_size(vs)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
entry_count=0;
|
|
Packit |
8f70b4 |
hash_size=1;
|
|
Packit |
8f70b4 |
new_map();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void _xmap::_empty()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
for(int i=0; i
|
|
Packit |
8f70b4 |
while(map[i])
|
|
Packit |
8f70b4 |
_remove(&map[i]);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
assert(entry_count==0);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
_xmap::~_xmap()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
_empty();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int _xmap::make_hash(const xstring& s) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(hash_size==1)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
unsigned hash=0x12345678;
|
|
Packit |
8f70b4 |
for(unsigned i=0; i
|
|
Packit |
8f70b4 |
hash+=(hash<<5)+s[i];
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
hash+=(hash<<5)+s.length();
|
|
Packit |
8f70b4 |
hash%=hash_size;
|
|
Packit |
8f70b4 |
return hash;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
_xmap::entry **_xmap::_lookup(const xstring& key)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int hash=make_hash(key);
|
|
Packit |
8f70b4 |
entry **ep=&map[hash];
|
|
Packit |
8f70b4 |
entry *e=*ep;
|
|
Packit |
8f70b4 |
while(e) {
|
|
Packit |
8f70b4 |
if(e->key.eq(key))
|
|
Packit |
8f70b4 |
return ep;
|
|
Packit |
8f70b4 |
ep=&e->next;
|
|
Packit |
8f70b4 |
e=*ep;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return ep;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
_xmap::entry *_xmap::_lookup_c(const xstring& key) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
for(entry *e=map[make_hash(key)]; e; e=e->next) {
|
|
Packit |
8f70b4 |
if(e->key.eq(key))
|
|
Packit |
8f70b4 |
return e;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void _xmap::rebuild_map()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
static const int primes[]={
|
|
Packit |
8f70b4 |
17,67,257,1031,4099,16411,65537,262147,1048583,4194319,16777259,
|
|
Packit |
8f70b4 |
67108879,268435459,1073741827
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
hash_size=entry_count*2;
|
|
Packit |
8f70b4 |
// a prime is better, find it.
|
|
Packit |
8f70b4 |
for(unsigned pi=0; pi
|
|
Packit |
8f70b4 |
if(hash_size
|
|
Packit |
8f70b4 |
hash_size=primes[pi];
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
xarray_p<_xmap::entry> old_map;
|
|
Packit |
8f70b4 |
old_map.move_here(map);
|
|
Packit |
8f70b4 |
new_map();
|
|
Packit |
8f70b4 |
for(int i=0; i
|
|
Packit |
8f70b4 |
entry *e=old_map[i];
|
|
Packit |
8f70b4 |
old_map[i]=0;
|
|
Packit |
8f70b4 |
while(e) {
|
|
Packit |
8f70b4 |
entry *next=e->next;
|
|
Packit |
8f70b4 |
int hash=make_hash(e->key);
|
|
Packit |
8f70b4 |
e->next=map[hash];
|
|
Packit |
8f70b4 |
map[hash]=e;
|
|
Packit |
8f70b4 |
e=next;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
_xmap::entry *_xmap::_add(const xstring& key)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
entry **ep=_lookup(key);
|
|
Packit |
8f70b4 |
if(*ep==0) {
|
|
Packit |
8f70b4 |
entry *n=(entry*)xmalloc(sizeof(entry)+value_size);
|
|
Packit |
8f70b4 |
memset(n,0,sizeof(entry)+value_size);
|
|
Packit |
8f70b4 |
n->next=0;
|
|
Packit |
8f70b4 |
n->key.set(key);
|
|
Packit |
8f70b4 |
*ep=n;
|
|
Packit |
8f70b4 |
entry_count++;
|
|
Packit |
8f70b4 |
if(entry_count>hash_size*2)
|
|
Packit |
8f70b4 |
rebuild_map();
|
|
Packit |
8f70b4 |
return n;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return *ep;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void _xmap::_remove(entry **ep)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!ep || !*ep)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
entry *e=*ep;
|
|
Packit |
8f70b4 |
e->key.unset();
|
|
Packit |
8f70b4 |
*ep=e->next;
|
|
Packit |
8f70b4 |
xfree(e);
|
|
Packit |
8f70b4 |
entry_count--;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
_xmap::entry *_xmap::_each_begin()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
each_entry=0;
|
|
Packit |
8f70b4 |
each_hash=-1;
|
|
Packit |
8f70b4 |
return _each_next();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
_xmap::entry *_xmap::_each_next()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
while(each_hash
|
|
Packit |
8f70b4 |
entry *e=each_entry;
|
|
Packit |
8f70b4 |
if(e) {
|
|
Packit |
8f70b4 |
last_entry=e;
|
|
Packit |
8f70b4 |
each_entry=e->next;
|
|
Packit |
8f70b4 |
return e;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
each_entry=map[++each_hash];
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
last_entry=0;
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void _xmap::_move_here(_xmap &o)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
value_size=o.value_size;
|
|
Packit |
8f70b4 |
hash_size=o.hash_size;
|
|
Packit |
8f70b4 |
entry_count=o.entry_count;
|
|
Packit |
8f70b4 |
map.move_here(o.map);
|
|
Packit |
8f70b4 |
o.hash_size=1;
|
|
Packit |
8f70b4 |
o.entry_count=0;
|
|
Packit |
8f70b4 |
o.new_map();
|
|
Packit |
8f70b4 |
}
|