Blame src/xmap.cc

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
}