Merge 8b878a841e into 5e6fdda16b
				
					
				
			This commit is contained in:
		
						commit
						a69e4a0e2d
					
				
							
								
								
									
										2
									
								
								.github/workflows/osrm-backend.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/osrm-backend.yml
									
									
									
									
										vendored
									
									
								
							@ -703,7 +703,7 @@ jobs:
 | 
			
		||||
              gunzip -c ./pr/test/data/poland_gps_traces.csv.gz > ~/gps_traces.csv
 | 
			
		||||
          else
 | 
			
		||||
              if [ ! -f "~/data.osm.pbf" ]; then
 | 
			
		||||
                wget http://download.geofabrik.de/europe/germany/berlin-latest.osm.pbf -O ~/data.osm.pbf
 | 
			
		||||
                wget http://download.geofabrik.de/europe/germany/berlin-latest.osm.pbf -O ~/data.osm.pbf --quiet
 | 
			
		||||
              else
 | 
			
		||||
                echo "Using cached data.osm.pbf"
 | 
			
		||||
              fi
 | 
			
		||||
 | 
			
		||||
@ -302,6 +302,10 @@ include_directories(SYSTEM ${PROTOZERO_INCLUDE_DIR})
 | 
			
		||||
set(VTZERO_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/vtzero/include")
 | 
			
		||||
include_directories(SYSTEM ${VTZERO_INCLUDE_DIR})
 | 
			
		||||
 | 
			
		||||
set(ANKERL_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/unordered_dense/include")
 | 
			
		||||
include_directories(SYSTEM ${ANKERL_INCLUDE_DIR})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
set(FLATBUFFERS_BUILD_TESTS OFF CACHE BOOL "Disable the build of Flatbuffers tests and samples.")
 | 
			
		||||
set(FLATBUFFERS_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/flatbuffers")
 | 
			
		||||
set(FLATBUFFERS_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/flatbuffers/include")
 | 
			
		||||
 | 
			
		||||
@ -5,58 +5,19 @@
 | 
			
		||||
#include <boost/heap/d_ary_heap.hpp>
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
#include <boost/unordered_map.hpp>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <limits>
 | 
			
		||||
#include <map>
 | 
			
		||||
#include <optional>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <unordered_set>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
namespace osrm::util
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
template <typename NodeID, typename Key> class GenerationArrayStorage
 | 
			
		||||
{
 | 
			
		||||
    using GenerationCounter = std::uint16_t;
 | 
			
		||||
 | 
			
		||||
  public:
 | 
			
		||||
    explicit GenerationArrayStorage(std::size_t size)
 | 
			
		||||
        : positions(size, 0), generation(1), generations(size, 0)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Key &operator[](NodeID node)
 | 
			
		||||
    {
 | 
			
		||||
        generation[node] = generation;
 | 
			
		||||
        return positions[node];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Key peek_index(const NodeID node) const
 | 
			
		||||
    {
 | 
			
		||||
        if (generations[node] < generation)
 | 
			
		||||
        {
 | 
			
		||||
            return std::numeric_limits<Key>::max();
 | 
			
		||||
        }
 | 
			
		||||
        return positions[node];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void Clear()
 | 
			
		||||
    {
 | 
			
		||||
        generation++;
 | 
			
		||||
        // if generation overflows we end up at 0 again and need to clear the vector
 | 
			
		||||
        if (generation == 0)
 | 
			
		||||
        {
 | 
			
		||||
            generation = 1;
 | 
			
		||||
            std::fill(generations.begin(), generations.end(), 0);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    GenerationCounter generation;
 | 
			
		||||
    std::vector<GenerationCounter> generations;
 | 
			
		||||
    std::vector<Key> positions;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename NodeID, typename Key> class ArrayStorage
 | 
			
		||||
{
 | 
			
		||||
  public:
 | 
			
		||||
@ -72,33 +33,10 @@ template <typename NodeID, typename Key> class ArrayStorage
 | 
			
		||||
    std::vector<Key> positions;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename NodeID, typename Key> class MapStorage
 | 
			
		||||
{
 | 
			
		||||
  public:
 | 
			
		||||
    explicit MapStorage(std::size_t) {}
 | 
			
		||||
 | 
			
		||||
    Key &operator[](NodeID node) { return nodes[node]; }
 | 
			
		||||
 | 
			
		||||
    void Clear() { nodes.clear(); }
 | 
			
		||||
 | 
			
		||||
    Key peek_index(const NodeID node) const
 | 
			
		||||
    {
 | 
			
		||||
        const auto iter = nodes.find(node);
 | 
			
		||||
        if (nodes.end() != iter)
 | 
			
		||||
        {
 | 
			
		||||
            return iter->second;
 | 
			
		||||
        }
 | 
			
		||||
        return std::numeric_limits<Key>::max();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    std::map<NodeID, Key> nodes;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename NodeID, typename Key> class UnorderedMapStorage
 | 
			
		||||
{
 | 
			
		||||
  public:
 | 
			
		||||
    explicit UnorderedMapStorage(std::size_t) { nodes.rehash(1000); }
 | 
			
		||||
    explicit UnorderedMapStorage(std::size_t) {}
 | 
			
		||||
 | 
			
		||||
    Key &operator[](const NodeID node) { return nodes[node]; }
 | 
			
		||||
 | 
			
		||||
@ -121,7 +59,7 @@ template <typename NodeID, typename Key> class UnorderedMapStorage
 | 
			
		||||
    void Clear() { nodes.clear(); }
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    std::unordered_map<NodeID, Key> nodes;
 | 
			
		||||
    ankerl::unordered_dense::segmented_map<NodeID, Key> nodes;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename NodeID,
 | 
			
		||||
 | 
			
		||||
@ -30,6 +30,9 @@ VTZERO_TAG=v1.1.0
 | 
			
		||||
FMT_PATH="fmtlib/fmt"
 | 
			
		||||
FMT_TAG=v10.2.1
 | 
			
		||||
 | 
			
		||||
ANKERL_PATH="martinus/unordered_dense"
 | 
			
		||||
ANKERL_TAG=v4.4.0
 | 
			
		||||
 | 
			
		||||
function update_subtree () {
 | 
			
		||||
    name=$(echo "$1" | tr '[:lower:]' '[:upper:]')
 | 
			
		||||
    path=$(tmpvar=${name}_PATH && echo ${!tmpvar})
 | 
			
		||||
@ -53,6 +56,6 @@ function update_subtree () {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
## Update dependencies
 | 
			
		||||
for dep in osmium sol rapidjson microtar protozero vtzero fmt; do
 | 
			
		||||
for dep in ankerl osmium sol rapidjson microtar protozero vtzero fmt; do
 | 
			
		||||
    update_subtree $dep
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										20
									
								
								third_party/unordered_dense/.clang-format
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								third_party/unordered_dense/.clang-format
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
			
		||||
# see https://clang.llvm.org/docs/ClangFormatStyleOptions.html
 | 
			
		||||
---
 | 
			
		||||
BasedOnStyle: LLVM
 | 
			
		||||
Language: Cpp
 | 
			
		||||
Standard: c++17
 | 
			
		||||
ColumnLimit: 127
 | 
			
		||||
 | 
			
		||||
AccessModifierOffset: -4
 | 
			
		||||
AlignEscapedNewlines: Left
 | 
			
		||||
AllowShortFunctionsOnASingleLine: Empty
 | 
			
		||||
AllowShortLambdasOnASingleLine: false
 | 
			
		||||
AlwaysBreakTemplateDeclarations: true
 | 
			
		||||
BinPackArguments: false
 | 
			
		||||
BinPackParameters: false
 | 
			
		||||
BreakConstructorInitializers: BeforeComma
 | 
			
		||||
BreakStringLiterals: false
 | 
			
		||||
IndentPPDirectives: AfterHash
 | 
			
		||||
IndentWidth: 4
 | 
			
		||||
PointerAlignment: Left
 | 
			
		||||
UseTab: Never
 | 
			
		||||
							
								
								
									
										55
									
								
								third_party/unordered_dense/.clang-tidy
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								third_party/unordered_dense/.clang-tidy
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,55 @@
 | 
			
		||||
---
 | 
			
		||||
Checks: '*
 | 
			
		||||
  -abseil-string-find-str-contains
 | 
			
		||||
  -altera*
 | 
			
		||||
  -bugprone-easily-swappable-parameters
 | 
			
		||||
  -cert-err58-cpp
 | 
			
		||||
  -cppcoreguidelines-avoid-magic-numbers
 | 
			
		||||
  -cppcoreguidelines-pro-bounds-constant-array-index
 | 
			
		||||
  -cppcoreguidelines-pro-bounds-pointer-arithmetic
 | 
			
		||||
  -fuchsia*
 | 
			
		||||
  -llvm-header-guard
 | 
			
		||||
  -llvmlibc*
 | 
			
		||||
  -readability-function-cognitive-complexity
 | 
			
		||||
  -readability-identifier-length
 | 
			
		||||
  -readability-magic-numbers
 | 
			
		||||
  '
 | 
			
		||||
HeaderFilterRegex: ''
 | 
			
		||||
CheckOptions:
 | 
			
		||||
  cppcoreguidelines-avoid-do-while.IgnoreMacros: 'true'
 | 
			
		||||
  readability-identifier-naming.MacroDefinitionCase: 'UPPER_CASE'
 | 
			
		||||
  readability-identifier-naming.TemplateParameterCase: 'CamelCase'
 | 
			
		||||
  readability-identifier-naming.TypeTemplateParameterCase: 'CamelCase'
 | 
			
		||||
  readability-identifier-naming.ValueTemplateParameterCase: 'CamelCase'
 | 
			
		||||
  readability-identifier-naming.ParameterPackCase: 'lower_case'
 | 
			
		||||
  readability-identifier-naming.AbstractClassCase: 'lower_case'
 | 
			
		||||
  readability-identifier-naming.ClassCase: 'lower_case'
 | 
			
		||||
  readability-identifier-naming.ClassMemberCase: 'lower_case'
 | 
			
		||||
  readability-identifier-naming.ConstantCase: 'lower_case'
 | 
			
		||||
  readability-identifier-naming.ConstexprVariableCase: 'lower_case'
 | 
			
		||||
  readability-identifier-naming.EnumCase: 'lower_case'
 | 
			
		||||
  readability-identifier-naming.EnumConstantCase: 'lower_case'
 | 
			
		||||
  readability-identifier-naming.FunctionCase: 'lower_case'
 | 
			
		||||
  readability-identifier-naming.GlobalConstantCase: 'lower_case'
 | 
			
		||||
  readability-identifier-naming.LocalVariableCase: 'lower_case'
 | 
			
		||||
  readability-identifier-naming.MemberCase: 'lower_case'
 | 
			
		||||
  readability-identifier-naming.NamespaceCase: 'lower_case'
 | 
			
		||||
  readability-identifier-naming.ParameterCase: 'lower_case'
 | 
			
		||||
  readability-identifier-naming.StructCase: 'lower_case'
 | 
			
		||||
  readability-identifier-naming.TypeAliasCase: 'lower_case'
 | 
			
		||||
  readability-identifier-naming.TypedefCase: 'lower_case'
 | 
			
		||||
  readability-identifier-naming.StaticConstantCase: 'lower_case'
 | 
			
		||||
  readability-identifier-naming.StaticVariableCase: 'lower_case'
 | 
			
		||||
  readability-identifier-naming.UnionCase: 'lower_case'
 | 
			
		||||
  readability-identifier-naming.VariableCase: 'lower_case'
 | 
			
		||||
  readability-identifier-naming.GlobalConstantPrefix: 'global_'
 | 
			
		||||
  readability-identifier-naming.GlobalVariablePrefix: 'global_'
 | 
			
		||||
  readability-identifier-naming.MemberPrefix: 'm_'
 | 
			
		||||
  readability-identifier-naming.PrivateMemberPrefix: 'm_'
 | 
			
		||||
  readability-identifier-naming.PrivateMemberPrefix: 'm_'
 | 
			
		||||
  readability-identifier-naming.ProtectedMemberPrefix: 'm_'
 | 
			
		||||
  readability-identifier-naming.PublicMemberPrefix: ''
 | 
			
		||||
  readability-identifier-naming.StaticConstantPrefix: 'static_'
 | 
			
		||||
  readability-identifier-naming.StaticVariablePrefix: 'static_'
 | 
			
		||||
  readability-identifier-naming.ClassMemberPrefix: 'static_'
 | 
			
		||||
...
 | 
			
		||||
							
								
								
									
										1
									
								
								third_party/unordered_dense/.fuzz-corpus-base-dir
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								third_party/unordered_dense/.fuzz-corpus-base-dir
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
data/fuzz
 | 
			
		||||
							
								
								
									
										13
									
								
								third_party/unordered_dense/.github/FUNDING.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								third_party/unordered_dense/.github/FUNDING.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
# These are supported funding model platforms
 | 
			
		||||
 | 
			
		||||
github: [martinus] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
 | 
			
		||||
patreon: # Replace with a single Patreon username
 | 
			
		||||
open_collective: # Replace with a single Open Collective username
 | 
			
		||||
ko_fi: # Replace with a single Ko-fi username
 | 
			
		||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
 | 
			
		||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
 | 
			
		||||
liberapay: # Replace with a single Liberapay username
 | 
			
		||||
issuehunt: # Replace with a single IssueHunt username
 | 
			
		||||
otechie: # Replace with a single Otechie username
 | 
			
		||||
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
 | 
			
		||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
 | 
			
		||||
							
								
								
									
										28
									
								
								third_party/unordered_dense/.github/ISSUE_TEMPLATE/bug_report.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								third_party/unordered_dense/.github/ISSUE_TEMPLATE/bug_report.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
			
		||||
---
 | 
			
		||||
name: Bug report
 | 
			
		||||
about: Create a report to help us improve
 | 
			
		||||
title: "[BUG] "
 | 
			
		||||
labels: bug
 | 
			
		||||
assignees: martinus
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
**Describe the bug**
 | 
			
		||||
A clear and concise description of what the bug is.
 | 
			
		||||
 | 
			
		||||
**To Reproduce**
 | 
			
		||||
Steps to reproduce the behavior:
 | 
			
		||||
1.
 | 
			
		||||
2.
 | 
			
		||||
3.
 | 
			
		||||
 | 
			
		||||
**Expected behavior**
 | 
			
		||||
A clear and concise description of what you expected to happen.
 | 
			
		||||
 | 
			
		||||
**System (please complete the following information):**
 | 
			
		||||
 - OS: [e.g. Linux]
 | 
			
		||||
 - Compiler: [e.g. clang++, g++]
 | 
			
		||||
 - Version [e.g. 13.0.1]
 | 
			
		||||
 | 
			
		||||
**Additional context**
 | 
			
		||||
Add any other context about the problem here.
 | 
			
		||||
							
								
								
									
										20
									
								
								third_party/unordered_dense/.github/ISSUE_TEMPLATE/feature_request.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								third_party/unordered_dense/.github/ISSUE_TEMPLATE/feature_request.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
			
		||||
---
 | 
			
		||||
name: Feature request
 | 
			
		||||
about: Suggest an idea for this project
 | 
			
		||||
title: ''
 | 
			
		||||
labels: enhancement
 | 
			
		||||
assignees: martinus
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
**Is your feature request related to a problem? Please describe.**
 | 
			
		||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
 | 
			
		||||
 | 
			
		||||
**Describe the solution you'd like**
 | 
			
		||||
A clear and concise description of what you want to happen.
 | 
			
		||||
 | 
			
		||||
**Describe alternatives you've considered**
 | 
			
		||||
A clear and concise description of any alternative solutions or features you've considered.
 | 
			
		||||
 | 
			
		||||
**Additional context**
 | 
			
		||||
Add any other context or screenshots about the feature request here.
 | 
			
		||||
							
								
								
									
										74
									
								
								third_party/unordered_dense/.github/workflows/main.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								third_party/unordered_dense/.github/workflows/main.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,74 @@
 | 
			
		||||
name: Build, Test, Lint
 | 
			
		||||
 | 
			
		||||
on: [push, pull_request]
 | 
			
		||||
 | 
			
		||||
# see https://github.com/mesonbuild/meson/blob/master/docs/markdown/Continuous-Integration.md
 | 
			
		||||
jobs:
 | 
			
		||||
 | 
			
		||||
  lint:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v3
 | 
			
		||||
    - uses: actions/setup-python@v4
 | 
			
		||||
      with:
 | 
			
		||||
        python-version: '3.x'
 | 
			
		||||
    - run: ./scripts/lint/lint-version.py
 | 
			
		||||
 | 
			
		||||
  linux:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v3
 | 
			
		||||
    - run: sudo apt-get install -yq libboost-dev
 | 
			
		||||
    - uses: hendrikmuhs/ccache-action@v1.2
 | 
			
		||||
    - uses: actions/setup-python@v4
 | 
			
		||||
      with:
 | 
			
		||||
        python-version: '3.x'
 | 
			
		||||
    - run: pip install meson ninja
 | 
			
		||||
    - run: meson setup builddir/
 | 
			
		||||
      env:
 | 
			
		||||
        CXX: ccache c++
 | 
			
		||||
    - run: meson test -C builddir/ -v
 | 
			
		||||
    - uses: actions/upload-artifact@v3
 | 
			
		||||
      if: failure()
 | 
			
		||||
      with:
 | 
			
		||||
        name: Linux_Meson_Testlog
 | 
			
		||||
        path: builddir/meson-logs/testlog.txt
 | 
			
		||||
 | 
			
		||||
  macos:
 | 
			
		||||
    runs-on: macos-latest
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v3
 | 
			
		||||
    - uses: actions/setup-python@v4
 | 
			
		||||
      with:
 | 
			
		||||
        python-version: '3.x'
 | 
			
		||||
    - run: brew install gcc ccache meson ninja
 | 
			
		||||
    - run: meson setup builddir/
 | 
			
		||||
      env:
 | 
			
		||||
        CXX: ccache c++
 | 
			
		||||
    - run: meson test -C builddir/ -v
 | 
			
		||||
    - uses: actions/upload-artifact@v3
 | 
			
		||||
      if: failure()
 | 
			
		||||
      with:
 | 
			
		||||
        name: MacOS_Meson_Testlog
 | 
			
		||||
        path: builddir/meson-logs/testlog.txt
 | 
			
		||||
  
 | 
			
		||||
  windows:
 | 
			
		||||
    runs-on: windows-latest
 | 
			
		||||
    steps:
 | 
			
		||||
    - uses: actions/checkout@v3
 | 
			
		||||
    - uses: actions/setup-python@v4
 | 
			
		||||
      with:
 | 
			
		||||
        python-version: '3.x'
 | 
			
		||||
    - uses: BSFishy/pip-action@v1
 | 
			
		||||
      with:
 | 
			
		||||
        packages: ninja meson
 | 
			
		||||
    - uses: ilammy/msvc-dev-cmd@v1
 | 
			
		||||
    - run: meson setup builddir
 | 
			
		||||
    - run: meson test -C builddir -v
 | 
			
		||||
    - uses: actions/upload-artifact@v3
 | 
			
		||||
      if: failure()
 | 
			
		||||
      with:
 | 
			
		||||
        name: Windows_Meson_Testlog
 | 
			
		||||
        path: |
 | 
			
		||||
          builddir/meson-logs/testlog.txt
 | 
			
		||||
          builddir/test/udm-test.exe
 | 
			
		||||
							
								
								
									
										14
									
								
								third_party/unordered_dense/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								third_party/unordered_dense/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
			
		||||
build
 | 
			
		||||
builddir
 | 
			
		||||
.cache
 | 
			
		||||
.vscode
 | 
			
		||||
compile_commands.json
 | 
			
		||||
 | 
			
		||||
# ignore all in subprojects except the .wrap files
 | 
			
		||||
/subprojects/*
 | 
			
		||||
!/subprojects/*.wrap
 | 
			
		||||
 | 
			
		||||
# c++ modules
 | 
			
		||||
*.pcm
 | 
			
		||||
a.out
 | 
			
		||||
*.o
 | 
			
		||||
							
								
								
									
										61
									
								
								third_party/unordered_dense/CMakeLists.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								third_party/unordered_dense/CMakeLists.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,61 @@
 | 
			
		||||
cmake_minimum_required(VERSION 3.12)
 | 
			
		||||
project("unordered_dense"
 | 
			
		||||
    VERSION 4.4.0
 | 
			
		||||
    DESCRIPTION "A fast & densely stored hashmap and hashset based on robin-hood backward shift deletion"
 | 
			
		||||
    HOMEPAGE_URL "https://github.com/martinus/unordered_dense")
 | 
			
		||||
 | 
			
		||||
include(GNUInstallDirs)
 | 
			
		||||
 | 
			
		||||
# determine whether this is a standalone project or included by other projects
 | 
			
		||||
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
 | 
			
		||||
    set(_unordered_dense_is_toplevel_project TRUE)
 | 
			
		||||
else()
 | 
			
		||||
    set(_unordered_dense_is_toplevel_project FALSE)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
add_library(unordered_dense INTERFACE)
 | 
			
		||||
add_library(unordered_dense::unordered_dense ALIAS unordered_dense)
 | 
			
		||||
 | 
			
		||||
target_include_directories(
 | 
			
		||||
    unordered_dense
 | 
			
		||||
    INTERFACE
 | 
			
		||||
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
 | 
			
		||||
        $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
 | 
			
		||||
 | 
			
		||||
target_compile_features(unordered_dense INTERFACE cxx_std_17)
 | 
			
		||||
 | 
			
		||||
if(_unordered_dense_is_toplevel_project)
 | 
			
		||||
    # locations are provided by GNUInstallDirs
 | 
			
		||||
    install(
 | 
			
		||||
        TARGETS unordered_dense
 | 
			
		||||
        EXPORT unordered_dense_Targets
 | 
			
		||||
        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
 | 
			
		||||
        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
 | 
			
		||||
        RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 | 
			
		||||
 | 
			
		||||
    include(CMakePackageConfigHelpers)
 | 
			
		||||
    write_basic_package_version_file(
 | 
			
		||||
        "unordered_denseConfigVersion.cmake"
 | 
			
		||||
        VERSION ${PROJECT_VERSION}
 | 
			
		||||
        COMPATIBILITY SameMajorVersion)
 | 
			
		||||
 | 
			
		||||
    configure_package_config_file(
 | 
			
		||||
        "${PROJECT_SOURCE_DIR}/cmake/unordered_denseConfig.cmake.in"
 | 
			
		||||
        "${PROJECT_BINARY_DIR}/unordered_denseConfig.cmake"
 | 
			
		||||
        INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
 | 
			
		||||
 | 
			
		||||
    install(
 | 
			
		||||
        EXPORT unordered_dense_Targets
 | 
			
		||||
        FILE unordered_denseTargets.cmake
 | 
			
		||||
        NAMESPACE unordered_dense::
 | 
			
		||||
        DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
 | 
			
		||||
 | 
			
		||||
    install(
 | 
			
		||||
        FILES "${PROJECT_BINARY_DIR}/unordered_denseConfig.cmake"
 | 
			
		||||
        "${PROJECT_BINARY_DIR}/unordered_denseConfigVersion.cmake"
 | 
			
		||||
        DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
 | 
			
		||||
 | 
			
		||||
    install(
 | 
			
		||||
        DIRECTORY ${PROJECT_SOURCE_DIR}/include/ankerl
 | 
			
		||||
        DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
 | 
			
		||||
endif()
 | 
			
		||||
							
								
								
									
										76
									
								
								third_party/unordered_dense/CODE_OF_CONDUCT.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								third_party/unordered_dense/CODE_OF_CONDUCT.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,76 @@
 | 
			
		||||
# Contributor Covenant Code of Conduct
 | 
			
		||||
 | 
			
		||||
## Our Pledge
 | 
			
		||||
 | 
			
		||||
In the interest of fostering an open and welcoming environment, we as
 | 
			
		||||
contributors and maintainers pledge to making participation in our project and
 | 
			
		||||
our community a harassment-free experience for everyone, regardless of age, body
 | 
			
		||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
 | 
			
		||||
level of experience, education, socio-economic status, nationality, personal
 | 
			
		||||
appearance, race, religion, or sexual identity and orientation.
 | 
			
		||||
 | 
			
		||||
## Our Standards
 | 
			
		||||
 | 
			
		||||
Examples of behavior that contributes to creating a positive environment
 | 
			
		||||
include:
 | 
			
		||||
 | 
			
		||||
* Using welcoming and inclusive language
 | 
			
		||||
* Being respectful of differing viewpoints and experiences
 | 
			
		||||
* Gracefully accepting constructive criticism
 | 
			
		||||
* Focusing on what is best for the community
 | 
			
		||||
* Showing empathy towards other community members
 | 
			
		||||
 | 
			
		||||
Examples of unacceptable behavior by participants include:
 | 
			
		||||
 | 
			
		||||
* The use of sexualized language or imagery and unwelcome sexual attention or
 | 
			
		||||
 advances
 | 
			
		||||
* Trolling, insulting/derogatory comments, and personal or political attacks
 | 
			
		||||
* Public or private harassment
 | 
			
		||||
* Publishing others' private information, such as a physical or electronic
 | 
			
		||||
 address, without explicit permission
 | 
			
		||||
* Other conduct which could reasonably be considered inappropriate in a
 | 
			
		||||
 professional setting
 | 
			
		||||
 | 
			
		||||
## Our Responsibilities
 | 
			
		||||
 | 
			
		||||
Project maintainers are responsible for clarifying the standards of acceptable
 | 
			
		||||
behavior and are expected to take appropriate and fair corrective action in
 | 
			
		||||
response to any instances of unacceptable behavior.
 | 
			
		||||
 | 
			
		||||
Project maintainers have the right and responsibility to remove, edit, or
 | 
			
		||||
reject comments, commits, code, wiki edits, issues, and other contributions
 | 
			
		||||
that are not aligned to this Code of Conduct, or to ban temporarily or
 | 
			
		||||
permanently any contributor for other behaviors that they deem inappropriate,
 | 
			
		||||
threatening, offensive, or harmful.
 | 
			
		||||
 | 
			
		||||
## Scope
 | 
			
		||||
 | 
			
		||||
This Code of Conduct applies both within project spaces and in public spaces
 | 
			
		||||
when an individual is representing the project or its community. Examples of
 | 
			
		||||
representing a project or community include using an official project e-mail
 | 
			
		||||
address, posting via an official social media account, or acting as an appointed
 | 
			
		||||
representative at an online or offline event. Representation of a project may be
 | 
			
		||||
further defined and clarified by project maintainers.
 | 
			
		||||
 | 
			
		||||
## Enforcement
 | 
			
		||||
 | 
			
		||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
 | 
			
		||||
reported by contacting the project team at martin.ankerl@gmail.com. All
 | 
			
		||||
complaints will be reviewed and investigated and will result in a response that
 | 
			
		||||
is deemed necessary and appropriate to the circumstances. The project team is
 | 
			
		||||
obligated to maintain confidentiality with regard to the reporter of an incident.
 | 
			
		||||
Further details of specific enforcement policies may be posted separately.
 | 
			
		||||
 | 
			
		||||
Project maintainers who do not follow or enforce the Code of Conduct in good
 | 
			
		||||
faith may face temporary or permanent repercussions as determined by other
 | 
			
		||||
members of the project's leadership.
 | 
			
		||||
 | 
			
		||||
## Attribution
 | 
			
		||||
 | 
			
		||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
 | 
			
		||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
 | 
			
		||||
 | 
			
		||||
[homepage]: https://www.contributor-covenant.org
 | 
			
		||||
 | 
			
		||||
For answers to common questions about this code of conduct, see
 | 
			
		||||
https://www.contributor-covenant.org/faq
 | 
			
		||||
							
								
								
									
										3
									
								
								third_party/unordered_dense/CONTRIBUTING.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								third_party/unordered_dense/CONTRIBUTING.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
			
		||||
* Coding style should be consistent with the code around you.
 | 
			
		||||
* Use automatic formatting with clang-format.
 | 
			
		||||
* One feature per pull request
 | 
			
		||||
							
								
								
									
										21
									
								
								third_party/unordered_dense/LICENSE
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								third_party/unordered_dense/LICENSE
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
MIT License
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2022 Martin Leitner-Ankerl
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
							
								
								
									
										374
									
								
								third_party/unordered_dense/README.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										374
									
								
								third_party/unordered_dense/README.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,374 @@
 | 
			
		||||
<a id="top"></a>
 | 
			
		||||
 | 
			
		||||
[](https://github.com/martinus/unordered_dense/releases)
 | 
			
		||||
[](https://raw.githubusercontent.com/martinus/unordered_dense/main/LICENSE)
 | 
			
		||||
[](https://github.com/martinus/unordered_dense/actions)
 | 
			
		||||
[](https://bestpractices.coreinfrastructure.org/projects/6220)
 | 
			
		||||
[](https://github.com/sponsors/martinus)
 | 
			
		||||
 | 
			
		||||
# 🚀 ankerl::unordered_dense::{map, set} <!-- omit in toc -->
 | 
			
		||||
 | 
			
		||||
A fast & densely stored hashmap and hashset based on robin-hood backward shift deletion for C++17 and later.
 | 
			
		||||
 | 
			
		||||
The classes `ankerl::unordered_dense::map` and `ankerl::unordered_dense::set` are (almost) drop-in replacements of `std::unordered_map` and `std::unordered_set`. While they don't have as strong iterator / reference stability guaranties, they are typically *much* faster.
 | 
			
		||||
 | 
			
		||||
Additionally, there are `ankerl::unordered_dense::segmented_map` and `ankerl::unordered_dense::segmented_set` with lower peak memory usage. and stable iterator/references on insert.
 | 
			
		||||
 | 
			
		||||
- [1. Overview](#1-overview)
 | 
			
		||||
- [2. Installation](#2-installation)
 | 
			
		||||
  - [2.1. Installing using cmake](#21-installing-using-cmake)
 | 
			
		||||
- [3. Usage](#3-usage)
 | 
			
		||||
  - [3.1. Modules](#31-modules)
 | 
			
		||||
  - [3.2. Hash](#32-hash)
 | 
			
		||||
    - [3.2.1. Simple Hash](#321-simple-hash)
 | 
			
		||||
    - [3.2.2. High Quality Hash](#322-high-quality-hash)
 | 
			
		||||
    - [3.2.3. Specialize `ankerl::unordered_dense::hash`](#323-specialize-ankerlunordered_densehash)
 | 
			
		||||
    - [3.2.4. Heterogeneous Overloads using `is_transparent`](#324-heterogeneous-overloads-using-is_transparent)
 | 
			
		||||
    - [3.2.5. Automatic Fallback to `std::hash`](#325-automatic-fallback-to-stdhash)
 | 
			
		||||
    - [3.2.6. Hash the Whole Memory](#326-hash-the-whole-memory)
 | 
			
		||||
  - [3.3. Container API](#33-container-api)
 | 
			
		||||
    - [3.3.1. `auto extract() && -> value_container_type`](#331-auto-extract----value_container_type)
 | 
			
		||||
    - [3.3.2. `extract()` single Elements](#332-extract-single-elements)
 | 
			
		||||
    - [3.3.3. `[[nodiscard]] auto values() const noexcept -> value_container_type const&`](#333-nodiscard-auto-values-const-noexcept---value_container_type-const)
 | 
			
		||||
    - [3.3.4. `auto replace(value_container_type&& container)`](#334-auto-replacevalue_container_type-container)
 | 
			
		||||
  - [3.4. Custom Container Types](#34-custom-container-types)
 | 
			
		||||
  - [3.5. Custom Bucket Types](#35-custom-bucket-types)
 | 
			
		||||
    - [3.5.1. `ankerl::unordered_dense::bucket_type::standard`](#351-ankerlunordered_densebucket_typestandard)
 | 
			
		||||
    - [3.5.2. `ankerl::unordered_dense::bucket_type::big`](#352-ankerlunordered_densebucket_typebig)
 | 
			
		||||
- [4. `segmented_map` and `segmented_set`](#4-segmented_map-and-segmented_set)
 | 
			
		||||
- [5. Design](#5-design)
 | 
			
		||||
  - [5.1. Inserts](#51-inserts)
 | 
			
		||||
  - [5.2. Lookups](#52-lookups)
 | 
			
		||||
  - [5.3. Removals](#53-removals)
 | 
			
		||||
- [6. Real World Usage](#6-real-world-usage)
 | 
			
		||||
 | 
			
		||||
## 1. Overview
 | 
			
		||||
 | 
			
		||||
The chosen design has a few advantages over `std::unordered_map`: 
 | 
			
		||||
 | 
			
		||||
* Perfect iteration speed - Data is stored in a `std::vector`, all data is contiguous!
 | 
			
		||||
* Very fast insertion & lookup speed, in the same ballpark as [`absl::flat_hash_map`](https://abseil.io/docs/cpp/guides/container`)
 | 
			
		||||
* Low memory usage
 | 
			
		||||
* Full support for `std::allocators`, and [polymorphic allocators](https://en.cppreference.com/w/cpp/memory/polymorphic_allocator). There are `ankerl::unordered_dense::pmr` typedefs available
 | 
			
		||||
* Customizeable storage type: with a template parameter you can e.g. switch from `std::vector` to `boost::interprocess::vector` or any other compatible random-access container.
 | 
			
		||||
* Better debugging: the underlying data can be easily seen in any debugger that can show an `std::vector`.
 | 
			
		||||
 | 
			
		||||
There's no free lunch, so there are a few disadvantages:
 | 
			
		||||
 | 
			
		||||
* Deletion speed is relatively slow. This needs two lookups: one for the element to delete, and one for the element that is moved onto the newly empty spot.
 | 
			
		||||
* no `const Key` in `std::pair<Key, Value>`
 | 
			
		||||
* Iterators and references are not stable on insert or erase.
 | 
			
		||||
 | 
			
		||||
## 2. Installation
 | 
			
		||||
 | 
			
		||||
<!-- See https://github.com/bernedom/SI/blob/main/doc/installation-guide.md -->
 | 
			
		||||
The default installation location is `/usr/local`.
 | 
			
		||||
 | 
			
		||||
### 2.1. Installing using cmake 
 | 
			
		||||
 | 
			
		||||
Clone the repository and run these commands in the cloned folder:
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
mkdir build && cd build
 | 
			
		||||
cmake ..
 | 
			
		||||
cmake --build . --target install
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Consider setting an install prefix if you do not want to install `unordered_dense` system wide, like so:
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
mkdir build && cd build
 | 
			
		||||
cmake -DCMAKE_INSTALL_PREFIX:PATH=${HOME}/unordered_dense_install ..
 | 
			
		||||
cmake --build . --target install
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
To make use of the installed library, add this to your project:
 | 
			
		||||
 | 
			
		||||
```cmake
 | 
			
		||||
find_package(unordered_dense CONFIG REQUIRED)
 | 
			
		||||
target_link_libraries(your_project_name unordered_dense::unordered_dense)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## 3. Usage
 | 
			
		||||
 | 
			
		||||
### 3.1. Modules
 | 
			
		||||
 | 
			
		||||
`ankerl::unordered_dense` supports c++20 modules. Simply compile `src/ankerl.unordered_dense.cpp` and use the resulting module, e.g. like so:
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
clang++ -std=c++20 -I include --precompile -x c++-module src/ankerl.unordered_dense.cpp
 | 
			
		||||
clang++ -std=c++20 -c ankerl.unordered_dense.pcm
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
To use the module with e.g. in `module_test.cpp`, use 
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
import ankerl.unordered_dense;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
and compile with e.g.
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
clang++ -std=c++20 -fprebuilt-module-path=. ankerl.unordered_dense.o module_test.cpp -o main
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
A simple demo script can be found in `test/modules`.
 | 
			
		||||
 | 
			
		||||
### 3.2. Hash
 | 
			
		||||
 | 
			
		||||
`ankerl::unordered_dense::hash` is a fast and high quality hash, based on [wyhash](https://github.com/wangyi-fudan/wyhash). The `ankerl::unordered_dense` map/set differentiates between hashes of high quality (good [avalanching effect](https://en.wikipedia.org/wiki/Avalanche_effect)) and bad quality. Hashes with good quality contain a special marker:
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
using is_avalanching = void;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This is the cases for the specializations `bool`, `char`, `signed char`, `unsigned char`, `char8_t`, `char16_t`, `char32_t`, `wchar_t`, `short`, `unsigned short`, `int`, `unsigned int`, `long`, `long long`, `unsigned long`, `unsigned long long`, `T*`, `std::unique_ptr<T>`, `std::shared_ptr<T>`, `enum`, `std::basic_string<C>`, and `std::basic_string_view<C>`.
 | 
			
		||||
 | 
			
		||||
Hashes that do not contain such a marker are assumed to be of bad quality and receive an additional mixing step inside the map/set implementation.
 | 
			
		||||
 | 
			
		||||
#### 3.2.1. Simple Hash
 | 
			
		||||
 | 
			
		||||
Consider a simple custom key type:
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
struct id {
 | 
			
		||||
    uint64_t value{};
 | 
			
		||||
 | 
			
		||||
    auto operator==(id const& other) const -> bool {
 | 
			
		||||
        return value == other.value;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The simplest implementation of a hash is this:
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
struct custom_hash_simple {
 | 
			
		||||
    auto operator()(id const& x) const noexcept -> uint64_t {
 | 
			
		||||
        return x.value;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
```
 | 
			
		||||
This can be used e.g. with 
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
auto ids = ankerl::unordered_dense::set<id, custom_hash_simple>();
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Since `custom_hash_simple` doesn't have a `using is_avalanching = void;` marker it is considered to be of bad quality and additional mixing of `x.value` is automatically provided inside the set.
 | 
			
		||||
 | 
			
		||||
#### 3.2.2. High Quality Hash
 | 
			
		||||
 | 
			
		||||
Back to the `id` example, we can easily implement a higher quality hash:
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
struct custom_hash_avalanching {
 | 
			
		||||
    using is_avalanching = void;
 | 
			
		||||
 | 
			
		||||
    auto operator()(id const& x) const noexcept -> uint64_t {
 | 
			
		||||
        return ankerl::unordered_dense::detail::wyhash::hash(x.value);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
We know `wyhash::hash` is of high quality, so we can add `using is_avalanching = void;` which makes the map/set directly use the returned value.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#### 3.2.3. Specialize `ankerl::unordered_dense::hash`
 | 
			
		||||
 | 
			
		||||
Instead of creating a new class you can also specialize `ankerl::unordered_dense::hash`:
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
template <>
 | 
			
		||||
struct ankerl::unordered_dense::hash<id> {
 | 
			
		||||
    using is_avalanching = void;
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] auto operator()(id const& x) const noexcept -> uint64_t {
 | 
			
		||||
        return detail::wyhash::hash(x.value);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### 3.2.4. Heterogeneous Overloads using `is_transparent`
 | 
			
		||||
 | 
			
		||||
This map/set supports heterogeneous overloads as described in [P2363 Extending associative containers with the remaining heterogeneous overloads](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2363r3.html) which is [targeted for C++26](https://wg21.link/p2077r2). This has overloads for `find`, `count`, `contains`, `equal_range` (see [P0919R3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0919r3.html)), `erase` (see [P2077R2](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2077r2.html)), and  `try_emplace`, `insert_or_assign`, `operator[]`, `at`, and `insert` & `emplace` for sets (see [P2363R3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2363r3.html)).
 | 
			
		||||
 | 
			
		||||
For heterogeneous overloads to take affect, both `hasher` and `key_equal` need to have the attribute `is_transparent` set.
 | 
			
		||||
 | 
			
		||||
Here is an example implementation that's usable with any string types that is convertible to `std::string_view` (e.g. `char const*` and `std::string`):
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
struct string_hash {
 | 
			
		||||
    using is_transparent = void; // enable heterogeneous overloads
 | 
			
		||||
    using is_avalanching = void; // mark class as high quality avalanching hash
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] auto operator()(std::string_view str) const noexcept -> uint64_t {
 | 
			
		||||
        return ankerl::unordered_dense::hash<std::string_view>{}(str);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
To make use of this hash you'll need to specify it as a type, and also a `key_equal` with `is_transparent` like [std::equal_to<>](https://en.cppreference.com/w/cpp/utility/functional/equal_to_void):
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
auto map = ankerl::unordered_dense::map<std::string, size_t, string_hash, std::equal_to<>>();
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
For more information see the examples in `test/unit/transparent.cpp`.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#### 3.2.5. Automatic Fallback to `std::hash`
 | 
			
		||||
 | 
			
		||||
When an implementation for `std::hash` of a custom type is available, this is automatically used and assumed to be of bad quality (thus `std::hash` is used, but an additional mixing step is performed).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#### 3.2.6. Hash the Whole Memory
 | 
			
		||||
 | 
			
		||||
When the type [has a unique object representation](https://en.cppreference.com/w/cpp/types/has_unique_object_representations) (no padding, trivially copyable), one can just hash the object's memory. Consider a simple class
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
struct point {
 | 
			
		||||
    int x{};
 | 
			
		||||
    int y{};
 | 
			
		||||
 | 
			
		||||
    auto operator==(point const& other) const -> bool {
 | 
			
		||||
        return x == other.x && y == other.y;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
A fast and high quality hash can be easily provided like so:
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
struct custom_hash_unique_object_representation {
 | 
			
		||||
    using is_avalanching = void;
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] auto operator()(point const& f) const noexcept -> uint64_t {
 | 
			
		||||
        static_assert(std::has_unique_object_representations_v<point>);
 | 
			
		||||
        return ankerl::unordered_dense::detail::wyhash::hash(&f, sizeof(f));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 3.3. Container API
 | 
			
		||||
 | 
			
		||||
In addition to the standard `std::unordered_map` API (see https://en.cppreference.com/w/cpp/container/unordered_map) we have additional API that is somewhat similar to the node API, but leverages the fact that we're using a random access container internally:
 | 
			
		||||
 | 
			
		||||
#### 3.3.1. `auto extract() && -> value_container_type`
 | 
			
		||||
 | 
			
		||||
Extracts the internally used container. `*this` is emptied.
 | 
			
		||||
 | 
			
		||||
#### 3.3.2. `extract()` single Elements
 | 
			
		||||
 | 
			
		||||
Similar to `erase()` I have an API call `extract()`. It behaves exactly the same as `erase`, except that the return value is the moved element that is removed from the container:
 | 
			
		||||
 | 
			
		||||
* `auto extract(const_iterator it) -> value_type`
 | 
			
		||||
* `auto extract(Key const& key) -> std::optional<value_type>`
 | 
			
		||||
* `template <class K> auto extract(K&& key) -> std::optional<value_type>`
 | 
			
		||||
 | 
			
		||||
Note that the `extract(key)` API returns an `std::optional<value_type>` that is empty when the key is not found.
 | 
			
		||||
 | 
			
		||||
#### 3.3.3. `[[nodiscard]] auto values() const noexcept -> value_container_type const&`
 | 
			
		||||
 | 
			
		||||
Exposes the underlying values container.
 | 
			
		||||
 | 
			
		||||
#### 3.3.4. `auto replace(value_container_type&& container)`
 | 
			
		||||
 | 
			
		||||
Discards the internally held container and replaces it with the one passed. Non-unique elements are
 | 
			
		||||
removed, and the container will be partly reordered when non-unique elements are found.
 | 
			
		||||
 | 
			
		||||
### 3.4. Custom Container Types
 | 
			
		||||
 | 
			
		||||
`unordered_dense` accepts a custom allocator, but you can also specify a custom container for that template argument. That way it is possible to replace the internally used `std::vector` with e.g. `std::deque` or any other container like `boost::interprocess::vector`. This supports fancy pointers (e.g. [offset_ptr](https://www.boost.org/doc/libs/1_80_0/doc/html/interprocess/offset_ptr.html)), so the container can be used with e.g. shared memory provided by `boost::interprocess`.
 | 
			
		||||
 | 
			
		||||
### 3.5. Custom Bucket Types
 | 
			
		||||
 | 
			
		||||
The map/set supports two different bucket types. The default should be good for pretty much everyone.
 | 
			
		||||
 | 
			
		||||
#### 3.5.1. `ankerl::unordered_dense::bucket_type::standard`
 | 
			
		||||
 | 
			
		||||
* Up to 2^32 = 4.29 billion elements.
 | 
			
		||||
* 8 bytes overhead per bucket.
 | 
			
		||||
 | 
			
		||||
#### 3.5.2. `ankerl::unordered_dense::bucket_type::big`
 | 
			
		||||
 | 
			
		||||
* up to 2^63 = 9223372036854775808 elements.
 | 
			
		||||
* 12 bytes overhead per bucket.
 | 
			
		||||
 | 
			
		||||
## 4. `segmented_map` and `segmented_set`
 | 
			
		||||
 | 
			
		||||
`ankerl::unordered_dense` provides a custom container implementation that has lower memory requirements than the default `std::vector`. Memory is not contiguous, but it can allocate segments without having to reallocate and move all the elements. In summary, this leads to
 | 
			
		||||
 | 
			
		||||
* Much smoother memory usage, memory usage increases continuously.
 | 
			
		||||
* No high peak memory usage.
 | 
			
		||||
* Faster insertion because elements never need to be moved to new allocated blocks
 | 
			
		||||
* Slightly slower indexing compared to `std::vector` because an additional indirection is needed.
 | 
			
		||||
 | 
			
		||||
Here is a comparison against `absl::flat_hash_map` and the `ankerl::unordered_dense::map` when inserting 10 million entries
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
Abseil is fastest for this simple inserting test, taking a bit over 0.8 seconds. It's peak memory usage is about 430 MB. Note how the memory usage goes down after the last peak; when it goes down to ~290MB it has finished rehashing and could free the previously used memory block.
 | 
			
		||||
 | 
			
		||||
`ankerl::unordered_dense::segmented_map` doesn't have these peaks, and instead has a smooth increase of memory usage. Note there are still sudden drops & increases in memory because the indexing data structure needs still needs to increase by a fixed factor. But due to holding the data in a separate container we are able to first free the old data structure, and then allocate a new, bigger indexing structure; thus we do not have peaks.
 | 
			
		||||
 | 
			
		||||
## 5. Design
 | 
			
		||||
 | 
			
		||||
The map/set has two data structures:
 | 
			
		||||
* `std::vector<value_type>` which holds all data. map/set iterators are just `std::vector<value_type>::iterator`!
 | 
			
		||||
* An indexing structure (bucket array), which is a flat array with 8-byte buckets.
 | 
			
		||||
 | 
			
		||||
### 5.1. Inserts
 | 
			
		||||
 | 
			
		||||
Whenever an element is added it is `emplace_back` to the vector. The key is hashed, and an entry (bucket) is added at the
 | 
			
		||||
corresponding location in the bucket array. The bucket has this structure:
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
struct Bucket {
 | 
			
		||||
    uint32_t dist_and_fingerprint;
 | 
			
		||||
    uint32_t value_idx;
 | 
			
		||||
};
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Each bucket stores 3 things:
 | 
			
		||||
* The distance of that value from the original hashed location (3 most significant bytes in `dist_and_fingerprint`)
 | 
			
		||||
* A fingerprint; 1 byte of the hash (lowest significant byte in `dist_and_fingerprint`)
 | 
			
		||||
* An index where in the vector the actual data is stored.
 | 
			
		||||
 | 
			
		||||
This structure is especially designed for the collision resolution strategy robin-hood hashing with backward shift
 | 
			
		||||
deletion.
 | 
			
		||||
 | 
			
		||||
### 5.2. Lookups
 | 
			
		||||
 | 
			
		||||
The key is hashed and the bucket array is searched if it has an entry at that location with that fingerprint. When found,
 | 
			
		||||
the key in the data vector is compared, and when equal the value is returned.
 | 
			
		||||
 | 
			
		||||
### 5.3. Removals
 | 
			
		||||
 | 
			
		||||
Since all data is stored in a vector, removals are a bit more complicated:
 | 
			
		||||
 | 
			
		||||
1. First, lookup the element to delete in the index array.
 | 
			
		||||
2. When found, replace that element in the vector with the last element in the vector. 
 | 
			
		||||
3. Update *two* locations in the bucket array: First remove the bucket for the removed element
 | 
			
		||||
4. Then, update the `value_idx` of the moved element. This requires another lookup.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## 6. Real World Usage
 | 
			
		||||
 | 
			
		||||
On 2023-09-10 I did a quick search on github to see if this map is used in any popular open source projects. Here are some of the projects
 | 
			
		||||
I found. Please send me a note if you want on that list!
 | 
			
		||||
 | 
			
		||||
* [PruaSlicer](https://github.com/prusa3d/PrusaSlicer) -  G-code generator for 3D printers (RepRap, Makerbot, Ultimaker etc.) 
 | 
			
		||||
* [Kismet](https://github.com/kismetwireless/kismet): Wi-Fi, Bluetooth, RF, and more. Kismet is a sniffer, WIDS, and wardriving tool for Wi-Fi, Bluetooth, Zigbee, RF, and more, which runs on Linux and macOS
 | 
			
		||||
* [Rspamd](https://github.com/rspamd/rspamd) - Fast, free and open-source spam filtering system.
 | 
			
		||||
* [kallisto](https://github.com/pachterlab/kallisto) -  Near-optimal RNA-Seq quantification
 | 
			
		||||
* [Slang](https://github.com/shader-slang/slang) - Slang is a shading language that makes it easier to build and maintain large shader codebases in a modular and extensible fashion.
 | 
			
		||||
* [CyberFSR2](https://github.com/PotatoOfDoom/CyberFSR2) - Drop-in DLSS replacement with FSR 2.0 for various games such as Cyberpunk 2077.
 | 
			
		||||
* [ossia score](https://github.com/ossia/score) - A free, open-source, cross-platform intermedia sequencer for precise and flexible scripting of interactive scenarios. 
 | 
			
		||||
* [HiveWE](https://github.com/stijnherfst/HiveWE) - A Warcraft III World Editor (WE) that focusses on speed and ease of use.
 | 
			
		||||
* [opentxs](https://github.com/Open-Transactions/opentxs) - The Open-Transactions project is a collaborative effort to develop a robust, commercial-grade, fully-featured, free-software toolkit implementing the OTX protocol as well as a full-strength financial cryptography library, API, GUI, command-line interface, and prototype notary server.
 | 
			
		||||
* [LuisaCompute](https://github.com/LuisaGroup/LuisaCompute) - High-Performance Rendering Framework on Stream Architectures
 | 
			
		||||
* [Lethe](https://github.com/lethe-cfd/lethe) - Lethe (pronounced /ˈliːθiː/) is open-source computational fluid dynamics (CFD) software which uses high-order continuous Galerkin formulations to solve the incompressible Navier–Stokes equations (among others).
 | 
			
		||||
* [PECOS](https://github.com/amzn/pecos) - PECOS is a versatile and modular machine learning (ML) framework for fast learning and inference on problems with large output spaces, such as extreme multi-label ranking (XMR) and large-scale retrieval.
 | 
			
		||||
* [Operon](https://github.com/heal-research/operon) - A modern C++ framework for symbolic regression that uses genetic programming to explore a hypothesis space of possible mathematical expressions in order to find the best-fitting model for a given regression target.
 | 
			
		||||
* [MashMap](https://github.com/marbl/MashMap) - A fast approximate aligner for long DNA sequences
 | 
			
		||||
* [minigpt4.cpp](https://github.com/Maknee/minigpt4.cpp) - Port of MiniGPT4 in C++ (4bit, 5bit, 6bit, 8bit, 16bit CPU inference with GGML)
 | 
			
		||||
							
								
								
									
										4
									
								
								third_party/unordered_dense/cmake/unordered_denseConfig.cmake.in
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								third_party/unordered_dense/cmake/unordered_denseConfig.cmake.in
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
			
		||||
@PACKAGE_INIT@
 | 
			
		||||
 | 
			
		||||
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
 | 
			
		||||
check_required_components("@PROJECT_NAME@")
 | 
			
		||||
							
								
								
									
										44
									
								
								third_party/unordered_dense/doc/allocated_memory.gnuplot
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										44
									
								
								third_party/unordered_dense/doc/allocated_memory.gnuplot
									
									
									
									
										vendored
									
									
										Executable file
									
								
							@ -0,0 +1,44 @@
 | 
			
		||||
#!/usr/bin/gnuplot
 | 
			
		||||
 | 
			
		||||
#set terminal pngcairo 
 | 
			
		||||
#set terminal pngcairo size 730,510 enhanced font 'Verdana,10'
 | 
			
		||||
set terminal pngcairo size 800,600 enhanced font 'Verdana,10'
 | 
			
		||||
 | 
			
		||||
# define axis
 | 
			
		||||
# remove border on top and right and set color to gray
 | 
			
		||||
set style line 11 lc rgb '#808080' lt 1
 | 
			
		||||
set border 3 back ls 11
 | 
			
		||||
set tics nomirror
 | 
			
		||||
# define grid
 | 
			
		||||
set style line 12 lc rgb '#808080' lt 0 lw 1
 | 
			
		||||
set grid back ls 12
 | 
			
		||||
 | 
			
		||||
# line styles
 | 
			
		||||
set style line 1 lt 1 lc rgb '#1B9E77' # dark teal
 | 
			
		||||
set style line 2 lt 1 lc rgb '#D95F02' # dark orange
 | 
			
		||||
set style line 3 lt 1 lc rgb '#7570B3' # dark lilac
 | 
			
		||||
set style line 4 lt 1 lc rgb '#E7298A' # dark magenta
 | 
			
		||||
set style line 5 lt 1 lc rgb '#66A61E' # dark lime green
 | 
			
		||||
set style line 6 lt 1 lc rgb '#E6AB02' # dark banana
 | 
			
		||||
set style line 7 lt 1 lc rgb '#A6761D' # dark tan
 | 
			
		||||
set style line 8 lt 1 lc rgb '#666666' # dark gray
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
set style line 101 lc rgb '#808080' lt 1 lw 1
 | 
			
		||||
set border 3 front ls 101
 | 
			
		||||
set tics nomirror out scale 0.75
 | 
			
		||||
 | 
			
		||||
set key left top
 | 
			
		||||
 | 
			
		||||
set output 'allocated_memory.png'
 | 
			
		||||
 | 
			
		||||
set xlabel "Runtime [s]"
 | 
			
		||||
set ylabel "Allocated memory [MB]"
 | 
			
		||||
 | 
			
		||||
set title "Inserting 10 Million uint64\\\_t -> uint64\\\_t pairs"
 | 
			
		||||
 | 
			
		||||
# allocated_memory_segmented_vector.txt  allocated_memory_std_unordered_map.txt  allocated_memory_std_vector.txt
 | 
			
		||||
plot \
 | 
			
		||||
    'allocated_memory_segmented_vector.txt' using ($1):($2/1e6) w steps ls 1 lw 2 title "ankerl::unordered\\\_dense::segmented\\\_map" , \
 | 
			
		||||
    'allocated_memory_std_vector.txt' using ($1):($2/1e6) w steps ls 2 lw 2 title "ankerl::unordered\\\_dense::map" , \
 | 
			
		||||
    'allocated_memory_absl_flat_hash_map.txt' using ($1):($2/1e6) w steps ls 3 lw 2 title "absl::flat\\\_hash\\\_map"
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								third_party/unordered_dense/doc/allocated_memory.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								third_party/unordered_dense/doc/allocated_memory.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 32 KiB  | 
							
								
								
									
										6
									
								
								third_party/unordered_dense/example/CMakeLists.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								third_party/unordered_dense/example/CMakeLists.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
			
		||||
cmake_minimum_required(VERSION 3.12)
 | 
			
		||||
project("UnorderedDenseExample")
 | 
			
		||||
 | 
			
		||||
add_executable(UnorderedDenseExample main.cpp)
 | 
			
		||||
find_package(unordered_dense CONFIG REQUIRED)
 | 
			
		||||
target_link_libraries(UnorderedDenseExample unordered_dense::unordered_dense)
 | 
			
		||||
							
								
								
									
										16
									
								
								third_party/unordered_dense/example/README.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								third_party/unordered_dense/example/README.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
A simple example that demonstrats how to make use of `unordered_dense` with cmake.
 | 
			
		||||
 | 
			
		||||
Use globally installed `unordered_dense`:
 | 
			
		||||
```sh
 | 
			
		||||
mkdir build && cd build
 | 
			
		||||
cmake -DCMAKE_INSTALL_PREFIX:PATH=${HOME}/unordered_dense_install ..
 | 
			
		||||
make
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Use locall installed `unordered_dense`, as in the main README.md:
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
mkdir build && cd build
 | 
			
		||||
cmake -DCMAKE_INSTALL_PREFIX:PATH=${HOME}/unordered_dense_install ..
 | 
			
		||||
make
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										13
									
								
								third_party/unordered_dense/example/main.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								third_party/unordered_dense/example/main.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
 | 
			
		||||
auto main() -> int {
 | 
			
		||||
    auto map = ankerl::unordered_dense::map<int, std::string>();
 | 
			
		||||
    map[123] = "hello";
 | 
			
		||||
    map[987] = "world!";
 | 
			
		||||
 | 
			
		||||
    for (auto const& [key, val] : map) {
 | 
			
		||||
        std::cout << key << " => " << val << std::endl;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2032
									
								
								third_party/unordered_dense/include/ankerl/unordered_dense.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2032
									
								
								third_party/unordered_dense/include/ankerl/unordered_dense.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										32
									
								
								third_party/unordered_dense/meson.build
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								third_party/unordered_dense/meson.build
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
			
		||||
# meson commands cheat sheet:
 | 
			
		||||
#
 | 
			
		||||
# # Setup ###################
 | 
			
		||||
#
 | 
			
		||||
# release & debug setup
 | 
			
		||||
#      CXX="ccache clang++" meson setup --buildtype release builddir/clang_release
 | 
			
		||||
#      CXX="ccache clang++" meson setup builddir/clang_debug
 | 
			
		||||
# c++20 build
 | 
			
		||||
#     CXX="ccache clang++" meson setup -Dcpp_std=c++20 builddir/clang_cpp20
 | 
			
		||||
# lcov coverage:
 | 
			
		||||
#     CXX="ccache clang++" meson setup -Db_coverage=true builddir/coverage
 | 
			
		||||
#     ninja clean && ninja test && ninja coverage
 | 
			
		||||
#
 | 
			
		||||
# # Testing ################
 | 
			
		||||
#
 | 
			
		||||
# Run with valgrind:
 | 
			
		||||
#     meson test --wrap='valgrind --leak-check=full --error-exitcode=1'
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
project('unordered_dense', 'cpp',
 | 
			
		||||
    version: '4.4.0',
 | 
			
		||||
    license: 'MIT',
 | 
			
		||||
    default_options : [
 | 
			
		||||
        'cpp_std=c++17', 
 | 
			
		||||
        'warning_level=3',
 | 
			
		||||
        'werror=true', 
 | 
			
		||||
        'b_ndebug=true', # otherwise absl is really slow!
 | 
			
		||||
    ])
 | 
			
		||||
 | 
			
		||||
incdir = include_directories('include')
 | 
			
		||||
subdir('test')
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										86
									
								
								third_party/unordered_dense/scripts/build.py
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										86
									
								
								third_party/unordered_dense/scripts/build.py
									
									
									
									
										vendored
									
									
										Executable file
									
								
							@ -0,0 +1,86 @@
 | 
			
		||||
#!/bin/env python
 | 
			
		||||
 | 
			
		||||
import os
 | 
			
		||||
from pathlib import Path
 | 
			
		||||
import subprocess
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
cmd_and_dir = [
 | 
			
		||||
    # needs honggfuzz installed
 | 
			
		||||
    ['env', 'CXX_LD=mold', 'CXX=ccache clang++', 'meson', 'setup', '--buildtype', 'debug',   '-Dcpp_std=c++17', 'builddir/clang_cpp17_debug'],
 | 
			
		||||
    ['env', 'CXX_LD=mold', 'CXX=ccache clang++', 'meson', 'setup', '--buildtype', 'release', '-Dcpp_std=c++17', 'builddir/clang_cpp17_release'],
 | 
			
		||||
    ['env', 'CXX_LD=mold', 'CXX=ccache g++',     'meson', 'setup', '--buildtype', 'release', '-Dcpp_std=c++17', 'builddir/gcc_cpp17_release'],
 | 
			
		||||
    ['env', 'CXX_LD=mold', 'CXX=ccache hfuzz-clang++ -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION', 'meson', 'setup', '--buildtype', 'release', '-Dcpp_std=c++17', 'builddir/hfuzz-clang_cpp17_release'],
 | 
			
		||||
    ['env', 'CXX_LD=mold', 'CXX=ccache g++',     'meson', 'setup', '--buildtype', 'debug',   '-Dcpp_std=c++17', 'builddir/gcc_cpp17_debug'],
 | 
			
		||||
 | 
			
		||||
    # 32bit. Install lib32-clang
 | 
			
		||||
    ['env', 'CXX_LD=mold', 'CXX=ccache g++',     'meson', 'setup', '--buildtype', 'debug', '-Dcpp_std=c++17', '-Dcpp_args=-m32', '-Dcpp_link_args=-m32', '-Dc_args=-m32', '-Dc_link_args=-m32', 'builddir/gcc_cpp17_debug_32'],
 | 
			
		||||
    ['env', 'CXX_LD=mold', 'CXX=ccache clang++', 'meson', 'setup', '--buildtype', 'debug', '-Dcpp_std=c++17', '-Dcpp_args=-m32', '-Dcpp_link_args=-m32', '-Dc_args=-m32', '-Dc_link_args=-m32', 'builddir/clang_cpp17_debug_32'],
 | 
			
		||||
 | 
			
		||||
    # c++20
 | 
			
		||||
    ['env', 'CXX_LD=mold', 'CXX=ccache clang++', 'meson', 'setup', '--buildtype', 'debug', '-Dcpp_std=c++20', 'builddir/clang_cpp20_debug'],
 | 
			
		||||
    ['env', 'CXX_LD=mold', 'CXX=ccache g++',     'meson', 'setup', '--buildtype', 'debug', '-Dcpp_std=c++20', 'builddir/gcc_cpp20_debug'],
 | 
			
		||||
 | 
			
		||||
    # coverage; use "ninja clean && ninja test && ninja coverage"
 | 
			
		||||
    #['env', 'CXX_LD=mold', 'CXX=ccache clang++', 'meson', 'setup', '-Db_coverage=true', 'builddir/coverage'],
 | 
			
		||||
 | 
			
		||||
    # sanitizers
 | 
			
		||||
    # It is not possible to combine more than one of the -fsanitize=address, -fsanitize=thread, and -fsanitize=memory checkers in the same program.
 | 
			
		||||
    # see https://clang.llvm.org/docs/UsersManual.html#controlling-code-generation
 | 
			
		||||
    #
 | 
			
		||||
    # can't use ccache, it doesn't work with the ignorelist.txt
 | 
			
		||||
    ['env', 'CXX_LD=mold', 'CXX=ccache g++',     'meson', 'setup', '-Db_sanitize=address',   'builddir/gcc_sanitize_address'],
 | 
			
		||||
    ['env', 'CXX_LD=mold', 'CXX=ccache clang++', 'meson', 'setup', '-Db_sanitize=address',   'builddir/clang_sanitize_address'],
 | 
			
		||||
 | 
			
		||||
    ['env', 'CXX_LD=mold', 'CXX=ccache g++',     'meson', 'setup', '-Db_sanitize=thread',    'builddir/gcc_sanitize_thread'],
 | 
			
		||||
    ['env', 'CXX_LD=mold', 'CXX=ccache clang++', 'meson', 'setup', '-Db_sanitize=thread',    'builddir/clang_sanitize_thread'],
 | 
			
		||||
 | 
			
		||||
    # ['env', 'CXX_LD=mold', 'CXX=ccache g++',     'meson', 'setup', '-Db_sanitize=memory',    'builddir/gcc_sanitize_memory'], # doesn't work due to STL, and ignore doesn't work either :-(
 | 
			
		||||
    # ['env', 'CXX_LD=mold', 'CXX=ccache clang++', 'meson', 'setup', '-Db_sanitize=memory',    'builddir/clang_sanitize_memory'], # doesn't work due to STL, and ignore doesn't work either :-(
 | 
			
		||||
 | 
			
		||||
    ['env', 'CXX_LD=mold', 'CXX=ccache g++',     'meson', 'setup', '-Db_sanitize=undefined', 'builddir/gcc_sanitize_undefined'],
 | 
			
		||||
    ['env', 'CXX_LD=mold', 'CXX=ccache clang++', 'meson', 'setup', '-Db_sanitize=undefined', 'builddir/clang_sanitize_undefined'],
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
root_path = Path(__file__).parent.parent
 | 
			
		||||
os.chdir(root_path)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def run(cmd):
 | 
			
		||||
    result = subprocess.run(cmd)
 | 
			
		||||
    if result.returncode != 0:
 | 
			
		||||
        exit(result.returncode)
 | 
			
		||||
 | 
			
		||||
run('scripts/lint/lint-all.py')
 | 
			
		||||
 | 
			
		||||
for cmd_dir in cmd_and_dir:
 | 
			
		||||
    workdir = cmd_dir[-1]
 | 
			
		||||
 | 
			
		||||
    # setup
 | 
			
		||||
    if not os.path.isdir(workdir):
 | 
			
		||||
        out = run(cmd_dir)
 | 
			
		||||
    
 | 
			
		||||
    # clean
 | 
			
		||||
    run(['meson', 'compile', '--clean', '-C', workdir])
 | 
			
		||||
 | 
			
		||||
    # compile everything
 | 
			
		||||
    run(['meson', 'compile', '-C', workdir])
 | 
			
		||||
 | 
			
		||||
    # test
 | 
			
		||||
    #if workdir.find("clang_cpp17_debug") != -1:
 | 
			
		||||
    #    run(['meson', 'test', '--wrap=\'valgrind --leak-check=full --error-exitcode=1\'', '-q', '--print-errorlogs', '-C', workdir])
 | 
			
		||||
    #else:
 | 
			
		||||
 | 
			
		||||
    if workdir.find("hfuzz") == -1:
 | 
			
		||||
        # no testing for hfuzz
 | 
			
		||||
        run(['meson', 'test', '-q', '--print-errorlogs', '-C', workdir])
 | 
			
		||||
 | 
			
		||||
    # coverage
 | 
			
		||||
    if workdir.find("coverage") != -1:
 | 
			
		||||
        print(workdir)
 | 
			
		||||
        run(['meson', 'compile', '--ninja-args', 'coverage', '-C', workdir])
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
for cmd_dir in cmd_and_dir:
 | 
			
		||||
    workdir = cmd_dir[-1]
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										11
									
								
								third_party/unordered_dense/scripts/fuzz_merge.sh
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										11
									
								
								third_party/unordered_dense/scripts/fuzz_merge.sh
									
									
									
									
										vendored
									
									
										Executable file
									
								
							@ -0,0 +1,11 @@
 | 
			
		||||
#!/bin/env bash
 | 
			
		||||
set -e
 | 
			
		||||
 | 
			
		||||
# Start from a build directory, usually clang_cpp17_release
 | 
			
		||||
# usage: fuzz_merge.sh <testname>
 | 
			
		||||
FUZZ_TARGET=$1
 | 
			
		||||
SCRIPT_DIR=`dirname "$0"`
 | 
			
		||||
CORPUS_SMALL=${SCRIPT_DIR}/../data/fuzz/${FUZZ_TARGET}
 | 
			
		||||
CORPUS_BIG=CORPUS_BIG/${FUZZ_TARGET}
 | 
			
		||||
ninja
 | 
			
		||||
./test/fuzz_${FUZZ_TARGET} -merge=1 ${CORPUS_SMALL} ${CORPUS_BIG}
 | 
			
		||||
							
								
								
									
										18
									
								
								third_party/unordered_dense/scripts/fuzz_run.sh
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										18
									
								
								third_party/unordered_dense/scripts/fuzz_run.sh
									
									
									
									
										vendored
									
									
										Executable file
									
								
							@ -0,0 +1,18 @@
 | 
			
		||||
#!/bin/env bash
 | 
			
		||||
set -ev
 | 
			
		||||
 | 
			
		||||
# Start from a build directory, usually clang_cpp17_release
 | 
			
		||||
#   ../../scripts/fuzz_run.sh <testname>
 | 
			
		||||
#
 | 
			
		||||
# Found a crash? Minimize it like so:
 | 
			
		||||
#   ./test/fuzz_replace -minimize_crash=1 ./crash-123abcdef
 | 
			
		||||
 | 
			
		||||
FUZZ_TARGET=$1
 | 
			
		||||
SCRIPT_DIR=`dirname "$0"`
 | 
			
		||||
CORPUS_SMALL=${SCRIPT_DIR}/../data/fuzz/${FUZZ_TARGET}
 | 
			
		||||
CORPUS_BIG=CORPUS_BIG/${FUZZ_TARGET}
 | 
			
		||||
NUM_JOBS=$(nproc)
 | 
			
		||||
 | 
			
		||||
mkdir -p ${CORPUS_BIG}
 | 
			
		||||
ninja
 | 
			
		||||
chrt -i 0 ./test/fuzz_${FUZZ_TARGET} -jobs=${NUM_JOBS} -workers=${NUM_JOBS} ${CORPUS_BIG} ${CORPUS_SMALL}
 | 
			
		||||
							
								
								
									
										30
									
								
								third_party/unordered_dense/scripts/lint/lint-all.py
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										30
									
								
								third_party/unordered_dense/scripts/lint/lint-all.py
									
									
									
									
										vendored
									
									
										Executable file
									
								
							@ -0,0 +1,30 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
 | 
			
		||||
from glob import glob
 | 
			
		||||
from pathlib import Path
 | 
			
		||||
from subprocess import run
 | 
			
		||||
from os import path
 | 
			
		||||
from time import time
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
time_start = time()
 | 
			
		||||
 | 
			
		||||
exit_code = 0
 | 
			
		||||
num_linters = 0
 | 
			
		||||
mod_path = Path(__file__).parent
 | 
			
		||||
for lint in glob(f"{mod_path}/lint-*"):
 | 
			
		||||
    lint = path.abspath(lint)
 | 
			
		||||
    if lint == path.abspath(__file__):
 | 
			
		||||
        continue
 | 
			
		||||
 | 
			
		||||
    num_linters += 1
 | 
			
		||||
    result = run([lint])
 | 
			
		||||
    if result.returncode == 0:
 | 
			
		||||
        continue
 | 
			
		||||
 | 
			
		||||
    print(f"^---- failure from {lint.split('/')[-1]}")
 | 
			
		||||
    exit_code |= result.returncode
 | 
			
		||||
 | 
			
		||||
time_end = time()
 | 
			
		||||
print(f"{num_linters} linters in {time_end - time_start:0.2}s")
 | 
			
		||||
exit(exit_code)
 | 
			
		||||
							
								
								
									
										50
									
								
								third_party/unordered_dense/scripts/lint/lint-clang-format.py
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										50
									
								
								third_party/unordered_dense/scripts/lint/lint-clang-format.py
									
									
									
									
										vendored
									
									
										Executable file
									
								
							@ -0,0 +1,50 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
 | 
			
		||||
from glob import glob
 | 
			
		||||
from pathlib import Path
 | 
			
		||||
from subprocess import run
 | 
			
		||||
from os import path
 | 
			
		||||
import subprocess
 | 
			
		||||
import sys
 | 
			
		||||
from time import time
 | 
			
		||||
import re
 | 
			
		||||
 | 
			
		||||
root_path = path.abspath(Path(__file__).parent.parent.parent)
 | 
			
		||||
 | 
			
		||||
globs = [
 | 
			
		||||
    f"{root_path}/include/**/*.h",
 | 
			
		||||
    f"{root_path}/test/**/*.h",
 | 
			
		||||
    f"{root_path}/test/**/*.cpp",
 | 
			
		||||
]
 | 
			
		||||
exclusions = [
 | 
			
		||||
    "nanobench\\.h",
 | 
			
		||||
    "FuzzedDataProvider\\.h",
 | 
			
		||||
    '/third-party/']
 | 
			
		||||
 | 
			
		||||
files = []
 | 
			
		||||
for g in globs:
 | 
			
		||||
    r = glob(g, recursive=True)
 | 
			
		||||
    files.extend(r)
 | 
			
		||||
 | 
			
		||||
# filter out exclusions
 | 
			
		||||
for exclusion in exclusions:
 | 
			
		||||
    l = filter(lambda file: re.search(exclusion, file) == None, files)
 | 
			
		||||
    files = list(l)
 | 
			
		||||
 | 
			
		||||
if len(files) == 0:
 | 
			
		||||
    print("could not find any files!")
 | 
			
		||||
    sys.exit(1)
 | 
			
		||||
 | 
			
		||||
command = ['clang-format', '--dry-run', '-Werror'] + files
 | 
			
		||||
p = subprocess.Popen(command,
 | 
			
		||||
                     stdout=subprocess.PIPE,
 | 
			
		||||
                     stderr=None,
 | 
			
		||||
                     stdin=subprocess.PIPE,
 | 
			
		||||
                     universal_newlines=True)
 | 
			
		||||
 | 
			
		||||
stdout, stderr = p.communicate()
 | 
			
		||||
 | 
			
		||||
print(f"clang-format checked {len(files)} files")
 | 
			
		||||
 | 
			
		||||
if p.returncode != 0:
 | 
			
		||||
    sys.exit(p.returncode)
 | 
			
		||||
							
								
								
									
										68
									
								
								third_party/unordered_dense/scripts/lint/lint-version.py
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										68
									
								
								third_party/unordered_dense/scripts/lint/lint-version.py
									
									
									
									
										vendored
									
									
										Executable file
									
								
							@ -0,0 +1,68 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
 | 
			
		||||
import os
 | 
			
		||||
import pathlib
 | 
			
		||||
import re
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
root = os.path.abspath(pathlib.Path(__file__).parent.parent.parent)
 | 
			
		||||
 | 
			
		||||
# filename, pattern, number of occurrences
 | 
			
		||||
file_pattern_count = [
 | 
			
		||||
    (
 | 
			
		||||
        f"{root}/meson.build",
 | 
			
		||||
        r"version: '(\d+)\.(\d+)\.(\d+)'",
 | 
			
		||||
        1),
 | 
			
		||||
    (
 | 
			
		||||
        f"{root}/include/ankerl/unordered_dense.h",
 | 
			
		||||
        r"Version (\d+)\.(\d+)\.(\d+)\n",
 | 
			
		||||
        1),
 | 
			
		||||
    (
 | 
			
		||||
        f"{root}/CMakeLists.txt",
 | 
			
		||||
        r"^\s+VERSION (\d+)\.(\d+)\.(\d+)\n",
 | 
			
		||||
        1),
 | 
			
		||||
    (
 | 
			
		||||
        f"{root}/test/unit/namespace.cpp",
 | 
			
		||||
        r"unordered_dense::v(\d+)_(\d+)_(\d+)",
 | 
			
		||||
        1
 | 
			
		||||
    )
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
# let's parse the reference from svector.h
 | 
			
		||||
major = "??"
 | 
			
		||||
minor = "??"
 | 
			
		||||
patch = "??"
 | 
			
		||||
with open(f"{root}/include/ankerl/unordered_dense.h", "r") as f:
 | 
			
		||||
    for line in f:
 | 
			
		||||
        r = re.search(r"#define ANKERL_UNORDERED_DENSE_VERSION_([A-Z]+) (\d+)", line)
 | 
			
		||||
        if not r:
 | 
			
		||||
            continue
 | 
			
		||||
 | 
			
		||||
        if "MAJOR" == r.group(1):
 | 
			
		||||
            major = r.group(2)
 | 
			
		||||
        elif "MINOR" == r.group(1):
 | 
			
		||||
            minor = r.group(2)
 | 
			
		||||
        elif "PATCH" == r.group(1):
 | 
			
		||||
            patch = r.group(2)
 | 
			
		||||
        else:
 | 
			
		||||
            "match but with something else!"
 | 
			
		||||
            exit(1)
 | 
			
		||||
 | 
			
		||||
is_ok = True
 | 
			
		||||
for (filename, pattern, count) in file_pattern_count:
 | 
			
		||||
    num_found = 0
 | 
			
		||||
    with open(filename, "r") as f:
 | 
			
		||||
        for line in f:
 | 
			
		||||
            r = re.search(pattern, line)
 | 
			
		||||
            if r:
 | 
			
		||||
                num_found += 1
 | 
			
		||||
                if major != r.group(1) or minor != r.group(2) or patch != r.group(3):
 | 
			
		||||
                    is_ok = False
 | 
			
		||||
                    print(f"ERROR in {filename}: got '{line.strip()}' but version should be '{major}.{minor}.{patch}'")
 | 
			
		||||
    if num_found != count:
 | 
			
		||||
        is_ok = False
 | 
			
		||||
        print(f"ERROR in {filename}: expected {count} occurrences but found it {num_found} times")
 | 
			
		||||
 | 
			
		||||
if not is_ok:
 | 
			
		||||
    exit(1)
 | 
			
		||||
    
 | 
			
		||||
							
								
								
									
										39
									
								
								third_party/unordered_dense/src/ankerl.unordered_dense.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								third_party/unordered_dense/src/ankerl.unordered_dense.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,39 @@
 | 
			
		||||
module;
 | 
			
		||||
 | 
			
		||||
// see https://github.com/fmtlib/fmt/blob/master/src/fmt.cc
 | 
			
		||||
 | 
			
		||||
// Put all implementation-provided headers into the global module fragment
 | 
			
		||||
// to prevent attachment to this module.
 | 
			
		||||
 | 
			
		||||
#include <array>            // for array
 | 
			
		||||
#include <cstdint>          // for uint64_t, uint32_t, uint8_t, UINT64_C
 | 
			
		||||
#include <cstring>          // for size_t, memcpy, memset
 | 
			
		||||
#include <functional>       // for equal_to, hash
 | 
			
		||||
#include <initializer_list> // for initializer_list
 | 
			
		||||
#include <iterator>         // for pair, distance
 | 
			
		||||
#include <limits>           // for numeric_limits
 | 
			
		||||
#include <memory>           // for allocator, allocator_traits, shared_ptr
 | 
			
		||||
#include <stdexcept>        // for out_of_range
 | 
			
		||||
#include <string>           // for basic_string
 | 
			
		||||
#include <string_view>      // for basic_string_view, hash
 | 
			
		||||
#include <tuple>            // for forward_as_tuple
 | 
			
		||||
#include <type_traits>      // for enable_if_t, declval, conditional_t, ena...
 | 
			
		||||
#include <utility>          // for forward, exchange, pair, as_const, piece...
 | 
			
		||||
#include <vector>           // for vector
 | 
			
		||||
#if defined(__has_include)
 | 
			
		||||
#    if __has_include(<memory_resource>)
 | 
			
		||||
#        include <memory_resource> // for polymorphic_allocator
 | 
			
		||||
#    elif __has_include(<experimental/memory_resource>)
 | 
			
		||||
#        include <experimental/memory_resource> // for polymorphic_allocator
 | 
			
		||||
#    endif
 | 
			
		||||
#endif
 | 
			
		||||
#if defined(_MSC_VER) && defined(_M_X64)
 | 
			
		||||
#    include <intrin.h>
 | 
			
		||||
#    pragma intrinsic(_umul128)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
export module ankerl.unordered_dense;
 | 
			
		||||
 | 
			
		||||
#define ANKERL_UNORDERED_DENSE_EXPORT export
 | 
			
		||||
 | 
			
		||||
#include "ankerl/unordered_dense.h"
 | 
			
		||||
							
								
								
									
										2
									
								
								third_party/unordered_dense/subprojects/.clang-tidy
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								third_party/unordered_dense/subprojects/.clang-tidy
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
			
		||||
---
 | 
			
		||||
Checks: '-*'
 | 
			
		||||
							
								
								
									
										23
									
								
								third_party/unordered_dense/subprojects/abseil-cpp.wrap
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								third_party/unordered_dense/subprojects/abseil-cpp.wrap
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
			
		||||
[wrap-file]
 | 
			
		||||
directory = abseil-cpp-20220623.0
 | 
			
		||||
source_url = https://github.com/abseil/abseil-cpp/archive/20220623.0.tar.gz
 | 
			
		||||
source_filename = abseil-cpp-20220623.0.tar.gz
 | 
			
		||||
source_hash = 4208129b49006089ba1d6710845a45e31c59b0ab6bff9e5788a87f55c5abd602
 | 
			
		||||
patch_filename = abseil-cpp_20220623.0-2_patch.zip
 | 
			
		||||
patch_url = https://wrapdb.mesonbuild.com/v2/abseil-cpp_20220623.0-2/get_patch
 | 
			
		||||
patch_hash = d19cb16610d9310658a815ebcd87a9e2966aafbd57964341c0d1a3a3778c03b6
 | 
			
		||||
wrapdb_version = 20220623.0-2
 | 
			
		||||
 | 
			
		||||
[provide]
 | 
			
		||||
absl_base = absl_base_dep
 | 
			
		||||
absl_container = absl_container_dep
 | 
			
		||||
absl_debugging = absl_debugging_dep
 | 
			
		||||
absl_flags = absl_flags_dep
 | 
			
		||||
absl_hash = absl_hash_dep
 | 
			
		||||
absl_numeric = absl_numeric_dep
 | 
			
		||||
absl_random = absl_random_dep
 | 
			
		||||
absl_status = absl_status_dep
 | 
			
		||||
absl_strings = absl_strings_dep
 | 
			
		||||
absl_synchronization = absl_synchronization_dep
 | 
			
		||||
absl_time = absl_time_dep
 | 
			
		||||
absl_types = absl_types_dep
 | 
			
		||||
							
								
								
									
										9
									
								
								third_party/unordered_dense/subprojects/doctest.wrap
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								third_party/unordered_dense/subprojects/doctest.wrap
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,9 @@
 | 
			
		||||
[wrap-file]
 | 
			
		||||
directory = doctest-2.4.9
 | 
			
		||||
source_url = https://github.com/doctest/doctest/archive/refs/tags/v2.4.9.tar.gz
 | 
			
		||||
source_filename = doctest-2.4.9.tar.gz
 | 
			
		||||
source_hash = 19b2df757f2f3703a5e63cee553d85596875f06d91a3333acd80a969ef210856
 | 
			
		||||
wrapdb_version = 2.4.9-1
 | 
			
		||||
 | 
			
		||||
[provide]
 | 
			
		||||
dependency_names = doctest
 | 
			
		||||
							
								
								
									
										12
									
								
								third_party/unordered_dense/subprojects/fmt.wrap
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								third_party/unordered_dense/subprojects/fmt.wrap
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
[wrap-file]
 | 
			
		||||
directory = fmt-9.1.0
 | 
			
		||||
source_url = https://github.com/fmtlib/fmt/archive/9.1.0.tar.gz
 | 
			
		||||
source_filename = fmt-9.1.0.tar.gz
 | 
			
		||||
source_hash = 5dea48d1fcddc3ec571ce2058e13910a0d4a6bab4cc09a809d8b1dd1c88ae6f2
 | 
			
		||||
patch_filename = fmt_9.1.0-1_patch.zip
 | 
			
		||||
patch_url = https://wrapdb.mesonbuild.com/v2/fmt_9.1.0-1/get_patch
 | 
			
		||||
patch_hash = 4557b9ba87b3eb63694ed9b21d1a2117d4a97ca56b91085b10288e9a5294adf8
 | 
			
		||||
wrapdb_version = 9.1.0-1
 | 
			
		||||
 | 
			
		||||
[provide]
 | 
			
		||||
fmt = fmt_dep
 | 
			
		||||
							
								
								
									
										75
									
								
								third_party/unordered_dense/test/app/checksum.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								third_party/unordered_dense/test/app/checksum.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,75 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <app/counter.h>
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <string_view>
 | 
			
		||||
 | 
			
		||||
namespace checksum {
 | 
			
		||||
 | 
			
		||||
// final step from MurmurHash3
 | 
			
		||||
[[nodiscard]] static inline auto mix(uint64_t k) -> uint64_t {
 | 
			
		||||
    k ^= k >> 33U;
 | 
			
		||||
    k *= 0xff51afd7ed558ccdULL;
 | 
			
		||||
    k ^= k >> 33U;
 | 
			
		||||
    k *= 0xc4ceb9fe1a85ec53ULL;
 | 
			
		||||
    k ^= k >> 33U;
 | 
			
		||||
    return k;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[[maybe_unused]] [[nodiscard]] static inline auto mix(std::string_view data) -> uint64_t {
 | 
			
		||||
    static constexpr uint64_t fnv_offset_basis = UINT64_C(14695981039346656037);
 | 
			
		||||
    static constexpr uint64_t fnv_prime = UINT64_C(1099511628211);
 | 
			
		||||
 | 
			
		||||
    uint64_t val = fnv_offset_basis;
 | 
			
		||||
    for (auto c : data) {
 | 
			
		||||
        val ^= static_cast<uint64_t>(c);
 | 
			
		||||
        val *= fnv_prime;
 | 
			
		||||
    }
 | 
			
		||||
    return val;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[[maybe_unused]] [[nodiscard]] static inline auto mix(counter::obj const& cdv) -> uint64_t {
 | 
			
		||||
    return mix(cdv.get());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// from boost::hash_combine, with additional fmix64 of value
 | 
			
		||||
[[maybe_unused]] [[nodiscard]] static inline auto combine(uint64_t seed, uint64_t value) -> uint64_t {
 | 
			
		||||
    return seed ^ (value + 0x9e3779b9 + (seed << 6U) + (seed >> 2U));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// calculates a hash of any iterable map. Order is irrelevant for the hash's result, as it simply
 | 
			
		||||
// xors the elements together.
 | 
			
		||||
template <typename M>
 | 
			
		||||
[[nodiscard]] auto map(const M& map) -> uint64_t {
 | 
			
		||||
    uint64_t combined_hash = 1;
 | 
			
		||||
 | 
			
		||||
    uint64_t num_elements = 0;
 | 
			
		||||
    for (auto const& entry : map) {
 | 
			
		||||
        auto entry_hash = combine(mix(entry.first), mix(entry.second));
 | 
			
		||||
 | 
			
		||||
        combined_hash ^= entry_hash;
 | 
			
		||||
        ++num_elements;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return combine(combined_hash, num_elements);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// map of maps
 | 
			
		||||
template <typename MM>
 | 
			
		||||
[[nodiscard]] auto mapmap(const MM& mapmap) -> uint64_t {
 | 
			
		||||
    uint64_t combined_hash = 1;
 | 
			
		||||
 | 
			
		||||
    uint64_t num_elements = 0;
 | 
			
		||||
    for (auto const& entry : mapmap) {
 | 
			
		||||
        auto entry_hash = combine(mix(entry.first), map(entry.second));
 | 
			
		||||
 | 
			
		||||
        combined_hash ^= entry_hash;
 | 
			
		||||
        ++num_elements;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return combine(combined_hash, num_elements);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace checksum
 | 
			
		||||
							
								
								
									
										254
									
								
								third_party/unordered_dense/test/app/counter.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										254
									
								
								third_party/unordered_dense/test/app/counter.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,254 @@
 | 
			
		||||
#include <app/counter.h>
 | 
			
		||||
 | 
			
		||||
#include <app/print.h> // for print
 | 
			
		||||
 | 
			
		||||
#include <cstdlib>       // for abort
 | 
			
		||||
#include <ostream>       // for ostream
 | 
			
		||||
#include <stdexcept>     // for runtime_error
 | 
			
		||||
#include <unordered_set> // for unordered_set
 | 
			
		||||
#include <utility>       // for swap, pair
 | 
			
		||||
 | 
			
		||||
static inline constexpr bool counter_enable_unordered_set = true;
 | 
			
		||||
 | 
			
		||||
auto singleton_constructed_objects() -> std::unordered_set<counter::obj const*>& {
 | 
			
		||||
    static std::unordered_set<counter::obj const*> static_data{};
 | 
			
		||||
    return static_data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
counter::obj::obj()
 | 
			
		||||
    : m_data(0)
 | 
			
		||||
    , m_counts(nullptr) {
 | 
			
		||||
    if constexpr (counter_enable_unordered_set) {
 | 
			
		||||
        if (!singleton_constructed_objects().emplace(this).second) {
 | 
			
		||||
            test::print("ERROR at {}({}): {}\n", __FILE__, __LINE__, __func__);
 | 
			
		||||
            std::abort();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    ++static_default_ctor;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
counter::obj::obj(const size_t& data, counter& counts)
 | 
			
		||||
    : m_data(data)
 | 
			
		||||
    , m_counts(&counts) {
 | 
			
		||||
    if constexpr (counter_enable_unordered_set) {
 | 
			
		||||
        if (!singleton_constructed_objects().emplace(this).second) {
 | 
			
		||||
            test::print("ERROR at {}({}): {}\n", __FILE__, __LINE__, __func__);
 | 
			
		||||
            std::abort();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    ++m_counts->m_data.m_ctor;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
counter::obj::obj(const counter::obj& o)
 | 
			
		||||
    : m_data(o.m_data)
 | 
			
		||||
    , m_counts(o.m_counts) {
 | 
			
		||||
    if constexpr (counter_enable_unordered_set) {
 | 
			
		||||
        if (1 != singleton_constructed_objects().count(&o)) {
 | 
			
		||||
            test::print("ERROR at {}({}): {}\n", __FILE__, __LINE__, __func__);
 | 
			
		||||
            std::abort();
 | 
			
		||||
        }
 | 
			
		||||
        if (!singleton_constructed_objects().emplace(this).second) {
 | 
			
		||||
            test::print("ERROR at {}({}): {}\n", __FILE__, __LINE__, __func__);
 | 
			
		||||
            std::abort();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (nullptr != m_counts) {
 | 
			
		||||
        ++m_counts->m_data.m_copy_ctor;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
counter::obj::obj(counter::obj&& o) noexcept
 | 
			
		||||
    : m_data(o.m_data)
 | 
			
		||||
    , m_counts(o.m_counts) {
 | 
			
		||||
    if constexpr (counter_enable_unordered_set) {
 | 
			
		||||
        if (1 != singleton_constructed_objects().count(&o)) {
 | 
			
		||||
            test::print("ERROR at {}({}): {}\n", __FILE__, __LINE__, __func__);
 | 
			
		||||
            std::abort();
 | 
			
		||||
        }
 | 
			
		||||
        if (!singleton_constructed_objects().emplace(this).second) {
 | 
			
		||||
            test::print("ERROR at {}({}): {}\n", __FILE__, __LINE__, __func__);
 | 
			
		||||
            std::abort();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (nullptr != m_counts) {
 | 
			
		||||
        ++m_counts->m_data.m_move_ctor;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
counter::obj::~obj() {
 | 
			
		||||
    if constexpr (counter_enable_unordered_set) {
 | 
			
		||||
        if (1 != singleton_constructed_objects().erase(this)) {
 | 
			
		||||
            test::print("ERROR at {}({}): {}\n", __FILE__, __LINE__, __func__);
 | 
			
		||||
            std::abort();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (nullptr != m_counts) {
 | 
			
		||||
        ++m_counts->m_data.m_dtor;
 | 
			
		||||
    } else {
 | 
			
		||||
        ++static_dtor;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto counter::obj::operator==(obj const& o) const -> bool {
 | 
			
		||||
    if constexpr (counter_enable_unordered_set) {
 | 
			
		||||
        if (1 != singleton_constructed_objects().count(this) || 1 != singleton_constructed_objects().count(&o)) {
 | 
			
		||||
            test::print("ERROR at {}({}): {}\n", __FILE__, __LINE__, __func__);
 | 
			
		||||
            std::abort();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (nullptr != m_counts) {
 | 
			
		||||
        ++m_counts->m_data.m_equals;
 | 
			
		||||
    }
 | 
			
		||||
    return m_data == o.m_data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto counter::obj::operator<(obj const& o) const -> bool {
 | 
			
		||||
    if constexpr (counter_enable_unordered_set) {
 | 
			
		||||
        if (1 != singleton_constructed_objects().count(this) || 1 != singleton_constructed_objects().count(&o)) {
 | 
			
		||||
            test::print("ERROR at {}({}): {}\n", __FILE__, __LINE__, __func__);
 | 
			
		||||
            std::abort();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (nullptr != m_counts) {
 | 
			
		||||
        ++m_counts->m_data.m_less;
 | 
			
		||||
    }
 | 
			
		||||
    return m_data < o.m_data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NOLINTNEXTLINE(bugprone-unhandled-self-assignment,cert-oop54-cpp)
 | 
			
		||||
auto counter::obj::operator=(obj const& o) -> counter::obj& {
 | 
			
		||||
    if constexpr (counter_enable_unordered_set) {
 | 
			
		||||
        if (1 != singleton_constructed_objects().count(this) || 1 != singleton_constructed_objects().count(&o)) {
 | 
			
		||||
            test::print("ERROR at {}({}): {}\n", __FILE__, __LINE__, __func__);
 | 
			
		||||
            std::abort();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    m_counts = o.m_counts;
 | 
			
		||||
    if (nullptr != m_counts) {
 | 
			
		||||
        ++m_counts->m_data.m_assign;
 | 
			
		||||
    }
 | 
			
		||||
    m_data = o.m_data;
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto counter::obj::operator=(obj&& o) noexcept -> counter::obj& {
 | 
			
		||||
    if constexpr (counter_enable_unordered_set) {
 | 
			
		||||
        if (1 != singleton_constructed_objects().count(this) || 1 != singleton_constructed_objects().count(&o)) {
 | 
			
		||||
            test::print("ERROR at {}({}): {}\n", __FILE__, __LINE__, __func__);
 | 
			
		||||
            std::abort();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (nullptr != o.m_counts) {
 | 
			
		||||
        m_counts = o.m_counts;
 | 
			
		||||
    }
 | 
			
		||||
    m_data = o.m_data;
 | 
			
		||||
    if (nullptr != m_counts) {
 | 
			
		||||
        ++m_counts->m_data.m_move_assign;
 | 
			
		||||
    }
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto counter::obj::get() const -> size_t const& {
 | 
			
		||||
    if (nullptr != m_counts) {
 | 
			
		||||
        ++m_counts->m_data.m_const_get;
 | 
			
		||||
    }
 | 
			
		||||
    return m_data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto counter::obj::get() -> size_t& {
 | 
			
		||||
    if (nullptr != m_counts) {
 | 
			
		||||
        ++m_counts->m_data.m_get;
 | 
			
		||||
    }
 | 
			
		||||
    return m_data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void counter::obj::swap(obj& other) {
 | 
			
		||||
    if constexpr (counter_enable_unordered_set) {
 | 
			
		||||
        if (1 != singleton_constructed_objects().count(this) || 1 != singleton_constructed_objects().count(&other)) {
 | 
			
		||||
            test::print("ERROR at {}({}): {}\n", __FILE__, __LINE__, __func__);
 | 
			
		||||
            std::abort();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    using std::swap;
 | 
			
		||||
    swap(m_data, other.m_data);
 | 
			
		||||
    swap(m_counts, other.m_counts);
 | 
			
		||||
    if (nullptr != m_counts) {
 | 
			
		||||
        ++m_counts->m_data.m_swaps;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto counter::obj::get_for_hash() const -> size_t {
 | 
			
		||||
    if (nullptr != m_counts) {
 | 
			
		||||
        ++m_counts->m_data.m_hash;
 | 
			
		||||
    }
 | 
			
		||||
    return m_data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
counter::counter() {
 | 
			
		||||
    counter::static_default_ctor = 0;
 | 
			
		||||
    counter::static_dtor = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void counter::check_all_done() const {
 | 
			
		||||
    if constexpr (counter_enable_unordered_set) {
 | 
			
		||||
        // check that all are destructed
 | 
			
		||||
        if (!singleton_constructed_objects().empty()) {
 | 
			
		||||
            test::print("ERROR at ~counter(): got {} objects still alive!", singleton_constructed_objects().size());
 | 
			
		||||
            std::abort();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (m_data.m_dtor + static_dtor !=
 | 
			
		||||
            m_data.m_ctor + static_default_ctor + m_data.m_copy_ctor + m_data.m_default_ctor + m_data.m_move_ctor) {
 | 
			
		||||
            test::print("ERROR at ~counter(): number of counts does not match!\n");
 | 
			
		||||
            test::print(
 | 
			
		||||
                "{} dtor + {} staticDtor != {} ctor + {} staticDefaultCtor + {} copyCtor + {} defaultCtor + {} moveCtor\n",
 | 
			
		||||
                m_data.m_dtor,
 | 
			
		||||
                static_dtor,
 | 
			
		||||
                m_data.m_ctor,
 | 
			
		||||
                static_default_ctor,
 | 
			
		||||
                m_data.m_copy_ctor,
 | 
			
		||||
                m_data.m_default_ctor,
 | 
			
		||||
                m_data.m_move_ctor);
 | 
			
		||||
            std::abort();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
counter::~counter() {
 | 
			
		||||
    check_all_done();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto counter::total() const -> size_t {
 | 
			
		||||
    return m_data.m_ctor + static_default_ctor + m_data.m_copy_ctor + (m_data.m_dtor + static_dtor) + m_data.m_equals +
 | 
			
		||||
           m_data.m_less + m_data.m_assign + m_data.m_swaps + m_data.m_get + m_data.m_const_get + m_data.m_hash +
 | 
			
		||||
           m_data.m_move_ctor + m_data.m_move_assign;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void counter::operator()(std::string_view title) {
 | 
			
		||||
    m_records += fmt::format("{:9}{:9}{:9}{:9}{:9}{:9}{:9}{:9}{:9}{:9}{:9}{:9}{:9}|{:9}| {}\n",
 | 
			
		||||
                             m_data.m_ctor,
 | 
			
		||||
                             static_default_ctor,
 | 
			
		||||
                             m_data.m_copy_ctor,
 | 
			
		||||
                             m_data.m_dtor + static_dtor,
 | 
			
		||||
                             m_data.m_assign,
 | 
			
		||||
                             m_data.m_swaps,
 | 
			
		||||
                             m_data.m_get,
 | 
			
		||||
                             m_data.m_const_get,
 | 
			
		||||
                             m_data.m_hash,
 | 
			
		||||
                             m_data.m_equals,
 | 
			
		||||
                             m_data.m_less,
 | 
			
		||||
                             m_data.m_move_ctor,
 | 
			
		||||
                             m_data.m_move_assign,
 | 
			
		||||
                             total(),
 | 
			
		||||
                             title);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto operator<<(std::ostream& os, counter const& c) -> std::ostream& {
 | 
			
		||||
    return os << c.m_records;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto operator new(size_t /*unused*/, counter::obj* /*unused*/) -> void* {
 | 
			
		||||
    throw std::runtime_error("operator new overload is taken! Cast to void* to ensure the void pointer overload is taken.");
 | 
			
		||||
}
 | 
			
		||||
size_t counter::static_default_ctor = 0; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
 | 
			
		||||
size_t counter::static_dtor = 0;         // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
 | 
			
		||||
							
								
								
									
										170
									
								
								third_party/unordered_dense/test/app/counter.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								third_party/unordered_dense/test/app/counter.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,170 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <fmt/core.h> // for format_context, format_parse_context, format_to
 | 
			
		||||
 | 
			
		||||
#include <cstddef>     // for size_t
 | 
			
		||||
#include <functional>  // for hash
 | 
			
		||||
#include <iosfwd>      // for ostream
 | 
			
		||||
#include <string>      // for allocator, string
 | 
			
		||||
#include <string_view> // for hash, string_view
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
 | 
			
		||||
class counter {
 | 
			
		||||
public:
 | 
			
		||||
    struct data_t {
 | 
			
		||||
        size_t m_ctor{};
 | 
			
		||||
        size_t m_default_ctor{};
 | 
			
		||||
        size_t m_copy_ctor{};
 | 
			
		||||
        size_t m_dtor{};
 | 
			
		||||
        size_t m_assign{};
 | 
			
		||||
        size_t m_swaps{};
 | 
			
		||||
        size_t m_get{};
 | 
			
		||||
        size_t m_const_get{};
 | 
			
		||||
        size_t m_hash{};
 | 
			
		||||
        size_t m_equals{};
 | 
			
		||||
        size_t m_less{};
 | 
			
		||||
        size_t m_move_ctor{};
 | 
			
		||||
        size_t m_move_assign{};
 | 
			
		||||
 | 
			
		||||
        friend auto operator==(data_t const& a, data_t const& b) -> bool {
 | 
			
		||||
            static_assert(std::has_unique_object_representations_v<data_t>);
 | 
			
		||||
            return 0 == std::memcmp(&a, &b, sizeof(data_t));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        friend auto operator!=(data_t const& a, data_t const& b) -> bool {
 | 
			
		||||
            return !(a == b);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    counter(counter const&) = delete;
 | 
			
		||||
    counter(counter&&) = delete;
 | 
			
		||||
    auto operator=(counter const&) -> counter& = delete;
 | 
			
		||||
    auto operator=(counter&&) -> counter&& = delete;
 | 
			
		||||
 | 
			
		||||
    // Obj for only swaps & equals. Used for optimizing.
 | 
			
		||||
    // Can't use static counters here because I want to do it in parallel.
 | 
			
		||||
    class obj {
 | 
			
		||||
    public:
 | 
			
		||||
        // required for operator[]
 | 
			
		||||
        obj();
 | 
			
		||||
        obj(const size_t& data, counter& counts);
 | 
			
		||||
        obj(const obj& o);
 | 
			
		||||
        obj(obj&& o) noexcept;
 | 
			
		||||
        ~obj();
 | 
			
		||||
 | 
			
		||||
        auto operator==(const obj& o) const -> bool;
 | 
			
		||||
        auto operator<(const obj& o) const -> bool;
 | 
			
		||||
        auto operator=(const obj& o) -> obj&;
 | 
			
		||||
        auto operator=(obj&& o) noexcept -> obj&;
 | 
			
		||||
 | 
			
		||||
        [[nodiscard]] auto get() const -> size_t const&;
 | 
			
		||||
        auto get() -> size_t&;
 | 
			
		||||
 | 
			
		||||
        void swap(obj& other);
 | 
			
		||||
        [[nodiscard]] auto get_for_hash() const -> size_t;
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        size_t m_data;
 | 
			
		||||
        counter* m_counts;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    counter();
 | 
			
		||||
    ~counter();
 | 
			
		||||
 | 
			
		||||
    void check_all_done() const;
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] auto ctor() const -> size_t {
 | 
			
		||||
        return m_data.m_ctor;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] auto default_ctor() const -> size_t {
 | 
			
		||||
        return m_data.m_default_ctor;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] auto copy_ctor() const -> size_t {
 | 
			
		||||
        return m_data.m_copy_ctor;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] auto dtor() const -> size_t {
 | 
			
		||||
        return m_data.m_dtor;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] auto equals() const -> size_t {
 | 
			
		||||
        return m_data.m_equals;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] auto less() const -> size_t {
 | 
			
		||||
        return m_data.m_less;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] auto assign() const -> size_t {
 | 
			
		||||
        return m_data.m_assign;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] auto swaps() const -> size_t {
 | 
			
		||||
        return m_data.m_swaps;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] auto get() const -> size_t {
 | 
			
		||||
        return m_data.m_get;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] auto const_get() const -> size_t {
 | 
			
		||||
        return m_data.m_const_get;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] auto hash() const -> size_t {
 | 
			
		||||
        return m_data.m_hash;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] auto move_ctor() const -> size_t {
 | 
			
		||||
        return m_data.m_move_ctor;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] auto move_assign() const -> size_t {
 | 
			
		||||
        return m_data.m_move_assign;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] auto data() const -> data_t const& {
 | 
			
		||||
        return m_data;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    friend auto operator<<(std::ostream& os, counter const& c) -> std::ostream&;
 | 
			
		||||
 | 
			
		||||
    void operator()(std::string_view title);
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] auto total() const -> size_t;
 | 
			
		||||
 | 
			
		||||
    static size_t static_default_ctor; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
 | 
			
		||||
    static size_t static_dtor;         // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    data_t m_data{};
 | 
			
		||||
 | 
			
		||||
    std::string m_records =
 | 
			
		||||
        "\n     ctor  defctor  cpyctor     dtor   assign    swaps      get  cnstget     hash   equals     less   ctormv assignmv|   total |\n";
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Throws an exception, this overload should never be taken!
 | 
			
		||||
inline auto operator new(size_t s, counter::obj* ptr) -> void*;
 | 
			
		||||
 | 
			
		||||
namespace std {
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct hash<counter::obj> {
 | 
			
		||||
    [[nodiscard]] auto operator()(const counter::obj& c) const noexcept -> size_t {
 | 
			
		||||
        return hash<size_t>{}(c.get_for_hash());
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace std
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct fmt::formatter<counter::obj> {
 | 
			
		||||
    static constexpr auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
 | 
			
		||||
        return ctx.end();
 | 
			
		||||
    }
 | 
			
		||||
    static auto format(counter::obj const& o, fmt::format_context& ctx) -> decltype(ctx.out()) {
 | 
			
		||||
        return fmt::format_to(ctx.out(), "{}", o.get());
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										138
									
								
								third_party/unordered_dense/test/app/counting_allocator.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								third_party/unordered_dense/test/app/counting_allocator.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,138 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <fmt/ostream.h>
 | 
			
		||||
 | 
			
		||||
#include <chrono>
 | 
			
		||||
#include <filesystem>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <limits>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
// Source: https://github.com/bitcoin/bitcoin/blob/master/src/memusage.h#L41-L61
 | 
			
		||||
static inline auto malloc_usage(size_t alloc) -> size_t {
 | 
			
		||||
    static_assert(sizeof(void*) == 8 || sizeof(void*) == 4);
 | 
			
		||||
 | 
			
		||||
    // Measured on libc6 2.19 on Linux.
 | 
			
		||||
    if constexpr (sizeof(void*) == 8U) {
 | 
			
		||||
        return ((alloc + 31U) >> 4U) << 4U;
 | 
			
		||||
    } else {
 | 
			
		||||
        return ((alloc + 15U) >> 3U) << 3U;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class counts_for_allocator {
 | 
			
		||||
    struct measurement_internal {
 | 
			
		||||
        std::chrono::steady_clock::time_point m_tp{};
 | 
			
		||||
        size_t m_diff{};
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct measurement {
 | 
			
		||||
        std::chrono::steady_clock::duration m_duration{};
 | 
			
		||||
        size_t m_num_bytes_allocated{};
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    std::vector<measurement_internal> m_measurements{};
 | 
			
		||||
    std::chrono::steady_clock::time_point m_start = std::chrono::steady_clock::now();
 | 
			
		||||
 | 
			
		||||
    template <typename Op>
 | 
			
		||||
    void each_measurement(Op op) const {
 | 
			
		||||
        auto total_bytes = size_t();
 | 
			
		||||
        auto const start_time = m_start;
 | 
			
		||||
        for (auto const& m : m_measurements) {
 | 
			
		||||
            bool is_add = true;
 | 
			
		||||
            size_t bytes = m.m_diff;
 | 
			
		||||
            if (bytes > (0U - bytes)) {
 | 
			
		||||
                // negative number
 | 
			
		||||
                is_add = false;
 | 
			
		||||
                bytes = 0U - bytes;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (is_add) {
 | 
			
		||||
                total_bytes += malloc_usage(bytes);
 | 
			
		||||
            } else {
 | 
			
		||||
                total_bytes -= malloc_usage(bytes);
 | 
			
		||||
            }
 | 
			
		||||
            op(measurement{m.m_tp - start_time, total_bytes});
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    void add(size_t count) {
 | 
			
		||||
        m_measurements.emplace_back(measurement_internal{std::chrono::steady_clock::now(), count});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void sub(size_t count) {
 | 
			
		||||
        // overflow, but it's ok
 | 
			
		||||
        m_measurements.emplace_back(measurement_internal{std::chrono::steady_clock::now(), 0U - count});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void save(std::filesystem::path const& filename) const {
 | 
			
		||||
        auto fout = std::ofstream(filename);
 | 
			
		||||
        each_measurement([&](measurement m) {
 | 
			
		||||
            fmt::print(fout, "{}; {}\n", std::chrono::duration<double>(m.m_duration).count(), m.m_num_bytes_allocated);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] auto size() const -> size_t {
 | 
			
		||||
        return m_measurements.size();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void reset() {
 | 
			
		||||
        m_measurements.clear();
 | 
			
		||||
        m_start = std::chrono::steady_clock::now();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Forwards all allocations/deallocations to the counts
 | 
			
		||||
 */
 | 
			
		||||
template <class T>
 | 
			
		||||
class counting_allocator {
 | 
			
		||||
    counts_for_allocator* m_counts;
 | 
			
		||||
 | 
			
		||||
    template <typename U>
 | 
			
		||||
    friend class counting_allocator;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    using value_type = T;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Not explicit so we can easily construct it with the correct resource
 | 
			
		||||
     */
 | 
			
		||||
    counting_allocator(counts_for_allocator* counts) noexcept // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
 | 
			
		||||
        : m_counts(counts) {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Not explicit so we can easily construct it with the correct resource
 | 
			
		||||
     */
 | 
			
		||||
    template <class U>
 | 
			
		||||
    // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions)
 | 
			
		||||
    counting_allocator(counting_allocator<U> const& other) noexcept
 | 
			
		||||
        : m_counts(other.m_counts) {}
 | 
			
		||||
 | 
			
		||||
    counting_allocator(counting_allocator const& other) noexcept = default;
 | 
			
		||||
    counting_allocator(counting_allocator&& other) noexcept = default;
 | 
			
		||||
    auto operator=(counting_allocator const& other) noexcept -> counting_allocator& = default;
 | 
			
		||||
    auto operator=(counting_allocator&& other) noexcept -> counting_allocator& = default;
 | 
			
		||||
    ~counting_allocator() = default;
 | 
			
		||||
 | 
			
		||||
    auto allocate(size_t n) -> T* {
 | 
			
		||||
        m_counts->add(sizeof(T) * n);
 | 
			
		||||
        return std::allocator<T>{}.allocate(n);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void deallocate(T* p, size_t n) noexcept {
 | 
			
		||||
        m_counts->sub(sizeof(T) * n);
 | 
			
		||||
        std::allocator<T>{}.deallocate(p, n);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <class U>
 | 
			
		||||
    friend auto operator==(counting_allocator const& a, counting_allocator<U> const& b) noexcept -> bool {
 | 
			
		||||
        return a.m_counts == b.m_counts;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <class U>
 | 
			
		||||
    friend auto operator!=(counting_allocator const& a, counting_allocator<U> const& b) noexcept -> bool {
 | 
			
		||||
        return a.m_counts != b.m_counts;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										10
									
								
								third_party/unordered_dense/test/app/doctest.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								third_party/unordered_dense/test/app/doctest.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
			
		||||
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
 | 
			
		||||
#include <doctest.h>
 | 
			
		||||
 | 
			
		||||
namespace doctest {
 | 
			
		||||
 | 
			
		||||
[[nodiscard]] auto current_test_name() -> char const* {
 | 
			
		||||
    return doctest::detail::g_cs->currentTest->m_name;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace doctest
 | 
			
		||||
							
								
								
									
										120
									
								
								third_party/unordered_dense/test/app/doctest.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								third_party/unordered_dense/test/app/doctest.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,120 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
#include <app/counter.h>
 | 
			
		||||
 | 
			
		||||
#include <doctest.h>
 | 
			
		||||
 | 
			
		||||
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
 | 
			
		||||
#    undef DOCTEST_REQUIRE
 | 
			
		||||
#    define DOCTEST_REQUIRE(...)  \
 | 
			
		||||
        do {                      \
 | 
			
		||||
            if (!(__VA_ARGS__)) { \
 | 
			
		||||
                std::abort();     \
 | 
			
		||||
            }                     \
 | 
			
		||||
        } while (0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
namespace doctest {
 | 
			
		||||
 | 
			
		||||
[[nodiscard]] auto current_test_name() -> char const*;
 | 
			
		||||
 | 
			
		||||
} // namespace doctest
 | 
			
		||||
 | 
			
		||||
#include <deque>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
 | 
			
		||||
template <class Key,
 | 
			
		||||
          class T,
 | 
			
		||||
          class Hash = ankerl::unordered_dense::hash<Key>,
 | 
			
		||||
          class KeyEqual = std::equal_to<Key>,
 | 
			
		||||
          class AllocatorOrContainer = std::deque<std::pair<Key, T>>,
 | 
			
		||||
          class Bucket = ankerl::unordered_dense::bucket_type::standard>
 | 
			
		||||
class deque_map : public ankerl::unordered_dense::detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket, false> {
 | 
			
		||||
    using base_t = ankerl::unordered_dense::detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket, false>;
 | 
			
		||||
    using base_t::base_t;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <class Key,
 | 
			
		||||
          class Hash = ankerl::unordered_dense::hash<Key>,
 | 
			
		||||
          class KeyEqual = std::equal_to<Key>,
 | 
			
		||||
          class AllocatorOrContainer = std::deque<Key>,
 | 
			
		||||
          class Bucket = ankerl::unordered_dense::bucket_type::standard>
 | 
			
		||||
class deque_set
 | 
			
		||||
    : public ankerl::unordered_dense::detail::table<Key, void, Hash, KeyEqual, AllocatorOrContainer, Bucket, false> {
 | 
			
		||||
    using base_t = ankerl::unordered_dense::detail::table<Key, void, Hash, KeyEqual, AllocatorOrContainer, Bucket, false>;
 | 
			
		||||
    using base_t::base_t;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
 | 
			
		||||
#define TEST_CASE_MAP(name, ...)                                            \
 | 
			
		||||
    TEST_CASE_TEMPLATE(name,                                                \
 | 
			
		||||
                       map_t,                                               \
 | 
			
		||||
                       ankerl::unordered_dense::map<__VA_ARGS__>,           \
 | 
			
		||||
                       ankerl::unordered_dense::segmented_map<__VA_ARGS__>, \
 | 
			
		||||
                       deque_map<__VA_ARGS__>)
 | 
			
		||||
 | 
			
		||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
 | 
			
		||||
#define TEST_CASE_SET(name, ...)                                            \
 | 
			
		||||
    TEST_CASE_TEMPLATE(name,                                                \
 | 
			
		||||
                       set_t,                                               \
 | 
			
		||||
                       ankerl::unordered_dense::set<__VA_ARGS__>,           \
 | 
			
		||||
                       ankerl::unordered_dense::segmented_set<__VA_ARGS__>, \
 | 
			
		||||
                       deque_set<__VA_ARGS__>)
 | 
			
		||||
 | 
			
		||||
#define TYPE_TO_STRING_MAP(...)                                          /*NOLINT*/ \
 | 
			
		||||
    TYPE_TO_STRING(ankerl::unordered_dense::map<__VA_ARGS__>);           /*NOLINT*/ \
 | 
			
		||||
    TYPE_TO_STRING(ankerl::unordered_dense::segmented_map<__VA_ARGS__>); /*NOLINT*/ \
 | 
			
		||||
    TYPE_TO_STRING(deque_map<__VA_ARGS__>)                               /*NOLINT*/
 | 
			
		||||
 | 
			
		||||
#define TYPE_TO_STRING_SET(...)                                          /*NOLINT*/ \
 | 
			
		||||
    TYPE_TO_STRING(ankerl::unordered_dense::set<__VA_ARGS__>);           /*NOLINT*/ \
 | 
			
		||||
    TYPE_TO_STRING(ankerl::unordered_dense::segmented_set<__VA_ARGS__>); /*NOLINT*/ \
 | 
			
		||||
    TYPE_TO_STRING(deque_set<__VA_ARGS__>)                               /*NOLINT*/
 | 
			
		||||
 | 
			
		||||
#if defined(ANKERL_UNORDERED_DENSE_PMR)
 | 
			
		||||
 | 
			
		||||
// unfortunately there's no std::experimental::pmr::deque on macos, so just skip this here
 | 
			
		||||
 | 
			
		||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
 | 
			
		||||
#    define TEST_CASE_PMR_MAP(name, ...)                                   \
 | 
			
		||||
        TEST_CASE_TEMPLATE(name,                                           \
 | 
			
		||||
                           map_t,                                          \
 | 
			
		||||
                           ankerl::unordered_dense::pmr::map<__VA_ARGS__>, \
 | 
			
		||||
                           ankerl::unordered_dense::pmr::segmented_map<__VA_ARGS__>)
 | 
			
		||||
 | 
			
		||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
 | 
			
		||||
#    define TEST_CASE_PMR_SET(name, ...)                                   \
 | 
			
		||||
        TEST_CASE_TEMPLATE(name,                                           \
 | 
			
		||||
                           set_t,                                          \
 | 
			
		||||
                           ankerl::unordered_dense::pmr::set<__VA_ARGS__>, \
 | 
			
		||||
                           ankerl::unordered_dense::pmr::segmented_set<__VA_ARGS__>)
 | 
			
		||||
 | 
			
		||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
 | 
			
		||||
#    define TYPE_TO_STRING_PMR_MAP(...)                                                     \
 | 
			
		||||
        TYPE_TO_STRING(ankerl::unordered_dense::pmr::map<__VA_ARGS__>);          /*NOLINT*/ \
 | 
			
		||||
        TYPE_TO_STRING(ankerl::unordered_dense::pmr::segmented_map<__VA_ARGS__>) /*NOLINT*/
 | 
			
		||||
 | 
			
		||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
 | 
			
		||||
#    define TYPE_TO_STRING_PMR_SET(...)                                                     \
 | 
			
		||||
        TYPE_TO_STRING(ankerl::unordered_dense::pmr::set<__VA_ARGS__>);          /*NOLINT*/ \
 | 
			
		||||
        TYPE_TO_STRING(ankerl::unordered_dense::pmr::segmented_set<__VA_ARGS__>) /*NOLINT*/
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// adds the most important type to strings here
 | 
			
		||||
 | 
			
		||||
TYPE_TO_STRING_MAP(counter::obj, counter::obj);
 | 
			
		||||
TYPE_TO_STRING_MAP(int, char const*);
 | 
			
		||||
TYPE_TO_STRING_MAP(int, int);
 | 
			
		||||
TYPE_TO_STRING_MAP(int, std::string);
 | 
			
		||||
TYPE_TO_STRING_MAP(std::string, size_t);
 | 
			
		||||
TYPE_TO_STRING_MAP(std::string, std::string);
 | 
			
		||||
TYPE_TO_STRING_MAP(uint64_t, uint64_t);
 | 
			
		||||
TYPE_TO_STRING_MAP(uint32_t, int);
 | 
			
		||||
TYPE_TO_STRING_MAP(uint64_t, int);
 | 
			
		||||
TYPE_TO_STRING_SET(counter::obj);
 | 
			
		||||
TYPE_TO_STRING_SET(int);
 | 
			
		||||
TYPE_TO_STRING_SET(std::string);
 | 
			
		||||
TYPE_TO_STRING_SET(uint32_t);
 | 
			
		||||
TYPE_TO_STRING_SET(uint64_t);
 | 
			
		||||
							
								
								
									
										24
									
								
								third_party/unordered_dense/test/app/geomean.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								third_party/unordered_dense/test/app/geomean.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <cmath>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
template <typename It, typename Op>
 | 
			
		||||
[[nodiscard]] auto geomean(It begin, It end, Op op) -> double {
 | 
			
		||||
    double sum = 0.0;
 | 
			
		||||
    size_t count = 0;
 | 
			
		||||
    while (begin != end) {
 | 
			
		||||
        sum += std::log(op(*begin));
 | 
			
		||||
        ++begin;
 | 
			
		||||
        ++count;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sum /= static_cast<double>(count);
 | 
			
		||||
    return std::exp(sum);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Container, typename Op>
 | 
			
		||||
[[nodiscard]] auto geomean(Container&& c, Op op) -> double {
 | 
			
		||||
    return geomean(std::begin(c), std::end(c), std::move(op));
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										31
									
								
								third_party/unordered_dense/test/app/name_of_type.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								third_party/unordered_dense/test/app/name_of_type.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,31 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <string_view>
 | 
			
		||||
 | 
			
		||||
namespace detail {
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
[[nodiscard]] constexpr auto name_of_type_raw() -> std::string_view {
 | 
			
		||||
#if defined(_MSC_VER)
 | 
			
		||||
    return __FUNCSIG__; // NOLINT
 | 
			
		||||
#else
 | 
			
		||||
    return __PRETTY_FUNCTION__; // NOLINT
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace detail
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
[[nodiscard]] constexpr auto name_of_type() -> std::string_view {
 | 
			
		||||
    using namespace std::literals;
 | 
			
		||||
 | 
			
		||||
    // idea from https://github.com/TheLartians/StaticTypeInfo/blob/master/include/static_type_info/type_name.h
 | 
			
		||||
    auto for_double = detail::name_of_type_raw<double>();
 | 
			
		||||
    auto n_before = for_double.find("double"sv);
 | 
			
		||||
    auto n_after = for_double.size() - (n_before + "double"sv.size());
 | 
			
		||||
 | 
			
		||||
    auto str = detail::name_of_type_raw<T>();
 | 
			
		||||
    str.remove_prefix(n_before);
 | 
			
		||||
    str.remove_suffix(n_after);
 | 
			
		||||
    return str;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								third_party/unordered_dense/test/app/nanobench.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								third_party/unordered_dense/test/app/nanobench.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
			
		||||
#define ANKERL_NANOBENCH_IMPLEMENT
 | 
			
		||||
#include <third-party/nanobench.h>
 | 
			
		||||
							
								
								
									
										19
									
								
								third_party/unordered_dense/test/app/print.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								third_party/unordered_dense/test/app/print.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
			
		||||
#include <fmt/format.h>
 | 
			
		||||
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
 | 
			
		||||
namespace test {
 | 
			
		||||
 | 
			
		||||
template <typename... Args>
 | 
			
		||||
constexpr void print(fmt::format_string<Args...> f, Args&&... args) {
 | 
			
		||||
    fmt::print(f, std::forward<Args>(args)...);
 | 
			
		||||
    (void)std::fflush(stdout);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifndef ENABLE_LOG_LINE
 | 
			
		||||
#    define LOG_LINE(what)
 | 
			
		||||
#else
 | 
			
		||||
#    define LOG_LINE(what) ::test::print("{}({:3}) {}\n", __FILE__, __LINE__, what)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace test
 | 
			
		||||
							
								
								
									
										41
									
								
								third_party/unordered_dense/test/app/stacktrace.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								third_party/unordered_dense/test/app/stacktrace.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,41 @@
 | 
			
		||||
#if __GNUC__
 | 
			
		||||
 | 
			
		||||
#    include <fmt/format.h>
 | 
			
		||||
 | 
			
		||||
#    include <array>
 | 
			
		||||
#    include <csignal>
 | 
			
		||||
#    include <cstdio>
 | 
			
		||||
#    include <cstdlib>
 | 
			
		||||
#    include <execinfo.h>
 | 
			
		||||
#    include <unistd.h>
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
void handle(int sig) {
 | 
			
		||||
    fmt::print(stderr, "Error: signal {}:\n", sig);
 | 
			
		||||
    auto ary = std::array<void*, 50>();
 | 
			
		||||
 | 
			
		||||
    // get void*'s for all entries on the stack
 | 
			
		||||
    auto size = backtrace(ary.data(), static_cast<int>(ary.size()));
 | 
			
		||||
 | 
			
		||||
    // print out all the frames to stderr
 | 
			
		||||
    fmt::print(stderr, "Error: signal {}. See stacktrace with\n", sig);
 | 
			
		||||
    fmt::print(stderr, "addr2line -Cafpie ./test/udm-test");
 | 
			
		||||
    for (size_t i = 0; i < static_cast<size_t>(size); ++i) {
 | 
			
		||||
        fmt::print(stderr, " {}", ary[i]);
 | 
			
		||||
    }
 | 
			
		||||
    exit(1); // NOLINT(concurrency-mt-unsafe)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class handler {
 | 
			
		||||
public:
 | 
			
		||||
    handler() {
 | 
			
		||||
        (void)signal(SIGTERM, handle);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
auto const global_h = handler();
 | 
			
		||||
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										17
									
								
								third_party/unordered_dense/test/app/ui/periodic.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								third_party/unordered_dense/test/app/ui/periodic.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
			
		||||
#include "periodic.h"
 | 
			
		||||
 | 
			
		||||
namespace ui {
 | 
			
		||||
 | 
			
		||||
periodic::periodic(std::chrono::steady_clock::duration interval)
 | 
			
		||||
    : m_interval(interval) {}
 | 
			
		||||
 | 
			
		||||
periodic::operator bool() {
 | 
			
		||||
    auto now = std::chrono::steady_clock::now();
 | 
			
		||||
    if (now < m_next) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    m_next = now + m_interval;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace ui
 | 
			
		||||
							
								
								
									
										16
									
								
								third_party/unordered_dense/test/app/ui/periodic.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								third_party/unordered_dense/test/app/ui/periodic.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <chrono>
 | 
			
		||||
 | 
			
		||||
namespace ui {
 | 
			
		||||
 | 
			
		||||
class periodic {
 | 
			
		||||
    std::chrono::steady_clock::time_point m_next{};
 | 
			
		||||
    std::chrono::steady_clock::duration m_interval{};
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    explicit periodic(std::chrono::steady_clock::duration interval);
 | 
			
		||||
    explicit operator bool();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace ui
 | 
			
		||||
							
								
								
									
										53
									
								
								third_party/unordered_dense/test/app/ui/progress_bar.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								third_party/unordered_dense/test/app/ui/progress_bar.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,53 @@
 | 
			
		||||
#include "progress_bar.h"
 | 
			
		||||
 | 
			
		||||
#include <algorithm> // for min
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
auto split(std::string_view symbols, char sep) -> std::vector<std::string> {
 | 
			
		||||
    auto s = std::vector<std::string>();
 | 
			
		||||
    while (true) {
 | 
			
		||||
        auto idx = symbols.find(sep);
 | 
			
		||||
        if (idx == std::string_view::npos) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        s.emplace_back(symbols.substr(0, idx));
 | 
			
		||||
        symbols.remove_prefix(idx + 1);
 | 
			
		||||
    }
 | 
			
		||||
    s.emplace_back(symbols);
 | 
			
		||||
    return s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
namespace ui {
 | 
			
		||||
 | 
			
		||||
progress_bar::progress_bar(size_t width, size_t total, std::string_view symbols)
 | 
			
		||||
    : m_width(width)
 | 
			
		||||
    , m_total(total)
 | 
			
		||||
    , m_symbols(split(symbols, ' ')) {}
 | 
			
		||||
 | 
			
		||||
auto progress_bar::operator()(size_t current) const -> std::string {
 | 
			
		||||
    auto const total_states = m_width * m_symbols.size() + 1;
 | 
			
		||||
    auto const current_state = total_states * current / m_total;
 | 
			
		||||
    std::string str;
 | 
			
		||||
    auto num_full = std::min(m_width, current_state / m_symbols.size());
 | 
			
		||||
    for (size_t i = 0; i < num_full; ++i) {
 | 
			
		||||
        str += m_symbols.back();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (num_full < m_width) {
 | 
			
		||||
        auto remaining = current_state - num_full * m_symbols.size();
 | 
			
		||||
        if (0U != remaining) {
 | 
			
		||||
            str += m_symbols[remaining - 1];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto num_fillers = m_width - num_full - (0U == remaining ? 0 : 1);
 | 
			
		||||
        for (size_t i = 0; i < num_fillers; ++i) {
 | 
			
		||||
            str.push_back(' ');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return str;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace ui
 | 
			
		||||
							
								
								
									
										21
									
								
								third_party/unordered_dense/test/app/ui/progress_bar.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								third_party/unordered_dense/test/app/ui/progress_bar.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <cstddef>     // for size_t
 | 
			
		||||
#include <string>      // for string, basic_string
 | 
			
		||||
#include <string_view> // for string_view
 | 
			
		||||
#include <vector>      // for vector
 | 
			
		||||
 | 
			
		||||
namespace ui {
 | 
			
		||||
 | 
			
		||||
class progress_bar {
 | 
			
		||||
    size_t m_width;
 | 
			
		||||
    size_t m_total;
 | 
			
		||||
    std::vector<std::string> m_symbols;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    progress_bar(size_t width, size_t total, std::string_view symbols = "⡀ ⡄ ⡆ ⡇ ⡏ ⡟ ⡿ ⣿");
 | 
			
		||||
 | 
			
		||||
    auto operator()(size_t current) const -> std::string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace ui
 | 
			
		||||
							
								
								
									
										3
									
								
								third_party/unordered_dense/test/app/unordered_dense.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								third_party/unordered_dense/test/app/unordered_dense.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
 | 
			
		||||
// this cpp file is only for include-what-you-use
 | 
			
		||||
							
								
								
									
										47
									
								
								third_party/unordered_dense/test/bench/copy.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								third_party/unordered_dense/test/bench/copy.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h> // for map, operator==
 | 
			
		||||
 | 
			
		||||
#include <third-party/nanobench.h> // for Rng, Bench
 | 
			
		||||
 | 
			
		||||
#include <app/doctest.h> // for TestCase, skip, TEST_CASE, test_...
 | 
			
		||||
#include <fmt/core.h>    // for format
 | 
			
		||||
 | 
			
		||||
#include <cstddef>       // for size_t
 | 
			
		||||
#include <cstdint>       // for uint64_t
 | 
			
		||||
#include <string_view>   // for string_view
 | 
			
		||||
#include <unordered_map> // for unordered_map, operator==
 | 
			
		||||
 | 
			
		||||
template <typename Map>
 | 
			
		||||
void bench(std::string_view name) {
 | 
			
		||||
    auto a = Map();
 | 
			
		||||
    auto rng = ankerl::nanobench::Rng(123);
 | 
			
		||||
    for (size_t i = 0; i < 1000000; ++i) {
 | 
			
		||||
        a.try_emplace(rng(), rng());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Map b;
 | 
			
		||||
    ankerl::nanobench::Bench().batch(a.size() * 2).run(fmt::format("copy {}", name), [&] {
 | 
			
		||||
        b = a;
 | 
			
		||||
        a = b;
 | 
			
		||||
    });
 | 
			
		||||
    REQUIRE(a == b);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
 | 
			
		||||
TEST_CASE("bench_copy_rhn" * doctest::test_suite("bench") * doctest::skip()) {
 | 
			
		||||
    bench<robin_hood::unordered_node_map<uint64_t, uint64_t>>("robin_hood::unordered_node_map");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("bench_copy_rhf" * doctest::test_suite("bench") * doctest::skip()) {
 | 
			
		||||
    bench<robin_hood::unordered_flat_map<uint64_t, uint64_t>>("robin_hood::unordered_flat_map");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("bench_copy_udm" * doctest::test_suite("bench") * doctest::skip(), uint64_t, uint64_t) {
 | 
			
		||||
    bench<map_t>("ankerl::unordered_dense::map");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("bench_copy_std" * doctest::test_suite("bench") * doctest::skip()) {
 | 
			
		||||
    bench<std::unordered_map<uint64_t, uint64_t>>("std::unordered_map");
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										101
									
								
								third_party/unordered_dense/test/bench/find_random.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								third_party/unordered_dense/test/bench/find_random.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,101 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h> // for map
 | 
			
		||||
 | 
			
		||||
#include <app/name_of_type.h>      // for name_of_type
 | 
			
		||||
#include <third-party/nanobench.h> // for Rng
 | 
			
		||||
 | 
			
		||||
#include <app/doctest.h> // for TestCase, skip, ResultBuilder
 | 
			
		||||
#include <fmt/core.h>    // for format, print
 | 
			
		||||
 | 
			
		||||
#include <algorithm>     // for fill_n
 | 
			
		||||
#include <array>         // for array
 | 
			
		||||
#include <chrono>        // for duration, operator-, steady_clock
 | 
			
		||||
#include <cstddef>       // for size_t
 | 
			
		||||
#include <unordered_map> // for unordered_map, operator!=
 | 
			
		||||
#include <vector>        // for vector
 | 
			
		||||
 | 
			
		||||
template <typename Map>
 | 
			
		||||
void bench() {
 | 
			
		||||
    static constexpr size_t num_total = 4;
 | 
			
		||||
 | 
			
		||||
    auto required_checksum = std::array<size_t, 5>{200000, 25198620, 50197240, 75195862, 100194482};
 | 
			
		||||
    auto total = std::chrono::steady_clock::duration();
 | 
			
		||||
 | 
			
		||||
    for (size_t num_found = 0; num_found < 5; ++num_found) {
 | 
			
		||||
        auto title = fmt::format("random find {}% success {}", num_found * 100 / num_total, name_of_type<Map>());
 | 
			
		||||
        auto rng = ankerl::nanobench::Rng(123);
 | 
			
		||||
 | 
			
		||||
        size_t checksum = 0;
 | 
			
		||||
 | 
			
		||||
        using ary_t = std::array<bool, num_total>;
 | 
			
		||||
        auto insert_random = ary_t();
 | 
			
		||||
        insert_random.fill(true);
 | 
			
		||||
        for (typename ary_t::size_type i = 0; i < num_found; ++i) {
 | 
			
		||||
            insert_random[i] = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto another_unrelated_rng = ankerl::nanobench::Rng(987654321);
 | 
			
		||||
        auto const another_unrelated_rng_initial_state = another_unrelated_rng.state();
 | 
			
		||||
        auto find_rng = ankerl::nanobench::Rng(another_unrelated_rng_initial_state);
 | 
			
		||||
 | 
			
		||||
        {
 | 
			
		||||
            static constexpr size_t num_inserts = 200000;
 | 
			
		||||
            static constexpr size_t num_finds_per_insert = 500;
 | 
			
		||||
            static constexpr size_t num_finds_per_iter = num_finds_per_insert * num_total;
 | 
			
		||||
 | 
			
		||||
            Map map;
 | 
			
		||||
            size_t i = 0;
 | 
			
		||||
            size_t find_count = 0;
 | 
			
		||||
            auto before = std::chrono::steady_clock::now();
 | 
			
		||||
            do {
 | 
			
		||||
                // insert numTotal entries: some random, some sequential.
 | 
			
		||||
                rng.shuffle(insert_random);
 | 
			
		||||
                for (bool const is_random_to_insert : insert_random) {
 | 
			
		||||
                    auto val = another_unrelated_rng();
 | 
			
		||||
                    if (is_random_to_insert) {
 | 
			
		||||
                        map[static_cast<size_t>(rng())] = static_cast<size_t>(1);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        map[static_cast<size_t>(val)] = static_cast<size_t>(1);
 | 
			
		||||
                    }
 | 
			
		||||
                    ++i;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // the actual benchmark code which should be as fast as possible
 | 
			
		||||
                for (size_t j = 0; j < num_finds_per_iter; ++j) {
 | 
			
		||||
                    if (++find_count > i) {
 | 
			
		||||
                        find_count = 0;
 | 
			
		||||
                        find_rng = ankerl::nanobench::Rng(another_unrelated_rng_initial_state);
 | 
			
		||||
                    }
 | 
			
		||||
                    auto it = map.find(static_cast<size_t>(find_rng()));
 | 
			
		||||
                    if (it != map.end()) {
 | 
			
		||||
                        checksum += it->second;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } while (i < num_inserts);
 | 
			
		||||
            checksum += map.size();
 | 
			
		||||
            auto after = std::chrono::steady_clock::now();
 | 
			
		||||
            total += after - before;
 | 
			
		||||
            fmt::print("{}s {}\n", std::chrono::duration<double>(after - before).count(), title);
 | 
			
		||||
        }
 | 
			
		||||
        REQUIRE(checksum == required_checksum[num_found]);
 | 
			
		||||
    }
 | 
			
		||||
    fmt::print("{}s total\n", std::chrono::duration<double>(total).count());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 26.81
 | 
			
		||||
TEST_CASE("bench_find_random_uo" * doctest::test_suite("bench") * doctest::skip()) {
 | 
			
		||||
    bench<std::unordered_map<size_t, size_t>>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
 | 
			
		||||
// 10.55
 | 
			
		||||
TEST_CASE("bench_find_random_rh" * doctest::test_suite("bench") * doctest::skip()) {
 | 
			
		||||
    bench<robin_hood::unordered_flat_map<size_t, size_t>>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// 8.87
 | 
			
		||||
TEST_CASE_MAP("bench_find_random_udm" * doctest::test_suite("bench") * doctest::skip(), size_t, size_t) {
 | 
			
		||||
    bench<map_t>();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										174
									
								
								third_party/unordered_dense/test/bench/game_of_life.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								third_party/unordered_dense/test/bench/game_of_life.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,174 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h> // for map
 | 
			
		||||
 | 
			
		||||
#include <app/counting_allocator.h>
 | 
			
		||||
 | 
			
		||||
#include <app/doctest.h> // for TestCase, skip, ResultBuilder
 | 
			
		||||
#include <fmt/core.h>    // for format, print
 | 
			
		||||
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#if __has_include("boost/unordered/unordered_flat_map.hpp")
 | 
			
		||||
#    if defined(__clang__)
 | 
			
		||||
#        pragma clang diagnostic ignored "-Wold-style-cast"
 | 
			
		||||
#    endif
 | 
			
		||||
#    include "boost/unordered/unordered_flat_map.hpp"
 | 
			
		||||
#    define HAS_BOOST_UNORDERED_FLAT_MAP() 1 // NOLINT(cppcoreguidelines-macro-usage)
 | 
			
		||||
#else
 | 
			
		||||
#    define HAS_BOOST_UNORDERED_FLAT_MAP() 0 // NOLINT(cppcoreguidelines-macro-usage)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if 0 && __has_include("absl/container/flat_hash_map.h")
 | 
			
		||||
#    if defined(__clang__)
 | 
			
		||||
#        pragma clang diagnostic ignored "-Wdeprecated-builtins"
 | 
			
		||||
#        pragma clang diagnostic ignored "-Wsign-conversion"
 | 
			
		||||
#    endif
 | 
			
		||||
#    include <absl/container/flat_hash_map.h>
 | 
			
		||||
#    define HAS_ABSL() 1 // NOLINT(cppcoreguidelines-macro-usage)
 | 
			
		||||
#else
 | 
			
		||||
#    define HAS_ABSL() 0 // NOLINT(cppcoreguidelines-macro-usage)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
class vec2 {
 | 
			
		||||
    uint32_t m_xy;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    constexpr vec2(uint16_t x, uint16_t y)
 | 
			
		||||
        : m_xy{static_cast<uint32_t>(x) << 16U | y} {}
 | 
			
		||||
 | 
			
		||||
    constexpr explicit vec2(uint32_t xy)
 | 
			
		||||
        : m_xy(xy) {}
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] constexpr auto pack() const -> uint32_t {
 | 
			
		||||
        return m_xy;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] constexpr auto add_x(uint16_t x) const -> vec2 {
 | 
			
		||||
        return vec2{m_xy + (static_cast<uint32_t>(x) << 16U)};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] constexpr auto add_y(uint16_t y) const -> vec2 {
 | 
			
		||||
        return vec2{(m_xy & 0xffff0000) | ((m_xy + y) & 0xffff)};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename Op>
 | 
			
		||||
    constexpr void for_each_surrounding(Op&& op) const {
 | 
			
		||||
        uint32_t v = m_xy;
 | 
			
		||||
 | 
			
		||||
        uint32_t upper = (v & 0xffff0000U) - 0x10000;
 | 
			
		||||
        uint32_t l1 = (v - 1) & 0xffffU;
 | 
			
		||||
        uint32_t l2 = v & 0xffffU;
 | 
			
		||||
        uint32_t l3 = (v + 1) & 0xffffU;
 | 
			
		||||
 | 
			
		||||
        op(upper | l1);
 | 
			
		||||
        op(upper | l2);
 | 
			
		||||
        op(upper | l3);
 | 
			
		||||
 | 
			
		||||
        upper += 0x10000;
 | 
			
		||||
        op(upper | l1);
 | 
			
		||||
        // op(upper | l2);
 | 
			
		||||
        op(upper | l3);
 | 
			
		||||
 | 
			
		||||
        upper += 0x10000;
 | 
			
		||||
        op(upper | l1);
 | 
			
		||||
        op(upper | l2);
 | 
			
		||||
        op(upper | l3);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename Map>
 | 
			
		||||
auto game_of_life(std::string_view name, size_t nsteps, Map map1, std::vector<vec2> state) -> size_t {
 | 
			
		||||
    auto before = std::chrono::steady_clock::now();
 | 
			
		||||
    map1.clear();
 | 
			
		||||
    auto map2 = map1; // copy the empty map so we get the allocator
 | 
			
		||||
 | 
			
		||||
    for (auto& v : state) {
 | 
			
		||||
        v = v.add_x(UINT16_MAX / 2).add_y(UINT16_MAX / 2);
 | 
			
		||||
        map1[v.pack()] = true;
 | 
			
		||||
        v.for_each_surrounding([&](uint32_t xy) {
 | 
			
		||||
            map1.emplace(xy, false);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto* m1 = &map1;
 | 
			
		||||
    auto* m2 = &map2;
 | 
			
		||||
    for (size_t i = 0; i < nsteps; ++i) {
 | 
			
		||||
        for (auto const& kv : *m1) {
 | 
			
		||||
            auto const& pos = kv.first;
 | 
			
		||||
            auto alive = kv.second;
 | 
			
		||||
            int neighbors = 0;
 | 
			
		||||
            vec2{pos}.for_each_surrounding([&](uint32_t xy) {
 | 
			
		||||
                if (auto x = m1->find(xy); x != m1->end()) {
 | 
			
		||||
                    neighbors += x->second;
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            if ((alive && (neighbors == 2 || neighbors == 3)) || (!alive && neighbors == 3)) {
 | 
			
		||||
                (*m2)[pos] = true;
 | 
			
		||||
                vec2{pos}.for_each_surrounding([&](uint32_t xy) {
 | 
			
		||||
                    m2->emplace(xy, false);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        m1->clear();
 | 
			
		||||
        std::swap(m1, m2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    size_t final_population = 0;
 | 
			
		||||
    for (auto const& kv : *m1) {
 | 
			
		||||
        final_population += kv.second;
 | 
			
		||||
    }
 | 
			
		||||
    auto after = std::chrono::steady_clock::now();
 | 
			
		||||
    fmt::print("{}s {}\n", std::chrono::duration<double>(after - before).count(), name);
 | 
			
		||||
    return final_population;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("gameoflife_gotts-dots" * doctest::test_suite("bench") * doctest::skip()) {
 | 
			
		||||
    // https://conwaylife.com/wiki/Gotts_dots
 | 
			
		||||
    auto state = std::vector<vec2>{
 | 
			
		||||
        {0, 0},    {0, 1},    {0, 2},                                                                                 // 1
 | 
			
		||||
        {4, 11},   {5, 12},   {6, 13},   {7, 12},   {8, 11},                                                          // 2
 | 
			
		||||
        {9, 13},   {9, 14},   {9, 15},                                                                                // 3
 | 
			
		||||
        {185, 24}, {186, 25}, {186, 26}, {186, 27}, {185, 27}, {184, 27}, {183, 27}, {182, 26},                       // 4
 | 
			
		||||
        {179, 28}, {180, 29}, {181, 29}, {179, 30},                                                                   // 5
 | 
			
		||||
        {182, 32}, {183, 31}, {184, 31}, {185, 31}, {186, 31}, {186, 32}, {186, 33}, {185, 34},                       // 6
 | 
			
		||||
        {175, 35}, {176, 36}, {170, 37}, {176, 37}, {171, 38}, {172, 38}, {173, 38}, {174, 38}, {175, 38}, {176, 38}, // 7
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // size_t nsteps = 200;
 | 
			
		||||
    // size_t nsteps = 2000;
 | 
			
		||||
    size_t nsteps = 4000;
 | 
			
		||||
    // size_t nsteps = 10000;
 | 
			
		||||
 | 
			
		||||
    auto pop = size_t();
 | 
			
		||||
    {
 | 
			
		||||
        using map_t = ankerl::unordered_dense::map<uint32_t, bool>;
 | 
			
		||||
        pop = game_of_life("ankerl::unordered_dense::map", nsteps, map_t(), state);
 | 
			
		||||
    }
 | 
			
		||||
    {
 | 
			
		||||
        using map_t = ankerl::unordered_dense::segmented_map<uint32_t, bool>;
 | 
			
		||||
        auto new_pop = game_of_life("ankerl::unordered_dense::segmented_map", nsteps, map_t(), state);
 | 
			
		||||
        REQUIRE(pop == new_pop);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#if HAS_BOOST_UNORDERED_FLAT_MAP
 | 
			
		||||
    {
 | 
			
		||||
        using map_t = boost::unordered_flat_map<uint32_t, bool>;
 | 
			
		||||
        auto new_pop = game_of_life("boost::unordered_flat_map", nsteps, map_t(), state);
 | 
			
		||||
        REQUIRE(pop == new_pop);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if HAS_ABSL()
 | 
			
		||||
    {
 | 
			
		||||
        using map_t = absl::flat_hash_map<uint32_t, bool>;
 | 
			
		||||
        auto new_pop = game_of_life("absl::flat_hash_map", nsteps, map_t(), state);
 | 
			
		||||
        REQUIRE(pop == new_pop);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        using map_t = std::unordered_map<uint32_t, bool>;
 | 
			
		||||
        auto new_pop = game_of_life("std::unordered_map", nsteps, map_t(), state);
 | 
			
		||||
        REQUIRE(pop == new_pop);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										344
									
								
								third_party/unordered_dense/test/bench/quick_overall_map.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										344
									
								
								third_party/unordered_dense/test/bench/quick_overall_map.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,344 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h> // for map, hash
 | 
			
		||||
 | 
			
		||||
#include <app/geomean.h>           // for geomean
 | 
			
		||||
#include <third-party/nanobench.h> // for Rng, doNotOptimizeAway, Bench
 | 
			
		||||
 | 
			
		||||
#include <doctest.h>  // for TestCase, skip, ResultBuilder
 | 
			
		||||
#include <fmt/core.h> // for print, format
 | 
			
		||||
 | 
			
		||||
#include <chrono>        // for duration, operator-, high_resolu...
 | 
			
		||||
#include <cstdint>       // for uint64_t
 | 
			
		||||
#include <cstring>       // for size_t, memcpy
 | 
			
		||||
#include <deque>         // for deque
 | 
			
		||||
#include <string>        // for string, basic_string, operator==
 | 
			
		||||
#include <string_view>   // for string_view, literals
 | 
			
		||||
#include <unordered_map> // for unordered_map, operator!=
 | 
			
		||||
#include <vector>        // for vector
 | 
			
		||||
 | 
			
		||||
using namespace std::literals;
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
template <typename K>
 | 
			
		||||
inline auto init_key() -> K {
 | 
			
		||||
    return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
inline void randomize_key(ankerl::nanobench::Rng* rng, int n, T* key) {
 | 
			
		||||
    // we limit ourselves to 32bit n
 | 
			
		||||
    auto limited = (((*rng)() >> 32U) * static_cast<uint64_t>(n)) >> 32U;
 | 
			
		||||
    *key = static_cast<T>(limited);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
[[nodiscard]] inline auto init_key<std::string>() -> std::string {
 | 
			
		||||
    std::string str;
 | 
			
		||||
    str.resize(200);
 | 
			
		||||
    return str;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void randomize_key(ankerl::nanobench::Rng* rng, int n, std::string* key) {
 | 
			
		||||
    uint64_t k{};
 | 
			
		||||
    randomize_key(rng, n, &k);
 | 
			
		||||
    std::memcpy(key->data(), &k, sizeof(k));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Random insert & erase
 | 
			
		||||
template <typename Map>
 | 
			
		||||
void bench_random_insert_erase(ankerl::nanobench::Bench* bench, std::string_view name) {
 | 
			
		||||
    bench->run(fmt::format("{} random insert erase", name), [&] {
 | 
			
		||||
        ankerl::nanobench::Rng rng(123);
 | 
			
		||||
        size_t verifier{};
 | 
			
		||||
        Map map;
 | 
			
		||||
        auto key = init_key<typename Map::key_type>();
 | 
			
		||||
        for (int n = 1; n < 20000; ++n) {
 | 
			
		||||
            for (int i = 0; i < 200; ++i) {
 | 
			
		||||
                randomize_key(&rng, n, &key);
 | 
			
		||||
                map[key];
 | 
			
		||||
                randomize_key(&rng, n, &key);
 | 
			
		||||
                verifier += map.erase(key);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        CHECK(verifier == 1994641U);
 | 
			
		||||
        CHECK(map.size() == 9987U);
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// iterate
 | 
			
		||||
template <typename Map>
 | 
			
		||||
void bench_iterate(ankerl::nanobench::Bench* bench, std::string_view name) {
 | 
			
		||||
    size_t const num_elements = 5000;
 | 
			
		||||
 | 
			
		||||
    auto key = init_key<typename Map::key_type>();
 | 
			
		||||
 | 
			
		||||
    // insert
 | 
			
		||||
    bench->run(fmt::format("{} iterate while adding then removing", name), [&] {
 | 
			
		||||
        ankerl::nanobench::Rng rng(555);
 | 
			
		||||
        Map map;
 | 
			
		||||
        size_t result = 0;
 | 
			
		||||
        for (size_t n = 0; n < num_elements; ++n) {
 | 
			
		||||
            randomize_key(&rng, 1000000, &key);
 | 
			
		||||
            map[key] = n;
 | 
			
		||||
            for (auto const& key_val : map) {
 | 
			
		||||
                result += key_val.second;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        rng = ankerl::nanobench::Rng(555);
 | 
			
		||||
        do {
 | 
			
		||||
            randomize_key(&rng, 1000000, &key);
 | 
			
		||||
            map.erase(key);
 | 
			
		||||
            for (auto const& key_val : map) {
 | 
			
		||||
                result += key_val.second;
 | 
			
		||||
            }
 | 
			
		||||
        } while (!map.empty());
 | 
			
		||||
 | 
			
		||||
        CHECK(result == 62282755409U);
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 111.903 222
 | 
			
		||||
// 112.023 123123
 | 
			
		||||
template <typename Map>
 | 
			
		||||
void bench_random_find(ankerl::nanobench::Bench* bench, std::string_view name) {
 | 
			
		||||
 | 
			
		||||
    bench->run(fmt::format("{} 50% probability to find", name), [&] {
 | 
			
		||||
        uint64_t const seed = 123123;
 | 
			
		||||
        ankerl::nanobench::Rng numbers_insert_rng(seed);
 | 
			
		||||
        size_t numbers_insert_rng_calls = 0;
 | 
			
		||||
 | 
			
		||||
        ankerl::nanobench::Rng numbers_search_rng(seed);
 | 
			
		||||
        size_t numbers_search_rng_calls = 0;
 | 
			
		||||
 | 
			
		||||
        ankerl::nanobench::Rng insertion_rng(123);
 | 
			
		||||
 | 
			
		||||
        size_t checksum = 0;
 | 
			
		||||
        size_t found = 0;
 | 
			
		||||
        size_t not_found = 0;
 | 
			
		||||
 | 
			
		||||
        Map map;
 | 
			
		||||
        auto key = init_key<typename Map::key_type>();
 | 
			
		||||
        for (size_t i = 0; i < 100000; ++i) {
 | 
			
		||||
            randomize_key(&numbers_insert_rng, 1000000, &key);
 | 
			
		||||
            ++numbers_insert_rng_calls;
 | 
			
		||||
 | 
			
		||||
            if (insertion_rng() & 1U) {
 | 
			
		||||
                map[key] = i;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // search 100 entries in the map
 | 
			
		||||
            for (size_t search = 0; search < 100; ++search) {
 | 
			
		||||
                randomize_key(&numbers_search_rng, 1000000, &key);
 | 
			
		||||
                ++numbers_search_rng_calls;
 | 
			
		||||
 | 
			
		||||
                auto it = map.find(key);
 | 
			
		||||
                if (it != map.end()) {
 | 
			
		||||
                    checksum += it->second;
 | 
			
		||||
                    ++found;
 | 
			
		||||
                } else {
 | 
			
		||||
                    ++not_found;
 | 
			
		||||
                }
 | 
			
		||||
                if (numbers_insert_rng_calls == numbers_search_rng_calls) {
 | 
			
		||||
                    numbers_search_rng = ankerl::nanobench::Rng(seed);
 | 
			
		||||
                    numbers_search_rng_calls = 0;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        ankerl::nanobench::doNotOptimizeAway(checksum);
 | 
			
		||||
        ankerl::nanobench::doNotOptimizeAway(found);
 | 
			
		||||
        ankerl::nanobench::doNotOptimizeAway(not_found);
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Map>
 | 
			
		||||
void bench_all(ankerl::nanobench::Bench* bench, std::string_view name) {
 | 
			
		||||
    bench->title("benchmarking");
 | 
			
		||||
    bench->minEpochTime(100ms);
 | 
			
		||||
    bench_iterate<Map>(bench, name);
 | 
			
		||||
    bench_random_insert_erase<Map>(bench, name);
 | 
			
		||||
    bench_random_find<Map>(bench, name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[[nodiscard]] auto geomean1(ankerl::nanobench::Bench const& bench) -> double {
 | 
			
		||||
    return geomean(bench.results(), [](ankerl::nanobench::Result const& result) {
 | 
			
		||||
        return result.median(ankerl::nanobench::Result::Measure::elapsed);
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
 | 
			
		||||
// A relatively quick benchmark that should get a relatively good single number of how good the map
 | 
			
		||||
// is. It calculates geometric mean of several benchmarks.
 | 
			
		||||
TEST_CASE("bench_quick_overall_rhf" * doctest::test_suite("bench") * doctest::skip()) {
 | 
			
		||||
    ankerl::nanobench::Bench bench;
 | 
			
		||||
    bench_all<robin_hood::unordered_flat_map<uint64_t, size_t>>(&bench, "robin_hood::unordered_flat_map<uint64_t, size_t>");
 | 
			
		||||
    bench_all<robin_hood::unordered_flat_map<std::string, size_t>>(&bench,
 | 
			
		||||
                                                                   "robin_hood::unordered_flat_map<std::string, size_t>");
 | 
			
		||||
    fmt::print("{} bench_quick_overall_rhf\n", geomean1(bench));
 | 
			
		||||
 | 
			
		||||
#    ifdef ROBIN_HOOD_COUNT_ENABLED
 | 
			
		||||
    std::cout << robin_hood::counts() << std::endl;
 | 
			
		||||
#    endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("bench_quick_overall_rhn" * doctest::test_suite("bench") * doctest::skip()) {
 | 
			
		||||
    ankerl::nanobench::Bench bench;
 | 
			
		||||
    bench_all<robin_hood::unordered_node_map<uint64_t, size_t>>(&bench, "robin_hood::unordered_node_map<uint64_t, size_t>");
 | 
			
		||||
    bench_all<robin_hood::unordered_node_map<std::string, size_t>>(&bench,
 | 
			
		||||
                                                                   "robin_hood::unordered_node_map<std::string, size_t>");
 | 
			
		||||
    fmt::print("{} bench_quick_overall_rhn\n", geomean1(bench));
 | 
			
		||||
 | 
			
		||||
#    ifdef ROBIN_HOOD_COUNT_ENABLED
 | 
			
		||||
    std::cout << robin_hood::counts() << std::endl;
 | 
			
		||||
#    endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
using hash_t = ankerl::unordered_dense::hash<uint64_t>;
 | 
			
		||||
using eq_t = std::equal_to<uint64_t>;
 | 
			
		||||
using pair_t = std::pair<uint64_t, size_t>;
 | 
			
		||||
 | 
			
		||||
using hash_str_t = ankerl::unordered_dense::hash<std::string>;
 | 
			
		||||
using eq_str_t = std::equal_to<std::string>;
 | 
			
		||||
using pair_str_t = std::pair<std::string, size_t>;
 | 
			
		||||
 | 
			
		||||
TEST_CASE("bench_quick_overall_std" * doctest::test_suite("bench") * doctest::skip()) {
 | 
			
		||||
    ankerl::nanobench::Bench bench;
 | 
			
		||||
    bench_all<std::unordered_map<uint64_t, size_t>>(&bench, "std::unordered_map<uint64_t, size_t>");
 | 
			
		||||
    bench_all<std::unordered_map<std::string, size_t>>(&bench, "std::unordered_map<std::string, size_t>");
 | 
			
		||||
    fmt::print("{} bench_quick_overall_map_std\n", geomean1(bench));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("bench_quick_overall_udm" * doctest::test_suite("bench") * doctest::skip()) {
 | 
			
		||||
    ankerl::nanobench::Bench bench;
 | 
			
		||||
    // bench.minEpochTime(1s);
 | 
			
		||||
 | 
			
		||||
    using map_t = ankerl::unordered_dense::map<uint64_t, size_t>;
 | 
			
		||||
    bench_all<map_t>(&bench, "ankerl::unordered_dense::map<uint64_t, size_t>");
 | 
			
		||||
 | 
			
		||||
    using map_str_t = ankerl::unordered_dense::map<std::string, size_t, hash_str_t>;
 | 
			
		||||
    bench_all<map_str_t>(&bench, "ankerl::unordered_dense::map<std::string, size_t>");
 | 
			
		||||
 | 
			
		||||
    fmt::print("{} bench_quick_overall_map_udm\n", geomean1(bench));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("bench_quick_overall_segmented_vector" * doctest::test_suite("bench") * doctest::skip()) {
 | 
			
		||||
    ankerl::nanobench::Bench bench;
 | 
			
		||||
    // bench.minEpochTime(1s);
 | 
			
		||||
    using vec_t = ankerl::unordered_dense::segmented_vector<pair_t>;
 | 
			
		||||
    using map_t = ankerl::unordered_dense::segmented_map<uint64_t, size_t, hash_t, eq_t, vec_t>;
 | 
			
		||||
    bench_all<map_t>(&bench, "ankerl::unordered_dense::map<uint64_t, size_t> segmented_vector");
 | 
			
		||||
 | 
			
		||||
    using vec_str_t = ankerl::unordered_dense::segmented_vector<pair_str_t>;
 | 
			
		||||
    using map_str_t = ankerl::unordered_dense::map<std::string, size_t, hash_str_t, eq_str_t, vec_str_t>;
 | 
			
		||||
    bench_all<map_str_t>(&bench, "ankerl::unordered_dense::map<std::string, size_t> segmented_vector");
 | 
			
		||||
 | 
			
		||||
    fmt::print("{} bench_quick_overall_segmented_vector\n", geomean1(bench));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("bench_quick_overall_deque" * doctest::test_suite("bench") * doctest::skip()) {
 | 
			
		||||
    ankerl::nanobench::Bench bench;
 | 
			
		||||
    // bench.minEpochTime(1s);
 | 
			
		||||
 | 
			
		||||
    using vec_t = std::deque<pair_t>;
 | 
			
		||||
    using map_t = ankerl::unordered_dense::map<uint64_t, size_t, hash_t, eq_t, vec_t>;
 | 
			
		||||
    bench_all<map_t>(&bench, "ankerl::unordered_dense::map<uint64_t, size_t> deque");
 | 
			
		||||
 | 
			
		||||
    using vec_str_t = std::deque<pair_str_t>;
 | 
			
		||||
    using map_str_t = ankerl::unordered_dense::map<std::string, size_t, hash_str_t, eq_str_t, vec_str_t>;
 | 
			
		||||
    bench_all<map_str_t>(&bench, "ankerl::unordered_dense::map<std::string, size_t> deque");
 | 
			
		||||
 | 
			
		||||
    fmt::print("{} bench_quick_overall_deque\n", geomean1(bench));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("bench_quick_overall_udm_bigbucket" * doctest::test_suite("bench") * doctest::skip()) {
 | 
			
		||||
    using bucket_t = ankerl::unordered_dense::bucket_type::big;
 | 
			
		||||
 | 
			
		||||
    ankerl::nanobench::Bench bench;
 | 
			
		||||
    // bench.minEpochTime(1s);
 | 
			
		||||
 | 
			
		||||
    using alloc_t = std::allocator<pair_t>;
 | 
			
		||||
    using map_t = ankerl::unordered_dense::map<uint64_t, size_t, hash_t, eq_t, alloc_t, bucket_t>;
 | 
			
		||||
    bench_all<map_t>(&bench, "ankerl::unordered_dense::map<uint64_t, size_t>");
 | 
			
		||||
 | 
			
		||||
    using alloc_str_t = std::allocator<pair_str_t>;
 | 
			
		||||
    using map_str_t = ankerl::unordered_dense::map<std::string, size_t, hash_str_t, eq_str_t, alloc_str_t, bucket_t>;
 | 
			
		||||
    bench_all<map_str_t>(&bench, "ankerl::unordered_dense::map<std::string, size_t>");
 | 
			
		||||
 | 
			
		||||
    fmt::print("{} bench_quick_overall_map_udm\n", geomean1(bench));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Map>
 | 
			
		||||
void test_big() {
 | 
			
		||||
    Map map;
 | 
			
		||||
    auto rng = ankerl::nanobench::Rng();
 | 
			
		||||
    for (uint64_t n = 0; n < 20000000; ++n) {
 | 
			
		||||
        map[rng()];
 | 
			
		||||
        map[rng()];
 | 
			
		||||
        map[rng()];
 | 
			
		||||
        map[rng()];
 | 
			
		||||
    }
 | 
			
		||||
    fmt::print("{} map.size()\n", map.size());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
 | 
			
		||||
// 3346376 max RSS, 0:12.40
 | 
			
		||||
TEST_CASE("memory_map_huge_rhf" * doctest::test_suite("bench") * doctest::skip()) {
 | 
			
		||||
    test_big<robin_hood::unordered_flat_map<uint64_t, size_t>>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 2616352 max RSS, 0:24.72
 | 
			
		||||
TEST_CASE("memory_map_huge_rhn" * doctest::test_suite("bench") * doctest::skip()) {
 | 
			
		||||
    test_big<robin_hood::unordered_node_map<uint64_t, size_t>>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// 3296524 max RSS, 0:50.76
 | 
			
		||||
TEST_CASE("memory_map_huge_uo" * doctest::test_suite("bench") * doctest::skip()) {
 | 
			
		||||
    test_big<std::unordered_map<uint64_t, size_t>>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 3149724 max RSS, 0:10.58
 | 
			
		||||
TEST_CASE("memory_map_huge_udm" * doctest::test_suite("bench") * doctest::skip()) {
 | 
			
		||||
    test_big<ankerl::unordered_dense::map<uint64_t, size_t>>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Set>
 | 
			
		||||
void bench_consecutive_insert(char const* name) {
 | 
			
		||||
    auto before = std::chrono::high_resolution_clock::now();
 | 
			
		||||
    Set s{};
 | 
			
		||||
    for (uint64_t x = 0; x < 100000000; ++x) {
 | 
			
		||||
        s.insert(x);
 | 
			
		||||
    }
 | 
			
		||||
    auto after = std::chrono::high_resolution_clock::now();
 | 
			
		||||
    fmt::print("\t{}s, size={} for {}\n", std::chrono::duration<double>(after - before).count(), s.size(), name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Set>
 | 
			
		||||
void bench_random_insert(char const* name) {
 | 
			
		||||
    ankerl::nanobench::Rng rng(23);
 | 
			
		||||
    auto before = std::chrono::high_resolution_clock::now();
 | 
			
		||||
    Set s{};
 | 
			
		||||
    for (uint64_t x = 0; x < 100000000; ++x) {
 | 
			
		||||
        s.insert(rng());
 | 
			
		||||
    }
 | 
			
		||||
    auto after = std::chrono::high_resolution_clock::now();
 | 
			
		||||
    fmt::print("\t{}s, size={} for {}\n", std::chrono::duration<double>(after - before).count(), s.size(), name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Set>
 | 
			
		||||
void bench_shifted_insert(char const* name) {
 | 
			
		||||
    auto before = std::chrono::high_resolution_clock::now();
 | 
			
		||||
    Set s{};
 | 
			
		||||
    for (uint64_t x = 0; x < 100000000; ++x) {
 | 
			
		||||
        s.insert(x << 4U);
 | 
			
		||||
    }
 | 
			
		||||
    auto after = std::chrono::high_resolution_clock::now();
 | 
			
		||||
    fmt::print("\t{}s, size={} for {}\n", std::chrono::duration<double>(after - before).count(), s.size(), name);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										114
									
								
								third_party/unordered_dense/test/bench/show_allocations.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								third_party/unordered_dense/test/bench/show_allocations.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,114 @@
 | 
			
		||||
// #include "absl/container/flat_hash_map.h"
 | 
			
		||||
#include <ankerl/unordered_dense.h> // for map, operator==
 | 
			
		||||
 | 
			
		||||
#include <app/counting_allocator.h>
 | 
			
		||||
 | 
			
		||||
#include <third-party/nanobench.h>
 | 
			
		||||
 | 
			
		||||
#if __has_include("boost/unordered/unordered_flat_map.hpp")
 | 
			
		||||
#    if defined(__clang__)
 | 
			
		||||
#        pragma clang diagnostic push
 | 
			
		||||
#        pragma clang diagnostic ignored "-Wold-style-cast"
 | 
			
		||||
#    endif
 | 
			
		||||
#    include "boost/unordered/unordered_flat_map.hpp"
 | 
			
		||||
#    define HAS_BOOST_UNORDERED_FLAT_MAP() 1 // NOLINT(cppcoreguidelines-macro-usage)
 | 
			
		||||
#else
 | 
			
		||||
#    define HAS_BOOST_UNORDERED_FLAT_MAP() 0 // NOLINT(cppcoreguidelines-macro-usage)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <doctest.h>
 | 
			
		||||
#include <fmt/ostream.h>
 | 
			
		||||
 | 
			
		||||
#include <deque>
 | 
			
		||||
#include <filesystem>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
 | 
			
		||||
template <typename Map>
 | 
			
		||||
void evaluate_map(Map& map) {
 | 
			
		||||
    auto rng = ankerl::nanobench::Rng{1234};
 | 
			
		||||
 | 
			
		||||
    auto num_elements = size_t{10'000'000};
 | 
			
		||||
    for (uint64_t i = 0; i < num_elements; ++i) {
 | 
			
		||||
        map[rng()] = i;
 | 
			
		||||
    }
 | 
			
		||||
    REQUIRE(map.size() == num_elements);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
using hash_t = ankerl::unordered_dense::hash<uint64_t>;
 | 
			
		||||
using eq_t = std::equal_to<uint64_t>;
 | 
			
		||||
using pair_t = std::pair<uint64_t, uint64_t>;
 | 
			
		||||
using pair_const_t = std::pair<const uint64_t, uint64_t>;
 | 
			
		||||
using alloc_t = counting_allocator<pair_t>;
 | 
			
		||||
using alloc_const_t = counting_allocator<pair_const_t>;
 | 
			
		||||
 | 
			
		||||
TEST_CASE("allocated_memory_std_vector" * doctest::skip()) {
 | 
			
		||||
    auto counters = counts_for_allocator{};
 | 
			
		||||
    {
 | 
			
		||||
        using vec_t = std::vector<pair_t, alloc_t>;
 | 
			
		||||
        using map_t = ankerl::unordered_dense::map<uint64_t, uint64_t, hash_t, eq_t, vec_t>;
 | 
			
		||||
        auto map = map_t(0, hash_t{}, eq_t{}, alloc_t{&counters});
 | 
			
		||||
        evaluate_map(map);
 | 
			
		||||
    }
 | 
			
		||||
    counters.save("allocated_memory_std_vector.txt");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if HAS_BOOST_UNORDERED_FLAT_MAP()
 | 
			
		||||
 | 
			
		||||
TEST_CASE("allocated_memory_boost_flat_map" * doctest::skip()) {
 | 
			
		||||
    auto counters = counts_for_allocator{};
 | 
			
		||||
    {
 | 
			
		||||
        using map_t = boost::unordered_flat_map<uint64_t, uint64_t, hash_t, eq_t, alloc_t>;
 | 
			
		||||
        auto map = map_t(alloc_t{&counters});
 | 
			
		||||
        evaluate_map(map);
 | 
			
		||||
    }
 | 
			
		||||
    counters.save("allocated_memory_unordered_flat_map.txt");
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
TEST_CASE("allocated_memory_std_deque" * doctest::skip()) {
 | 
			
		||||
    auto counters = counts_for_allocator{};
 | 
			
		||||
    {
 | 
			
		||||
        using vec_t = std::deque<pair_t, alloc_t>;
 | 
			
		||||
        using map_t = ankerl::unordered_dense::map<uint64_t, uint64_t, hash_t, eq_t, vec_t>;
 | 
			
		||||
        auto map = map_t(0, hash_t{}, eq_t{}, alloc_t{&counters});
 | 
			
		||||
        evaluate_map(map);
 | 
			
		||||
    }
 | 
			
		||||
    counters.save("allocated_memory_std_deque.txt");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("allocated_memory_segmented_vector" * doctest::skip()) {
 | 
			
		||||
    auto counters = counts_for_allocator{};
 | 
			
		||||
    {
 | 
			
		||||
        using vec_t = ankerl::unordered_dense::segmented_vector<pair_t, alloc_t>;
 | 
			
		||||
        using map_t = ankerl::unordered_dense::segmented_map<uint64_t, uint64_t, hash_t, eq_t, vec_t>;
 | 
			
		||||
        auto map = map_t{0, hash_t{}, eq_t{}, alloc_t{&counters}};
 | 
			
		||||
        evaluate_map(map);
 | 
			
		||||
    }
 | 
			
		||||
    counters.save("allocated_memory_segmented_vector.txt");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
 | 
			
		||||
TEST_CASE("allocated_memory_std_unordered_map" * doctest::skip()) {
 | 
			
		||||
    auto counters = counts_for_allocator{};
 | 
			
		||||
    {
 | 
			
		||||
        using map_t = std::unordered_map<uint64_t, uint64_t, hash_t, eq_t, alloc_const_t>;
 | 
			
		||||
        auto map = map_t(0, alloc_t{&counters});
 | 
			
		||||
        evaluate_map(map);
 | 
			
		||||
    }
 | 
			
		||||
    counters.save("allocated_memory_std_unordered_map.txt");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("allocated_memory_boost_unordered_flat_map" * doctest::skip()) {
 | 
			
		||||
    auto counters = counts_for_allocator{};
 | 
			
		||||
    {
 | 
			
		||||
        using map_t = absl::
 | 
			
		||||
            flat_hash_map<uint64_t, uint64_t, absl::container_internal::hash_default_hash<uint64_t>, eq_t, alloc_const_t>;
 | 
			
		||||
        auto map = map_t(0, alloc_t{&counters});
 | 
			
		||||
        evaluate_map(map);
 | 
			
		||||
    }
 | 
			
		||||
    counters.save("allocated_memory_absl_flat_hash_map.txt");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										53
									
								
								third_party/unordered_dense/test/bench/swap.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								third_party/unordered_dense/test/bench/swap.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,53 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h> // for map
 | 
			
		||||
#include <third-party/nanobench.h>  // for Rng, doNotOptimizeAway, Bench
 | 
			
		||||
 | 
			
		||||
#include <doctest.h>  // for TestCase, skip, TEST_CASE, test_...
 | 
			
		||||
#include <fmt/core.h> // for format
 | 
			
		||||
 | 
			
		||||
#include <cstddef>       // for size_t
 | 
			
		||||
#include <cstdint>       // for uint64_t
 | 
			
		||||
#include <string_view>   // for string_view
 | 
			
		||||
#include <unordered_map> // for unordered_map, swap
 | 
			
		||||
#include <utility>       // for swap
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
template <typename Map>
 | 
			
		||||
void bench(std::string_view name) {
 | 
			
		||||
    Map a;
 | 
			
		||||
    Map b;
 | 
			
		||||
    ankerl::nanobench::Rng rng(123);
 | 
			
		||||
 | 
			
		||||
    ankerl::nanobench::Bench bench;
 | 
			
		||||
    for (size_t j = 0; j < 10000; ++j) {
 | 
			
		||||
        a[rng()];
 | 
			
		||||
        b[rng()];
 | 
			
		||||
    }
 | 
			
		||||
    bench.run(fmt::format("swap {}", name), [&] {
 | 
			
		||||
        std::swap(a, b);
 | 
			
		||||
    });
 | 
			
		||||
    ankerl::nanobench::doNotOptimizeAway(&a);
 | 
			
		||||
    ankerl::nanobench::doNotOptimizeAway(&b);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
 | 
			
		||||
TEST_CASE("bench_swap_rhn" * doctest::test_suite("bench") * doctest::skip()) {
 | 
			
		||||
    bench<robin_hood::unordered_node_map<uint64_t, uint64_t>>("robin_hood::unordered_node_map");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("bench_swap_rhf" * doctest::test_suite("bench") * doctest::skip()) {
 | 
			
		||||
    bench<robin_hood::unordered_flat_map<uint64_t, uint64_t>>("robin_hood::unordered_flat_map");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
TEST_CASE("bench_swap_std" * doctest::test_suite("bench") * doctest::skip()) {
 | 
			
		||||
    bench<std::unordered_map<uint64_t, uint64_t>>("std::unordered_map");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("bench_swap_udm" * doctest::test_suite("bench") * doctest::skip()) {
 | 
			
		||||
    bench<ankerl::unordered_dense::map<uint64_t, uint64_t>>("ankerl::unordered_dense::map");
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										205
									
								
								third_party/unordered_dense/test/fuzz/provider.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										205
									
								
								third_party/unordered_dense/test/fuzz/provider.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,205 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <climits>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
#include <limits>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
 | 
			
		||||
namespace fuzz {
 | 
			
		||||
 | 
			
		||||
// Helper to provide a little bit more convenient interface than FuzzedDataProvider itself
 | 
			
		||||
class provider {
 | 
			
		||||
    uint8_t const* m_data;
 | 
			
		||||
    size_t m_remaining_bytes;
 | 
			
		||||
 | 
			
		||||
    // Reads one byte and returns a bool, or false when no data remains.
 | 
			
		||||
    [[nodiscard]] inline auto consume_bool() -> bool {
 | 
			
		||||
        return (1U & consume_integral<uint8_t>()) != 0U;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Returns a number in the range [Type's min, Type's max]. The value might
 | 
			
		||||
    // not be uniformly distributed in the given range. If there's no input data
 | 
			
		||||
    // left, always returns |min|.
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    [[nodiscard]] auto consume_integral() -> T {
 | 
			
		||||
        return consume_integral_in_range(std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Returns a number in the range [min, max] by consuming bytes from the
 | 
			
		||||
    // input data. The value might not be uniformly distributed in the given
 | 
			
		||||
    // range. If there's no input data left, always returns |min|. |min| must
 | 
			
		||||
    // be less than or equal to |max|.
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    [[nodiscard]] auto consume_integral_in_range(T min, T max) -> T {
 | 
			
		||||
        static_assert(std::is_integral<T>::value, "An integral type is required.");
 | 
			
		||||
        static_assert(sizeof(T) <= sizeof(uint64_t), "Unsupported integral type.");
 | 
			
		||||
 | 
			
		||||
        if (min > max) {
 | 
			
		||||
            std::abort();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Use the biggest type possible to hold the range and the result.
 | 
			
		||||
        uint64_t range = static_cast<uint64_t>(max) - static_cast<uint64_t>(min);
 | 
			
		||||
        uint64_t result = 0;
 | 
			
		||||
        size_t offset = 0;
 | 
			
		||||
 | 
			
		||||
        while (offset < sizeof(T) * CHAR_BIT && (range >> offset) > 0 && m_remaining_bytes != 0) {
 | 
			
		||||
            // Pull bytes off the end of the seed data. Experimentally, this seems to
 | 
			
		||||
            // allow the fuzzer to more easily explore the input space. This makes
 | 
			
		||||
            // sense, since it works by modifying inputs that caused new code to run,
 | 
			
		||||
            // and this data is often used to encode length of data read by
 | 
			
		||||
            // |ConsumeBytes|. Separating out read lengths makes it easier modify the
 | 
			
		||||
            // contents of the data that is actually read.
 | 
			
		||||
            --m_remaining_bytes;
 | 
			
		||||
            result = (result << CHAR_BIT) | m_data[m_remaining_bytes];
 | 
			
		||||
            offset += CHAR_BIT;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Avoid division by 0, in case |range + 1| results in overflow.
 | 
			
		||||
        if (range != std::numeric_limits<decltype(range)>::max()) {
 | 
			
		||||
            result = result % (range + 1);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return static_cast<T>(static_cast<uint64_t>(min) + result);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline void advance_unchecked(size_t num_bytes) {
 | 
			
		||||
        m_data += num_bytes;
 | 
			
		||||
        m_remaining_bytes -= num_bytes;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Returns a std::string of length from 0 to |max_length|. When it runs out of
 | 
			
		||||
    // input data, returns what remains of the input. Designed to be more stable
 | 
			
		||||
    // with respect to a fuzzer inserting characters than just picking a random
 | 
			
		||||
    // length and then consuming that many bytes with |ConsumeBytes|.
 | 
			
		||||
    [[nodiscard]] inline auto consume_random_length_string(size_t max_length) -> std::string {
 | 
			
		||||
        // Reads bytes from the start of |data_ptr_|. Maps "\\" to "\", and maps "\"
 | 
			
		||||
        // followed by anything else to the end of the string. As a result of this
 | 
			
		||||
        // logic, a fuzzer can insert characters into the string, and the string
 | 
			
		||||
        // will be lengthened to include those new characters, resulting in a more
 | 
			
		||||
        // stable fuzzer than picking the length of a string independently from
 | 
			
		||||
        // picking its contents.
 | 
			
		||||
        std::string result;
 | 
			
		||||
 | 
			
		||||
        // Reserve the anticipated capacity to prevent several reallocations.
 | 
			
		||||
        result.reserve(std::min(max_length, m_remaining_bytes));
 | 
			
		||||
        for (size_t i = 0; i < max_length && m_remaining_bytes != 0; ++i) {
 | 
			
		||||
            auto next = m_data[0];
 | 
			
		||||
            advance_unchecked(1);
 | 
			
		||||
            if (next == '\\' && m_remaining_bytes != 0) {
 | 
			
		||||
                next = m_data[0];
 | 
			
		||||
                advance_unchecked(1);
 | 
			
		||||
                if (next != '\\') {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            result += static_cast<char>(next);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        result.shrink_to_fit();
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    provider(provider const&) = default;
 | 
			
		||||
    auto operator=(provider const&) -> provider& = default;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    provider(provider&&) = default;
 | 
			
		||||
    auto operator=(provider&&) -> provider& = default;
 | 
			
		||||
    ~provider() = default;
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] auto copy() const -> provider {
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline explicit provider(void const* data, size_t size)
 | 
			
		||||
        : m_data(reinterpret_cast<uint8_t const*>(data)) /* NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) */
 | 
			
		||||
        , m_remaining_bytes(size) /* NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) */ {}
 | 
			
		||||
 | 
			
		||||
    // random number in inclusive range [min, max]
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    auto range(T min, T max) -> T {
 | 
			
		||||
        return consume_integral_in_range<T>(min, max);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    auto bounded(T max_exclusive) -> T {
 | 
			
		||||
        if (0 == max_exclusive) {
 | 
			
		||||
            return {};
 | 
			
		||||
        }
 | 
			
		||||
        return consume_integral_in_range<T>(0, max_exclusive - 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    auto integral() -> T {
 | 
			
		||||
        if constexpr (std::is_same_v<bool, T>) {
 | 
			
		||||
            return consume_bool();
 | 
			
		||||
        } else {
 | 
			
		||||
            return consume_integral<T>();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline auto string(size_t max_length) -> std::string {
 | 
			
		||||
        return consume_random_length_string(max_length);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename... Args>
 | 
			
		||||
    auto pick(Args&&... args) -> std::common_type_t<decltype(args)...>& {
 | 
			
		||||
        static constexpr auto num_ops = sizeof...(args);
 | 
			
		||||
 | 
			
		||||
        auto idx = size_t{};
 | 
			
		||||
        auto const chosen_idx = consume_integral_in_range<size_t>(0, num_ops - 1);
 | 
			
		||||
        std::common_type_t<decltype(args)...>* result = nullptr;
 | 
			
		||||
        ((idx++ == chosen_idx ? (result = &args, true) : false) || ...);
 | 
			
		||||
        return *result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename... Ops>
 | 
			
		||||
    void repeat_oneof(Ops&&... op) {
 | 
			
		||||
        static constexpr auto num_ops = sizeof...(op);
 | 
			
		||||
 | 
			
		||||
        do {
 | 
			
		||||
            if constexpr (num_ops == 1) {
 | 
			
		||||
                (op(), ...);
 | 
			
		||||
            } else {
 | 
			
		||||
                auto chosen_op_idx = range<size_t>(0, num_ops - 1);
 | 
			
		||||
                auto op_idx = size_t{};
 | 
			
		||||
                ((op_idx++ == chosen_op_idx ? op() : void()), ...);
 | 
			
		||||
            }
 | 
			
		||||
        } while (0 != m_remaining_bytes);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename... Ops>
 | 
			
		||||
    void limited_repeat_oneof(size_t min, size_t max, Ops&&... op) {
 | 
			
		||||
        static constexpr auto num_ops = sizeof...(op);
 | 
			
		||||
 | 
			
		||||
        size_t const num_evaluations = consume_integral_in_range(min, max);
 | 
			
		||||
        for (size_t i = 0; i < num_evaluations; ++i) {
 | 
			
		||||
            if constexpr (num_ops == 1) {
 | 
			
		||||
                (op(), ...);
 | 
			
		||||
            } else {
 | 
			
		||||
                auto chosen_op_idx = range<size_t>(0, num_ops - 1);
 | 
			
		||||
                auto op_idx = size_t{};
 | 
			
		||||
                ((op_idx++ == chosen_op_idx ? op() : void()), ...);
 | 
			
		||||
            }
 | 
			
		||||
            if (m_remaining_bytes == 0) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] auto has_remaining_bytes() const -> bool {
 | 
			
		||||
        return 0U != m_remaining_bytes;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static inline void require(bool b) {
 | 
			
		||||
        if (!b) {
 | 
			
		||||
            std::abort();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace fuzz
 | 
			
		||||
							
								
								
									
										133
									
								
								third_party/unordered_dense/test/fuzz/run.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								third_party/unordered_dense/test/fuzz/run.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,133 @@
 | 
			
		||||
#include <fuzz/run.h>
 | 
			
		||||
 | 
			
		||||
#include <app/doctest.h>
 | 
			
		||||
#include <fmt/format.h>
 | 
			
		||||
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
#include <filesystem>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <optional>
 | 
			
		||||
#include <stdexcept>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <string_view>
 | 
			
		||||
 | 
			
		||||
namespace fuzz::detail {
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
[[nodiscard]] constexpr auto is_alpha(char c) -> bool {
 | 
			
		||||
    return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[[nodiscard]] constexpr auto is_digit(char c) -> bool {
 | 
			
		||||
    return c >= '0' && c <= '9';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[[nodiscard]] constexpr auto is_alnum(char c) -> bool {
 | 
			
		||||
    return is_alpha(c) || is_digit(c);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[[nodiscard]] constexpr auto contains(std::string_view haystack, char needle) -> bool {
 | 
			
		||||
    return std::string_view::npos != haystack.find_first_of(needle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[[nodiscard]] constexpr auto is_valid_filename(std::string_view name) -> bool {
 | 
			
		||||
    using namespace std::literals;
 | 
			
		||||
    for (auto c : name) {
 | 
			
		||||
        if (!is_alnum(c) && !contains("_-+", c)) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto env(char const* varname) -> std::optional<std::string> {
 | 
			
		||||
#ifdef _MSC_VER
 | 
			
		||||
    char* pValue = nullptr;
 | 
			
		||||
    size_t len = 0;
 | 
			
		||||
    errno_t err = _dupenv_s(&pValue, &len, varname);
 | 
			
		||||
    if (err || nullptr == pValue) {
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
    auto str = std::string(pValue);
 | 
			
		||||
    free(pValue);
 | 
			
		||||
    return str;
 | 
			
		||||
#else
 | 
			
		||||
    char const* val = std::getenv(varname); // NOLINT(concurrency-mt-unsafe,clang-analyzer-cplusplus.StringChecker)
 | 
			
		||||
    if (nullptr == val) {
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
    return val;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[[nodiscard]] auto read_file(std::filesystem::path const& p) -> std::optional<std::string> {
 | 
			
		||||
    auto f = std::ifstream(p);
 | 
			
		||||
    if (!f) {
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
    auto content = std::string((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
 | 
			
		||||
    if (f.bad()) {
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
    return content;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[[nodiscard]] auto find_fuzz_corpus_base_dir() -> std::optional<std::filesystem::path> {
 | 
			
		||||
    auto corpus_base_dir = env("FUZZ_CORPUS_BASE_DIR");
 | 
			
		||||
    if (corpus_base_dir) {
 | 
			
		||||
        return corpus_base_dir.value();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto p = std::filesystem::current_path();
 | 
			
		||||
    while (true) {
 | 
			
		||||
        auto const filename = p / ".fuzz-corpus-base-dir";
 | 
			
		||||
        // INFO(fmt::format("trying '{}'", filename.string()));
 | 
			
		||||
        if (std::filesystem::exists(filename)) {
 | 
			
		||||
            if (auto file_content = read_file(p / ".fuzz-corpus-base-dir"); file_content) {
 | 
			
		||||
                auto f = std::filesystem::path(file_content.value()).make_preferred();
 | 
			
		||||
                // INFO(fmt::format("got it! p='{}, f='{}', p/f='{}'\n", p.string(), f.string(), (p / f).string()));
 | 
			
		||||
                return p / f;
 | 
			
		||||
            }
 | 
			
		||||
            // could not read file
 | 
			
		||||
            throw std::runtime_error(fmt::format("could not read '{}'", filename.string()));
 | 
			
		||||
        }
 | 
			
		||||
        if (p == p.root_path()) {
 | 
			
		||||
            return {};
 | 
			
		||||
        }
 | 
			
		||||
        p = p.parent_path();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
void evaluate_corpus(std::function<void(provider)> const& op) {
 | 
			
		||||
    if (!is_valid_filename(doctest::current_test_name())) {
 | 
			
		||||
        throw std::runtime_error("test case name needs to be a valid filename. only [a-zA-Z0-9_-+] are allowed");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 2 ways
 | 
			
		||||
 | 
			
		||||
    auto corpus_base_dir = find_fuzz_corpus_base_dir();
 | 
			
		||||
    if (!corpus_base_dir) {
 | 
			
		||||
        throw std::runtime_error("could not find corpus base dir :-(");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto path = std::filesystem::path(corpus_base_dir.value()) / doctest::current_test_name();
 | 
			
		||||
    INFO("path=\"" << path.string() << "\"");
 | 
			
		||||
    auto num_files = size_t();
 | 
			
		||||
    for (auto const& dir_entry : std::filesystem::directory_iterator(path)) {
 | 
			
		||||
        ++num_files;
 | 
			
		||||
        auto const& test_file = dir_entry.path();
 | 
			
		||||
        CAPTURE(test_file);
 | 
			
		||||
 | 
			
		||||
        auto f = std::ifstream(test_file);
 | 
			
		||||
        auto content = std::string((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
 | 
			
		||||
 | 
			
		||||
        // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
 | 
			
		||||
        op(provider(content.data(), content.size()));
 | 
			
		||||
    }
 | 
			
		||||
    REQUIRE(num_files > 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace fuzz::detail
 | 
			
		||||
							
								
								
									
										47
									
								
								third_party/unordered_dense/test/fuzz/run.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								third_party/unordered_dense/test/fuzz/run.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <fuzz/provider.h>
 | 
			
		||||
 | 
			
		||||
#include <functional>
 | 
			
		||||
 | 
			
		||||
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
 | 
			
		||||
extern "C" {
 | 
			
		||||
void HF_ITER(const uint8_t** buf_ptr, size_t* len_ptr);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
namespace fuzz {
 | 
			
		||||
 | 
			
		||||
namespace detail {
 | 
			
		||||
 | 
			
		||||
void evaluate_corpus(std::function<void(provider)> const& op);
 | 
			
		||||
 | 
			
		||||
} // namespace detail
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * There are 2 modes how this the op() will be executed:
 | 
			
		||||
 *
 | 
			
		||||
 * Driven by honggfuzz: this is enabled when compiling with -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION.
 | 
			
		||||
 * This is done to fuzz a particular test.
 | 
			
		||||
 *
 | 
			
		||||
 * Otherwise, this is run in "corpus" mode, where all files in a directory named by the testname are evaluated
 | 
			
		||||
 * This should be done in normal unit testing. The location of the corpus base directory is determined in this order:
 | 
			
		||||
 * 1. Use FUZZ_CORPUS_BASE_DIR environment variable
 | 
			
		||||
 * 2. If this is not set, look in the working directory for a ".fuzz-corpus-base-dir" file which should contain
 | 
			
		||||
 *    the path to the base directory (relative to that particular file)
 | 
			
		||||
 */
 | 
			
		||||
template <typename Op>
 | 
			
		||||
void run(Op const& op) {
 | 
			
		||||
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
 | 
			
		||||
    size_t len = 0;
 | 
			
		||||
    uint8_t const* buf = nullptr;
 | 
			
		||||
    while (true) {
 | 
			
		||||
        ::HF_ITER(&buf, &len);
 | 
			
		||||
        op(provider(buf, len));
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    detail::evaluate_corpus(op);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace fuzz
 | 
			
		||||
							
								
								
									
										192
									
								
								third_party/unordered_dense/test/meson.build
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								third_party/unordered_dense/test/meson.build
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,192 @@
 | 
			
		||||
test_sources = [
 | 
			
		||||
    'app/counter.cpp',
 | 
			
		||||
    'app/doctest.cpp',
 | 
			
		||||
    'app/nanobench.cpp',
 | 
			
		||||
    'app/stacktrace.cpp',
 | 
			
		||||
    'app/ui/periodic.cpp',
 | 
			
		||||
    'app/ui/progress_bar.cpp',
 | 
			
		||||
    'app/unordered_dense.cpp',
 | 
			
		||||
 | 
			
		||||
    'bench/swap.cpp',
 | 
			
		||||
    'bench/show_allocations.cpp',
 | 
			
		||||
    'bench/quick_overall_map.cpp',
 | 
			
		||||
    'bench/game_of_life.cpp',
 | 
			
		||||
    'bench/find_random.cpp',
 | 
			
		||||
    'bench/copy.cpp',
 | 
			
		||||
 | 
			
		||||
    'fuzz/run.cpp',
 | 
			
		||||
 | 
			
		||||
    'unit/assign_to_move.cpp',
 | 
			
		||||
    'unit/assignment_combinations.cpp',
 | 
			
		||||
    'unit/at.cpp',
 | 
			
		||||
    'unit/bucket.cpp',
 | 
			
		||||
    'unit/contains.cpp',
 | 
			
		||||
    'unit/copy_and_assign_maps.cpp',
 | 
			
		||||
    'unit/copyassignment.cpp',
 | 
			
		||||
    'unit/count.cpp',
 | 
			
		||||
    'unit/ctors.cpp',
 | 
			
		||||
    'unit/custom_container_boost.cpp',
 | 
			
		||||
    'unit/custom_container.cpp',
 | 
			
		||||
    'unit/custom_hash.cpp',
 | 
			
		||||
    'unit/deduction_guides.cpp',
 | 
			
		||||
    'unit/diamond.cpp',
 | 
			
		||||
    'unit/empty.cpp',
 | 
			
		||||
    'unit/equal_range.cpp',
 | 
			
		||||
    'unit/erase_if.cpp',
 | 
			
		||||
    'unit/erase_range.cpp',
 | 
			
		||||
    'unit/erase.cpp',
 | 
			
		||||
    'unit/explicit.cpp',
 | 
			
		||||
    'unit/extract.cpp',
 | 
			
		||||
    'unit/fuzz_api.cpp',
 | 
			
		||||
    'unit/fuzz_insert_erase.cpp',
 | 
			
		||||
    'unit/fuzz_replace_map.cpp',
 | 
			
		||||
    'unit/fuzz_string.cpp',
 | 
			
		||||
    'unit/hash_char_types.cpp',
 | 
			
		||||
    'unit/hash_smart_ptr.cpp',
 | 
			
		||||
    'unit/hash_string_view.cpp',
 | 
			
		||||
    'unit/hash.cpp',
 | 
			
		||||
    'unit/include_only.cpp',
 | 
			
		||||
    'unit/initializer_list.cpp',
 | 
			
		||||
    'unit/insert_or_assign.cpp',
 | 
			
		||||
    'unit/insert.cpp',
 | 
			
		||||
    'unit/iterators_empty.cpp',
 | 
			
		||||
    'unit/iterators_erase.cpp',
 | 
			
		||||
    'unit/iterators_insert.cpp',
 | 
			
		||||
    'unit/load_factor.cpp',
 | 
			
		||||
    'unit/maps_of_maps.cpp',
 | 
			
		||||
    'unit/max.cpp',
 | 
			
		||||
    'unit/move_to_moved.cpp',
 | 
			
		||||
    'unit/multiple_apis.cpp',
 | 
			
		||||
    'unit/namespace.cpp',
 | 
			
		||||
    'unit/not_copyable.cpp',
 | 
			
		||||
    'unit/not_moveable.cpp',
 | 
			
		||||
    'unit/pmr_move_with_allocators.cpp',
 | 
			
		||||
    'unit/pmr.cpp',
 | 
			
		||||
    'unit/rehash.cpp',
 | 
			
		||||
    'unit/replace.cpp',
 | 
			
		||||
    'unit/reserve_and_assign.cpp',
 | 
			
		||||
    'unit/reserve.cpp',
 | 
			
		||||
    'unit/segmented_vector.cpp',
 | 
			
		||||
    'unit/set_or_map_types.cpp',
 | 
			
		||||
    'unit/set.cpp',
 | 
			
		||||
    'unit/std_hash.cpp',
 | 
			
		||||
    'unit/swap.cpp',
 | 
			
		||||
    'unit/transparent.cpp',
 | 
			
		||||
    'unit/try_emplace.cpp',
 | 
			
		||||
    'unit/tuple_hash.cpp',
 | 
			
		||||
    'unit/unique_ptr.cpp',
 | 
			
		||||
    'unit/unordered_set.cpp',
 | 
			
		||||
    'unit/vectorofmaps.cpp',
 | 
			
		||||
    'unit/windows_include.cpp',
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
# additional compile options
 | 
			
		||||
# see https://mesonbuild.com/Reference-tables.html
 | 
			
		||||
cpp_args = []
 | 
			
		||||
compiler = meson.get_compiler('cpp')
 | 
			
		||||
foreach arg : [
 | 
			
		||||
            # gcc
 | 
			
		||||
            '-Wno-stringop-overflow', # g++ error in fmtlib
 | 
			
		||||
            '-Warith-conversion',
 | 
			
		||||
            '-Wshadow=global',
 | 
			
		||||
            '-Wno-array-bounds', # gcc 13 gives incorrect warning
 | 
			
		||||
 | 
			
		||||
            # gcc / clang
 | 
			
		||||
            '-Wconversion',
 | 
			
		||||
            '-Wextra',
 | 
			
		||||
            '-Wunreachable-code',
 | 
			
		||||
            '-Wuninitialized',
 | 
			
		||||
            '-pedantic-errors',
 | 
			
		||||
            '-Wold-style-cast',
 | 
			
		||||
            '-Wno-unused-function',
 | 
			
		||||
            # '-Weffc++', doesn't work with fmt
 | 
			
		||||
            
 | 
			
		||||
            # '-march=native',
 | 
			
		||||
        ]
 | 
			
		||||
    if compiler.has_argument(arg)
 | 
			
		||||
        cpp_args += [arg]
 | 
			
		||||
    endif
 | 
			
		||||
endforeach
 | 
			
		||||
 | 
			
		||||
if compiler.get_id() == 'msvc'
 | 
			
		||||
    add_global_arguments(
 | 
			
		||||
        '/wd4189', # fmt: 'zero': local variable is initialized but not referenced, fixed in https://github.com/fmtlib/fmt/issues/2891
 | 
			
		||||
        '/wd4251', # 'fmt::v8::ostream::file_': class 'fmt::v8::file' needs to have dll-interface to be used by clients of class 'fmt::v8::ostream'
 | 
			
		||||
        language: 'cpp')
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
# for include-what-you-use
 | 
			
		||||
#cpp_args += '-isystem'
 | 
			
		||||
#cpp_args += '/usr/lib64/clang/14.0.0/include/'
 | 
			
		||||
 | 
			
		||||
fmt_method = 'auto'
 | 
			
		||||
if get_option('cpp_args').contains('-m32')
 | 
			
		||||
    # use builtin so we can compile it for 32bit. 
 | 
			
		||||
    # Can't use it as a default or sanitizer doesn't work...
 | 
			
		||||
    fmt_method = 'builtin'
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
# use e.g.
 | 
			
		||||
# CXX='ccache clang++' BOOST_ROOT=/home/martinus/dev/boost_1_81_0/ meson setup --buildtype release -Dcpp_std=c++17 build
 | 
			
		||||
opt_boost = dependency('boost', required: false)
 | 
			
		||||
link_args = []
 | 
			
		||||
if opt_boost.found()
 | 
			
		||||
    add_global_arguments('-DANKERL_UNORDERED_DENSE_HAS_BOOST=1', language: 'cpp')
 | 
			
		||||
    link_args += ['-lrt']
 | 
			
		||||
else
 | 
			
		||||
    add_global_arguments('-DANKERL_UNORDERED_DENSE_HAS_BOOST=0', language: 'cpp')
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
#opt_absl = dependency('absl_container', required: true, )
 | 
			
		||||
#if opt_boost.found()
 | 
			
		||||
#    add_global_arguments('-DANKERL_UNORDERED_DENSE_HAS_ABSL=1', language: 'cpp')
 | 
			
		||||
#else
 | 
			
		||||
#    add_global_arguments('-DANKERL_UNORDERED_DENSE_HAS_ABSL=0', language: 'cpp')
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
cpp_args += [
 | 
			
		||||
    #'-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION',
 | 
			
		||||
    #'-fsanitize-undefined-trap-on-error',
 | 
			
		||||
    #'-fsanitize=undefined,address',
 | 
			
		||||
    #'-fno-sanitize=thread',
 | 
			
		||||
    #'-ftrivial-auto-var-init=pattern',
 | 
			
		||||
    #'-g',
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
link_args += [
 | 
			
		||||
    #'-fsanitize=undefined,address',
 | 
			
		||||
    #'-fno-sanitize=thread'
 | 
			
		||||
    #'-Wl,-shuffle-sections' # for benchmarking with mold linker
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
test_exe = executable(
 | 
			
		||||
    'udm-test',
 | 
			
		||||
    test_sources,
 | 
			
		||||
    include_directories: incdir,
 | 
			
		||||
    cpp_args: cpp_args,
 | 
			
		||||
    link_args: link_args,
 | 
			
		||||
    dependencies: [
 | 
			
		||||
        dependency('threads'), # add dependency for threads (-lpthread, see https://mesonbuild.com/howtox.html),
 | 
			
		||||
 | 
			
		||||
        # see what's in the [provide] sections for the dependency names
 | 
			
		||||
        dependency('doctest'),
 | 
			
		||||
        dependency('fmt', method: fmt_method),
 | 
			
		||||
 | 
			
		||||
        # disable these two if you don't want them
 | 
			
		||||
        #dependency('boost'),
 | 
			
		||||
        #dependency('absl_container', default_options: ['warning_level=0', 'werror=false'])
 | 
			
		||||
        # dependency('absl_hash', method: 'builtin', default_options: ['warning_level=0', 'werror=false'])
 | 
			
		||||
    ],
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
benchmark(
 | 
			
		||||
    'bench',
 | 
			
		||||
    test_exe,
 | 
			
		||||
    args: ['-ns', '-ts=bench'],
 | 
			
		||||
    verbose: true)
 | 
			
		||||
 | 
			
		||||
test(
 | 
			
		||||
    'unit',
 | 
			
		||||
    test_exe,
 | 
			
		||||
    verbose: true)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										20
									
								
								third_party/unordered_dense/test/modules/module_test.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								third_party/unordered_dense/test/modules/module_test.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
			
		||||
import ankerl.unordered_dense;
 | 
			
		||||
 | 
			
		||||
#include <cassert>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
    ankerl::unordered_dense::map<std::string, int> m;
 | 
			
		||||
    m["24535"] = 4;
 | 
			
		||||
    assert(m.size() == 1);
 | 
			
		||||
 | 
			
		||||
    auto h_int = ankerl::unordered_dense::hash<int>();
 | 
			
		||||
    assert(h_int(123) != 123);
 | 
			
		||||
 | 
			
		||||
    auto h_str = ankerl::unordered_dense::hash<std::string>();
 | 
			
		||||
    assert(h_str("123") != 123);
 | 
			
		||||
 | 
			
		||||
    auto h_ptr = ankerl::unordered_dense::hash<int*>();
 | 
			
		||||
    int i = 0;
 | 
			
		||||
    assert(h_ptr(&i) != 0);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								third_party/unordered_dense/test/modules/test.sh
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										12
									
								
								third_party/unordered_dense/test/modules/test.sh
									
									
									
									
										vendored
									
									
										Executable file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
set -xe
 | 
			
		||||
 | 
			
		||||
rm -f *.o *.pcm a.out
 | 
			
		||||
 | 
			
		||||
clang++ -std=c++20 -I ../../include --precompile -x c++-module ../../src/ankerl.unordered_dense.cpp
 | 
			
		||||
clang++ -std=c++20 -c ankerl.unordered_dense.pcm
 | 
			
		||||
clang++ -std=c++20 -fprebuilt-module-path=. ankerl.unordered_dense.o module_test.cpp -o a.out
 | 
			
		||||
 | 
			
		||||
./a.out
 | 
			
		||||
 | 
			
		||||
rm -f *.o *.pcm a.out
 | 
			
		||||
							
								
								
									
										7
									
								
								third_party/unordered_dense/test/third-party/.clang-tidy
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								third_party/unordered_dense/test/third-party/.clang-tidy
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
---
 | 
			
		||||
Checks: '-*,
 | 
			
		||||
    bugprone-infinite-loop
 | 
			
		||||
    '
 | 
			
		||||
WarningsAsErrors: ''
 | 
			
		||||
HeaderFilterRegex: ''
 | 
			
		||||
...
 | 
			
		||||
							
								
								
									
										397
									
								
								third_party/unordered_dense/test/third-party/FuzzedDataProvider.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										397
									
								
								third_party/unordered_dense/test/third-party/FuzzedDataProvider.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,397 @@
 | 
			
		||||
//===- FuzzedDataProvider.h - Utility header for fuzz targets ---*- C++ -* ===//
 | 
			
		||||
//
 | 
			
		||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
			
		||||
// See https://llvm.org/LICENSE.txt for license information.
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
			
		||||
//
 | 
			
		||||
//===----------------------------------------------------------------------===//
 | 
			
		||||
// A single header library providing an utility class to break up an array of
 | 
			
		||||
// bytes. Whenever run on the same input, provides the same output, as long as
 | 
			
		||||
// its methods are called in the same order, with the same arguments.
 | 
			
		||||
//===----------------------------------------------------------------------===//
 | 
			
		||||
 | 
			
		||||
#ifndef LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_
 | 
			
		||||
#define LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <climits>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <initializer_list>
 | 
			
		||||
#include <limits>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
// In addition to the comments below, the API is also briefly documented at
 | 
			
		||||
// https://github.com/google/fuzzing/blob/master/docs/split-inputs.md#fuzzed-data-provider
 | 
			
		||||
class FuzzedDataProvider {
 | 
			
		||||
 public:
 | 
			
		||||
  // |data| is an array of length |size| that the FuzzedDataProvider wraps to
 | 
			
		||||
  // provide more granular access. |data| must outlive the FuzzedDataProvider.
 | 
			
		||||
  FuzzedDataProvider(const uint8_t *data, size_t size)
 | 
			
		||||
      : data_ptr_(data), remaining_bytes_(size) {}
 | 
			
		||||
  ~FuzzedDataProvider() = default;
 | 
			
		||||
 | 
			
		||||
  // See the implementation below (after the class definition) for more verbose
 | 
			
		||||
  // comments for each of the methods.
 | 
			
		||||
 | 
			
		||||
  // Methods returning std::vector of bytes. These are the most popular choice
 | 
			
		||||
  // when splitting fuzzing input into pieces, as every piece is put into a
 | 
			
		||||
  // separate buffer (i.e. ASan would catch any under-/overflow) and the memory
 | 
			
		||||
  // will be released automatically.
 | 
			
		||||
  template <typename T> std::vector<T> ConsumeBytes(size_t num_bytes);
 | 
			
		||||
  template <typename T>
 | 
			
		||||
  std::vector<T> ConsumeBytesWithTerminator(size_t num_bytes, T terminator = 0);
 | 
			
		||||
  template <typename T> std::vector<T> ConsumeRemainingBytes();
 | 
			
		||||
 | 
			
		||||
  // Methods returning strings. Use only when you need a std::string or a null
 | 
			
		||||
  // terminated C-string. Otherwise, prefer the methods returning std::vector.
 | 
			
		||||
  std::string ConsumeBytesAsString(size_t num_bytes);
 | 
			
		||||
  std::string ConsumeRandomLengthString(size_t max_length);
 | 
			
		||||
  std::string ConsumeRandomLengthString();
 | 
			
		||||
  std::string ConsumeRemainingBytesAsString();
 | 
			
		||||
 | 
			
		||||
  // Methods returning integer values.
 | 
			
		||||
  template <typename T> T ConsumeIntegral();
 | 
			
		||||
  template <typename T> T ConsumeIntegralInRange(T min, T max);
 | 
			
		||||
 | 
			
		||||
  // Methods returning floating point values.
 | 
			
		||||
  template <typename T> T ConsumeFloatingPoint();
 | 
			
		||||
  template <typename T> T ConsumeFloatingPointInRange(T min, T max);
 | 
			
		||||
 | 
			
		||||
  // 0 <= return value <= 1.
 | 
			
		||||
  template <typename T> T ConsumeProbability();
 | 
			
		||||
 | 
			
		||||
  bool ConsumeBool();
 | 
			
		||||
 | 
			
		||||
  // Returns a value chosen from the given enum.
 | 
			
		||||
  template <typename T> T ConsumeEnum();
 | 
			
		||||
 | 
			
		||||
  // Returns a value from the given array.
 | 
			
		||||
  template <typename T, size_t size> T PickValueInArray(const T (&array)[size]);
 | 
			
		||||
  template <typename T, size_t size>
 | 
			
		||||
  T PickValueInArray(const std::array<T, size> &array);
 | 
			
		||||
  template <typename T> T PickValueInArray(std::initializer_list<const T> list);
 | 
			
		||||
 | 
			
		||||
  // Writes data to the given destination and returns number of bytes written.
 | 
			
		||||
  size_t ConsumeData(void *destination, size_t num_bytes);
 | 
			
		||||
 | 
			
		||||
  // Reports the remaining bytes available for fuzzed input.
 | 
			
		||||
  size_t remaining_bytes() { return remaining_bytes_; }
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  FuzzedDataProvider(const FuzzedDataProvider &) = delete;
 | 
			
		||||
  FuzzedDataProvider &operator=(const FuzzedDataProvider &) = delete;
 | 
			
		||||
 | 
			
		||||
  void CopyAndAdvance(void *destination, size_t num_bytes);
 | 
			
		||||
 | 
			
		||||
  void Advance(size_t num_bytes);
 | 
			
		||||
 | 
			
		||||
  template <typename T>
 | 
			
		||||
  std::vector<T> ConsumeBytes(size_t size, size_t num_bytes);
 | 
			
		||||
 | 
			
		||||
  template <typename TS, typename TU> TS ConvertUnsignedToSigned(TU value);
 | 
			
		||||
 | 
			
		||||
  const uint8_t *data_ptr_;
 | 
			
		||||
  size_t remaining_bytes_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Returns a std::vector containing |num_bytes| of input data. If fewer than
 | 
			
		||||
// |num_bytes| of data remain, returns a shorter std::vector containing all
 | 
			
		||||
// of the data that's left. Can be used with any byte sized type, such as
 | 
			
		||||
// char, unsigned char, uint8_t, etc.
 | 
			
		||||
template <typename T>
 | 
			
		||||
std::vector<T> FuzzedDataProvider::ConsumeBytes(size_t num_bytes) {
 | 
			
		||||
  num_bytes = std::min(num_bytes, remaining_bytes_);
 | 
			
		||||
  return ConsumeBytes<T>(num_bytes, num_bytes);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Similar to |ConsumeBytes|, but also appends the terminator value at the end
 | 
			
		||||
// of the resulting vector. Useful, when a mutable null-terminated C-string is
 | 
			
		||||
// needed, for example. But that is a rare case. Better avoid it, if possible,
 | 
			
		||||
// and prefer using |ConsumeBytes| or |ConsumeBytesAsString| methods.
 | 
			
		||||
template <typename T>
 | 
			
		||||
std::vector<T> FuzzedDataProvider::ConsumeBytesWithTerminator(size_t num_bytes,
 | 
			
		||||
                                                              T terminator) {
 | 
			
		||||
  num_bytes = std::min(num_bytes, remaining_bytes_);
 | 
			
		||||
  std::vector<T> result = ConsumeBytes<T>(num_bytes + 1, num_bytes);
 | 
			
		||||
  result.back() = terminator;
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns a std::vector containing all remaining bytes of the input data.
 | 
			
		||||
template <typename T>
 | 
			
		||||
std::vector<T> FuzzedDataProvider::ConsumeRemainingBytes() {
 | 
			
		||||
  return ConsumeBytes<T>(remaining_bytes_);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns a std::string containing |num_bytes| of input data. Using this and
 | 
			
		||||
// |.c_str()| on the resulting string is the best way to get an immutable
 | 
			
		||||
// null-terminated C string. If fewer than |num_bytes| of data remain, returns
 | 
			
		||||
// a shorter std::string containing all of the data that's left.
 | 
			
		||||
inline std::string FuzzedDataProvider::ConsumeBytesAsString(size_t num_bytes) {
 | 
			
		||||
  static_assert(sizeof(std::string::value_type) == sizeof(uint8_t),
 | 
			
		||||
                "ConsumeBytesAsString cannot convert the data to a string.");
 | 
			
		||||
 | 
			
		||||
  num_bytes = std::min(num_bytes, remaining_bytes_);
 | 
			
		||||
  std::string result(
 | 
			
		||||
      reinterpret_cast<const std::string::value_type *>(data_ptr_), num_bytes);
 | 
			
		||||
  Advance(num_bytes);
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns a std::string of length from 0 to |max_length|. When it runs out of
 | 
			
		||||
// input data, returns what remains of the input. Designed to be more stable
 | 
			
		||||
// with respect to a fuzzer inserting characters than just picking a random
 | 
			
		||||
// length and then consuming that many bytes with |ConsumeBytes|.
 | 
			
		||||
inline std::string
 | 
			
		||||
FuzzedDataProvider::ConsumeRandomLengthString(size_t max_length) {
 | 
			
		||||
  // Reads bytes from the start of |data_ptr_|. Maps "\\" to "\", and maps "\"
 | 
			
		||||
  // followed by anything else to the end of the string. As a result of this
 | 
			
		||||
  // logic, a fuzzer can insert characters into the string, and the string
 | 
			
		||||
  // will be lengthened to include those new characters, resulting in a more
 | 
			
		||||
  // stable fuzzer than picking the length of a string independently from
 | 
			
		||||
  // picking its contents.
 | 
			
		||||
  std::string result;
 | 
			
		||||
 | 
			
		||||
  // Reserve the anticipated capaticity to prevent several reallocations.
 | 
			
		||||
  result.reserve(std::min(max_length, remaining_bytes_));
 | 
			
		||||
  for (size_t i = 0; i < max_length && remaining_bytes_ != 0; ++i) {
 | 
			
		||||
    char next = ConvertUnsignedToSigned<char>(data_ptr_[0]);
 | 
			
		||||
    Advance(1);
 | 
			
		||||
    if (next == '\\' && remaining_bytes_ != 0) {
 | 
			
		||||
      next = ConvertUnsignedToSigned<char>(data_ptr_[0]);
 | 
			
		||||
      Advance(1);
 | 
			
		||||
      if (next != '\\')
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    result += next;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  result.shrink_to_fit();
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns a std::string of length from 0 to |remaining_bytes_|.
 | 
			
		||||
inline std::string FuzzedDataProvider::ConsumeRandomLengthString() {
 | 
			
		||||
  return ConsumeRandomLengthString(remaining_bytes_);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns a std::string containing all remaining bytes of the input data.
 | 
			
		||||
// Prefer using |ConsumeRemainingBytes| unless you actually need a std::string
 | 
			
		||||
// object.
 | 
			
		||||
inline std::string FuzzedDataProvider::ConsumeRemainingBytesAsString() {
 | 
			
		||||
  return ConsumeBytesAsString(remaining_bytes_);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns a number in the range [Type's min, Type's max]. The value might
 | 
			
		||||
// not be uniformly distributed in the given range. If there's no input data
 | 
			
		||||
// left, always returns |min|.
 | 
			
		||||
template <typename T> T FuzzedDataProvider::ConsumeIntegral() {
 | 
			
		||||
  return ConsumeIntegralInRange(std::numeric_limits<T>::min(),
 | 
			
		||||
                                std::numeric_limits<T>::max());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns a number in the range [min, max] by consuming bytes from the
 | 
			
		||||
// input data. The value might not be uniformly distributed in the given
 | 
			
		||||
// range. If there's no input data left, always returns |min|. |min| must
 | 
			
		||||
// be less than or equal to |max|.
 | 
			
		||||
template <typename T>
 | 
			
		||||
T FuzzedDataProvider::ConsumeIntegralInRange(T min, T max) {
 | 
			
		||||
  static_assert(std::is_integral<T>::value, "An integral type is required.");
 | 
			
		||||
  static_assert(sizeof(T) <= sizeof(uint64_t), "Unsupported integral type.");
 | 
			
		||||
 | 
			
		||||
  if (min > max)
 | 
			
		||||
    abort();
 | 
			
		||||
 | 
			
		||||
  // Use the biggest type possible to hold the range and the result.
 | 
			
		||||
  uint64_t range = static_cast<uint64_t>(max) - static_cast<uint64_t>(min);
 | 
			
		||||
  uint64_t result = 0;
 | 
			
		||||
  size_t offset = 0;
 | 
			
		||||
 | 
			
		||||
  while (offset < sizeof(T) * CHAR_BIT && (range >> offset) > 0 &&
 | 
			
		||||
         remaining_bytes_ != 0) {
 | 
			
		||||
    // Pull bytes off the end of the seed data. Experimentally, this seems to
 | 
			
		||||
    // allow the fuzzer to more easily explore the input space. This makes
 | 
			
		||||
    // sense, since it works by modifying inputs that caused new code to run,
 | 
			
		||||
    // and this data is often used to encode length of data read by
 | 
			
		||||
    // |ConsumeBytes|. Separating out read lengths makes it easier modify the
 | 
			
		||||
    // contents of the data that is actually read.
 | 
			
		||||
    --remaining_bytes_;
 | 
			
		||||
    result = (result << CHAR_BIT) | data_ptr_[remaining_bytes_];
 | 
			
		||||
    offset += CHAR_BIT;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Avoid division by 0, in case |range + 1| results in overflow.
 | 
			
		||||
  if (range != std::numeric_limits<decltype(range)>::max())
 | 
			
		||||
    result = result % (range + 1);
 | 
			
		||||
 | 
			
		||||
  return static_cast<T>(static_cast<uint64_t>(min) + result);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns a floating point value in the range [Type's lowest, Type's max] by
 | 
			
		||||
// consuming bytes from the input data. If there's no input data left, always
 | 
			
		||||
// returns approximately 0.
 | 
			
		||||
template <typename T> T FuzzedDataProvider::ConsumeFloatingPoint() {
 | 
			
		||||
  return ConsumeFloatingPointInRange<T>(std::numeric_limits<T>::lowest(),
 | 
			
		||||
                                        std::numeric_limits<T>::max());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns a floating point value in the given range by consuming bytes from
 | 
			
		||||
// the input data. If there's no input data left, returns |min|. Note that
 | 
			
		||||
// |min| must be less than or equal to |max|.
 | 
			
		||||
template <typename T>
 | 
			
		||||
T FuzzedDataProvider::ConsumeFloatingPointInRange(T min, T max) {
 | 
			
		||||
  if (min > max)
 | 
			
		||||
    abort();
 | 
			
		||||
 | 
			
		||||
  T range = .0;
 | 
			
		||||
  T result = min;
 | 
			
		||||
  constexpr T zero(.0);
 | 
			
		||||
  if (max > zero && min < zero && max > min + std::numeric_limits<T>::max()) {
 | 
			
		||||
    // The diff |max - min| would overflow the given floating point type. Use
 | 
			
		||||
    // the half of the diff as the range and consume a bool to decide whether
 | 
			
		||||
    // the result is in the first of the second part of the diff.
 | 
			
		||||
    range = (max / 2.0) - (min / 2.0);
 | 
			
		||||
    if (ConsumeBool()) {
 | 
			
		||||
      result += range;
 | 
			
		||||
    }
 | 
			
		||||
  } else {
 | 
			
		||||
    range = max - min;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return result + range * ConsumeProbability<T>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns a floating point number in the range [0.0, 1.0]. If there's no
 | 
			
		||||
// input data left, always returns 0.
 | 
			
		||||
template <typename T> T FuzzedDataProvider::ConsumeProbability() {
 | 
			
		||||
  static_assert(std::is_floating_point<T>::value,
 | 
			
		||||
                "A floating point type is required.");
 | 
			
		||||
 | 
			
		||||
  // Use different integral types for different floating point types in order
 | 
			
		||||
  // to provide better density of the resulting values.
 | 
			
		||||
  using IntegralType =
 | 
			
		||||
      typename std::conditional<(sizeof(T) <= sizeof(uint32_t)), uint32_t,
 | 
			
		||||
                                uint64_t>::type;
 | 
			
		||||
 | 
			
		||||
  T result = static_cast<T>(ConsumeIntegral<IntegralType>());
 | 
			
		||||
  result /= static_cast<T>(std::numeric_limits<IntegralType>::max());
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Reads one byte and returns a bool, or false when no data remains.
 | 
			
		||||
inline bool FuzzedDataProvider::ConsumeBool() {
 | 
			
		||||
  return 1 & ConsumeIntegral<uint8_t>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns an enum value. The enum must start at 0 and be contiguous. It must
 | 
			
		||||
// also contain |kMaxValue| aliased to its largest (inclusive) value. Such as:
 | 
			
		||||
// enum class Foo { SomeValue, OtherValue, kMaxValue = OtherValue };
 | 
			
		||||
template <typename T> T FuzzedDataProvider::ConsumeEnum() {
 | 
			
		||||
  static_assert(std::is_enum<T>::value, "|T| must be an enum type.");
 | 
			
		||||
  return static_cast<T>(
 | 
			
		||||
      ConsumeIntegralInRange<uint32_t>(0, static_cast<uint32_t>(T::kMaxValue)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns a copy of the value selected from the given fixed-size |array|.
 | 
			
		||||
template <typename T, size_t size>
 | 
			
		||||
T FuzzedDataProvider::PickValueInArray(const T (&array)[size]) {
 | 
			
		||||
  static_assert(size > 0, "The array must be non empty.");
 | 
			
		||||
  return array[ConsumeIntegralInRange<size_t>(0, size - 1)];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, size_t size>
 | 
			
		||||
T FuzzedDataProvider::PickValueInArray(const std::array<T, size> &array) {
 | 
			
		||||
  static_assert(size > 0, "The array must be non empty.");
 | 
			
		||||
  return array[ConsumeIntegralInRange<size_t>(0, size - 1)];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
T FuzzedDataProvider::PickValueInArray(std::initializer_list<const T> list) {
 | 
			
		||||
  // TODO(Dor1s): switch to static_assert once C++14 is allowed.
 | 
			
		||||
  if (!list.size())
 | 
			
		||||
    abort();
 | 
			
		||||
 | 
			
		||||
  return *(list.begin() + ConsumeIntegralInRange<size_t>(0, list.size() - 1));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Writes |num_bytes| of input data to the given destination pointer. If there
 | 
			
		||||
// is not enough data left, writes all remaining bytes. Return value is the
 | 
			
		||||
// number of bytes written.
 | 
			
		||||
// In general, it's better to avoid using this function, but it may be useful
 | 
			
		||||
// in cases when it's necessary to fill a certain buffer or object with
 | 
			
		||||
// fuzzing data.
 | 
			
		||||
inline size_t FuzzedDataProvider::ConsumeData(void *destination,
 | 
			
		||||
                                              size_t num_bytes) {
 | 
			
		||||
  num_bytes = std::min(num_bytes, remaining_bytes_);
 | 
			
		||||
  CopyAndAdvance(destination, num_bytes);
 | 
			
		||||
  return num_bytes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Private methods.
 | 
			
		||||
inline void FuzzedDataProvider::CopyAndAdvance(void *destination,
 | 
			
		||||
                                               size_t num_bytes) {
 | 
			
		||||
  std::memcpy(destination, data_ptr_, num_bytes);
 | 
			
		||||
  Advance(num_bytes);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline void FuzzedDataProvider::Advance(size_t num_bytes) {
 | 
			
		||||
  if (num_bytes > remaining_bytes_)
 | 
			
		||||
    abort();
 | 
			
		||||
 | 
			
		||||
  data_ptr_ += num_bytes;
 | 
			
		||||
  remaining_bytes_ -= num_bytes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
std::vector<T> FuzzedDataProvider::ConsumeBytes(size_t size, size_t num_bytes) {
 | 
			
		||||
  static_assert(sizeof(T) == sizeof(uint8_t), "Incompatible data type.");
 | 
			
		||||
 | 
			
		||||
  // The point of using the size-based constructor below is to increase the
 | 
			
		||||
  // odds of having a vector object with capacity being equal to the length.
 | 
			
		||||
  // That part is always implementation specific, but at least both libc++ and
 | 
			
		||||
  // libstdc++ allocate the requested number of bytes in that constructor,
 | 
			
		||||
  // which seems to be a natural choice for other implementations as well.
 | 
			
		||||
  // To increase the odds even more, we also call |shrink_to_fit| below.
 | 
			
		||||
  std::vector<T> result(size);
 | 
			
		||||
  if (size == 0) {
 | 
			
		||||
    if (num_bytes != 0)
 | 
			
		||||
      abort();
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  CopyAndAdvance(result.data(), num_bytes);
 | 
			
		||||
 | 
			
		||||
  // Even though |shrink_to_fit| is also implementation specific, we expect it
 | 
			
		||||
  // to provide an additional assurance in case vector's constructor allocated
 | 
			
		||||
  // a buffer which is larger than the actual amount of data we put inside it.
 | 
			
		||||
  result.shrink_to_fit();
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename TS, typename TU>
 | 
			
		||||
TS FuzzedDataProvider::ConvertUnsignedToSigned(TU value) {
 | 
			
		||||
  static_assert(sizeof(TS) == sizeof(TU), "Incompatible data types.");
 | 
			
		||||
  static_assert(!std::numeric_limits<TU>::is_signed,
 | 
			
		||||
                "Source type must be unsigned.");
 | 
			
		||||
 | 
			
		||||
  // TODO(Dor1s): change to `if constexpr` once C++17 becomes mainstream.
 | 
			
		||||
  if (std::numeric_limits<TS>::is_modulo)
 | 
			
		||||
    return static_cast<TS>(value);
 | 
			
		||||
 | 
			
		||||
  // Avoid using implementation-defined unsigned to signed conversions.
 | 
			
		||||
  // To learn more, see https://stackoverflow.com/questions/13150449.
 | 
			
		||||
  if (value <= std::numeric_limits<TS>::max()) {
 | 
			
		||||
    return static_cast<TS>(value);
 | 
			
		||||
  } else {
 | 
			
		||||
    constexpr auto TS_min = std::numeric_limits<TS>::min();
 | 
			
		||||
    return static_cast<TS>(TS_min + static_cast<TS>(value - TS_min));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif // LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_
 | 
			
		||||
							
								
								
									
										3365
									
								
								third_party/unordered_dense/test/third-party/nanobench.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3365
									
								
								third_party/unordered_dense/test/third-party/nanobench.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2527
									
								
								third_party/unordered_dense/test/third-party/robin_hood.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2527
									
								
								third_party/unordered_dense/test/third-party/robin_hood.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										84
									
								
								third_party/unordered_dense/test/unit/assign_to_move.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								third_party/unordered_dense/test/unit/assign_to_move.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,84 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
 | 
			
		||||
#define ENABLE_LOG_LINE
 | 
			
		||||
#include <app/print.h>
 | 
			
		||||
 | 
			
		||||
#include <app/doctest.h>
 | 
			
		||||
 | 
			
		||||
#include <type_traits> // for remove_reference, remove_referen...
 | 
			
		||||
#include <utility>     // for move
 | 
			
		||||
#include <vector>      // for vector
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("assign_to_moved", int, int) {
 | 
			
		||||
    auto a = map_t();
 | 
			
		||||
    a[1] = 2;
 | 
			
		||||
    auto moved = std::move(a);
 | 
			
		||||
    REQUIRE(moved.size() == 1U);
 | 
			
		||||
 | 
			
		||||
    auto c = map_t();
 | 
			
		||||
    c[3] = 4;
 | 
			
		||||
 | 
			
		||||
    // assign to a moved map
 | 
			
		||||
    a = c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("move_to_moved", int, int) {
 | 
			
		||||
    auto a = map_t();
 | 
			
		||||
    a[1] = 2;
 | 
			
		||||
    auto moved = std::move(a);
 | 
			
		||||
 | 
			
		||||
    auto c = map_t();
 | 
			
		||||
    c[3] = 4;
 | 
			
		||||
 | 
			
		||||
    // assign to a moved map
 | 
			
		||||
    a = std::move(c);
 | 
			
		||||
 | 
			
		||||
    a[5] = 6;
 | 
			
		||||
    moved[6] = 7;
 | 
			
		||||
    REQUIRE(moved[6] == 7);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("swap", int, int) {
 | 
			
		||||
    {
 | 
			
		||||
        auto b = map_t();
 | 
			
		||||
        {
 | 
			
		||||
            auto a = map_t();
 | 
			
		||||
            b[1] = 2;
 | 
			
		||||
 | 
			
		||||
            a.swap(b);
 | 
			
		||||
            REQUIRE(a.end() != a.find(1));
 | 
			
		||||
            REQUIRE(b.end() == b.find(1));
 | 
			
		||||
        }
 | 
			
		||||
        REQUIRE(b.end() == b.find(1));
 | 
			
		||||
        b[2] = 3;
 | 
			
		||||
        REQUIRE(b.end() != b.find(2));
 | 
			
		||||
        REQUIRE(b.size() == 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        auto a = map_t();
 | 
			
		||||
        {
 | 
			
		||||
            auto b = map_t();
 | 
			
		||||
            b[1] = 2;
 | 
			
		||||
 | 
			
		||||
            a.swap(b);
 | 
			
		||||
            REQUIRE(a.end() != a.find(1));
 | 
			
		||||
            REQUIRE(b.end() == b.find(1));
 | 
			
		||||
        }
 | 
			
		||||
        REQUIRE(a.end() != a.find(1));
 | 
			
		||||
        a[2] = 3;
 | 
			
		||||
        REQUIRE(a.end() != a.find(2));
 | 
			
		||||
        REQUIRE(a.size() == 2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        auto a = map_t();
 | 
			
		||||
        {
 | 
			
		||||
            auto b = map_t();
 | 
			
		||||
            a.swap(b);
 | 
			
		||||
            REQUIRE(a.end() == a.find(1));
 | 
			
		||||
            REQUIRE(b.end() == b.find(1));
 | 
			
		||||
        }
 | 
			
		||||
        REQUIRE(a.end() == a.find(1));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										167
									
								
								third_party/unordered_dense/test/unit/assignment_combinations.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								third_party/unordered_dense/test/unit/assignment_combinations.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,167 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
 | 
			
		||||
#define ENABLE_LOG_LINE
 | 
			
		||||
#include <app/doctest.h>
 | 
			
		||||
#include <app/print.h>
 | 
			
		||||
 | 
			
		||||
#include <cstdint> // for uint64_t
 | 
			
		||||
#include <utility> // for pair
 | 
			
		||||
#include <vector>  // for vector
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("assignment_combinations_1", uint64_t, uint64_t) {
 | 
			
		||||
    map_t a;
 | 
			
		||||
    map_t b;
 | 
			
		||||
    b = a;
 | 
			
		||||
    REQUIRE(b == a);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("assignment_combinations_2", uint64_t, uint64_t) {
 | 
			
		||||
    map_t a;
 | 
			
		||||
    map_t const& a_const = a;
 | 
			
		||||
    map_t b;
 | 
			
		||||
    a[123] = 321;
 | 
			
		||||
    b = a;
 | 
			
		||||
 | 
			
		||||
    REQUIRE(a.find(123)->second == 321);
 | 
			
		||||
    REQUIRE(a_const.find(123)->second == 321);
 | 
			
		||||
 | 
			
		||||
    REQUIRE(b.find(123)->second == 321);
 | 
			
		||||
    a[123] = 111;
 | 
			
		||||
    REQUIRE(a.find(123)->second == 111);
 | 
			
		||||
    REQUIRE(a_const.find(123)->second == 111);
 | 
			
		||||
    REQUIRE(b.find(123)->second == 321);
 | 
			
		||||
    b[123] = 222;
 | 
			
		||||
    REQUIRE(a.find(123)->second == 111);
 | 
			
		||||
    REQUIRE(a_const.find(123)->second == 111);
 | 
			
		||||
    REQUIRE(b.find(123)->second == 222);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("assignment_combinations_3", uint64_t, uint64_t) {
 | 
			
		||||
    map_t a;
 | 
			
		||||
    map_t b;
 | 
			
		||||
    a[123] = 321;
 | 
			
		||||
    a.clear();
 | 
			
		||||
    b = a;
 | 
			
		||||
 | 
			
		||||
    REQUIRE(a.size() == 0);
 | 
			
		||||
    REQUIRE(b.size() == 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("assignment_combinations_4", uint64_t, uint64_t) {
 | 
			
		||||
    map_t a;
 | 
			
		||||
    map_t b;
 | 
			
		||||
    b[123] = 321;
 | 
			
		||||
    b = a;
 | 
			
		||||
 | 
			
		||||
    REQUIRE(a.size() == 0);
 | 
			
		||||
    REQUIRE(b.size() == 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("assignment_combinations_5", uint64_t, uint64_t) {
 | 
			
		||||
    map_t a;
 | 
			
		||||
    map_t b;
 | 
			
		||||
    b[123] = 321;
 | 
			
		||||
    b.clear();
 | 
			
		||||
    b = a;
 | 
			
		||||
 | 
			
		||||
    REQUIRE(a.size() == 0);
 | 
			
		||||
    REQUIRE(b.size() == 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("assignment_combinations_6", uint64_t, uint64_t) {
 | 
			
		||||
    map_t a;
 | 
			
		||||
    a[1] = 2;
 | 
			
		||||
    map_t b;
 | 
			
		||||
    b[3] = 4;
 | 
			
		||||
    b = a;
 | 
			
		||||
 | 
			
		||||
    REQUIRE(a.size() == 1);
 | 
			
		||||
    REQUIRE(b.size() == 1);
 | 
			
		||||
    REQUIRE(b.find(1)->second == 2);
 | 
			
		||||
    a[1] = 123;
 | 
			
		||||
    REQUIRE(a.size() == 1);
 | 
			
		||||
    REQUIRE(b.size() == 1);
 | 
			
		||||
    REQUIRE(b.find(1)->second == 2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("assignment_combinations_7", uint64_t, uint64_t) {
 | 
			
		||||
    map_t a;
 | 
			
		||||
    a[1] = 2;
 | 
			
		||||
    a.clear();
 | 
			
		||||
    map_t b;
 | 
			
		||||
    REQUIRE(a == b);
 | 
			
		||||
    b[3] = 4;
 | 
			
		||||
    REQUIRE(a != b);
 | 
			
		||||
    b = a;
 | 
			
		||||
    REQUIRE(a == b);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("assignment_combinations_7", uint64_t, uint64_t) {
 | 
			
		||||
    map_t a;
 | 
			
		||||
    a[1] = 2;
 | 
			
		||||
    map_t b;
 | 
			
		||||
    REQUIRE(a != b);
 | 
			
		||||
    b[3] = 4;
 | 
			
		||||
    b.clear();
 | 
			
		||||
    REQUIRE(a != b);
 | 
			
		||||
    b = a;
 | 
			
		||||
    REQUIRE(a == b);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("assignment_combinations_8", uint64_t, uint64_t) {
 | 
			
		||||
    map_t a;
 | 
			
		||||
    a[1] = 2;
 | 
			
		||||
    a.clear();
 | 
			
		||||
    map_t b;
 | 
			
		||||
    b[3] = 4;
 | 
			
		||||
    REQUIRE(a != b);
 | 
			
		||||
    b.clear();
 | 
			
		||||
    REQUIRE(a == b);
 | 
			
		||||
    b = a;
 | 
			
		||||
    REQUIRE(a == b);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("assignment_combinations_9", uint64_t, uint64_t) {
 | 
			
		||||
    map_t a;
 | 
			
		||||
    a[1] = 2;
 | 
			
		||||
 | 
			
		||||
    // self assignment should work too
 | 
			
		||||
    map_t* b = &a;
 | 
			
		||||
    a = *b;
 | 
			
		||||
    REQUIRE(a == a);
 | 
			
		||||
    REQUIRE(a.size() == 1);
 | 
			
		||||
    REQUIRE(a.find(1) != a.end());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("assignment_combinations_10", uint64_t, uint64_t) {
 | 
			
		||||
    map_t a;
 | 
			
		||||
    a[1] = 2;
 | 
			
		||||
    map_t b;
 | 
			
		||||
    b[2] = 1;
 | 
			
		||||
 | 
			
		||||
    // maps have the same number of elements, but are not equal.
 | 
			
		||||
    REQUIRE(!(a == b));
 | 
			
		||||
    REQUIRE(a != b);
 | 
			
		||||
    REQUIRE(b != a);
 | 
			
		||||
    REQUIRE(!(a == b));
 | 
			
		||||
    REQUIRE(!(b == a));
 | 
			
		||||
 | 
			
		||||
    map_t c;
 | 
			
		||||
    c[1] = 3;
 | 
			
		||||
    REQUIRE(a != c);
 | 
			
		||||
    REQUIRE(c != a);
 | 
			
		||||
    REQUIRE(!(a == c));
 | 
			
		||||
    REQUIRE(!(c == a));
 | 
			
		||||
 | 
			
		||||
    b.clear();
 | 
			
		||||
    REQUIRE(a != b);
 | 
			
		||||
    REQUIRE(b != a);
 | 
			
		||||
    REQUIRE(!(a == b));
 | 
			
		||||
    REQUIRE(!(b == a));
 | 
			
		||||
 | 
			
		||||
    map_t empty;
 | 
			
		||||
    REQUIRE(b == empty);
 | 
			
		||||
    REQUIRE(empty == b);
 | 
			
		||||
    REQUIRE(!(b != empty));
 | 
			
		||||
    REQUIRE(!(empty != b));
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								third_party/unordered_dense/test/unit/at.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								third_party/unordered_dense/test/unit/at.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
 | 
			
		||||
#include <app/doctest.h>
 | 
			
		||||
 | 
			
		||||
#include <stdexcept> // for out_of_range
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("at", int, int) {
 | 
			
		||||
    map_t map;
 | 
			
		||||
    map_t const& cmap = map;
 | 
			
		||||
 | 
			
		||||
    // NOLINTNEXTLINE(llvm-else-after-return,readability-else-after-return)
 | 
			
		||||
    REQUIRE_THROWS_AS(map.at(123), std::out_of_range);
 | 
			
		||||
 | 
			
		||||
    // NOLINTNEXTLINE(llvm-else-after-return,readability-else-after-return)
 | 
			
		||||
    REQUIRE_THROWS_AS(static_cast<void>(map.at(0)), std::out_of_range);
 | 
			
		||||
 | 
			
		||||
    // NOLINTNEXTLINE(llvm-else-after-return,readability-else-after-return)
 | 
			
		||||
    REQUIRE_THROWS_AS(static_cast<void>(cmap.at(123)), std::out_of_range);
 | 
			
		||||
 | 
			
		||||
    // NOLINTNEXTLINE(llvm-else-after-return,readability-else-after-return)
 | 
			
		||||
    REQUIRE_THROWS_AS(static_cast<void>(cmap.at(0)), std::out_of_range);
 | 
			
		||||
 | 
			
		||||
    map[123] = 333;
 | 
			
		||||
    REQUIRE(map.at(123) == 333);
 | 
			
		||||
    REQUIRE(cmap.at(123) == 333);
 | 
			
		||||
 | 
			
		||||
    // NOLINTNEXTLINE(llvm-else-after-return,readability-else-after-return)
 | 
			
		||||
    REQUIRE_THROWS_AS(static_cast<void>(map.at(0)), std::out_of_range);
 | 
			
		||||
 | 
			
		||||
    // NOLINTNEXTLINE(llvm-else-after-return,readability-else-after-return)
 | 
			
		||||
    REQUIRE_THROWS_AS(static_cast<void>(cmap.at(0)), std::out_of_range);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										82
									
								
								third_party/unordered_dense/test/unit/bucket.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								third_party/unordered_dense/test/unit/bucket.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,82 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
 | 
			
		||||
#include <app/counter.h>
 | 
			
		||||
#include <app/doctest.h>
 | 
			
		||||
 | 
			
		||||
#include <fmt/format.h>
 | 
			
		||||
 | 
			
		||||
#include <limits>
 | 
			
		||||
#include <stdexcept> // for out_of_range
 | 
			
		||||
 | 
			
		||||
using map_default_t = ankerl::unordered_dense::map<std::string, size_t>;
 | 
			
		||||
 | 
			
		||||
// big bucket type allows 2^64 elements, but has more memory & CPU overhead.
 | 
			
		||||
using map_big_t = ankerl::unordered_dense::map<std::string,
 | 
			
		||||
                                               size_t,
 | 
			
		||||
                                               ankerl::unordered_dense::hash<std::string>,
 | 
			
		||||
                                               std::equal_to<std::string>,
 | 
			
		||||
                                               std::allocator<std::pair<std::string, size_t>>,
 | 
			
		||||
                                               ankerl::unordered_dense::bucket_type::big>;
 | 
			
		||||
 | 
			
		||||
static_assert(sizeof(map_default_t::bucket_type) == 8U);
 | 
			
		||||
static_assert(sizeof(map_big_t::bucket_type) == sizeof(size_t) + 4U);
 | 
			
		||||
static_assert(map_default_t::max_size() == map_default_t::max_bucket_count());
 | 
			
		||||
 | 
			
		||||
#if SIZE_MAX == UINT32_MAX
 | 
			
		||||
static_assert(map_default_t::max_size() == uint64_t{1} << 31U);
 | 
			
		||||
static_assert(map_big_t::max_size() == uint64_t{1} << 31U);
 | 
			
		||||
#else
 | 
			
		||||
static_assert(map_default_t::max_size() == uint64_t{1} << 32U);
 | 
			
		||||
static_assert(map_big_t::max_size() == uint64_t{1} << 63U);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct bucket_micro {
 | 
			
		||||
    static constexpr uint8_t dist_inc = 1U << 1U;             // 1 bits for fingerprint
 | 
			
		||||
    static constexpr uint8_t fingerprint_mask = dist_inc - 1; // 11 bit = 2048 positions for distance
 | 
			
		||||
 | 
			
		||||
    uint8_t m_dist_and_fingerprint;
 | 
			
		||||
    uint8_t m_value_idx;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
TYPE_TO_STRING_MAP(counter::obj,
 | 
			
		||||
                   counter::obj,
 | 
			
		||||
                   ankerl::unordered_dense::hash<counter::obj>,
 | 
			
		||||
                   std::equal_to<counter::obj>,
 | 
			
		||||
                   std::allocator<std::pair<counter::obj, counter::obj>>,
 | 
			
		||||
                   bucket_micro);
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("bucket_micro",
 | 
			
		||||
              counter::obj,
 | 
			
		||||
              counter::obj,
 | 
			
		||||
              ankerl::unordered_dense::hash<counter::obj>,
 | 
			
		||||
              std::equal_to<counter::obj>,
 | 
			
		||||
              std::allocator<std::pair<counter::obj, counter::obj>>,
 | 
			
		||||
              bucket_micro) {
 | 
			
		||||
    counter counts;
 | 
			
		||||
    INFO(counts);
 | 
			
		||||
 | 
			
		||||
    auto map = map_t();
 | 
			
		||||
    INFO("map_t::max_size()=" << map_t::max_size());
 | 
			
		||||
    for (size_t i = 0; i < map_t::max_size(); ++i) {
 | 
			
		||||
        if (i == 255) {
 | 
			
		||||
            INFO("i=" << i);
 | 
			
		||||
        }
 | 
			
		||||
        auto const r = map.try_emplace({i, counts}, i, counts);
 | 
			
		||||
        REQUIRE(r.second);
 | 
			
		||||
 | 
			
		||||
        auto it = map.find({0, counts});
 | 
			
		||||
        REQUIRE(it != map.end());
 | 
			
		||||
    }
 | 
			
		||||
    // NOLINTNEXTLINE(llvm-else-after-return,readability-else-after-return)
 | 
			
		||||
    REQUIRE_THROWS_AS(map.try_emplace({map_t::max_size(), counts}, map_t::max_size(), counts), std::overflow_error);
 | 
			
		||||
 | 
			
		||||
    // check that all elements are there
 | 
			
		||||
    REQUIRE(map.size() == map_t::max_size());
 | 
			
		||||
    for (size_t i = 0; i < map_t::max_size(); ++i) {
 | 
			
		||||
        INFO(i);
 | 
			
		||||
        auto it = map.find({i, counts});
 | 
			
		||||
        REQUIRE(it != map.end());
 | 
			
		||||
        REQUIRE(it->first.get() == i);
 | 
			
		||||
        REQUIRE(it->second.get() == i);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								third_party/unordered_dense/test/unit/contains.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								third_party/unordered_dense/test/unit/contains.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
 | 
			
		||||
#include <app/doctest.h>
 | 
			
		||||
 | 
			
		||||
#include <cstdint> // for uint64_t
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("contains", uint64_t, uint64_t) {
 | 
			
		||||
    static_assert(std::is_same_v<bool, decltype(map_t{}.contains(1))>);
 | 
			
		||||
 | 
			
		||||
    auto map = map_t();
 | 
			
		||||
 | 
			
		||||
    REQUIRE(!map.contains(0));
 | 
			
		||||
    REQUIRE(!map.contains(123));
 | 
			
		||||
    map[123];
 | 
			
		||||
    REQUIRE(!map.contains(0));
 | 
			
		||||
    REQUIRE(map.contains(123));
 | 
			
		||||
    map.clear();
 | 
			
		||||
    REQUIRE(!map.contains(0));
 | 
			
		||||
    REQUIRE(!map.contains(123));
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										81
									
								
								third_party/unordered_dense/test/unit/copy_and_assign_maps.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								third_party/unordered_dense/test/unit/copy_and_assign_maps.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,81 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
 | 
			
		||||
#define ENABLE_LOG_LINE
 | 
			
		||||
#include <app/doctest.h>
 | 
			
		||||
#include <app/print.h>
 | 
			
		||||
 | 
			
		||||
#include <utility> // for pair
 | 
			
		||||
#include <vector>  // for vector
 | 
			
		||||
 | 
			
		||||
// creates a map with some data in it
 | 
			
		||||
template <class M>
 | 
			
		||||
[[nodiscard]] auto create_map(int num_elements) -> M {
 | 
			
		||||
    M m;
 | 
			
		||||
    for (int i = 0; i < num_elements; ++i) {
 | 
			
		||||
        m[static_cast<typename M::key_type>((i + 123) * 7)] = static_cast<typename M::mapped_type>(i);
 | 
			
		||||
    }
 | 
			
		||||
    return m;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("copy_and_assign_maps_1", int, int) {
 | 
			
		||||
    auto a = create_map<map_t>(15);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("copy_and_assign_maps_2", int, int) {
 | 
			
		||||
    auto a = create_map<map_t>(100);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("copy_and_assign_maps_3", int, int) {
 | 
			
		||||
    auto a = create_map<map_t>(1);
 | 
			
		||||
    // NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
 | 
			
		||||
    auto b = a;
 | 
			
		||||
    REQUIRE(a == b);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("copy_and_assign_maps_4", int, int) {
 | 
			
		||||
    map_t a;
 | 
			
		||||
    REQUIRE(a.empty());
 | 
			
		||||
    a.clear();
 | 
			
		||||
    REQUIRE(a.empty());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("copy_and_assign_maps_5", int, int) {
 | 
			
		||||
    auto a = create_map<map_t>(100);
 | 
			
		||||
    // NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
 | 
			
		||||
    auto b = a;
 | 
			
		||||
    REQUIRE(b == a);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("copy_and_assign_maps_6", int, int) {
 | 
			
		||||
    map_t a;
 | 
			
		||||
    a[123] = 321;
 | 
			
		||||
    a.clear();
 | 
			
		||||
    auto const maps = std::vector<map_t>(10, a);
 | 
			
		||||
 | 
			
		||||
    for (auto const& map : maps) {
 | 
			
		||||
        REQUIRE(map.empty());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("copy_and_assign_maps_7", int, int) {
 | 
			
		||||
    auto const maps = std::vector<map_t>(10);
 | 
			
		||||
    REQUIRE(maps.size() == 10U);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("copy_and_assign_maps_8", int, int) {
 | 
			
		||||
    map_t a;
 | 
			
		||||
    auto const maps = std::vector<map_t>(12, a);
 | 
			
		||||
    REQUIRE(maps.size() == 12U);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("copy_and_assign_maps_9", int, int) {
 | 
			
		||||
    map_t a;
 | 
			
		||||
    a[123] = 321;
 | 
			
		||||
    auto const maps = std::vector<map_t>(10, a);
 | 
			
		||||
    a[123] = 1;
 | 
			
		||||
 | 
			
		||||
    for (auto const& map : maps) {
 | 
			
		||||
        REQUIRE(map.size() == 1);
 | 
			
		||||
        REQUIRE(map.find(123)->second == 321);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										28
									
								
								third_party/unordered_dense/test/unit/copyassignment.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								third_party/unordered_dense/test/unit/copyassignment.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
 | 
			
		||||
#include <app/doctest.h>
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("copyassignment", std::string, std::string) {
 | 
			
		||||
    auto map = map_t();
 | 
			
		||||
    auto tmp = map_t();
 | 
			
		||||
 | 
			
		||||
    map.emplace("a", "b");
 | 
			
		||||
    map = tmp;
 | 
			
		||||
    map.emplace("c", "d");
 | 
			
		||||
 | 
			
		||||
    REQUIRE(map.size() == 1);
 | 
			
		||||
    REQUIRE(map["c"] == "d");
 | 
			
		||||
    REQUIRE(map.size() == 1);
 | 
			
		||||
 | 
			
		||||
    REQUIRE(tmp.size() == 0);
 | 
			
		||||
 | 
			
		||||
    map["e"] = "f";
 | 
			
		||||
    REQUIRE(map.size() == 2);
 | 
			
		||||
    REQUIRE(tmp.size() == 0);
 | 
			
		||||
 | 
			
		||||
    tmp["g"] = "h";
 | 
			
		||||
    REQUIRE(map.size() == 2);
 | 
			
		||||
    REQUIRE(tmp.size() == 1);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								third_party/unordered_dense/test/unit/count.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								third_party/unordered_dense/test/unit/count.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
 | 
			
		||||
#include <app/doctest.h>
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("count", int, int) {
 | 
			
		||||
    auto map = map_t();
 | 
			
		||||
    REQUIRE(map.count(123) == 0);
 | 
			
		||||
    REQUIRE(map.count(0) == 0);
 | 
			
		||||
    map[123];
 | 
			
		||||
    REQUIRE(map.count(123) == 1);
 | 
			
		||||
    REQUIRE(map.count(0) == 0);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										89
									
								
								third_party/unordered_dense/test/unit/ctors.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								third_party/unordered_dense/test/unit/ctors.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,89 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
 | 
			
		||||
#include <app/counter.h>
 | 
			
		||||
#include <app/doctest.h>
 | 
			
		||||
 | 
			
		||||
#include <cstddef> // for size_t
 | 
			
		||||
#include <utility> // for pair
 | 
			
		||||
 | 
			
		||||
// very minimal input iterator
 | 
			
		||||
// https://en.cppreference.com/w/cpp/named_req/InputIterator#Concept
 | 
			
		||||
class it {
 | 
			
		||||
    std::pair<counter::obj, counter::obj> m_kv;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    it(size_t val, counter& counts)
 | 
			
		||||
        : m_kv({val, counts}, {val, counts}) {}
 | 
			
		||||
 | 
			
		||||
    auto operator++() -> it& {
 | 
			
		||||
        ++m_kv.first.get();
 | 
			
		||||
        ++m_kv.second.get();
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto operator*() -> std::pair<counter::obj, counter::obj> const& {
 | 
			
		||||
        return m_kv;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto operator!=(it const& other) const -> bool {
 | 
			
		||||
        return other.m_kv.first.get() != m_kv.first.get() || other.m_kv.second.get() != m_kv.second.get();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("ctors_map", counter::obj, counter::obj) {
 | 
			
		||||
    using alloc_t = typename map_t::allocator_type;
 | 
			
		||||
    using hash_t = typename map_t::hasher;
 | 
			
		||||
    using key_eq_t = typename map_t::key_equal;
 | 
			
		||||
 | 
			
		||||
    auto counts = counter();
 | 
			
		||||
    INFO(counts);
 | 
			
		||||
 | 
			
		||||
    { auto m = map_t{}; }
 | 
			
		||||
    { auto m = map_t{0, alloc_t{}}; }
 | 
			
		||||
    { auto m = map_t{0, hash_t{}, alloc_t{}}; }
 | 
			
		||||
    { auto m = map_t{alloc_t{}}; }
 | 
			
		||||
    REQUIRE(counts.dtor() == 0);
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        auto begin_it = it{size_t{0}, counts};
 | 
			
		||||
        auto end_it = it{size_t{10}, counts};
 | 
			
		||||
        auto m = map_t{begin_it, end_it};
 | 
			
		||||
        REQUIRE(m.size() == 10);
 | 
			
		||||
    }
 | 
			
		||||
    {
 | 
			
		||||
        auto begin_it = it{size_t{0}, counts};
 | 
			
		||||
        auto end_it = it{size_t{10}, counts};
 | 
			
		||||
        auto m = map_t{begin_it, end_it, 0, alloc_t{}};
 | 
			
		||||
        REQUIRE(m.size() == 10);
 | 
			
		||||
    }
 | 
			
		||||
    {
 | 
			
		||||
        auto begin_it = it{size_t{0}, counts};
 | 
			
		||||
        auto end_it = it{size_t{10}, counts};
 | 
			
		||||
        auto m = map_t{begin_it, end_it, 0, hash_t{}, alloc_t{}};
 | 
			
		||||
        REQUIRE(m.size() == 10);
 | 
			
		||||
    }
 | 
			
		||||
    {
 | 
			
		||||
        auto begin_it = it{size_t{0}, counts};
 | 
			
		||||
        auto end_it = it{size_t{10}, counts};
 | 
			
		||||
        auto m = map_t{begin_it, end_it, 0, hash_t{}, key_eq_t{}};
 | 
			
		||||
        REQUIRE(m.size() == 10);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("ctor_bucket_count_map", counter::obj, counter::obj) {
 | 
			
		||||
    {
 | 
			
		||||
        auto m = map_t{};
 | 
			
		||||
        // depends on initial bucket count, could also be 0
 | 
			
		||||
        // REQUIRE(m.bucket_count() == 2U);
 | 
			
		||||
    }
 | 
			
		||||
    {
 | 
			
		||||
        auto m = map_t{150U};
 | 
			
		||||
        REQUIRE(m.bucket_count() == 256U);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_SET("ctor_bucket_count_set", int) {
 | 
			
		||||
    auto m = ankerl::unordered_dense::set<int>{{1, 2, 3, 4}, 300U};
 | 
			
		||||
    REQUIRE(m.size() == 4U);
 | 
			
		||||
    REQUIRE(m.bucket_count() == 512U);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										34
									
								
								third_party/unordered_dense/test/unit/custom_container.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								third_party/unordered_dense/test/unit/custom_container.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
 | 
			
		||||
#include <app/doctest.h>
 | 
			
		||||
 | 
			
		||||
#include <deque>
 | 
			
		||||
 | 
			
		||||
static_assert(
 | 
			
		||||
    ankerl::unordered_dense::detail::is_detected_v<ankerl::unordered_dense::detail::detect_iterator, std::deque<int>>);
 | 
			
		||||
 | 
			
		||||
static_assert(
 | 
			
		||||
    !ankerl::unordered_dense::detail::is_detected_v<ankerl::unordered_dense::detail::detect_iterator, std::allocator<int>>);
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("custom_container",
 | 
			
		||||
              int,
 | 
			
		||||
              std::string,
 | 
			
		||||
              ankerl::unordered_dense::hash<int>,
 | 
			
		||||
              std::equal_to<int>,
 | 
			
		||||
              std::deque<std::pair<int, std::string>>) {
 | 
			
		||||
    auto map = map_t();
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < 10; ++i) {
 | 
			
		||||
        map[i] = std::to_string(i);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    REQUIRE(std::is_same_v<std::deque<std::pair<int, std::string>>, typename map_t::value_container_type>);
 | 
			
		||||
    std::deque<std::pair<int, std::string>> const container = std::move(map).extract();
 | 
			
		||||
 | 
			
		||||
    auto m2 = map_t();
 | 
			
		||||
    // we allow use-after-move
 | 
			
		||||
    m2 = map; // NOLINT(bugprone-use-after-move,hicpp-invalid-access-moved)
 | 
			
		||||
 | 
			
		||||
    auto map2 = map;
 | 
			
		||||
    std::swap(map2, map);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										78
									
								
								third_party/unordered_dense/test/unit/custom_container_boost.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								third_party/unordered_dense/test/unit/custom_container_boost.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,78 @@
 | 
			
		||||
#if ANKERL_UNORDERED_DENSE_HAS_BOOST
 | 
			
		||||
 | 
			
		||||
#    if __clang__
 | 
			
		||||
#        pragma clang diagnostic push
 | 
			
		||||
#        pragma clang diagnostic ignored "-Wold-style-cast"
 | 
			
		||||
#    endif
 | 
			
		||||
#    include <ankerl/unordered_dense.h>
 | 
			
		||||
 | 
			
		||||
#    include <app/doctest.h>
 | 
			
		||||
 | 
			
		||||
#    include <boost/container/vector.hpp>
 | 
			
		||||
#    include <boost/interprocess/allocators/allocator.hpp>
 | 
			
		||||
#    include <boost/interprocess/allocators/node_allocator.hpp>
 | 
			
		||||
#    include <boost/interprocess/containers/vector.hpp>
 | 
			
		||||
#    include <boost/interprocess/managed_shared_memory.hpp>
 | 
			
		||||
 | 
			
		||||
#    include <deque>
 | 
			
		||||
 | 
			
		||||
// Alias an STL-like allocator of ints that allocates ints from the segment
 | 
			
		||||
using shmem_allocator =
 | 
			
		||||
    boost::interprocess::allocator<std::pair<int, std::string>, boost::interprocess::managed_shared_memory::segment_manager>;
 | 
			
		||||
using shmem_vector = boost::interprocess::vector<std::pair<int, std::string>, shmem_allocator>;
 | 
			
		||||
 | 
			
		||||
// Remove shared memory on construction and destruction
 | 
			
		||||
struct shm_remove {
 | 
			
		||||
    shm_remove() {
 | 
			
		||||
        boost::interprocess::shared_memory_object::remove("MySharedMemory");
 | 
			
		||||
    }
 | 
			
		||||
    ~shm_remove() {
 | 
			
		||||
        boost::interprocess::shared_memory_object::remove("MySharedMemory");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    shm_remove(shm_remove const&) = delete;
 | 
			
		||||
    shm_remove(shm_remove&&) = delete;
 | 
			
		||||
    auto operator=(shm_remove const&) -> shm_remove = delete;
 | 
			
		||||
    auto operator=(shm_remove&&) -> shm_remove = delete;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
TYPE_TO_STRING_MAP(int, std::string, ankerl::unordered_dense::hash<int>, std::equal_to<int>, shmem_vector);
 | 
			
		||||
 | 
			
		||||
// See https://www.boost.org/doc/libs/1_80_0/doc/html/interprocess/allocators_containers.html
 | 
			
		||||
TEST_CASE_TEMPLATE(
 | 
			
		||||
    "boost_container_vector",
 | 
			
		||||
    map_t,
 | 
			
		||||
    ankerl::unordered_dense::map<int, std::string, ankerl::unordered_dense::hash<int>, std::equal_to<int>, shmem_vector>,
 | 
			
		||||
    ankerl::unordered_dense::
 | 
			
		||||
        segmented_map<int, std::string, ankerl::unordered_dense::hash<int>, std::equal_to<int>, shmem_allocator>) {
 | 
			
		||||
 | 
			
		||||
    auto remover = shm_remove();
 | 
			
		||||
 | 
			
		||||
    // Create shared memory
 | 
			
		||||
    auto segment = boost::interprocess::managed_shared_memory(boost::interprocess::create_only, "MySharedMemory", 1024 * 1024);
 | 
			
		||||
    auto map = map_t{shmem_allocator{segment.get_segment_manager()}};
 | 
			
		||||
 | 
			
		||||
    int total = 10000;
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < total; ++i) {
 | 
			
		||||
        map.try_emplace(i, std::to_string(i));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    REQUIRE(map.size() == static_cast<size_t>(total));
 | 
			
		||||
    for (int i = 0; i < total; ++i) {
 | 
			
		||||
        auto it = map.find(i);
 | 
			
		||||
        REQUIRE(it != map.end());
 | 
			
		||||
        REQUIRE(it->first == i);
 | 
			
		||||
        REQUIRE(it->second == std::to_string(i));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    map.erase(total + 123);
 | 
			
		||||
    REQUIRE(map.size() == static_cast<size_t>(total));
 | 
			
		||||
    map.erase(29);
 | 
			
		||||
    REQUIRE(map.size() == static_cast<size_t>(total - 1));
 | 
			
		||||
 | 
			
		||||
    map.emplace(std::pair<int, std::string>(9999999, "hello"));
 | 
			
		||||
    REQUIRE(map.size() == static_cast<size_t>(total));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif // ANKERL_UNORDERED_DENSE_HAS_BOOST
 | 
			
		||||
							
								
								
									
										94
									
								
								third_party/unordered_dense/test/unit/custom_hash.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								third_party/unordered_dense/test/unit/custom_hash.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,94 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
 | 
			
		||||
#include <app/doctest.h>
 | 
			
		||||
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
struct id {
 | 
			
		||||
    uint64_t value{}; // NOLINT
 | 
			
		||||
 | 
			
		||||
    auto operator==(id const& other) const -> bool {
 | 
			
		||||
        return value == other.value;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct custom_hash_simple {
 | 
			
		||||
    [[nodiscard]] auto operator()(id const& x) const noexcept -> uint64_t {
 | 
			
		||||
        return x.value;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct custom_hash_avalanching {
 | 
			
		||||
    using is_avalanching = void;
 | 
			
		||||
 | 
			
		||||
    auto operator()(id const& x) const noexcept -> uint64_t {
 | 
			
		||||
        return ankerl::unordered_dense::detail::wyhash::hash(x.value);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct point {
 | 
			
		||||
    int x{}; // NOLINT
 | 
			
		||||
    int y{}; // NOLINT
 | 
			
		||||
 | 
			
		||||
    auto operator==(point const& other) const -> bool {
 | 
			
		||||
        return x == other.x && y == other.y;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct custom_hash_unique_object_representation {
 | 
			
		||||
    using is_avalanching = void;
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] auto operator()(point const& f) const noexcept -> uint64_t {
 | 
			
		||||
        static_assert(std::has_unique_object_representations_v<point>);
 | 
			
		||||
        return ankerl::unordered_dense::detail::wyhash::hash(&f, sizeof(f));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct ankerl::unordered_dense::hash<id> {
 | 
			
		||||
    using is_avalanching = void;
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] auto operator()(id const& x) const noexcept -> uint64_t {
 | 
			
		||||
        return detail::wyhash::hash(x.value);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
TYPE_TO_STRING_SET(id);
 | 
			
		||||
TYPE_TO_STRING_SET(id, custom_hash_simple);
 | 
			
		||||
TYPE_TO_STRING_SET(id, custom_hash_avalanching);
 | 
			
		||||
TYPE_TO_STRING_SET(point, custom_hash_unique_object_representation);
 | 
			
		||||
 | 
			
		||||
TEST_CASE_SET("custom_hash_simple", id, custom_hash_simple) {
 | 
			
		||||
    auto set = set_t();
 | 
			
		||||
    set.insert(id{124});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_SET("custom_hash_avalanching", id, custom_hash_avalanching) {
 | 
			
		||||
    auto set = set_t();
 | 
			
		||||
    set.insert(id{124});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_SET("custom_hash_unique", point, custom_hash_unique_object_representation) {
 | 
			
		||||
    auto set = set_t();
 | 
			
		||||
    set.insert(point{123, 321});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_SET("custom_hash_default", id) {
 | 
			
		||||
    auto set = set_t();
 | 
			
		||||
    set.insert(id{124});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static_assert(
 | 
			
		||||
    !ankerl::unordered_dense::detail::is_detected_v<ankerl::unordered_dense::detail::detect_avalanching, custom_hash_simple>);
 | 
			
		||||
 | 
			
		||||
static_assert(ankerl::unordered_dense::detail::is_detected_v<ankerl::unordered_dense::detail::detect_avalanching,
 | 
			
		||||
                                                             custom_hash_avalanching>);
 | 
			
		||||
static_assert(ankerl::unordered_dense::detail::is_detected_v<ankerl::unordered_dense::detail::detect_avalanching,
 | 
			
		||||
                                                             custom_hash_unique_object_representation>);
 | 
			
		||||
 | 
			
		||||
static_assert(!ankerl::unordered_dense::detail::is_detected_v<ankerl::unordered_dense::detail::detect_avalanching,
 | 
			
		||||
                                                              ankerl::unordered_dense::hash<point>>);
 | 
			
		||||
							
								
								
									
										7
									
								
								third_party/unordered_dense/test/unit/deduction_guides.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								third_party/unordered_dense/test/unit/deduction_guides.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
#include <doctest.h> // for TestCase, skip, TEST_CASE, test_...
 | 
			
		||||
 | 
			
		||||
TEST_CASE("deduction_guide") {
 | 
			
		||||
    // TODO(martinus) not yet possible, only in c++20. See
 | 
			
		||||
    // https://stackoverflow.com/a/41008415
 | 
			
		||||
    // https://en.cppreference.com/w/cpp/language/class_template_argument_deduction
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								third_party/unordered_dense/test/unit/diamond.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								third_party/unordered_dense/test/unit/diamond.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
 | 
			
		||||
#include <app/doctest.h>
 | 
			
		||||
 | 
			
		||||
#include <cstddef> // for size_t
 | 
			
		||||
#include <vector>  // for vector
 | 
			
		||||
 | 
			
		||||
// struct that provides both hash and equals operator
 | 
			
		||||
struct hash_with_equal {
 | 
			
		||||
    auto operator()(int x) const -> size_t {
 | 
			
		||||
        return static_cast<size_t>(x);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto operator()(int a, int b) const -> bool {
 | 
			
		||||
        return a == b;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
TYPE_TO_STRING_MAP(int, int, hash_with_equal, hash_with_equal);
 | 
			
		||||
 | 
			
		||||
// make sure the map works with the same type (check that it handles the diamond problem)
 | 
			
		||||
TEST_CASE_MAP("diamond_problem", int, int, hash_with_equal, hash_with_equal) {
 | 
			
		||||
    auto map = map_t();
 | 
			
		||||
    map[1] = 2;
 | 
			
		||||
    REQUIRE(map.size() == 1);
 | 
			
		||||
    REQUIRE(map.find(1) != map.end());
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										44
									
								
								third_party/unordered_dense/test/unit/empty.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								third_party/unordered_dense/test/unit/empty.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,44 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
 | 
			
		||||
#include <app/doctest.h>
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("empty_map_operations", int, int) {
 | 
			
		||||
    map_t m;
 | 
			
		||||
 | 
			
		||||
    REQUIRE(m.end() == m.find(123));
 | 
			
		||||
    REQUIRE(m.end() == m.begin());
 | 
			
		||||
    m[32];
 | 
			
		||||
    REQUIRE(m.end() != m.begin());
 | 
			
		||||
    REQUIRE(m.end() == m.find(123));
 | 
			
		||||
    REQUIRE(m.end() != m.find(32));
 | 
			
		||||
 | 
			
		||||
    m = map_t();
 | 
			
		||||
    REQUIRE(m.end() == m.begin());
 | 
			
		||||
    REQUIRE(m.end() == m.find(123));
 | 
			
		||||
    REQUIRE(m.end() == m.find(32));
 | 
			
		||||
 | 
			
		||||
    map_t m2(m);
 | 
			
		||||
    REQUIRE(m2.end() == m2.begin());
 | 
			
		||||
    REQUIRE(m2.end() == m2.find(123));
 | 
			
		||||
    REQUIRE(m2.end() == m2.find(32));
 | 
			
		||||
    m2[32];
 | 
			
		||||
    REQUIRE(m2.end() != m2.begin());
 | 
			
		||||
    REQUIRE(m2.end() == m2.find(123));
 | 
			
		||||
    REQUIRE(m2.end() != m2.find(32));
 | 
			
		||||
 | 
			
		||||
    map_t empty;
 | 
			
		||||
    map_t m3(empty);
 | 
			
		||||
    REQUIRE(m3.end() == m3.begin());
 | 
			
		||||
    REQUIRE(m3.end() == m3.find(123));
 | 
			
		||||
    REQUIRE(m3.end() == m3.find(32));
 | 
			
		||||
    m3[32];
 | 
			
		||||
    REQUIRE(m3.end() != m3.begin());
 | 
			
		||||
    REQUIRE(m3.end() == m3.find(123));
 | 
			
		||||
    REQUIRE(m3.end() != m3.find(32));
 | 
			
		||||
 | 
			
		||||
    map_t m4(std::move(empty));
 | 
			
		||||
    REQUIRE(m4.count(123) == 0);
 | 
			
		||||
    REQUIRE(m4.end() == m4.begin());
 | 
			
		||||
    REQUIRE(m4.end() == m4.find(123));
 | 
			
		||||
    REQUIRE(m4.end() == m4.find(32));
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										34
									
								
								third_party/unordered_dense/test/unit/equal_range.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								third_party/unordered_dense/test/unit/equal_range.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
 | 
			
		||||
#include <app/doctest.h>
 | 
			
		||||
 | 
			
		||||
#include <type_traits> // for add_const_t
 | 
			
		||||
#include <utility>     // for pair, as_const
 | 
			
		||||
#include <vector>      // for vector
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("equal_range", int, int) {
 | 
			
		||||
    auto map = map_t();
 | 
			
		||||
    // auto map = std::unordered_map<int, int>();
 | 
			
		||||
 | 
			
		||||
    auto range = map.equal_range(123);
 | 
			
		||||
    REQUIRE(range.first == map.end());
 | 
			
		||||
    REQUIRE(range.second == map.end());
 | 
			
		||||
 | 
			
		||||
    map.try_emplace(1, 1);
 | 
			
		||||
    range = map.equal_range(123);
 | 
			
		||||
    REQUIRE(range.first == map.end());
 | 
			
		||||
    REQUIRE(range.second == map.end());
 | 
			
		||||
 | 
			
		||||
    int const x = 1;
 | 
			
		||||
    auto const_range = std::as_const(map).equal_range(x);
 | 
			
		||||
    REQUIRE(const_range.first == map.begin());
 | 
			
		||||
    REQUIRE(const_range.second == map.end());
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < 100; ++i) {
 | 
			
		||||
        map.try_emplace(i, i);
 | 
			
		||||
    }
 | 
			
		||||
    range = map.equal_range(50);
 | 
			
		||||
    auto after_first = ++range.first;
 | 
			
		||||
    REQUIRE(range.second == after_first);
 | 
			
		||||
    REQUIRE(range.second != map.end());
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										49
									
								
								third_party/unordered_dense/test/unit/erase.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								third_party/unordered_dense/test/unit/erase.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,49 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
 | 
			
		||||
#include <third-party/nanobench.h>
 | 
			
		||||
 | 
			
		||||
#include <app/doctest.h>
 | 
			
		||||
 | 
			
		||||
#include <algorithm>     // for all_of
 | 
			
		||||
#include <cstddef>       // for size_t
 | 
			
		||||
#include <cstdint>       // for uint32_t
 | 
			
		||||
#include <unordered_set> // for unordered_set, operator!=
 | 
			
		||||
#include <vector>        // for vector
 | 
			
		||||
 | 
			
		||||
template <typename A, typename B>
 | 
			
		||||
[[nodiscard]] auto is_eq(A const& a, B const& b) -> bool {
 | 
			
		||||
    if (a.size() != b.size()) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    return std::all_of(a.begin(), a.end(), [&b](auto const& k) {
 | 
			
		||||
        return b.end() != b.find(k);
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_SET("insert_erase_random", uint32_t) {
 | 
			
		||||
    auto uds = set_t();
 | 
			
		||||
    auto us = std::unordered_set<uint32_t>();
 | 
			
		||||
    auto rng = ankerl::nanobench::Rng(123);
 | 
			
		||||
    for (size_t i = 0; i < 10000; ++i) {
 | 
			
		||||
        auto key = rng.bounded(1000);
 | 
			
		||||
        uds.insert(key);
 | 
			
		||||
        us.insert(key);
 | 
			
		||||
        REQUIRE(uds.size() == us.size());
 | 
			
		||||
 | 
			
		||||
        key = rng.bounded(1000);
 | 
			
		||||
        REQUIRE(uds.erase(key) == us.erase(key));
 | 
			
		||||
        REQUIRE(uds.size() == us.size());
 | 
			
		||||
    }
 | 
			
		||||
    REQUIRE(is_eq(uds, us));
 | 
			
		||||
    auto k = *uds.begin();
 | 
			
		||||
    uds.erase(k);
 | 
			
		||||
    REQUIRE(!is_eq(uds, us));
 | 
			
		||||
    us.erase(k);
 | 
			
		||||
    REQUIRE(is_eq(uds, us));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("erase", int, int) {
 | 
			
		||||
    auto map = ankerl::unordered_dense::map<int, int>();
 | 
			
		||||
    REQUIRE(0 == map.erase(123));
 | 
			
		||||
    REQUIRE(0 == map.count(0));
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										54
									
								
								third_party/unordered_dense/test/unit/erase_if.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								third_party/unordered_dense/test/unit/erase_if.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,54 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
 | 
			
		||||
#include <app/counter.h>
 | 
			
		||||
#include <app/doctest.h>
 | 
			
		||||
 | 
			
		||||
#include <cstddef> // for size_t
 | 
			
		||||
#include <cstdint> // for uint64_t
 | 
			
		||||
#include <utility> // for pair
 | 
			
		||||
 | 
			
		||||
TEST_CASE_SET("erase_if_set", counter::obj) {
 | 
			
		||||
    auto counts = counter();
 | 
			
		||||
    INFO(counts);
 | 
			
		||||
    auto set = set_t();
 | 
			
		||||
 | 
			
		||||
    for (size_t i = 0; i < 1000; ++i) {
 | 
			
		||||
        set.emplace(i, counts);
 | 
			
		||||
    }
 | 
			
		||||
    REQUIRE(set.size() == 1000);
 | 
			
		||||
    auto num_erased = std::erase_if(set, [](counter::obj const& obj) {
 | 
			
		||||
        return 0 == obj.get() % 3;
 | 
			
		||||
    });
 | 
			
		||||
    REQUIRE(num_erased == 334);
 | 
			
		||||
 | 
			
		||||
    REQUIRE(set.size() == 666);
 | 
			
		||||
    for (size_t i = 0; i < 1000; ++i) {
 | 
			
		||||
        if (0 == i % 3) {
 | 
			
		||||
            REQUIRE(!set.contains({i, counts}));
 | 
			
		||||
        } else {
 | 
			
		||||
            REQUIRE(set.contains({i, counts}));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("erase_if_map", uint64_t, uint64_t) {
 | 
			
		||||
    auto map = map_t();
 | 
			
		||||
    for (size_t i = 0; i < 1000; ++i) {
 | 
			
		||||
        map.try_emplace(i, i);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    REQUIRE(map.size() == 1000);
 | 
			
		||||
    auto num_erased = std::erase_if(map, [](std::pair<uint64_t, uint64_t> const& x) {
 | 
			
		||||
        return 0 == x.second % 2;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    REQUIRE(num_erased == 500);
 | 
			
		||||
    REQUIRE(map.size() == 500);
 | 
			
		||||
    for (size_t i = 0; i < 1000; ++i) {
 | 
			
		||||
        if (0 == i % 2) {
 | 
			
		||||
            REQUIRE(!map.contains(i));
 | 
			
		||||
        } else {
 | 
			
		||||
            REQUIRE(map.contains(i));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								third_party/unordered_dense/test/unit/erase_range.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								third_party/unordered_dense/test/unit/erase_range.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
 | 
			
		||||
#include <app/counter.h>
 | 
			
		||||
#include <app/doctest.h>
 | 
			
		||||
#include <third-party/nanobench.h>
 | 
			
		||||
 | 
			
		||||
#include <cstddef> // for size_t
 | 
			
		||||
#include <vector>  // for vector
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("erase_range", counter::obj, counter::obj) {
 | 
			
		||||
    int const num_elements = 10;
 | 
			
		||||
 | 
			
		||||
    for (int first_pos = 0; first_pos <= num_elements; ++first_pos) {
 | 
			
		||||
        for (int last_pos = first_pos; last_pos <= num_elements; ++last_pos) {
 | 
			
		||||
            auto counts = counter();
 | 
			
		||||
            INFO(counts);
 | 
			
		||||
 | 
			
		||||
            auto map = map_t();
 | 
			
		||||
 | 
			
		||||
            for (size_t i = 0; i < num_elements; ++i) {
 | 
			
		||||
                auto key = i;
 | 
			
		||||
                auto val = i * 1000;
 | 
			
		||||
                map.try_emplace({key, counts}, val, counts);
 | 
			
		||||
            }
 | 
			
		||||
            REQUIRE(map.size() == num_elements);
 | 
			
		||||
 | 
			
		||||
            auto it_ret = map.erase(map.cbegin() + first_pos, map.cbegin() + last_pos);
 | 
			
		||||
            REQUIRE(map.size() == static_cast<size_t>(num_elements - (last_pos - first_pos)));
 | 
			
		||||
            REQUIRE(it_ret == map.begin() + first_pos);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										33
									
								
								third_party/unordered_dense/test/unit/explicit.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								third_party/unordered_dense/test/unit/explicit.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
 | 
			
		||||
#include <app/doctest.h>
 | 
			
		||||
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
struct texture {
 | 
			
		||||
    int m_width;
 | 
			
		||||
    int m_height;
 | 
			
		||||
    void* m_data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct per_image {
 | 
			
		||||
    std::unordered_map<void*, texture*> m_texture_index;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename Map>
 | 
			
		||||
struct scene {
 | 
			
		||||
    std::vector<per_image> m_per_image;
 | 
			
		||||
    Map m_textures_per_key;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename Map>
 | 
			
		||||
struct app_state {
 | 
			
		||||
    scene<Map> m_scene;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
TYPE_TO_STRING_MAP(void*, texture*);
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("unit_create_AppState_issue_97", void*, texture*) {
 | 
			
		||||
    app_state<map_t> const app_state{};
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										62
									
								
								third_party/unordered_dense/test/unit/extract.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								third_party/unordered_dense/test/unit/extract.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,62 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
 | 
			
		||||
#include <app/counter.h>
 | 
			
		||||
#include <app/doctest.h>
 | 
			
		||||
 | 
			
		||||
#include <fmt/format.h>
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("extract", counter::obj, counter::obj) {
 | 
			
		||||
    auto counts = counter();
 | 
			
		||||
    INFO(counts);
 | 
			
		||||
 | 
			
		||||
    auto container = typename map_t::value_container_type();
 | 
			
		||||
    {
 | 
			
		||||
        auto map = map_t();
 | 
			
		||||
 | 
			
		||||
        for (size_t i = 0; i < 100; ++i) {
 | 
			
		||||
            map.try_emplace(counter::obj{i, counts}, i, counts);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        container = std::move(map).extract();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    REQUIRE(container.size() == 100U);
 | 
			
		||||
    for (size_t i = 0; i < container.size(); ++i) {
 | 
			
		||||
        REQUIRE(container[i].first.get() == i);
 | 
			
		||||
        REQUIRE(container[i].second.get() == i);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("extract_element", counter::obj, counter::obj) {
 | 
			
		||||
    auto counts = counter();
 | 
			
		||||
    INFO(counts);
 | 
			
		||||
 | 
			
		||||
    counts("init");
 | 
			
		||||
    auto map = map_t();
 | 
			
		||||
    for (size_t i = 0; i < 100; ++i) {
 | 
			
		||||
        map.try_emplace(counter::obj{i, counts}, i, counts);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // extract(key)
 | 
			
		||||
    for (size_t i = 0; i < 20; ++i) {
 | 
			
		||||
        auto query = counter::obj{i, counts};
 | 
			
		||||
        counts("before remove 1");
 | 
			
		||||
        auto opt = map.extract(query);
 | 
			
		||||
        counts("after remove 1");
 | 
			
		||||
        REQUIRE(opt);
 | 
			
		||||
        REQUIRE(opt->first.get() == i);
 | 
			
		||||
        REQUIRE(opt->second.get() == i);
 | 
			
		||||
    }
 | 
			
		||||
    REQUIRE(map.size() == 80);
 | 
			
		||||
 | 
			
		||||
    // extract iterator
 | 
			
		||||
    for (size_t i = 20; i < 100; ++i) {
 | 
			
		||||
        auto query = counter::obj{i, counts};
 | 
			
		||||
        auto it = map.find(query);
 | 
			
		||||
        REQUIRE(it != map.end());
 | 
			
		||||
        auto opt = map.extract(it);
 | 
			
		||||
        REQUIRE(opt.first.get() == i);
 | 
			
		||||
        REQUIRE(opt.second.get() == i);
 | 
			
		||||
    }
 | 
			
		||||
    REQUIRE(map.empty());
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										121
									
								
								third_party/unordered_dense/test/unit/fuzz_api.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								third_party/unordered_dense/test/unit/fuzz_api.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,121 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
#include <app/doctest.h>
 | 
			
		||||
#include <fuzz/provider.h>
 | 
			
		||||
#include <fuzz/run.h>
 | 
			
		||||
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
 | 
			
		||||
template <typename Map>
 | 
			
		||||
void do_fuzz_api(fuzz::provider p) {
 | 
			
		||||
    auto counts = counter();
 | 
			
		||||
    auto map = Map();
 | 
			
		||||
    p.repeat_oneof(
 | 
			
		||||
        [&] {
 | 
			
		||||
            auto key = p.integral<size_t>();
 | 
			
		||||
            auto it = map.try_emplace(counter::obj(key, counts), counter::obj(key, counts)).first;
 | 
			
		||||
            REQUIRE(it != map.end());
 | 
			
		||||
            REQUIRE(it->first.get() == key);
 | 
			
		||||
        },
 | 
			
		||||
        [&] {
 | 
			
		||||
            auto key = p.integral<size_t>();
 | 
			
		||||
            map.emplace(std::piecewise_construct, std::forward_as_tuple(key, counts), std::forward_as_tuple(key + 77, counts));
 | 
			
		||||
        },
 | 
			
		||||
        [&] {
 | 
			
		||||
            auto key = p.integral<size_t>();
 | 
			
		||||
            map[counter::obj(key, counts)] = counter::obj(key + 123, counts);
 | 
			
		||||
        },
 | 
			
		||||
        [&] {
 | 
			
		||||
            auto key = p.integral<size_t>();
 | 
			
		||||
            map.insert(std::pair<counter::obj, counter::obj>(counter::obj(key, counts), counter::obj(key, counts)));
 | 
			
		||||
        },
 | 
			
		||||
        [&] {
 | 
			
		||||
            auto key = p.integral<size_t>();
 | 
			
		||||
            map.insert_or_assign(counter::obj(key, counts), counter::obj(key + 1, counts));
 | 
			
		||||
        },
 | 
			
		||||
        [&] {
 | 
			
		||||
            auto key = p.integral<size_t>();
 | 
			
		||||
            map.erase(counter::obj(key, counts));
 | 
			
		||||
        },
 | 
			
		||||
        [&] {
 | 
			
		||||
            map = Map{};
 | 
			
		||||
        },
 | 
			
		||||
        [&] {
 | 
			
		||||
            auto m = Map{};
 | 
			
		||||
            m.swap(map);
 | 
			
		||||
        },
 | 
			
		||||
        [&] {
 | 
			
		||||
            map.clear();
 | 
			
		||||
        },
 | 
			
		||||
        [&] {
 | 
			
		||||
            auto s = p.bounded<size_t>(1025);
 | 
			
		||||
            map.rehash(s);
 | 
			
		||||
        },
 | 
			
		||||
        [&] {
 | 
			
		||||
            auto s = p.bounded<size_t>(1025);
 | 
			
		||||
            map.reserve(s);
 | 
			
		||||
        },
 | 
			
		||||
        [&] {
 | 
			
		||||
            auto key = p.integral<size_t>();
 | 
			
		||||
            auto it = map.find(counter::obj(key, counts));
 | 
			
		||||
            auto d = std::distance(map.begin(), it);
 | 
			
		||||
            REQUIRE(0 <= d);
 | 
			
		||||
            REQUIRE(d <= static_cast<std::ptrdiff_t>(map.size()));
 | 
			
		||||
        },
 | 
			
		||||
        [&] {
 | 
			
		||||
            if (!map.empty()) {
 | 
			
		||||
                auto idx = p.bounded(static_cast<int>(map.size()));
 | 
			
		||||
                auto it = map.cbegin() + idx;
 | 
			
		||||
                auto const& key = it->first;
 | 
			
		||||
                auto found_it = map.find(key);
 | 
			
		||||
                REQUIRE(it == found_it);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        [&] {
 | 
			
		||||
            if (!map.empty()) {
 | 
			
		||||
                auto it = map.begin() + p.bounded(static_cast<int>(map.size()));
 | 
			
		||||
                map.erase(it);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        [&] {
 | 
			
		||||
            auto tmp = Map();
 | 
			
		||||
            std::swap(tmp, map);
 | 
			
		||||
        },
 | 
			
		||||
        [&] {
 | 
			
		||||
            map = std::initializer_list<std::pair<counter::obj, counter::obj>>{
 | 
			
		||||
                {{1, counts}, {2, counts}},
 | 
			
		||||
                {{3, counts}, {4, counts}},
 | 
			
		||||
                {{5, counts}, {6, counts}},
 | 
			
		||||
            };
 | 
			
		||||
            REQUIRE(map.size() == 3);
 | 
			
		||||
        },
 | 
			
		||||
        [&] {
 | 
			
		||||
            auto first_idx = 0;
 | 
			
		||||
            auto last_idx = 0;
 | 
			
		||||
            if (!map.empty()) {
 | 
			
		||||
                first_idx = p.bounded(static_cast<int>(map.size()));
 | 
			
		||||
                last_idx = p.bounded(static_cast<int>(map.size()));
 | 
			
		||||
                if (first_idx > last_idx) {
 | 
			
		||||
                    std::swap(first_idx, last_idx);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            map.erase(map.cbegin() + first_idx, map.cbegin() + last_idx);
 | 
			
		||||
        },
 | 
			
		||||
        [&] {
 | 
			
		||||
            map.~Map();
 | 
			
		||||
            counts.check_all_done();
 | 
			
		||||
            new (&map) Map();
 | 
			
		||||
        },
 | 
			
		||||
        [&] {
 | 
			
		||||
            std::erase_if(map, [&](typename Map::value_type const& /*v*/) {
 | 
			
		||||
                return p.integral<bool>();
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("fuzz_api" * doctest::test_suite("fuzz")) {
 | 
			
		||||
    fuzz::run([](fuzz::provider p) {
 | 
			
		||||
        do_fuzz_api<ankerl::unordered_dense::map<counter::obj, counter::obj>>(p.copy());
 | 
			
		||||
        do_fuzz_api<ankerl::unordered_dense::segmented_map<counter::obj, counter::obj>>(p.copy());
 | 
			
		||||
        do_fuzz_api<deque_map<counter::obj, counter::obj>>(p.copy());
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										52
									
								
								third_party/unordered_dense/test/unit/fuzz_insert_erase.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								third_party/unordered_dense/test/unit/fuzz_insert_erase.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,52 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
#include <fuzz/run.h>
 | 
			
		||||
 | 
			
		||||
#include <app/doctest.h>
 | 
			
		||||
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
// Using DummyHash to make it easier for the fuzzer
 | 
			
		||||
struct dummy_hash {
 | 
			
		||||
    using is_avalanching = void;
 | 
			
		||||
 | 
			
		||||
    auto operator()(uint64_t x) const noexcept -> size_t {
 | 
			
		||||
        return static_cast<size_t>(x);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename Map>
 | 
			
		||||
void insert_erase(fuzz::provider p) {
 | 
			
		||||
    auto ank = Map();
 | 
			
		||||
    auto ref = std::unordered_map<uint64_t, uint64_t>();
 | 
			
		||||
 | 
			
		||||
    auto c = uint64_t();
 | 
			
		||||
    while (p.has_remaining_bytes()) {
 | 
			
		||||
        auto key = p.integral<uint64_t>();
 | 
			
		||||
        ank[key] = c;
 | 
			
		||||
        ref[key] = c;
 | 
			
		||||
        ++c;
 | 
			
		||||
 | 
			
		||||
        key = p.integral<uint64_t>();
 | 
			
		||||
        REQUIRE(ank.erase(key) == ref.erase(key));
 | 
			
		||||
        REQUIRE(ank.size() == ref.size());
 | 
			
		||||
    }
 | 
			
		||||
    auto cpy = std::unordered_map(ank.begin(), ank.end());
 | 
			
		||||
    REQUIRE(cpy == ref);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
TEST_CASE("fuzz_insert_erase" * doctest::test_suite("fuzz")) {
 | 
			
		||||
    fuzz::run([](fuzz::provider p) {
 | 
			
		||||
        // try all 3 different map styles with the same input
 | 
			
		||||
        insert_erase<ankerl::unordered_dense::map<uint64_t, uint64_t, dummy_hash>>(p.copy());
 | 
			
		||||
        insert_erase<ankerl::unordered_dense::segmented_map<uint64_t, uint64_t, dummy_hash>>(p.copy());
 | 
			
		||||
        insert_erase<ankerl::unordered_dense::map<uint64_t,
 | 
			
		||||
                                                  uint64_t,
 | 
			
		||||
                                                  ankerl::unordered_dense::hash<uint64_t>,
 | 
			
		||||
                                                  std::equal_to<uint64_t>,
 | 
			
		||||
                                                  std::deque<std::pair<uint64_t, uint64_t>>>>(p.copy());
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										71
									
								
								third_party/unordered_dense/test/unit/fuzz_replace_map.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								third_party/unordered_dense/test/unit/fuzz_replace_map.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,71 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
#include <app/doctest.h>
 | 
			
		||||
#include <fuzz/run.h>
 | 
			
		||||
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
template <typename Map>
 | 
			
		||||
void replace_map(fuzz::provider p) {
 | 
			
		||||
    auto counts = counter{};
 | 
			
		||||
 | 
			
		||||
    using map_t = Map;
 | 
			
		||||
 | 
			
		||||
    auto initial_size = p.bounded<size_t>(100);
 | 
			
		||||
    auto map = map_t{};
 | 
			
		||||
    for (size_t i = 0; i < initial_size; ++i) {
 | 
			
		||||
        map.try_emplace(counter::obj{i, counts}, counter::obj{i, counts});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // create a container with data in it provided by fuzzer
 | 
			
		||||
    auto container = typename map_t::value_container_type{};
 | 
			
		||||
    auto comparison_container = std::vector<std::pair<size_t, size_t>>();
 | 
			
		||||
    auto v = size_t{};
 | 
			
		||||
    while (p.has_remaining_bytes()) {
 | 
			
		||||
        auto key = p.integral<size_t>();
 | 
			
		||||
        container.emplace_back(counter::obj{key, counts}, counter::obj{v, counts});
 | 
			
		||||
        comparison_container.emplace_back(key, v);
 | 
			
		||||
        ++v;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // create comparison map with the same move-back-forward algorithm
 | 
			
		||||
    auto comparison_map = std::unordered_map<size_t, size_t>{};
 | 
			
		||||
    size_t idx = 0;
 | 
			
		||||
    while (idx != comparison_container.size()) {
 | 
			
		||||
        auto [key, val] = comparison_container[idx];
 | 
			
		||||
        if (comparison_map.try_emplace(key, val).second) {
 | 
			
		||||
            ++idx;
 | 
			
		||||
        } else {
 | 
			
		||||
            comparison_container[idx] = comparison_container.back();
 | 
			
		||||
            comparison_container.pop_back();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    map.replace(std::move(container));
 | 
			
		||||
 | 
			
		||||
    // now check if the data in the map is exactly what we expect
 | 
			
		||||
    REQUIRE(map.size() == comparison_map.size());
 | 
			
		||||
    for (auto [key, val] : comparison_map) {
 | 
			
		||||
        auto key_obj = counter::obj{key, counts};
 | 
			
		||||
        auto val_obj = counter::obj{val, counts};
 | 
			
		||||
        auto it = map.find(key_obj);
 | 
			
		||||
        REQUIRE(it != map.end());
 | 
			
		||||
        REQUIRE(it->first == key_obj);
 | 
			
		||||
        REQUIRE(it->second == val_obj);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
TEST_CASE("fuzz_replace_map" * doctest::test_suite("fuzz")) {
 | 
			
		||||
    fuzz::run([](fuzz::provider p) {
 | 
			
		||||
        replace_map<ankerl::unordered_dense::map<counter::obj, counter::obj>>(p.copy());
 | 
			
		||||
        replace_map<ankerl::unordered_dense::segmented_map<counter::obj, counter::obj>>(p.copy());
 | 
			
		||||
        replace_map<ankerl::unordered_dense::map<counter::obj,
 | 
			
		||||
                                                 counter::obj,
 | 
			
		||||
                                                 ankerl::unordered_dense::hash<counter::obj>,
 | 
			
		||||
                                                 std::equal_to<counter::obj>,
 | 
			
		||||
                                                 std::deque<std::pair<counter::obj, counter::obj>>>>(p.copy());
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										53
									
								
								third_party/unordered_dense/test/unit/fuzz_string.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								third_party/unordered_dense/test/unit/fuzz_string.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,53 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
#include <fuzz/provider.h>
 | 
			
		||||
#include <fuzz/run.h>
 | 
			
		||||
 | 
			
		||||
#include <app/doctest.h>
 | 
			
		||||
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
template <typename Map>
 | 
			
		||||
void do_string(fuzz::provider p) {
 | 
			
		||||
    auto ank = Map();
 | 
			
		||||
    auto ref = std::unordered_map<std::string, std::string>();
 | 
			
		||||
 | 
			
		||||
    while (p.has_remaining_bytes()) {
 | 
			
		||||
        auto str = p.string(32);
 | 
			
		||||
        REQUIRE(ank.try_emplace(str, "hello!").second == ref.try_emplace(str, "hello!").second);
 | 
			
		||||
 | 
			
		||||
        str = p.string(32);
 | 
			
		||||
        auto it_ank = ank.find(str);
 | 
			
		||||
        auto it_ref = ref.find(str);
 | 
			
		||||
        REQUIRE((it_ank == ank.end()) == (it_ref == ref.end()));
 | 
			
		||||
 | 
			
		||||
        if (it_ank != ank.end()) {
 | 
			
		||||
            ank.erase(it_ank);
 | 
			
		||||
            ref.erase(it_ref);
 | 
			
		||||
        }
 | 
			
		||||
        REQUIRE(ank.size() == ref.size());
 | 
			
		||||
 | 
			
		||||
        str = p.string(32);
 | 
			
		||||
        REQUIRE(ank.try_emplace(str, "huh").second == ref.try_emplace(str, "huh").second);
 | 
			
		||||
 | 
			
		||||
        str = p.string(32);
 | 
			
		||||
        REQUIRE(ank.erase(str) == ref.erase(str));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    REQUIRE(std::unordered_map(ank.begin(), ank.end()) == ref);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
TEST_CASE("fuzz_string" * doctest::test_suite("fuzz")) {
 | 
			
		||||
    fuzz::run([](fuzz::provider p) {
 | 
			
		||||
        do_string<ankerl::unordered_dense::map<std::string, std::string>>(p.copy());
 | 
			
		||||
        do_string<ankerl::unordered_dense::segmented_map<std::string, std::string>>(p.copy());
 | 
			
		||||
        do_string<ankerl::unordered_dense::map<std::string,
 | 
			
		||||
                                               std::string,
 | 
			
		||||
                                               ankerl::unordered_dense::hash<std::string>,
 | 
			
		||||
                                               std::equal_to<std::string>,
 | 
			
		||||
                                               std::deque<std::pair<std::string, std::string>>>>(p.copy());
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								third_party/unordered_dense/test/unit/hash.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								third_party/unordered_dense/test/unit/hash.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
 | 
			
		||||
#include <doctest.h> // for ResultBuilder, TestCase, REQUIRE
 | 
			
		||||
 | 
			
		||||
#include <cstddef>       // for size_t
 | 
			
		||||
#include <cstdint>       // for uint64_t
 | 
			
		||||
#include <string>        // for string, basic_string
 | 
			
		||||
#include <unordered_set> // for unordered_set
 | 
			
		||||
 | 
			
		||||
TEST_CASE("hash_string") {
 | 
			
		||||
    auto h = ankerl::unordered_dense::hash<std::string>();
 | 
			
		||||
 | 
			
		||||
    auto set = std::unordered_set<uint64_t>();
 | 
			
		||||
    auto str = std::string();
 | 
			
		||||
    for (size_t l = 0; l < 100; ++l) {
 | 
			
		||||
        set.insert(h(str));
 | 
			
		||||
        str.push_back('x');
 | 
			
		||||
    }
 | 
			
		||||
    REQUIRE(set.size() == 100);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										6
									
								
								third_party/unordered_dense/test/unit/hash_char_types.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								third_party/unordered_dense/test/unit/hash_char_types.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
			
		||||
#include <doctest.h>
 | 
			
		||||
 | 
			
		||||
TEST_CASE("hash_char_types") {
 | 
			
		||||
    // TODO(martinus) make hash generic?
 | 
			
		||||
    // REQUIRE(123 != ankerl::hash<wchar_t>{}(123));
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								third_party/unordered_dense/test/unit/hash_smart_ptr.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								third_party/unordered_dense/test/unit/hash_smart_ptr.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
 | 
			
		||||
#include <doctest.h> // for ResultBuilder, TestCase, REQUIRE
 | 
			
		||||
 | 
			
		||||
#include <cstdint>     // for uint64_t
 | 
			
		||||
#include <memory>      // for shared_ptr, __unique_ptr_t, make...
 | 
			
		||||
#include <type_traits> // for declval
 | 
			
		||||
 | 
			
		||||
template <typename Ptr>
 | 
			
		||||
void check(Ptr const& ptr) {
 | 
			
		||||
    REQUIRE(ankerl::unordered_dense::hash<Ptr>{}(ptr) ==
 | 
			
		||||
            ankerl::unordered_dense::hash<decltype(std::declval<Ptr>().get())>{}(ptr.get()));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("hash_smart_ptr") {
 | 
			
		||||
    check(std::unique_ptr<uint64_t>{});
 | 
			
		||||
    check(std::shared_ptr<uint64_t>{});
 | 
			
		||||
    check(std::make_shared<uint64_t>(123U));
 | 
			
		||||
    check(std::make_unique<uint64_t>(123U));
 | 
			
		||||
    check(std::make_unique<uint64_t>(uint64_t{123U}));
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								third_party/unordered_dense/test/unit/hash_string_view.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								third_party/unordered_dense/test/unit/hash_string_view.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
 | 
			
		||||
#include <doctest.h>
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <string_view>
 | 
			
		||||
 | 
			
		||||
TEST_CASE("hash_string_view") {
 | 
			
		||||
    auto const* cstr = "The ships hung in the sky in much the same way that bricks don't.";
 | 
			
		||||
    REQUIRE(ankerl::unordered_dense::hash<std::string>{}(std::string{cstr}) ==
 | 
			
		||||
            ankerl::unordered_dense::hash<std::string_view>{}(std::string_view{cstr}));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("unit_hash_u32string") {
 | 
			
		||||
    auto str = std::u32string{};
 | 
			
		||||
    str.push_back(1);
 | 
			
		||||
    str.push_back(2);
 | 
			
		||||
    str.push_back(3);
 | 
			
		||||
    str.push_back(4);
 | 
			
		||||
    str.push_back(5);
 | 
			
		||||
 | 
			
		||||
    REQUIRE(ankerl::unordered_dense::hash<std::u32string>{}(str) == ankerl::unordered_dense::hash<std::u32string_view>{}(str));
 | 
			
		||||
    REQUIRE(ankerl::unordered_dense::hash<std::u32string>{}(str) != std::hash<std::u32string>{}(str));
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								third_party/unordered_dense/test/unit/include_only.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								third_party/unordered_dense/test/unit/include_only.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
							
								
								
									
										81
									
								
								third_party/unordered_dense/test/unit/initializer_list.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								third_party/unordered_dense/test/unit/initializer_list.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,81 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
 | 
			
		||||
#include <app/doctest.h>
 | 
			
		||||
 | 
			
		||||
#include <cstddef>     // for size_t
 | 
			
		||||
#include <string>      // for string, operator==, allocator
 | 
			
		||||
#include <string_view> // for basic_string_view, operator""sv
 | 
			
		||||
#include <utility>     // for pair
 | 
			
		||||
#include <vector>      // for vector
 | 
			
		||||
 | 
			
		||||
using namespace std::literals;
 | 
			
		||||
 | 
			
		||||
template <class Map, class First, class Second>
 | 
			
		||||
auto has(Map const& map, First const& first, Second const& second) -> bool {
 | 
			
		||||
    auto it = map.find(first);
 | 
			
		||||
    return it != map.end() && it->second == second;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("insert_initializer_list", int, int) {
 | 
			
		||||
    auto m = map_t();
 | 
			
		||||
    m.insert({{1, 2}, {3, 4}, {5, 6}});
 | 
			
		||||
    REQUIRE(m.size() == 3U);
 | 
			
		||||
    REQUIRE(m[1] == 2);
 | 
			
		||||
    REQUIRE(m[3] == 4);
 | 
			
		||||
    REQUIRE(m[5] == 6);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("initializerlist_string", std::string, size_t) {
 | 
			
		||||
    size_t const n1 = 17;
 | 
			
		||||
    size_t const n2 = 10;
 | 
			
		||||
 | 
			
		||||
    auto m1 = map_t{{"duck", n1}, {"lion", n2}};
 | 
			
		||||
    auto m2 = map_t{{"duck", n1}, {"lion", n2}};
 | 
			
		||||
 | 
			
		||||
    REQUIRE(m1.size() == 2);
 | 
			
		||||
    REQUIRE(m1["duck"] == n1);
 | 
			
		||||
    REQUIRE(m1["lion"] == n2);
 | 
			
		||||
 | 
			
		||||
    REQUIRE(m2.size() == 2);
 | 
			
		||||
    auto it = m2.find("duck");
 | 
			
		||||
    REQUIRE((it != m2.end() && it->second == n1));
 | 
			
		||||
    REQUIRE(m2["lion"] == n2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("insert_initializer_list_string", int, std::string) {
 | 
			
		||||
    auto m = map_t();
 | 
			
		||||
    m.insert({{1, "a"}, {3, "b"}, {5, "c"}});
 | 
			
		||||
    REQUIRE(m.size() == 3U);
 | 
			
		||||
    REQUIRE(m[1] == "a");
 | 
			
		||||
    REQUIRE(m[3] == "b");
 | 
			
		||||
    REQUIRE(m[5] == "c");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("initializer_list_assign", int, char const*) {
 | 
			
		||||
    auto map = map_t();
 | 
			
		||||
    map[3] = "nope";
 | 
			
		||||
    map = {{1, "a"}, {2, "hello"}, {12346, "world!"}};
 | 
			
		||||
    REQUIRE(map.size() == 3);
 | 
			
		||||
    REQUIRE(has(map, 1, "a"sv));
 | 
			
		||||
    REQUIRE(has(map, 2, "hello"sv));
 | 
			
		||||
    REQUIRE(has(map, 12346, "world!"sv));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("initializer_list_ctor_alloc", int, char const*) {
 | 
			
		||||
    using alloc_t = std::allocator<std::pair<int, char const*>>;
 | 
			
		||||
    auto map = map_t({{1, "a"}, {2, "hello"}, {12346, "world!"}}, 0, alloc_t{});
 | 
			
		||||
    REQUIRE(map.size() == 3);
 | 
			
		||||
    REQUIRE(has(map, 1, "a"sv));
 | 
			
		||||
    REQUIRE(has(map, 2, "hello"sv));
 | 
			
		||||
    REQUIRE(has(map, 12346, "world!"sv));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("initializer_list_ctor_hash_alloc", int, char const*) {
 | 
			
		||||
    using hash_t = ankerl::unordered_dense::hash<int>;
 | 
			
		||||
    using alloc_t = std::allocator<std::pair<int, char const*>>;
 | 
			
		||||
    auto map = map_t({{1, "a"}, {2, "hello"}, {12346, "world!"}}, 0, hash_t{}, alloc_t{});
 | 
			
		||||
    REQUIRE(map.size() == 3);
 | 
			
		||||
    REQUIRE(has(map, 1, "a"sv));
 | 
			
		||||
    REQUIRE(has(map, 2, "hello"sv));
 | 
			
		||||
    REQUIRE(has(map, 12346, "world!"sv));
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										36
									
								
								third_party/unordered_dense/test/unit/insert.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								third_party/unordered_dense/test/unit/insert.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,36 @@
 | 
			
		||||
#include <ankerl/unordered_dense.h>
 | 
			
		||||
 | 
			
		||||
#include <app/doctest.h>
 | 
			
		||||
 | 
			
		||||
#include <tuple>   // for forward_as_tuple
 | 
			
		||||
#include <utility> // for piecewise_construct
 | 
			
		||||
#include <vector>  // for vector
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("insert", unsigned int, int) {
 | 
			
		||||
    auto map = map_t();
 | 
			
		||||
    auto const val = typename map_t::value_type(123U, 321);
 | 
			
		||||
    map.insert(val);
 | 
			
		||||
    REQUIRE(map.size() == 1);
 | 
			
		||||
 | 
			
		||||
    REQUIRE(map[123U] == 321);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE_MAP("insert_hint", unsigned int, int) {
 | 
			
		||||
    auto map = map_t();
 | 
			
		||||
    auto it = map.insert(map.begin(), {1, 2});
 | 
			
		||||
 | 
			
		||||
    auto vt = typename decltype(map)::value_type{3, 4};
 | 
			
		||||
    map.insert(it, vt);
 | 
			
		||||
    REQUIRE(map.size() == 2);
 | 
			
		||||
    REQUIRE(map[1] == 2);
 | 
			
		||||
    REQUIRE(map[3] == 4);
 | 
			
		||||
 | 
			
		||||
    auto const vt2 = typename decltype(map)::value_type{10, 11};
 | 
			
		||||
    map.insert(it, vt2);
 | 
			
		||||
    REQUIRE(map.size() == 3);
 | 
			
		||||
    REQUIRE(map[10] == 11);
 | 
			
		||||
 | 
			
		||||
    it = map.emplace_hint(it, std::piecewise_construct, std::forward_as_tuple(123), std::forward_as_tuple(321));
 | 
			
		||||
    REQUIRE(map.size() == 4);
 | 
			
		||||
    REQUIRE(map[123] == 321);
 | 
			
		||||
}
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue
	
	Block a user