2015-12-08 15:45:58 -07:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2015 Cisco and/or its affiliates.
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at:
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
Copyright (c) 2005 Eliot Dresselhaus
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
|
|
a copy of this software and associated documentation files (the
|
|
|
|
"Software"), to deal in the Software without restriction, including
|
|
|
|
without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
distribute, sublicense, and/or sell copies of the Software, and to
|
|
|
|
permit persons to whom the Software is furnished to do so, subject to
|
|
|
|
the following conditions:
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be
|
|
|
|
included in all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
|
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
|
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
|
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
|
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef included_phash_h
|
|
|
|
#define included_phash_h
|
|
|
|
|
2016-08-15 11:12:27 -04:00
|
|
|
#include <vppinfra/hash.h> /* for Bob's mixing functions */
|
2015-12-08 15:45:58 -07:00
|
|
|
|
2016-08-15 11:12:27 -04:00
|
|
|
typedef struct
|
|
|
|
{
|
2015-12-08 15:45:58 -07:00
|
|
|
/* Maybe either pointer to vector or inline word. */
|
|
|
|
uword key;
|
|
|
|
|
|
|
|
/* Hash code (A, B). */
|
|
|
|
u32 a, b;
|
|
|
|
} phash_key_t;
|
|
|
|
|
|
|
|
/* Table indexed by B. */
|
2016-08-15 11:12:27 -04:00
|
|
|
typedef struct
|
|
|
|
{
|
2015-12-08 15:45:58 -07:00
|
|
|
/* Vector of key indices with this same value of B. */
|
2016-08-15 11:12:27 -04:00
|
|
|
u32 *keys;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
/* hash=a^tabb[b].val_b */
|
|
|
|
u32 val_b;
|
|
|
|
|
|
|
|
/* High watermark of who has visited this map node. */
|
|
|
|
u32 water_b;
|
|
|
|
} phash_tabb_t;
|
|
|
|
|
|
|
|
always_inline void
|
|
|
|
phash_tabb_free (phash_tabb_t * b)
|
|
|
|
{
|
|
|
|
vec_free (b->keys);
|
|
|
|
b->val_b = b->water_b = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
/* b that currently occupies this hash */
|
|
|
|
u32 b_q;
|
|
|
|
|
|
|
|
/* Queue position of parent that could use this hash. */
|
|
|
|
u32 parent_q;
|
|
|
|
|
|
|
|
/* What to change parent tab[b] to use this hash. */
|
|
|
|
u32 newval_q;
|
|
|
|
|
|
|
|
/* Original value of tab[b]. */
|
|
|
|
u32 oldval_q;
|
|
|
|
} phash_tabq_t;
|
|
|
|
|
2016-08-15 11:12:27 -04:00
|
|
|
typedef struct
|
|
|
|
{
|
2015-12-08 15:45:58 -07:00
|
|
|
u8 a_bits, b_bits, s_bits, a_shift;
|
|
|
|
u32 b_mask;
|
2016-08-15 11:12:27 -04:00
|
|
|
u32 *tab;
|
|
|
|
u32 *scramble;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
/* Seed value for hash mixer. */
|
|
|
|
u64 hash_seed;
|
|
|
|
|
|
|
|
u32 flags;
|
|
|
|
|
|
|
|
/* Key functions want 64 bit keys.
|
|
|
|
Use hash_mix64 rather than hash_mix32. */
|
|
|
|
#define PHASH_FLAG_MIX64 (1 << 0)
|
|
|
|
#define PHASH_FLAG_MIX32 (0 << 0)
|
|
|
|
|
|
|
|
/* When b_bits is large enough (>= 12) we scramble. */
|
|
|
|
#define PHASH_FLAG_USE_SCRAMBLE (1 << 1)
|
|
|
|
|
|
|
|
/* Slow mode gives smaller tables but at the expense of more run time. */
|
|
|
|
#define PHASH_FLAG_SLOW_MODE (0 << 2)
|
|
|
|
#define PHASH_FLAG_FAST_MODE (1 << 2)
|
|
|
|
|
|
|
|
/* Generate minimal perfect hash instead of perfect hash. */
|
|
|
|
#define PHASH_FLAG_NON_MINIMAL (0 << 3)
|
|
|
|
#define PHASH_FLAG_MINIMAL (1 << 3)
|
|
|
|
|
|
|
|
/* vec_len (keys) for minimal hash;
|
|
|
|
1 << s_bits for non-minimal hash. */
|
|
|
|
u32 hash_max;
|
|
|
|
|
|
|
|
/* Vector of keys. */
|
2016-08-15 11:12:27 -04:00
|
|
|
phash_key_t *keys;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
/* Used by callbacks to identify keys. */
|
2016-08-15 11:12:27 -04:00
|
|
|
void *private;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
/* Key comparison callback. */
|
2016-08-15 11:12:27 -04:00
|
|
|
int (*key_is_equal) (void *private, uword key1, uword key2);
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
/* Callback to reduce single key -> hash seeds. */
|
2016-08-15 11:12:27 -04:00
|
|
|
void (*key_seed1) (void *private, uword key, void *seed);
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
/* Callback to reduce two key2 -> hash seeds. */
|
2016-08-15 11:12:27 -04:00
|
|
|
void (*key_seed2) (void *private, uword key1, uword key2, void *seed);
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
/* Stuff used to compute perfect hash. */
|
|
|
|
u32 random_seed;
|
|
|
|
|
|
|
|
/* Stuff indexed by B. */
|
2016-08-15 11:12:27 -04:00
|
|
|
phash_tabb_t *tabb;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
/* Table of B ordered by number of keys in tabb[b]. */
|
2016-08-15 11:12:27 -04:00
|
|
|
u32 *tabb_sort;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
/* Unique key (or ~0 if none) for a given hash
|
|
|
|
H = A ^ scramble[tab[B].val_b]. */
|
2016-08-15 11:12:27 -04:00
|
|
|
u32 *tabh;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
/* Stuff indexed by q. */
|
2016-08-15 11:12:27 -04:00
|
|
|
phash_tabq_t *tabq;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
/* Stats. */
|
|
|
|
u32 n_seed_trials, n_perfect_calls;
|
|
|
|
} phash_main_t;
|
|
|
|
|
|
|
|
always_inline void
|
|
|
|
phash_main_free_working_memory (phash_main_t * pm)
|
|
|
|
{
|
|
|
|
vec_free (pm->tabb);
|
|
|
|
vec_free (pm->tabq);
|
|
|
|
vec_free (pm->tabh);
|
|
|
|
vec_free (pm->tabb_sort);
|
2016-08-15 11:12:27 -04:00
|
|
|
if (!(pm->flags & PHASH_FLAG_USE_SCRAMBLE))
|
2015-12-08 15:45:58 -07:00
|
|
|
vec_free (pm->scramble);
|
|
|
|
}
|
|
|
|
|
|
|
|
always_inline void
|
|
|
|
phash_main_free (phash_main_t * pm)
|
|
|
|
{
|
|
|
|
phash_main_free_working_memory (pm);
|
|
|
|
vec_free (pm->tab);
|
|
|
|
vec_free (pm->keys);
|
2018-10-17 10:38:51 -04:00
|
|
|
clib_memset (pm, 0, sizeof (pm[0]));
|
2015-12-08 15:45:58 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Slow hash computation for general keys. */
|
|
|
|
uword phash_hash_slow (phash_main_t * pm, uword key);
|
|
|
|
|
|
|
|
/* Main routine to compute perfect hash. */
|
2016-08-15 11:12:27 -04:00
|
|
|
clib_error_t *phash_find_perfect_hash (phash_main_t * pm);
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
/* Validates that hash is indeed perfect. */
|
2016-08-15 11:12:27 -04:00
|
|
|
clib_error_t *phash_validate (phash_main_t * pm);
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
/* Unit test. */
|
|
|
|
int phash_test_main (unformat_input_t * input);
|
|
|
|
|
|
|
|
#endif /* included_phash_h */
|
2016-08-15 11:12:27 -04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* fd.io coding-style-patch-verification: ON
|
|
|
|
*
|
|
|
|
* Local Variables:
|
|
|
|
* eval: (c-set-style "gnu")
|
|
|
|
* End:
|
|
|
|
*/
|