160 lines
3.5 KiB
C++
160 lines
3.5 KiB
C++
// Copyright (c) 2019 GeometryFactory Sarl (France)
|
|
// All rights reserved.
|
|
//
|
|
// This file is part of CGAL (www.cgal.org)
|
|
//
|
|
// $URL: https://github.com/CGAL/cgal/blob/v5.1/STL_Extension/include/CGAL/Small_unordered_map.h $
|
|
// $Id: Small_unordered_map.h 0779373 2020-03-26T13:31:46+01:00 Sébastien Loriot
|
|
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
|
|
//
|
|
// Author(s) : Andreas Fabri
|
|
|
|
#ifndef CGAL_SMALL_UNORDERED_MAP_H
|
|
#define CGAL_SMALL_UNORDERED_MAP_H
|
|
|
|
#include <array>
|
|
#include <iostream>
|
|
|
|
//#define CGAL_SMALL_UNORDERED_MAP_STATS
|
|
namespace CGAL {
|
|
|
|
|
|
template <typename K, typename T, typename H, unsigned int M>
|
|
class Small_unordered_map{
|
|
#ifdef CGAL_SMALL_UNORDERED_MAP_STATS
|
|
std::array<int,20> collisions = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
#endif
|
|
int head = -2;
|
|
mutable std::array<int, M> occupied;
|
|
std::array<int, M> unfreelist;
|
|
std::array<std::pair<K,T>, M> data;
|
|
const H hash = {};
|
|
|
|
public:
|
|
Small_unordered_map()
|
|
{
|
|
occupied.fill(-1);
|
|
}
|
|
|
|
#ifdef CGAL_SMALL_UNORDERED_MAP_STATS
|
|
~Small_unordered_map()
|
|
{
|
|
int total = 0;
|
|
std::cout << "0 " << collisions[0] << std::endl;
|
|
for(int i = 1; i < 20; i++){
|
|
total += collisions[i];
|
|
if(collisions[i] != 0){
|
|
std::cout << i << " " << collisions[i] << std::endl;
|
|
}
|
|
}
|
|
std::cout << "Total: " << total << " " << 100 * (double(total) / double(total + collisions[0])) << "%" << std::endl;
|
|
}
|
|
#endif
|
|
|
|
/// Set only once for a key and not more than N
|
|
void set(const K& k, const T& t)
|
|
{
|
|
unsigned int h = hash(k)%M;
|
|
unsigned i = h;
|
|
#ifdef CGAL_SMALL_UNORDERED_MAP_STATS
|
|
int collision = 0;
|
|
#endif
|
|
do {
|
|
if(occupied[i]== -1){
|
|
occupied[i] = 1;
|
|
data[i].first = k;
|
|
data[i].second = t;
|
|
unfreelist[i] = head;
|
|
head = i;
|
|
#ifdef CGAL_SMALL_UNORDERED_MAP_STATS
|
|
if(collision>19){
|
|
std::cerr << collision << " collisions" << std::endl;
|
|
}else{
|
|
++collisions[collision];
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
i = (i+1)%M;
|
|
#ifdef CGAL_SMALL_UNORDERED_MAP_STATS
|
|
++collision;
|
|
#endif
|
|
}while(i != h);
|
|
CGAL_error();
|
|
}
|
|
|
|
// et only once as it is erased
|
|
const T& get_and_erase(const K& k) const
|
|
{
|
|
unsigned int h = hash(k)%M;
|
|
unsigned int i = h;
|
|
do{
|
|
if((occupied[i] == 1) && (data[i].first == k)){
|
|
occupied[i] = -1;
|
|
return data[i].second;
|
|
}
|
|
i = (i+1)%M;
|
|
}while(i != h);
|
|
CGAL_error();
|
|
}
|
|
|
|
void clear()
|
|
{
|
|
head = -2;
|
|
// without erase we would have to call occupied.fill(-1); which is costly
|
|
}
|
|
|
|
struct iterator {
|
|
const Small_unordered_map& map;
|
|
int pos;
|
|
|
|
iterator(const Small_unordered_map& map)
|
|
: map(map),pos(-2)
|
|
{}
|
|
|
|
iterator(const Small_unordered_map& map, int pos)
|
|
: map(map), pos(pos)
|
|
{}
|
|
|
|
bool operator==(const iterator& other) const
|
|
{
|
|
return pos == other.pos;
|
|
}
|
|
|
|
bool operator!=(const iterator& other) const
|
|
{
|
|
return pos != other.pos;
|
|
}
|
|
iterator operator++()
|
|
{
|
|
pos = map.unfreelist[pos];
|
|
return *this;
|
|
}
|
|
|
|
const std::pair<K,T>& operator*()const
|
|
{
|
|
return map.data[pos];
|
|
}
|
|
};
|
|
|
|
iterator begin() const
|
|
{
|
|
return iterator(*this,head);
|
|
}
|
|
|
|
iterator end() const
|
|
{
|
|
return iterator(*this);
|
|
}
|
|
|
|
void clear(const iterator it)
|
|
{
|
|
occupied[it.pos] = -1;
|
|
}
|
|
|
|
friend struct iterator;
|
|
};
|
|
|
|
} // namespace CGAL
|
|
#endif // CGAL_SMALL_UNORDERED_MAP_H
|