1296 lines
38 KiB
C
1296 lines
38 KiB
C
/******************************************************************************
|
|
* Copyright (c) 1998 Lawrence Livermore National Security, LLC and other
|
|
* HYPRE Project Developers. See the top-level COPYRIGHT file for details.
|
|
*
|
|
* SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
|
******************************************************************************/
|
|
|
|
/**
|
|
* Hopscotch hash is modified from the code downloaded from
|
|
* https://sites.google.com/site/cconcurrencypackage/hopscotch-hashing
|
|
* with the following terms of usage
|
|
*/
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//TERMS OF USAGE
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// Permission to use, copy, modify and distribute this software and
|
|
// its documentation for any purpose is hereby granted without fee,
|
|
// provided that due acknowledgments to the authors are provided and
|
|
// this permission notice appears in all copies of the software.
|
|
// The software is provided "as is". There is no warranty of any kind.
|
|
//
|
|
//Authors:
|
|
// Maurice Herlihy
|
|
// Brown University
|
|
// and
|
|
// Nir Shavit
|
|
// Tel-Aviv University
|
|
// and
|
|
// Moran Tzafrir
|
|
// Tel-Aviv University
|
|
//
|
|
// Date: July 15, 2008.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Programmer : Moran Tzafrir (MoranTza@gmail.com)
|
|
// Modified : Jongsoo Park (jongsoo.park@intel.com)
|
|
// Oct 1, 2015.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifndef hypre_HOPSCOTCH_HASH_HEADER
|
|
#define hypre_HOPSCOTCH_HASH_HEADER
|
|
|
|
//#include <strings.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <limits.h>
|
|
//#include <math.h>
|
|
|
|
#ifdef HYPRE_USING_OPENMP
|
|
#include <omp.h>
|
|
#endif
|
|
|
|
//#include "_hypre_utilities.h"
|
|
|
|
// Potentially architecture specific features used here:
|
|
// __sync_val_compare_and_swap
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/******************************************************************************
|
|
* This next section of code is here instead of in _hypre_utilities.h to get
|
|
* around some portability issues with Visual Studio. By putting it here, we
|
|
* can explicitly include this '.h' file in a few files in hypre and compile
|
|
* them with C++ instead of C (VS does not support C99 'inline').
|
|
******************************************************************************/
|
|
|
|
#ifdef HYPRE_USING_ATOMIC
|
|
static inline HYPRE_Int
|
|
hypre_compare_and_swap( HYPRE_Int *ptr, HYPRE_Int oldval, HYPRE_Int newval )
|
|
{
|
|
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40100
|
|
return __sync_val_compare_and_swap(ptr, oldval, newval);
|
|
//#elif defind _MSC_VER
|
|
//return _InterlockedCompareExchange((long *)ptr, newval, oldval);
|
|
//#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__)
|
|
// JSP: not many compilers have implemented this, so comment out for now
|
|
//_Atomic HYPRE_Int *atomic_ptr = ptr;
|
|
//atomic_compare_exchange_strong(atomic_ptr, &oldval, newval);
|
|
//return oldval;
|
|
#endif
|
|
}
|
|
|
|
static inline HYPRE_Int
|
|
hypre_fetch_and_add( HYPRE_Int *ptr, HYPRE_Int value )
|
|
{
|
|
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) && (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40100
|
|
return __sync_fetch_and_add(ptr, value);
|
|
//#elif defined _MSC_VER
|
|
//return _InterlockedExchangeAdd((long *)ptr, value);
|
|
//#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__)
|
|
// JSP: not many compilers have implemented this, so comment out for now
|
|
//_Atomic HYPRE_Int *atomic_ptr = ptr;
|
|
//return atomic_fetch_add(atomic_ptr, value);
|
|
#endif
|
|
}
|
|
#else // !HYPRE_USING_ATOMIC
|
|
static inline HYPRE_Int
|
|
hypre_compare_and_swap( HYPRE_Int *ptr, HYPRE_Int oldval, HYPRE_Int newval )
|
|
{
|
|
if (*ptr == oldval)
|
|
{
|
|
*ptr = newval;
|
|
return oldval;
|
|
}
|
|
else { return *ptr; }
|
|
}
|
|
|
|
static inline HYPRE_Int
|
|
hypre_fetch_and_add( HYPRE_Int *ptr, HYPRE_Int value )
|
|
{
|
|
HYPRE_Int oldval = *ptr;
|
|
*ptr += value;
|
|
return oldval;
|
|
}
|
|
#endif // !HYPRE_USING_ATOMIC
|
|
|
|
/******************************************************************************/
|
|
|
|
// Constants ................................................................
|
|
#define HYPRE_HOPSCOTCH_HASH_HOP_RANGE (32)
|
|
#define HYPRE_HOPSCOTCH_HASH_INSERT_RANGE (4*1024)
|
|
|
|
#define HYPRE_HOPSCOTCH_HASH_EMPTY (0)
|
|
#define HYPRE_HOPSCOTCH_HASH_BUSY (1)
|
|
|
|
// Small Utilities ..........................................................
|
|
static inline HYPRE_Int
|
|
first_lsb_bit_indx( hypre_uint x )
|
|
{
|
|
HYPRE_Int pos;
|
|
#if defined(_MSC_VER) || defined(__MINGW64__)
|
|
if (x == 0)
|
|
{
|
|
pos = 0;
|
|
}
|
|
else
|
|
{
|
|
for (pos = 1; !(x & 1); ++pos)
|
|
{
|
|
x >>= 1;
|
|
}
|
|
}
|
|
#else
|
|
pos = ffs(x);
|
|
#endif
|
|
return (pos - 1);
|
|
}
|
|
/**
|
|
* hypre_Hash is adapted from xxHash with the following license.
|
|
*/
|
|
/*
|
|
xxHash - Extremely Fast Hash algorithm
|
|
Header File
|
|
Copyright (C) 2012-2015, Yann Collet.
|
|
|
|
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are
|
|
met:
|
|
|
|
* Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
* Redistributions in binary form must reproduce the above
|
|
copyright notice, this list of conditions and the following disclaimer
|
|
in the documentation and/or other materials provided with the
|
|
distribution.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
You can contact the author at :
|
|
- xxHash source repository : https://github.com/Cyan4973/xxHash
|
|
*/
|
|
|
|
/***************************************
|
|
* Constants
|
|
***************************************/
|
|
#define HYPRE_XXH_PRIME32_1 2654435761U
|
|
#define HYPRE_XXH_PRIME32_2 2246822519U
|
|
#define HYPRE_XXH_PRIME32_3 3266489917U
|
|
#define HYPRE_XXH_PRIME32_4 668265263U
|
|
#define HYPRE_XXH_PRIME32_5 374761393U
|
|
|
|
#define HYPRE_XXH_PRIME64_1 11400714785074694791ULL
|
|
#define HYPRE_XXH_PRIME64_2 14029467366897019727ULL
|
|
#define HYPRE_XXH_PRIME64_3 1609587929392839161ULL
|
|
#define HYPRE_XXH_PRIME64_4 9650029242287828579ULL
|
|
#define HYPRE_XXH_PRIME64_5 2870177450012600261ULL
|
|
|
|
#define HYPRE_XXH_rotl32(x,r) ((x << r) | (x >> (32 - r)))
|
|
#define HYPRE_XXH_rotl64(x,r) ((x << r) | (x >> (64 - r)))
|
|
|
|
#if defined(HYPRE_MIXEDINT) || defined(HYPRE_BIGINT)
|
|
static inline HYPRE_BigInt
|
|
hypre_BigHash( HYPRE_BigInt input )
|
|
{
|
|
hypre_ulonglongint h64 = HYPRE_XXH_PRIME64_5 + sizeof(input);
|
|
|
|
hypre_ulonglongint k1 = input;
|
|
k1 *= HYPRE_XXH_PRIME64_2;
|
|
k1 = HYPRE_XXH_rotl64(k1, 31);
|
|
k1 *= HYPRE_XXH_PRIME64_1;
|
|
h64 ^= k1;
|
|
h64 = HYPRE_XXH_rotl64(h64, 27) * HYPRE_XXH_PRIME64_1 + HYPRE_XXH_PRIME64_4;
|
|
|
|
h64 ^= h64 >> 33;
|
|
h64 *= HYPRE_XXH_PRIME64_2;
|
|
h64 ^= h64 >> 29;
|
|
h64 *= HYPRE_XXH_PRIME64_3;
|
|
h64 ^= h64 >> 32;
|
|
|
|
#ifndef NDEBUG
|
|
if (HYPRE_HOPSCOTCH_HASH_EMPTY == h64)
|
|
{
|
|
hypre_printf("hash(%lld) = %d\n", h64, HYPRE_HOPSCOTCH_HASH_EMPTY);
|
|
hypre_assert(HYPRE_HOPSCOTCH_HASH_EMPTY != h64);
|
|
}
|
|
#endif
|
|
|
|
return h64;
|
|
}
|
|
|
|
#else
|
|
static inline HYPRE_Int
|
|
hypre_BigHash(HYPRE_Int input)
|
|
{
|
|
hypre_uint h32 = HYPRE_XXH_PRIME32_5 + sizeof(input);
|
|
|
|
// 1665863975 is added to input so that
|
|
// only -1073741824 gives HYPRE_HOPSCOTCH_HASH_EMPTY.
|
|
// Hence, we're fine as long as key is non-negative.
|
|
h32 += (input + 1665863975) * HYPRE_XXH_PRIME32_3;
|
|
h32 = HYPRE_XXH_rotl32(h32, 17) * HYPRE_XXH_PRIME32_4;
|
|
|
|
h32 ^= h32 >> 15;
|
|
h32 *= HYPRE_XXH_PRIME32_2;
|
|
h32 ^= h32 >> 13;
|
|
h32 *= HYPRE_XXH_PRIME32_3;
|
|
h32 ^= h32 >> 16;
|
|
|
|
//hypre_assert(HYPRE_HOPSCOTCH_HASH_EMPTY != h32);
|
|
|
|
return h32;
|
|
}
|
|
#endif
|
|
|
|
#ifdef HYPRE_BIGINT
|
|
static inline HYPRE_Int
|
|
hypre_Hash(HYPRE_Int input)
|
|
{
|
|
hypre_ulonglongint h64 = HYPRE_XXH_PRIME64_5 + sizeof(input);
|
|
|
|
hypre_ulonglongint k1 = input;
|
|
k1 *= HYPRE_XXH_PRIME64_2;
|
|
k1 = HYPRE_XXH_rotl64(k1, 31);
|
|
k1 *= HYPRE_XXH_PRIME64_1;
|
|
h64 ^= k1;
|
|
h64 = HYPRE_XXH_rotl64(h64, 27) * HYPRE_XXH_PRIME64_1 + HYPRE_XXH_PRIME64_4;
|
|
|
|
h64 ^= h64 >> 33;
|
|
h64 *= HYPRE_XXH_PRIME64_2;
|
|
h64 ^= h64 >> 29;
|
|
h64 *= HYPRE_XXH_PRIME64_3;
|
|
h64 ^= h64 >> 32;
|
|
|
|
#ifndef NDEBUG
|
|
if (HYPRE_HOPSCOTCH_HASH_EMPTY == h64)
|
|
{
|
|
hypre_printf("hash(%lld) = %d\n", h64, HYPRE_HOPSCOTCH_HASH_EMPTY);
|
|
hypre_assert(HYPRE_HOPSCOTCH_HASH_EMPTY != h64);
|
|
}
|
|
#endif
|
|
|
|
return h64;
|
|
}
|
|
|
|
#else
|
|
static inline HYPRE_Int
|
|
hypre_Hash(HYPRE_Int input)
|
|
{
|
|
hypre_uint h32 = HYPRE_XXH_PRIME32_5 + sizeof(input);
|
|
|
|
// 1665863975 is added to input so that
|
|
// only -1073741824 gives HYPRE_HOPSCOTCH_HASH_EMPTY.
|
|
// Hence, we're fine as long as key is non-negative.
|
|
h32 += (input + 1665863975) * HYPRE_XXH_PRIME32_3;
|
|
h32 = HYPRE_XXH_rotl32(h32, 17) * HYPRE_XXH_PRIME32_4;
|
|
|
|
h32 ^= h32 >> 15;
|
|
h32 *= HYPRE_XXH_PRIME32_2;
|
|
h32 ^= h32 >> 13;
|
|
h32 *= HYPRE_XXH_PRIME32_3;
|
|
h32 ^= h32 >> 16;
|
|
|
|
//hypre_assert(HYPRE_HOPSCOTCH_HASH_EMPTY != h32);
|
|
|
|
return h32;
|
|
}
|
|
#endif
|
|
|
|
static inline void
|
|
hypre_UnorderedIntSetFindCloserFreeBucket( hypre_UnorderedIntSet *s,
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
hypre_HopscotchSegment *start_seg,
|
|
#endif
|
|
HYPRE_Int *free_bucket,
|
|
HYPRE_Int *free_dist )
|
|
{
|
|
HYPRE_Int move_bucket = *free_bucket - (HYPRE_HOPSCOTCH_HASH_HOP_RANGE - 1);
|
|
HYPRE_Int move_free_dist;
|
|
for (move_free_dist = HYPRE_HOPSCOTCH_HASH_HOP_RANGE - 1; move_free_dist > 0; --move_free_dist)
|
|
{
|
|
hypre_uint start_hop_info = s->hopInfo[move_bucket];
|
|
HYPRE_Int move_new_free_dist = -1;
|
|
hypre_uint mask = 1;
|
|
HYPRE_Int i;
|
|
for (i = 0; i < move_free_dist; ++i, mask <<= 1)
|
|
{
|
|
if (mask & start_hop_info)
|
|
{
|
|
move_new_free_dist = i;
|
|
break;
|
|
}
|
|
}
|
|
if (-1 != move_new_free_dist)
|
|
{
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
hypre_HopscotchSegment* move_segment = &(s->segments[move_bucket & s->segmentMask]);
|
|
|
|
if (start_seg != move_segment)
|
|
{
|
|
omp_set_lock(&move_segment->lock);
|
|
}
|
|
#endif
|
|
|
|
if (start_hop_info == s->hopInfo[move_bucket])
|
|
{
|
|
// new_free_bucket -> free_bucket and empty new_free_bucket
|
|
HYPRE_Int new_free_bucket = move_bucket + move_new_free_dist;
|
|
s->key[*free_bucket] = s->key[new_free_bucket];
|
|
s->hash[*free_bucket] = s->hash[new_free_bucket];
|
|
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
++move_segment->timestamp;
|
|
#pragma omp flush
|
|
#endif
|
|
|
|
s->hopInfo[move_bucket] |= (1U << move_free_dist);
|
|
s->hopInfo[move_bucket] &= ~(1U << move_new_free_dist);
|
|
|
|
*free_bucket = new_free_bucket;
|
|
*free_dist -= move_free_dist - move_new_free_dist;
|
|
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
if (start_seg != move_segment)
|
|
{
|
|
omp_unset_lock(&move_segment->lock);
|
|
}
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
if (start_seg != move_segment)
|
|
{
|
|
omp_unset_lock(&move_segment->lock);
|
|
}
|
|
#endif
|
|
}
|
|
++move_bucket;
|
|
}
|
|
*free_bucket = -1;
|
|
*free_dist = 0;
|
|
}
|
|
|
|
static inline void
|
|
hypre_UnorderedBigIntSetFindCloserFreeBucket( hypre_UnorderedBigIntSet *s,
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
hypre_HopscotchSegment *start_seg,
|
|
#endif
|
|
HYPRE_Int *free_bucket,
|
|
HYPRE_Int *free_dist )
|
|
{
|
|
HYPRE_Int move_bucket = *free_bucket - (HYPRE_HOPSCOTCH_HASH_HOP_RANGE - 1);
|
|
HYPRE_Int move_free_dist;
|
|
for (move_free_dist = HYPRE_HOPSCOTCH_HASH_HOP_RANGE - 1; move_free_dist > 0; --move_free_dist)
|
|
{
|
|
hypre_uint start_hop_info = s->hopInfo[move_bucket];
|
|
HYPRE_Int move_new_free_dist = -1;
|
|
hypre_uint mask = 1;
|
|
HYPRE_Int i;
|
|
for (i = 0; i < move_free_dist; ++i, mask <<= 1)
|
|
{
|
|
if (mask & start_hop_info)
|
|
{
|
|
move_new_free_dist = i;
|
|
break;
|
|
}
|
|
}
|
|
if (-1 != move_new_free_dist)
|
|
{
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
hypre_HopscotchSegment* move_segment = &(s->segments[move_bucket & s->segmentMask]);
|
|
|
|
if (start_seg != move_segment)
|
|
{
|
|
omp_set_lock(&move_segment->lock);
|
|
}
|
|
#endif
|
|
|
|
if (start_hop_info == s->hopInfo[move_bucket])
|
|
{
|
|
// new_free_bucket -> free_bucket and empty new_free_bucket
|
|
HYPRE_Int new_free_bucket = move_bucket + move_new_free_dist;
|
|
s->key[*free_bucket] = s->key[new_free_bucket];
|
|
s->hash[*free_bucket] = s->hash[new_free_bucket];
|
|
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
++move_segment->timestamp;
|
|
#pragma omp flush
|
|
#endif
|
|
|
|
s->hopInfo[move_bucket] |= (1U << move_free_dist);
|
|
s->hopInfo[move_bucket] &= ~(1U << move_new_free_dist);
|
|
|
|
*free_bucket = new_free_bucket;
|
|
*free_dist -= move_free_dist - move_new_free_dist;
|
|
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
if (start_seg != move_segment)
|
|
{
|
|
omp_unset_lock(&move_segment->lock);
|
|
}
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
if (start_seg != move_segment)
|
|
{
|
|
omp_unset_lock(&move_segment->lock);
|
|
}
|
|
#endif
|
|
}
|
|
++move_bucket;
|
|
}
|
|
*free_bucket = -1;
|
|
*free_dist = 0;
|
|
}
|
|
|
|
static inline void
|
|
hypre_UnorderedIntMapFindCloserFreeBucket( hypre_UnorderedIntMap *m,
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
hypre_HopscotchSegment *start_seg,
|
|
#endif
|
|
hypre_HopscotchBucket **free_bucket,
|
|
HYPRE_Int *free_dist)
|
|
{
|
|
hypre_HopscotchBucket* move_bucket = *free_bucket - (HYPRE_HOPSCOTCH_HASH_HOP_RANGE - 1);
|
|
HYPRE_Int move_free_dist;
|
|
for (move_free_dist = HYPRE_HOPSCOTCH_HASH_HOP_RANGE - 1; move_free_dist > 0; --move_free_dist)
|
|
{
|
|
hypre_uint start_hop_info = move_bucket->hopInfo;
|
|
HYPRE_Int move_new_free_dist = -1;
|
|
hypre_uint mask = 1;
|
|
HYPRE_Int i;
|
|
for (i = 0; i < move_free_dist; ++i, mask <<= 1)
|
|
{
|
|
if (mask & start_hop_info)
|
|
{
|
|
move_new_free_dist = i;
|
|
break;
|
|
}
|
|
}
|
|
if (-1 != move_new_free_dist)
|
|
{
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
hypre_HopscotchSegment* move_segment = &(m->segments[(move_bucket - m->table) & m->segmentMask]);
|
|
|
|
if (start_seg != move_segment)
|
|
{
|
|
omp_set_lock(&move_segment->lock);
|
|
}
|
|
#endif
|
|
|
|
if (start_hop_info == move_bucket->hopInfo)
|
|
{
|
|
// new_free_bucket -> free_bucket and empty new_free_bucket
|
|
hypre_HopscotchBucket* new_free_bucket = move_bucket + move_new_free_dist;
|
|
(*free_bucket)->data = new_free_bucket->data;
|
|
(*free_bucket)->key = new_free_bucket->key;
|
|
(*free_bucket)->hash = new_free_bucket->hash;
|
|
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
++move_segment->timestamp;
|
|
|
|
#pragma omp flush
|
|
#endif
|
|
|
|
move_bucket->hopInfo |= (1U << move_free_dist);
|
|
move_bucket->hopInfo &= ~(1U << move_new_free_dist);
|
|
|
|
*free_bucket = new_free_bucket;
|
|
*free_dist -= move_free_dist - move_new_free_dist;
|
|
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
if (start_seg != move_segment)
|
|
{
|
|
omp_unset_lock(&move_segment->lock);
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
if (start_seg != move_segment)
|
|
{
|
|
omp_unset_lock(&move_segment->lock);
|
|
}
|
|
#endif
|
|
}
|
|
++move_bucket;
|
|
}
|
|
*free_bucket = NULL;
|
|
*free_dist = 0;
|
|
}
|
|
|
|
static inline void
|
|
hypre_UnorderedBigIntMapFindCloserFreeBucket( hypre_UnorderedBigIntMap *m,
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
hypre_HopscotchSegment *start_seg,
|
|
#endif
|
|
hypre_BigHopscotchBucket **free_bucket,
|
|
HYPRE_Int *free_dist)
|
|
{
|
|
hypre_BigHopscotchBucket* move_bucket = *free_bucket - (HYPRE_HOPSCOTCH_HASH_HOP_RANGE - 1);
|
|
HYPRE_Int move_free_dist;
|
|
for (move_free_dist = HYPRE_HOPSCOTCH_HASH_HOP_RANGE - 1; move_free_dist > 0; --move_free_dist)
|
|
{
|
|
hypre_uint start_hop_info = move_bucket->hopInfo;
|
|
HYPRE_Int move_new_free_dist = -1;
|
|
hypre_uint mask = 1;
|
|
HYPRE_Int i;
|
|
for (i = 0; i < move_free_dist; ++i, mask <<= 1)
|
|
{
|
|
if (mask & start_hop_info)
|
|
{
|
|
move_new_free_dist = i;
|
|
break;
|
|
}
|
|
}
|
|
if (-1 != move_new_free_dist)
|
|
{
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
hypre_HopscotchSegment* move_segment = &(m->segments[(move_bucket - m->table) & m->segmentMask]);
|
|
|
|
if (start_seg != move_segment)
|
|
{
|
|
omp_set_lock(&move_segment->lock);
|
|
}
|
|
#endif
|
|
|
|
if (start_hop_info == move_bucket->hopInfo)
|
|
{
|
|
// new_free_bucket -> free_bucket and empty new_free_bucket
|
|
hypre_BigHopscotchBucket* new_free_bucket = move_bucket + move_new_free_dist;
|
|
(*free_bucket)->data = new_free_bucket->data;
|
|
(*free_bucket)->key = new_free_bucket->key;
|
|
(*free_bucket)->hash = new_free_bucket->hash;
|
|
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
++move_segment->timestamp;
|
|
|
|
#pragma omp flush
|
|
#endif
|
|
|
|
move_bucket->hopInfo |= (1U << move_free_dist);
|
|
move_bucket->hopInfo &= ~(1U << move_new_free_dist);
|
|
|
|
*free_bucket = new_free_bucket;
|
|
*free_dist -= move_free_dist - move_new_free_dist;
|
|
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
if (start_seg != move_segment)
|
|
{
|
|
omp_unset_lock(&move_segment->lock);
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
if (start_seg != move_segment)
|
|
{
|
|
omp_unset_lock(&move_segment->lock);
|
|
}
|
|
#endif
|
|
}
|
|
++move_bucket;
|
|
}
|
|
*free_bucket = NULL;
|
|
*free_dist = 0;
|
|
}
|
|
|
|
void hypre_UnorderedIntSetCreate( hypre_UnorderedIntSet *s,
|
|
HYPRE_Int inCapacity,
|
|
HYPRE_Int concurrencyLevel);
|
|
void hypre_UnorderedBigIntSetCreate( hypre_UnorderedBigIntSet *s,
|
|
HYPRE_Int inCapacity,
|
|
HYPRE_Int concurrencyLevel);
|
|
void hypre_UnorderedIntMapCreate( hypre_UnorderedIntMap *m,
|
|
HYPRE_Int inCapacity,
|
|
HYPRE_Int concurrencyLevel);
|
|
void hypre_UnorderedBigIntMapCreate( hypre_UnorderedBigIntMap *m,
|
|
HYPRE_Int inCapacity,
|
|
HYPRE_Int concurrencyLevel);
|
|
|
|
void hypre_UnorderedIntSetDestroy( hypre_UnorderedIntSet *s );
|
|
void hypre_UnorderedBigIntSetDestroy( hypre_UnorderedBigIntSet *s );
|
|
void hypre_UnorderedIntMapDestroy( hypre_UnorderedIntMap *m );
|
|
void hypre_UnorderedBigIntMapDestroy( hypre_UnorderedBigIntMap *m );
|
|
|
|
// Query Operations .........................................................
|
|
static inline HYPRE_Int
|
|
hypre_UnorderedIntSetContains( hypre_UnorderedIntSet *s,
|
|
HYPRE_Int key )
|
|
{
|
|
//CALCULATE HASH ..........................
|
|
#ifdef HYPRE_BIGINT
|
|
HYPRE_Int hash = hypre_BigHash(key);
|
|
#else
|
|
HYPRE_Int hash = hypre_Hash(key);
|
|
#endif
|
|
|
|
//CHECK IF ALREADY CONTAIN ................
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
hypre_HopscotchSegment *segment = &s->segments[hash & s->segmentMask];
|
|
#endif
|
|
HYPRE_Int bucket = hash & s->bucketMask;
|
|
hypre_uint hopInfo = s->hopInfo[bucket];
|
|
|
|
if (0 == hopInfo)
|
|
{
|
|
return 0;
|
|
}
|
|
else if (1 == hopInfo )
|
|
{
|
|
if (hash == s->hash[bucket] && key == s->key[bucket])
|
|
{
|
|
return 1;
|
|
}
|
|
else { return 0; }
|
|
}
|
|
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
HYPRE_Int startTimestamp = segment->timestamp;
|
|
#endif
|
|
while (0 != hopInfo)
|
|
{
|
|
HYPRE_Int i = first_lsb_bit_indx(hopInfo);
|
|
HYPRE_Int currElm = bucket + i;
|
|
|
|
if (hash == s->hash[currElm] && key == s->key[currElm])
|
|
{
|
|
return 1;
|
|
}
|
|
hopInfo &= ~(1U << i);
|
|
}
|
|
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
if (segment->timestamp == startTimestamp)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
HYPRE_Int i;
|
|
for (i = 0; i < HYPRE_HOPSCOTCH_HASH_HOP_RANGE; ++i)
|
|
{
|
|
if (hash == s->hash[bucket + i] && key == s->key[bucket + i])
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static inline HYPRE_Int
|
|
hypre_UnorderedBigIntSetContains( hypre_UnorderedBigIntSet *s,
|
|
HYPRE_BigInt key )
|
|
{
|
|
//CALCULATE HASH ..........................
|
|
#if defined(HYPRE_BIGINT) || defined(HYPRE_MIXEDINT)
|
|
HYPRE_BigInt hash = hypre_BigHash(key);
|
|
#else
|
|
HYPRE_BigInt hash = hypre_Hash(key);
|
|
#endif
|
|
|
|
//CHECK IF ALREADY CONTAIN ................
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
hypre_HopscotchSegment *segment = &s->segments[(HYPRE_Int)(hash & s->segmentMask)];
|
|
#endif
|
|
HYPRE_Int bucket = (HYPRE_Int)(hash & s->bucketMask);
|
|
hypre_uint hopInfo = s->hopInfo[bucket];
|
|
|
|
if (0 == hopInfo)
|
|
{
|
|
return 0;
|
|
}
|
|
else if (1 == hopInfo )
|
|
{
|
|
if (hash == s->hash[bucket] && key == s->key[bucket])
|
|
{
|
|
return 1;
|
|
}
|
|
else { return 0; }
|
|
}
|
|
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
HYPRE_Int startTimestamp = segment->timestamp;
|
|
#endif
|
|
while (0 != hopInfo)
|
|
{
|
|
HYPRE_Int i = first_lsb_bit_indx(hopInfo);
|
|
HYPRE_Int currElm = bucket + i;
|
|
|
|
if (hash == s->hash[currElm] && key == s->key[currElm])
|
|
{
|
|
return 1;
|
|
}
|
|
hopInfo &= ~(1U << i);
|
|
}
|
|
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
if (segment->timestamp == startTimestamp)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
HYPRE_Int i;
|
|
for (i = 0; i < HYPRE_HOPSCOTCH_HASH_HOP_RANGE; ++i)
|
|
{
|
|
if (hash == s->hash[bucket + i] && key == s->key[bucket + i])
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @ret -1 if key doesn't exist
|
|
*/
|
|
static inline HYPRE_Int
|
|
hypre_UnorderedIntMapGet( hypre_UnorderedIntMap *m,
|
|
HYPRE_Int key )
|
|
{
|
|
//CALCULATE HASH ..........................
|
|
#ifdef HYPRE_BIGINT
|
|
HYPRE_Int hash = hypre_BigHash(key);
|
|
#else
|
|
HYPRE_Int hash = hypre_Hash(key);
|
|
#endif
|
|
|
|
//CHECK IF ALREADY CONTAIN ................
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
hypre_HopscotchSegment *segment = &m->segments[hash & m->segmentMask];
|
|
#endif
|
|
hypre_HopscotchBucket *elmAry = &(m->table[hash & m->bucketMask]);
|
|
hypre_uint hopInfo = elmAry->hopInfo;
|
|
if (0 == hopInfo)
|
|
{
|
|
return -1;
|
|
}
|
|
else if (1 == hopInfo )
|
|
{
|
|
if (hash == elmAry->hash && key == elmAry->key)
|
|
{
|
|
return elmAry->data;
|
|
}
|
|
else { return -1; }
|
|
}
|
|
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
HYPRE_Int startTimestamp = segment->timestamp;
|
|
#endif
|
|
while (0 != hopInfo)
|
|
{
|
|
HYPRE_Int i = first_lsb_bit_indx(hopInfo);
|
|
hypre_HopscotchBucket* currElm = elmAry + i;
|
|
if (hash == currElm->hash && key == currElm->key)
|
|
{
|
|
return currElm->data;
|
|
}
|
|
hopInfo &= ~(1U << i);
|
|
}
|
|
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
if (segment->timestamp == startTimestamp)
|
|
{
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
hypre_HopscotchBucket *currBucket = &(m->table[hash & m->bucketMask]);
|
|
HYPRE_Int i;
|
|
for (i = 0; i < HYPRE_HOPSCOTCH_HASH_HOP_RANGE; ++i, ++currBucket)
|
|
{
|
|
if (hash == currBucket->hash && key == currBucket->key)
|
|
{
|
|
return currBucket->data;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static inline
|
|
HYPRE_Int hypre_UnorderedBigIntMapGet( hypre_UnorderedBigIntMap *m,
|
|
HYPRE_BigInt key )
|
|
{
|
|
//CALCULATE HASH ..........................
|
|
#if defined(HYPRE_BIGINT) || defined(HYPRE_MIXEDINT)
|
|
HYPRE_BigInt hash = hypre_BigHash(key);
|
|
#else
|
|
HYPRE_BigInt hash = hypre_Hash(key);
|
|
#endif
|
|
|
|
//CHECK IF ALREADY CONTAIN ................
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
hypre_HopscotchSegment *segment = &m->segments[(HYPRE_Int)(hash & m->segmentMask)];
|
|
#endif
|
|
hypre_BigHopscotchBucket *elmAry = &(m->table[(HYPRE_Int)(hash & m->bucketMask)]);
|
|
hypre_uint hopInfo = elmAry->hopInfo;
|
|
if (0 == hopInfo)
|
|
{
|
|
return -1;
|
|
}
|
|
else if (1 == hopInfo )
|
|
{
|
|
if (hash == elmAry->hash && key == elmAry->key)
|
|
{
|
|
return elmAry->data;
|
|
}
|
|
else { return -1; }
|
|
}
|
|
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
HYPRE_Int startTimestamp = segment->timestamp;
|
|
#endif
|
|
while (0 != hopInfo)
|
|
{
|
|
HYPRE_Int i = first_lsb_bit_indx(hopInfo);
|
|
hypre_BigHopscotchBucket* currElm = elmAry + i;
|
|
if (hash == currElm->hash && key == currElm->key)
|
|
{
|
|
return currElm->data;
|
|
}
|
|
hopInfo &= ~(1U << i);
|
|
}
|
|
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
if (segment->timestamp == startTimestamp)
|
|
{
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
hypre_BigHopscotchBucket *currBucket = &(m->table[hash & m->bucketMask]);
|
|
HYPRE_Int i;
|
|
for (i = 0; i < HYPRE_HOPSCOTCH_HASH_HOP_RANGE; ++i, ++currBucket)
|
|
{
|
|
if (hash == currBucket->hash && key == currBucket->key)
|
|
{
|
|
return currBucket->data;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
//status Operations .........................................................
|
|
static inline
|
|
HYPRE_Int hypre_UnorderedIntSetSize( hypre_UnorderedIntSet *s )
|
|
{
|
|
HYPRE_Int counter = 0;
|
|
HYPRE_Int n = s->bucketMask + HYPRE_HOPSCOTCH_HASH_INSERT_RANGE;
|
|
HYPRE_Int i;
|
|
for (i = 0; i < n; ++i)
|
|
{
|
|
if (HYPRE_HOPSCOTCH_HASH_EMPTY != s->hash[i])
|
|
{
|
|
++counter;
|
|
}
|
|
}
|
|
return counter;
|
|
}
|
|
|
|
static inline
|
|
HYPRE_Int hypre_UnorderedBigIntSetSize( hypre_UnorderedBigIntSet *s )
|
|
{
|
|
HYPRE_Int counter = 0;
|
|
HYPRE_BigInt n = s->bucketMask + HYPRE_HOPSCOTCH_HASH_INSERT_RANGE;
|
|
HYPRE_Int i;
|
|
for (i = 0; i < n; ++i)
|
|
{
|
|
if (HYPRE_HOPSCOTCH_HASH_EMPTY != s->hash[i])
|
|
{
|
|
++counter;
|
|
}
|
|
}
|
|
return counter;
|
|
}
|
|
|
|
static inline HYPRE_Int
|
|
hypre_UnorderedIntMapSize( hypre_UnorderedIntMap *m )
|
|
{
|
|
HYPRE_Int counter = 0;
|
|
HYPRE_Int n = m->bucketMask + HYPRE_HOPSCOTCH_HASH_INSERT_RANGE;
|
|
HYPRE_Int i;
|
|
for (i = 0; i < n; ++i)
|
|
{
|
|
if ( HYPRE_HOPSCOTCH_HASH_EMPTY != m->table[i].hash )
|
|
{
|
|
++counter;
|
|
}
|
|
}
|
|
return counter;
|
|
}
|
|
|
|
static inline HYPRE_Int
|
|
hypre_UnorderedBigIntMapSize( hypre_UnorderedBigIntMap *m )
|
|
{
|
|
HYPRE_Int counter = 0;
|
|
HYPRE_Int n = m->bucketMask + HYPRE_HOPSCOTCH_HASH_INSERT_RANGE;
|
|
HYPRE_Int i;
|
|
for (i = 0; i < n; ++i)
|
|
{
|
|
if ( HYPRE_HOPSCOTCH_HASH_EMPTY != m->table[i].hash )
|
|
{
|
|
++counter;
|
|
}
|
|
}
|
|
return counter;
|
|
}
|
|
|
|
HYPRE_Int *hypre_UnorderedIntSetCopyToArray( hypre_UnorderedIntSet *s, HYPRE_Int *len );
|
|
HYPRE_BigInt *hypre_UnorderedBigIntSetCopyToArray( hypre_UnorderedBigIntSet *s, HYPRE_Int *len );
|
|
|
|
//modification Operations ...................................................
|
|
static inline void
|
|
hypre_UnorderedIntSetPut( hypre_UnorderedIntSet *s,
|
|
HYPRE_Int key )
|
|
{
|
|
//CALCULATE HASH ..........................
|
|
#ifdef HYPRE_BIGINT
|
|
HYPRE_Int hash = hypre_BigHash(key);
|
|
#else
|
|
HYPRE_Int hash = hypre_Hash(key);
|
|
#endif
|
|
|
|
//LOCK KEY HASH ENTERY ....................
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
hypre_HopscotchSegment *segment = &s->segments[hash & s->segmentMask];
|
|
omp_set_lock(&segment->lock);
|
|
#endif
|
|
HYPRE_Int bucket = hash & s->bucketMask;
|
|
|
|
//CHECK IF ALREADY CONTAIN ................
|
|
hypre_uint hopInfo = s->hopInfo[bucket];
|
|
while (0 != hopInfo)
|
|
{
|
|
HYPRE_Int i = first_lsb_bit_indx(hopInfo);
|
|
HYPRE_Int currElm = bucket + i;
|
|
|
|
if (hash == s->hash[currElm] && key == s->key[currElm])
|
|
{
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
omp_unset_lock(&segment->lock);
|
|
#endif
|
|
return;
|
|
}
|
|
hopInfo &= ~(1U << i);
|
|
}
|
|
|
|
//LOOK FOR FREE BUCKET ....................
|
|
HYPRE_Int free_bucket = bucket;
|
|
HYPRE_Int free_dist = 0;
|
|
for ( ; free_dist < HYPRE_HOPSCOTCH_HASH_INSERT_RANGE; ++free_dist, ++free_bucket)
|
|
{
|
|
if ( (HYPRE_HOPSCOTCH_HASH_EMPTY == s->hash[free_bucket]) &&
|
|
(HYPRE_HOPSCOTCH_HASH_EMPTY ==
|
|
hypre_compare_and_swap((HYPRE_Int *)&s->hash[free_bucket],
|
|
(HYPRE_Int)HYPRE_HOPSCOTCH_HASH_EMPTY,
|
|
(HYPRE_Int)HYPRE_HOPSCOTCH_HASH_BUSY)) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//PLACE THE NEW KEY .......................
|
|
if (free_dist < HYPRE_HOPSCOTCH_HASH_INSERT_RANGE)
|
|
{
|
|
do
|
|
{
|
|
if (free_dist < HYPRE_HOPSCOTCH_HASH_HOP_RANGE)
|
|
{
|
|
s->key[free_bucket] = key;
|
|
s->hash[free_bucket] = hash;
|
|
s->hopInfo[bucket] |= 1U << free_dist;
|
|
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
omp_unset_lock(&segment->lock);
|
|
#endif
|
|
return;
|
|
}
|
|
hypre_UnorderedIntSetFindCloserFreeBucket(s,
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
segment,
|
|
#endif
|
|
&free_bucket, &free_dist);
|
|
}
|
|
while (-1 != free_bucket);
|
|
}
|
|
|
|
//NEED TO RESIZE ..........................
|
|
hypre_error_w_msg(HYPRE_ERROR_GENERIC, "ERROR - RESIZE is not implemented\n");
|
|
/*fprintf(stderr, "ERROR - RESIZE is not implemented\n");*/
|
|
exit(1);
|
|
return;
|
|
}
|
|
|
|
static inline void
|
|
hypre_UnorderedBigIntSetPut( hypre_UnorderedBigIntSet *s,
|
|
HYPRE_BigInt key )
|
|
{
|
|
//CALCULATE HASH ..........................
|
|
#if defined(HYPRE_BIGINT) || defined(HYPRE_MIXEDINT)
|
|
HYPRE_BigInt hash = hypre_BigHash(key);
|
|
#else
|
|
HYPRE_BigInt hash = hypre_Hash(key);
|
|
#endif
|
|
|
|
//LOCK KEY HASH ENTERY ....................
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
hypre_HopscotchSegment *segment = &s->segments[hash & s->segmentMask];
|
|
omp_set_lock(&segment->lock);
|
|
#endif
|
|
HYPRE_Int bucket = (HYPRE_Int)(hash & s->bucketMask);
|
|
|
|
//CHECK IF ALREADY CONTAIN ................
|
|
hypre_uint hopInfo = s->hopInfo[bucket];
|
|
while (0 != hopInfo)
|
|
{
|
|
HYPRE_Int i = first_lsb_bit_indx(hopInfo);
|
|
HYPRE_Int currElm = bucket + i;
|
|
|
|
if (hash == s->hash[currElm] && key == s->key[currElm])
|
|
{
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
omp_unset_lock(&segment->lock);
|
|
#endif
|
|
return;
|
|
}
|
|
hopInfo &= ~(1U << i);
|
|
}
|
|
|
|
//LOOK FOR FREE BUCKET ....................
|
|
HYPRE_Int free_bucket = bucket;
|
|
HYPRE_Int free_dist = 0;
|
|
for ( ; free_dist < HYPRE_HOPSCOTCH_HASH_INSERT_RANGE; ++free_dist, ++free_bucket)
|
|
{
|
|
if ( (HYPRE_HOPSCOTCH_HASH_EMPTY == s->hash[free_bucket]) &&
|
|
(HYPRE_HOPSCOTCH_HASH_EMPTY ==
|
|
hypre_compare_and_swap((HYPRE_Int *)&s->hash[free_bucket],
|
|
(HYPRE_Int)HYPRE_HOPSCOTCH_HASH_EMPTY,
|
|
(HYPRE_Int)HYPRE_HOPSCOTCH_HASH_BUSY)) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//PLACE THE NEW KEY .......................
|
|
if (free_dist < HYPRE_HOPSCOTCH_HASH_INSERT_RANGE)
|
|
{
|
|
do
|
|
{
|
|
if (free_dist < HYPRE_HOPSCOTCH_HASH_HOP_RANGE)
|
|
{
|
|
s->key[free_bucket] = key;
|
|
s->hash[free_bucket] = hash;
|
|
s->hopInfo[bucket] |= 1U << free_dist;
|
|
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
omp_unset_lock(&segment->lock);
|
|
#endif
|
|
return;
|
|
}
|
|
hypre_UnorderedBigIntSetFindCloserFreeBucket(s,
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
segment,
|
|
#endif
|
|
&free_bucket, &free_dist);
|
|
}
|
|
while (-1 != free_bucket);
|
|
}
|
|
|
|
//NEED TO RESIZE ..........................
|
|
hypre_error_w_msg(HYPRE_ERROR_GENERIC, "ERROR - RESIZE is not implemented\n");
|
|
/*fprintf(stderr, "ERROR - RESIZE is not implemented\n");*/
|
|
exit(1);
|
|
return;
|
|
}
|
|
|
|
static inline HYPRE_Int
|
|
hypre_UnorderedIntMapPutIfAbsent( hypre_UnorderedIntMap *m,
|
|
HYPRE_Int key, HYPRE_Int data )
|
|
{
|
|
//CALCULATE HASH ..........................
|
|
#ifdef HYPRE_BIGINT
|
|
HYPRE_Int hash = hypre_BigHash(key);
|
|
#else
|
|
HYPRE_Int hash = hypre_Hash(key);
|
|
#endif
|
|
|
|
//LOCK KEY HASH ENTERY ....................
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
hypre_HopscotchSegment *segment = &m->segments[hash & m->segmentMask];
|
|
omp_set_lock(&segment->lock);
|
|
#endif
|
|
hypre_HopscotchBucket* startBucket = &(m->table[hash & m->bucketMask]);
|
|
|
|
//CHECK IF ALREADY CONTAIN ................
|
|
hypre_uint hopInfo = startBucket->hopInfo;
|
|
while (0 != hopInfo)
|
|
{
|
|
HYPRE_Int i = first_lsb_bit_indx(hopInfo);
|
|
hypre_HopscotchBucket* currElm = startBucket + i;
|
|
if (hash == currElm->hash && key == currElm->key)
|
|
{
|
|
HYPRE_Int rc = currElm->data;
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
omp_unset_lock(&segment->lock);
|
|
#endif
|
|
return rc;
|
|
}
|
|
hopInfo &= ~(1U << i);
|
|
}
|
|
|
|
//LOOK FOR FREE BUCKET ....................
|
|
hypre_HopscotchBucket* free_bucket = startBucket;
|
|
HYPRE_Int free_dist = 0;
|
|
for ( ; free_dist < HYPRE_HOPSCOTCH_HASH_INSERT_RANGE; ++free_dist, ++free_bucket)
|
|
{
|
|
if ( (HYPRE_HOPSCOTCH_HASH_EMPTY == free_bucket->hash) &&
|
|
(HYPRE_HOPSCOTCH_HASH_EMPTY ==
|
|
hypre_compare_and_swap((HYPRE_Int *)&free_bucket->hash,
|
|
(HYPRE_Int)HYPRE_HOPSCOTCH_HASH_EMPTY,
|
|
(HYPRE_Int)HYPRE_HOPSCOTCH_HASH_BUSY)) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//PLACE THE NEW KEY .......................
|
|
if (free_dist < HYPRE_HOPSCOTCH_HASH_INSERT_RANGE)
|
|
{
|
|
do
|
|
{
|
|
if (free_dist < HYPRE_HOPSCOTCH_HASH_HOP_RANGE)
|
|
{
|
|
free_bucket->data = data;
|
|
free_bucket->key = key;
|
|
free_bucket->hash = hash;
|
|
startBucket->hopInfo |= 1U << free_dist;
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
omp_unset_lock(&segment->lock);
|
|
#endif
|
|
return HYPRE_HOPSCOTCH_HASH_EMPTY;
|
|
}
|
|
hypre_UnorderedIntMapFindCloserFreeBucket(m,
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
segment,
|
|
#endif
|
|
&free_bucket, &free_dist);
|
|
}
|
|
while (NULL != free_bucket);
|
|
}
|
|
|
|
//NEED TO RESIZE ..........................
|
|
hypre_error_w_msg(HYPRE_ERROR_GENERIC, "ERROR - RESIZE is not implemented\n");
|
|
/*fprintf(stderr, "ERROR - RESIZE is not implemented\n");*/
|
|
exit(1);
|
|
return HYPRE_HOPSCOTCH_HASH_EMPTY;
|
|
}
|
|
|
|
static inline HYPRE_Int
|
|
hypre_UnorderedBigIntMapPutIfAbsent( hypre_UnorderedBigIntMap *m,
|
|
HYPRE_BigInt key, HYPRE_Int data)
|
|
{
|
|
//CALCULATE HASH ..........................
|
|
#if defined(HYPRE_BIGINT) || defined(HYPRE_MIXEDINT)
|
|
HYPRE_BigInt hash = hypre_BigHash(key);
|
|
#else
|
|
HYPRE_BigInt hash = hypre_Hash(key);
|
|
#endif
|
|
|
|
//LOCK KEY HASH ENTERY ....................
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
hypre_HopscotchSegment *segment = &m->segments[hash & m->segmentMask];
|
|
omp_set_lock(&segment->lock);
|
|
#endif
|
|
hypre_BigHopscotchBucket* startBucket = &(m->table[hash & m->bucketMask]);
|
|
|
|
//CHECK IF ALREADY CONTAIN ................
|
|
hypre_uint hopInfo = startBucket->hopInfo;
|
|
while (0 != hopInfo)
|
|
{
|
|
HYPRE_Int i = first_lsb_bit_indx(hopInfo);
|
|
hypre_BigHopscotchBucket* currElm = startBucket + i;
|
|
if (hash == currElm->hash && key == currElm->key)
|
|
{
|
|
HYPRE_Int rc = currElm->data;
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
omp_unset_lock(&segment->lock);
|
|
#endif
|
|
return rc;
|
|
}
|
|
hopInfo &= ~(1U << i);
|
|
}
|
|
|
|
//LOOK FOR FREE BUCKET ....................
|
|
hypre_BigHopscotchBucket* free_bucket = startBucket;
|
|
HYPRE_Int free_dist = 0;
|
|
for ( ; free_dist < HYPRE_HOPSCOTCH_HASH_INSERT_RANGE; ++free_dist, ++free_bucket)
|
|
{
|
|
if ( (HYPRE_HOPSCOTCH_HASH_EMPTY == free_bucket->hash) &&
|
|
(HYPRE_HOPSCOTCH_HASH_EMPTY ==
|
|
hypre_compare_and_swap((HYPRE_Int *)&free_bucket->hash,
|
|
(HYPRE_Int)HYPRE_HOPSCOTCH_HASH_EMPTY,
|
|
(HYPRE_Int)HYPRE_HOPSCOTCH_HASH_BUSY)) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//PLACE THE NEW KEY .......................
|
|
if (free_dist < HYPRE_HOPSCOTCH_HASH_INSERT_RANGE)
|
|
{
|
|
do
|
|
{
|
|
if (free_dist < HYPRE_HOPSCOTCH_HASH_HOP_RANGE)
|
|
{
|
|
free_bucket->data = data;
|
|
free_bucket->key = key;
|
|
free_bucket->hash = hash;
|
|
startBucket->hopInfo |= 1U << free_dist;
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
omp_unset_lock(&segment->lock);
|
|
#endif
|
|
return HYPRE_HOPSCOTCH_HASH_EMPTY;
|
|
}
|
|
hypre_UnorderedBigIntMapFindCloserFreeBucket(m,
|
|
#ifdef HYPRE_CONCURRENT_HOPSCOTCH
|
|
segment,
|
|
#endif
|
|
&free_bucket, &free_dist);
|
|
}
|
|
while (NULL != free_bucket);
|
|
}
|
|
|
|
//NEED TO RESIZE ..........................
|
|
hypre_error_w_msg(HYPRE_ERROR_GENERIC, "ERROR - RESIZE is not implemented\n");
|
|
/*fprintf(stderr, "ERROR - RESIZE is not implemented\n");*/
|
|
exit(1);
|
|
return HYPRE_HOPSCOTCH_HASH_EMPTY;
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
} // extern "C"
|
|
#endif
|
|
|
|
#endif // hypre_HOPSCOTCH_HASH_HEADER
|