/*
*
* gengraph - generation of random simple connected graphs with prescribed
* degree sequence
*
* Copyright (C) 2006 Fabien Viger
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef HASH_H
#define HASH_H
#include
#include "gengraph_definitions.h"
//_________________________________________________________________________
// Hash table profiling... Active only if definition below is uncommented
//_________________________________________________________________________
//#define _HASH_PROFILE
namespace gengraph {
#ifdef _HASH_PROFILE
void _hash_add_iter();
void _hash_add_call();
void _hash_put_iter();
void _hash_put_call();
void _hash_rm_iter();
void _hash_rm_call();
void _hash_find_iter();
void _hash_find_call();
void _hash_rand_iter();
void _hash_rand_call();
void _hash_expand_call();
void _hash_prof();
#define _HASH_ADD_ITER() _hash_add_iter()
#define _HASH_ADD_CALL() _hash_add_call()
#define _HASH_PUT_ITER() _hash_put_iter()
#define _HASH_PUT_CALL() _hash_put_call()
#define _HASH_RM_ITER() _hash_rm_iter()
#define _HASH_RM_CALL() _hash_rm_call()
#define _HASH_FIND_ITER() _hash_find_iter()
#define _HASH_FIND_CALL() _hash_find_call()
#define _HASH_RAND_ITER() _hash_rand_iter()
#define _HASH_RAND_CALL() _hash_rand_call()
#define _HASH_EXP_CALL() _hash_expand_call()
#else
#define _HASH_ADD_ITER() {}
#define _HASH_ADD_CALL() {}
#define _HASH_PUT_ITER() {}
#define _HASH_PUT_CALL() {}
#define _HASH_RM_ITER() {}
#define _HASH_RM_CALL() {}
#define _HASH_FIND_ITER() {}
#define _HASH_FIND_CALL() {}
#define _HASH_RAND_ITER() {}
#define _HASH_RAND_CALL() {}
#define _HASH_EXP_CALL() {}
#endif
//_________________________________________________________________________
// Hash Table properties. Works best when HASH_SIZE_IS_POWER2 is uncommented
// but takes 2.25 times the needed space, in average (from 1.5 to 3)
// If you have memory issues, Try to comment it: tables will take 1.5 times
// the minimal space
//_________________________________________________________________________
#define HASH_SIZE_IS_POWER2
#define MACRO_RATHER_THAN_INLINE
// under HASH_MIN_SIZE, vectors are not hash table (just a simle array)
#define HASH_MIN_SIZE 100
#define IS_HASH(x) ((x)>HASH_MIN_SIZE)
#define HASH_NONE (-1)
#ifdef HASH_SIZE_IS_POWER2
inline int HASH_EXPAND(int x) {
_HASH_EXP_CALL();
x += x;
x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16;
return x + 1;
}
#define HASH_KEY(x,size) ((x*2198737)&((size)-1))
#endif //HASH_SIZE_IS_POWER2
#ifdef MACRO_RATHER_THAN_INLINE
#ifndef HASH_SIZE_IS_POWER2
#define HASH_EXPAND(x) ((x)+((x)>>1))
#define HASH_UNEXPAND(x) ((((x)<<1)+1)/3)
#define HASH_KEY(x,size) ((x)%(size))
#endif //HASH_SIZE_IS_POWER2
#define HASH_SIZE(x) (IS_HASH(x) ? HASH_EXPAND(x) : (x) )
#define HASH_REKEY(k,size) ((k)==0 ? (size)-1 : (k)-1)
#else //MACRO_RATHER_THAN_INLINE
#ifndef HASH_SIZE_IS_POWER2
inline int HASH_KEY(const int x, const int size) {
assert(x >= 0);
return x % size;
};
inline int HASH_EXPAND(const int x) {
_HASH_EXP_CALL();
return x + (x >> 1);
};
inline int HASH_UNEXPAND(const int x) {
return ((x << 1) + 1) / 3;
};
#endif //HASH_SIZE_IS_POWER2
inline int HASH_REKEY(const int k, const int s) {
assert(k >= 0);
if (k == 0) {
return s - 1;
} else {
return k - 1;
}
};
inline int HASH_SIZE(const int x) {
if (IS_HASH(x)) {
return HASH_EXPAND(x);
} else {
return x;
}
};
#endif //MACRO_RATHER_THAN_INLINE
inline int HASH_PAIR_KEY(const int x, const int y, const int size) {
return HASH_KEY(x * 1434879443 + y, size);
}
//_________________________________________________________________________
// Hash-only functions : table must NOT be Raw.
// the argument 'size' is the total size of the hash table
//_________________________________________________________________________
// copy hash table into raw vector
inline void H_copy(int *mem, int *h, int size) {
for (int i = HASH_EXPAND(size); i--; h++) if (*h != HASH_NONE) {
*(mem++) = *h;
}
}
// Look for the place to add an element. Return NULL if element is already here.
inline int* H_add(int* h, const int size, int a) {
_HASH_ADD_CALL();
_HASH_ADD_ITER();
int k = HASH_KEY(a, size);
if (h[k] == HASH_NONE) {
return h + k;
}
while (h[k] != a) {
_HASH_ADD_ITER();
k = HASH_REKEY(k, size);
if (h[k] == HASH_NONE) {
return h + k;
}
}
return NULL;
}
// would element be well placed in newk ?
inline bool H_better(const int a, const int size, const int currentk, const int newk) {
int k = HASH_KEY(a, size);
if (newk < currentk) {
return (k < currentk && k >= newk);
} else {
return (k < currentk || k >= newk);
}
}
// removes h[k]
inline void H_rm(int* h, const int size, int k) {
_HASH_RM_CALL();
int lasthole = k;
do {
_HASH_RM_ITER();
k = HASH_REKEY(k, size);
int next = h[k];
if (next == HASH_NONE) {
break;
}
if (H_better(next, size, k, lasthole)) {
h[lasthole] = next;
lasthole = k;
}
} while (true);
h[lasthole] = HASH_NONE;
}
//put a
inline int* H_put(int* h, const int size, const int a) {
assert(H_add(h, size, a) != NULL);
_HASH_PUT_CALL();
_HASH_PUT_ITER();
int k = HASH_KEY(a, size);
while (h[k] != HASH_NONE) {
k = HASH_REKEY(k, size);
_HASH_PUT_ITER();
}
h[k] = a;
assert(H_add(h, size, a) == NULL);
return h + k;
}
// find A
inline int H_find(int *h, int size, const int a) {
assert(H_add(h, size, a) == NULL);
_HASH_FIND_CALL();
_HASH_FIND_ITER();
int k = HASH_KEY(a, size);
while (h[k] != a) {
k = HASH_REKEY(k, size);
_HASH_FIND_ITER();
}
return k;
}
// Look for the place to add an element. Return NULL if element is already here.
inline bool H_pair_insert(int* h, const int size, int a, int b) {
_HASH_ADD_CALL();
_HASH_ADD_ITER();
int k = HASH_PAIR_KEY(a, b, size);
if (h[2 * k] == HASH_NONE) {
h[2 * k] = a;
h[2 * k + 1] = b;
return true;
}
while (h[2 * k] != a || h[2 * k + 1] != b) {
_HASH_ADD_ITER();
k = HASH_REKEY(k, size);
if (h[2 * k] == HASH_NONE) {
h[2 * k] = a;
h[2 * k + 1] = b;
return true;
}
}
return false;
}
//_________________________________________________________________________
// Generic functions : table can be either Hash or Raw.
// the argument 'size' is the number of elements
//_________________________________________________________________________
// Look for an element
inline bool H_is(int *mem, const int size, const int elem) {
if (IS_HASH(size)) {
return (H_add(mem, HASH_EXPAND(size), elem) == NULL);
} else {
return fast_search(mem, size, elem) != NULL;
}
}
//pick random location (containing an element)
inline int* H_random(int* mem, int size) {
if (!IS_HASH(size)) {
return mem + (my_random() % size);
}
_HASH_RAND_CALL();
size = HASH_EXPAND(size);
int* yo;
do {
yo = mem + HASH_KEY(my_random(), size);
_HASH_RAND_ITER();
} while (*yo == HASH_NONE);
return yo;
}
// replace *k by b
inline int* H_rpl(int *mem, int size, int* k, const int b) {
assert(!H_is(mem, size, b));
if (!IS_HASH(size)) {
*k = b;
return k;
} else {
size = HASH_EXPAND(size);
assert(mem + int(k - mem) == k);
H_rm(mem, size, int(k - mem));
return H_put(mem, size, b);
}
}
// replace a by b
inline int* H_rpl(int *mem, int size, const int a, const int b) {
assert(H_is(mem, size, a));
assert(!H_is(mem, size, b));
if (!IS_HASH(size)) {
return fast_rpl(mem, a, b);
} else {
size = HASH_EXPAND(size);
H_rm(mem, size, H_find(mem, size, a));
return H_put(mem, size, b);
}
}
} // namespace gengraph
#endif //HASH_H