Compare commits

..

30 Commits

Author SHA1 Message Date
joaquintides 669918498c run npm audit fix (#346) 2026-04-08 16:54:24 +02:00
Braden Ganetsky f1e2fa38b0 Fix issue with constructing an FOA container from a class with a template conversion operator (#334)
* Add missing compile-only tests in CMake

* Rewrite the FOA containers' CFOA constructors so that a class with a template conversion operator does not instantiate the CFOA container

* Rewrite the CFOA containers' FOA constructors so that a class with a template conversion operator does not instantiate the FOA container
2026-03-12 16:29:30 +01:00
joaquintides 4fd90dc706 fixed https://nvd.nist.gov/vuln/detail/CVE-2026-27903 (#345) 2026-03-06 10:35:06 +01:00
joaquintides b00e7c4624 fixed cfoa range insert functions to return the number of elements inserted instead of the size of the input range (#344)
* fixed cfoa range insert functions to return the number of elements inserted instead of the size of the input range

* avoided variable shadowing

* fixed calculation error in test

* updated release notes
2026-02-14 18:08:20 +01:00
Braden Ganetsky df2dfe6140 Fix GDB pretty-printers to work with GCC and C++26 (#342) 2026-01-27 20:47:24 +01:00
Peter Dimov 08aa7fe1c3 Update test/cmake_subdir_test 2026-01-23 17:12:01 +02:00
Peter Dimov 33169aaf41 Merge pull request #341 from Lastique/feature/remove_static_assert
Remove dependencies on Boost.StaticAssert
2026-01-23 17:08:41 +02:00
Andrey Semashev ba00d17236 Remove dependencies on Boost.StaticAssert.
Boost.StaticAssert has been merged into Boost.Config, so remove
the dependency.
2026-01-22 19:38:52 +03:00
joaquintides 83395442ab fixed some issues with doc building (#339)
* added cleanup_node_modules_ to target boostrelease

* removed antora_docs.sh
2026-01-08 13:17:05 +01:00
joaquintides d60d9069f0 improved cleanup-node-modules (#337) 2026-01-05 13:15:31 +01:00
Peter Dimov 597276dd9a Fix -Wundef warning in transparent_tests.cpp 2026-01-05 05:26:25 +02:00
Peter Dimov 86521cc4a4 Enable -Wundef in test/Jamfile.v2 2026-01-05 05:26:25 +02:00
Sam Darwin c09d52fe84 Docs: download extension (#332) 2026-01-04 11:18:49 +01:00
joaquintides af47772876 simplified doc/Jamfile.v2 (#336) 2026-01-03 16:50:37 +01:00
Peter Dimov 719e77f113 Merge pull request #317 from boostorg/cmake
Mark natvis file as PUBLIC in CMakeLists.txt
2026-01-01 22:00:48 +02:00
Peter Dimov 8d68f6d22b Merge branch 'feature/gha' into develop 2026-01-01 21:59:24 +02:00
joaquintides c5cd88e2a8 solved https://www.cve.org/CVERecord?id=CVE-2025-64718 (#335) 2026-01-01 19:50:07 +01:00
Peter Dimov 665371e6da Check __cpp_aligned_new in test/helpers/pmr.hpp before using std::align_val_t 2026-01-01 19:25:00 +02:00
Peter Dimov c70208609e Add clang-19, clang-20, macos-26 to ci.yml. Replace macos-13 with macos-latest. 2026-01-01 15:20:55 +02:00
Braden Ganetsky 009bd32c3d Mark natvis file as PUBLIC in CMakeLists.txt, mirroring the CMake in Boost.Assert 2025-12-31 17:46:15 -06:00
joaquintides 11e05a3c4c updated package-lock.json (#328) 2025-10-21 20:47:01 +02:00
joaquintides e9ca2a2def added /doc/html/unordered.html redirect (#327)
* added /doc/html/unordered.html redirect
* added trailing newline
2025-10-20 09:04:57 +02:00
joaquintides 9c8da06481 raised Antora version requirements (#326) 2025-10-19 17:02:32 +02:00
Peter Dimov e01b7b52a6 BOOST_TEST_THROWS requires a semicolon after https://github.com/boostorg/core/pull/205 2025-10-18 17:53:23 +03:00
Sam Darwin 4ec5cb59cd Drone: llvm apt installation (#323) 2025-10-15 09:40:04 +02:00
joaquintides 09d6416755 made boost::unordered_[multi](map|set)::[const_][local_]iterator instantiable with incomplete value_type (#321)
* made boost::unordered_[multi](map|set)::[const_][local_]iterator instantiable with incomplete value_type
* qualified name to avoid self-definition
2025-10-12 13:14:16 +02:00
joaquintides 4b76ac84ec removed ccache for macos-13 (#320) 2025-10-11 17:49:06 +02:00
Alexander Grund dcc485bcb5 Update Link to regression test matrix in README (#316)
* Update Link to regression test matrix in README

* Use boost.org instead of boost.io
2025-09-19 09:07:03 +02:00
joaquintides cc9a787f14 microoptimized unchecked_countr_zero for GCC/Clang 2025-08-26 17:08:01 +02:00
Braden Ganetsky 6fd63ab727 Fix pretty-printers not working when constexpr variables are optimized away (#315)
* Move unordered_printers.hpp into 'detail', where it should have been from the beginning

This is not a public header. It is only meant to be consumed as a transitive include.

* Store self.table instead of self.val

* Fix pretty-printers not working when constexpr variables are optimized away

Also do a few other things.
* `groups` and `elements` are now stored inside `self`
* `mask`, `n0`, and `n` aren't declared ahead of their first assignment
* Remove trailing whitespace

* Update the generated pretty-printer header
2025-08-22 10:15:49 +02:00
35 changed files with 2445 additions and 1778 deletions
+4 -1
View File
@@ -34,8 +34,9 @@ local linux_pipeline(name, image, environment, packages = "", sources = [], arch
commands:
[
'set -e',
'echo $DRONE_STAGE_MACHINE',
'uname -a',
'wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -',
'curl -sSL --retry 5 https://apt.llvm.org/llvm-snapshot.gpg.key | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/llvm-snapshot.gpg',
] +
(if sources != [] then [ ('apt-add-repository "' + source + '"') for source in sources ] else []) +
(if packages != "" then [ 'apt-get update', 'apt-get -y install ' + packages ] else []) +
@@ -66,6 +67,8 @@ local macos_pipeline(name, environment, xcode_version = "12.2", osx_version = "c
environment: environment + { "DEVELOPER_DIR": "/Applications/Xcode-" + xcode_version + ".app/Contents/Developer" },
commands:
[
'echo $DRONE_STAGE_MACHINE',
'sw_vers',
'uname -a',
'export LIBRARY=' + library,
'./.drone/drone.sh',
+9 -3
View File
@@ -101,6 +101,10 @@ jobs:
- { compiler: 'clang-17', cxxstd: '17,20,2b', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-17 libc++-17-dev libc++abi-17-dev' }
- { compiler: 'clang-18', cxxstd: '11,14', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-18 libc++-18-dev libc++abi-18-dev' }
- { compiler: 'clang-18', cxxstd: '17,20,2b', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-18 libc++-18-dev libc++abi-18-dev' }
- { compiler: 'clang-19', cxxstd: '11,14', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-19 libc++-19-dev libc++abi-19-dev' }
- { compiler: 'clang-19', cxxstd: '17,20,2b', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-19 libc++-19-dev libc++abi-19-dev' }
- { compiler: 'clang-20', cxxstd: '11,14,17', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-20 libc++-20-dev libc++abi-20-dev' }
- { compiler: 'clang-20', cxxstd: '20,23,2c', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-20 libc++-20-dev libc++abi-20-dev' }
# not using libc++ because of https://github.com/llvm/llvm-project/issues/52771
- { name: "clang-18 w/ sanitizers (11,14)", sanitize: yes,
@@ -117,10 +121,12 @@ jobs:
stdlib: libc++, install: 'clang-18 libc++-18-dev libc++abi-18-dev', ccache_key: "tsan" }
# OSX, clang
- { compiler: clang, cxxstd: '11,14,17,20,2b', os: 'macos-13', sanitize: yes, ccache_key: "san1" }
- { compiler: clang, cxxstd: '11,14,17,20,2b', os: 'macos-13', thread-sanitize: yes, targets: 'libs/unordered/test//cfoa_tests', ccache_key: "tsan" }
- { compiler: clang, cxxstd: '11,14,17,20,2b', os: 'macos-latest', sanitize: yes, ccache: no, ccache_key: "san1" }
- { compiler: clang, cxxstd: '11,14,17,20,2b', os: 'macos-latest', thread-sanitize: yes, targets: 'libs/unordered/test//cfoa_tests', ccache: no, ccache_key: "tsan" }
- { compiler: clang, cxxstd: '11,14,17,20,2b', os: 'macos-14' }
- { compiler: clang, cxxstd: '11,14,17,20,2b', os: 'macos-15' }
- { compiler: clang, cxxstd: '11,14,17,20,23,2c', os: 'macos-15' }
- { compiler: clang, cxxstd: '11,14,17,20,23,2c', os: 'macos-26' }
timeout-minutes: 360
# posix (gcc-12 w/ sanitizers is taking longer than 210 minutes
+21 -5
View File
@@ -23,12 +23,28 @@ target_link_libraries(boost_unordered
Boost::throw_exception
)
if(CMAKE_VERSION VERSION_GREATER 3.18 AND CMAKE_GENERATOR MATCHES "Visual Studio")
# Add headers and .natvis to project, for better IDE integration
file(GLOB_RECURSE boost_unordered_IDEFILES CONFIGURE_DEPENDS include/*.hpp)
source_group(TREE ${PROJECT_SOURCE_DIR}/include FILES ${boost_unordered_IDEFILES} PREFIX "Header Files")
list(APPEND boost_unordered_IDEFILES extra/boost_unordered.natvis)
target_sources(boost_unordered PRIVATE ${boost_unordered_IDEFILES})
if(NOT CMAKE_VERSION VERSION_LESS 3.19)
# Using target_sources with PRIVATE or PUBLIC on INTERFACE targets requires 3.19
file(GLOB_RECURSE headers CONFIGURE_DEPENDS include/*.hpp)
target_sources(boost_unordered PRIVATE ${headers})
unset(headers)
if(MSVC)
# Only Visual Studio needs this, but the generator may also be Ninja
target_sources(boost_unordered PUBLIC extra/boost_unordered.natvis)
endif()
# Make IDE project folders match directory structure
get_target_property(sources boost_unordered SOURCES)
source_group(TREE ${PROJECT_SOURCE_DIR} FILES ${sources})
unset(sources)
endif()
+2 -2
View File
@@ -1,7 +1,7 @@
# Boost.Unordered
[![Branch](https://img.shields.io/badge/branch-master-brightgreen.svg)](https://github.com/boostorg/unordered/tree/master) [![CI](https://github.com/boostorg/unordered/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/boostorg/unordered/actions/workflows/ci.yml) [![Drone status](https://img.shields.io/drone/build/boostorg/unordered/master?server=https%3A%2F%2Fdrone.cpp.al&logo=drone&logoColor=%23CCCCCC&label=CI)](https://drone.cpp.al/boostorg/unordered) [![Build status](https://img.shields.io/appveyor/build/cppalliance/unordered/master?logo=appveyor&label=CI)](https://ci.appveyor.com/project/cppalliance/unordered/branch/master) [![codecov](https://codecov.io/gh/boostorg/unordered/branch/master/graph/badge.svg)](https://codecov.io/gh/boostorg/unordered/branch/master) [![Deps](https://img.shields.io/badge/deps-master-brightgreen.svg)](https://pdimov.github.io/boostdep-report/master/unordered.html) [![Documentation](https://img.shields.io/badge/docs-master-brightgreen.svg)](https://www.boost.org/doc/libs/master/libs/unordered/index.html) [![Enter the Matrix](https://img.shields.io/badge/matrix-master-brightgreen.svg)](http://www.boost.org/development/tests/master/developer/unordered.html)<br/>
[![Branch](https://img.shields.io/badge/branch-develop-brightgreen.svg)](https://github.com/boostorg/unordered/tree/develop) [![CI](https://github.com/boostorg/unordered/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/boostorg/unordered/actions/workflows/ci.yml) [![Drone status](https://img.shields.io/drone/build/boostorg/unordered/develop?server=https%3A%2F%2Fdrone.cpp.al&logo=drone&logoColor=%23CCCCCC&label=CI)](https://drone.cpp.al/boostorg/unordered) [![Build status](https://img.shields.io/appveyor/build/cppalliance/unordered/develop?logo=appveyor&label=CI)](https://ci.appveyor.com/project/cppalliance/unordered/branch/develop) [![codecov](https://codecov.io/gh/boostorg/unordered/branch/develop/graph/badge.svg)](https://codecov.io/gh/boostorg/unordered/branch/develop) [![Deps](https://img.shields.io/badge/deps-develop-brightgreen.svg)](https://pdimov.github.io/boostdep-report/develop/unordered.html) [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](https://www.boost.org/doc/libs/develop/libs/unordered/index.html) [![Enter the Matrix](https://img.shields.io/badge/matrix-develop-brightgreen.svg)](http://www.boost.org/development/tests/develop/developer/unordered.html)<br/>
[![Branch](https://img.shields.io/badge/branch-master-brightgreen.svg)](https://github.com/boostorg/unordered/tree/master) [![CI](https://github.com/boostorg/unordered/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/boostorg/unordered/actions/workflows/ci.yml) [![Drone status](https://img.shields.io/drone/build/boostorg/unordered/master?server=https%3A%2F%2Fdrone.cpp.al&logo=drone&logoColor=%23CCCCCC&label=CI)](https://drone.cpp.al/boostorg/unordered) [![Build status](https://img.shields.io/appveyor/build/cppalliance/unordered/master?logo=appveyor&label=CI)](https://ci.appveyor.com/project/cppalliance/unordered/branch/master) [![codecov](https://codecov.io/gh/boostorg/unordered/branch/master/graph/badge.svg)](https://codecov.io/gh/boostorg/unordered/branch/master) [![Deps](https://img.shields.io/badge/deps-master-brightgreen.svg)](https://pdimov.github.io/boostdep-report/master/unordered.html) [![Documentation](https://img.shields.io/badge/docs-master-brightgreen.svg)](https://www.boost.org/doc/libs/master/libs/unordered/index.html) [![Enter the Matrix](https://img.shields.io/badge/matrix-master-brightgreen.svg)](https://regression.boost.org/master/developer/unordered.html)<br/>
[![Branch](https://img.shields.io/badge/branch-develop-brightgreen.svg)](https://github.com/boostorg/unordered/tree/develop) [![CI](https://github.com/boostorg/unordered/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/boostorg/unordered/actions/workflows/ci.yml) [![Drone status](https://img.shields.io/drone/build/boostorg/unordered/develop?server=https%3A%2F%2Fdrone.cpp.al&logo=drone&logoColor=%23CCCCCC&label=CI)](https://drone.cpp.al/boostorg/unordered) [![Build status](https://img.shields.io/appveyor/build/cppalliance/unordered/develop?logo=appveyor&label=CI)](https://ci.appveyor.com/project/cppalliance/unordered/branch/develop) [![codecov](https://codecov.io/gh/boostorg/unordered/branch/develop/graph/badge.svg)](https://codecov.io/gh/boostorg/unordered/branch/develop) [![Deps](https://img.shields.io/badge/deps-develop-brightgreen.svg)](https://pdimov.github.io/boostdep-report/develop/unordered.html) [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](https://www.boost.org/doc/libs/develop/libs/unordered/index.html) [![Enter the Matrix](https://img.shields.io/badge/matrix-develop-brightgreen.svg)](https://regression.boost.org/develop/developer/unordered.html)<br/>
[![BSL 1.0](https://img.shields.io/badge/license-BSL_1.0-blue.svg)](https://www.boost.org/users/license.html) <img alt="C++11 required" src="https://img.shields.io/badge/standard-C%2b%2b11-blue.svg"> <img alt="Header-only library" src="https://img.shields.io/badge/build-header--only-blue.svg">
Boost.Unordered offers a catalog of hash containers with different standards compliance levels, performances and intented usage scenarios:
+14 -43
View File
@@ -1,57 +1,28 @@
import generate ;
# Copyright 2026 Joaquin M Lopez Munoz
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
import path ;
import property-set ;
import virtual-target ;
path-constant HERE : . ;
make html_ : build_antora.sh : @run-script ;
make html/index.html : build_antora.sh : @run-script ;
generate files-to-install : html/index.html : <generating-rule>@delayed-glob ;
install install
: files-to-install
: <location>html
<install-source-root>html/unordered
;
explicit html/index.html files-to-install ;
# this runs the antora script
actions run-script
{
bash $(>)
}
# this globs after its sources are created
rule delayed-glob ( project name : property-set : sources * )
path-constant DOC_DIR : . ;
.node_modules = [ path.join $(DOC_DIR) node_modules ] ;
make cleanup_node_modules_ : html_ : @cleanup-node-modules ;
actions cleanup-node-modules
{
for local src in $(sources)
{
# the next line causes the source to be generated immediately
# and not later (which it normally would)
UPDATE_NOW [ $(src).actualize ] ;
}
# we need to construct the path to the globbed directory;
# this path would be <current-project>/antora
local root = [ path.root html [ $(project).location ] ] ;
local files ;
# actual globbing happens here
for local file in [ path.glob-tree $(root) : * ]
{
# we have to skip directories, because our match expression accepts anything
if [ CHECK_IF_FILE $(file) ]
{
# we construct a list of targets to copy
files += [ virtual-target.from-file $(file:D=) : $(file:D) : $(project) ] ;
}
}
# we prepend empty usage requirements to the result
return [ property-set.empty ] $(files) ;
rm -rf $(.node_modules)
}
###############################################################################
alias boostdoc ;
explicit boostdoc ;
alias boostrelease : install ;
explicit boostrelease ;
alias boostrelease : html_ cleanup_node_modules_ ;
explicit boostrelease ;
-9
View File
@@ -1,9 +0,0 @@
#!/bin/bash
set -ex
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
cd "$SCRIPT_DIR"
npm ci
npx antora unordered-playbook.yml
+1
View File
@@ -7,3 +7,4 @@ cd "$SCRIPT_DIR"
npm ci
npx antora unordered-playbook.yml
cp -f html/index.html html/unordered.html
+5
View File
@@ -6,6 +6,11 @@
:github-pr-url: https://github.com/boostorg/unordered/pull
:cpp: C++
== Release 1.91.0
* Fixed the returned value of range insertion in concurrent containers
({github-pr-url}/344[PR#344^]).
== Release 1.89.0
* Deprecated `boost::unordered::hash_is_avalanching` is now a using-declaration of
+1 -1
View File
@@ -11,7 +11,7 @@ Copyright (C) 2005-2008 Daniel James
Copyright (C) 2022-2025 Christian Mazakas
Copyright (C) 2022-2025 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz
Copyright (C) 2022-2026 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz
Copyright (C) 2022-2023 Peter Dimov
+1931 -1541
View File
File diff suppressed because it is too large Load Diff
+6 -3
View File
@@ -1,7 +1,10 @@
{
"devDependencies": {
"@antora/cli": "3.1.10",
"@antora/site-generator": "3.1.10",
"antora": "3.1.10"
"@antora/cli": ">=3.1.14",
"@antora/site-generator": ">=3.1.14",
"antora": ">=3.1.14"
},
"dependencies": {
"@cppalliance/antora-downloads-extension": "^0.0.2"
}
}
+4
View File
@@ -12,3 +12,7 @@ ui:
bundle:
url: https://github.com/boostorg/unordered-ui-bundle/raw/c80db72a7ba804256beb36e3a46d9c7df265d8d7/ui-bundle.zip
output_dir: unordered/_
antora:
extensions:
- require: '@cppalliance/antora-downloads-extension'
+48 -44
View File
@@ -1,4 +1,4 @@
# Copyright 2024 Braden Ganetsky
# Copyright 2024-2026 Braden Ganetsky
# Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt
@@ -14,10 +14,16 @@ class BoostUnorderedHelpers:
return n.cast(underlying_type)
else:
return n
def maybe_unwrap_foa_element(e):
if f"{e.type.strip_typedefs()}".startswith("boost::unordered::detail::foa::element_type<"):
return e["p"]
# Sometimes the complex typedefs can't be resolved through a pointer
if e.type.strip_typedefs().code == gdb.TYPE_CODE_PTR:
foa_element = e.dereference()
else:
foa_element = e
if f"{foa_element.type.strip_typedefs()}".startswith("boost::unordered::detail::foa::element_type<"):
return foa_element["p"]
else:
return e
@@ -45,14 +51,15 @@ class BoostUnorderedPointerCustomizationPoint:
class BoostUnorderedFcaPrinter:
def __init__(self, val):
self.val = BoostUnorderedHelpers.maybe_unwrap_reference(val)
self.name = f"{self.val.type.strip_typedefs()}".split("<")[0]
val = BoostUnorderedHelpers.maybe_unwrap_reference(val)
self.table = val["table_"]
self.name = f"{val.type.strip_typedefs()}".split("<")[0]
self.name = self.name.replace("boost::unordered::", "boost::")
self.is_map = self.name.endswith("map")
self.cpo = BoostUnorderedPointerCustomizationPoint(self.val["table_"]["buckets_"]["buckets"])
self.cpo = BoostUnorderedPointerCustomizationPoint(self.table["buckets_"]["buckets"])
def to_string(self):
size = self.val["table_"]["size_"]
size = self.table["size_"]
return f"{self.name} with {size} elements"
def display_hint(self):
@@ -60,7 +67,7 @@ class BoostUnorderedFcaPrinter:
def children(self):
def generator():
grouped_buckets = self.val["table_"]["buckets_"]
grouped_buckets = self.table["buckets_"]
size = grouped_buckets["size_"]
buckets = grouped_buckets["buckets"]
@@ -83,7 +90,7 @@ class BoostUnorderedFcaPrinter:
count += 1
node = self.cpo.to_address(node.dereference()["next"])
bucket_index += 1
return generator()
class BoostUnorderedFcaIteratorPrinter:
@@ -118,7 +125,7 @@ class BoostUnorderedFoaTableCoreCumulativeStatsPrinter:
yield "", member
yield "", self.val[member]
return generator()
class BoostUnorderedFoaCumulativeStatsPrinter:
def __init__(self, val):
self.val = val
@@ -127,7 +134,7 @@ class BoostUnorderedFoaCumulativeStatsPrinter:
def display_hint(self):
return "map"
def children(self):
def generator():
yield "", "count"
@@ -154,14 +161,20 @@ class BoostUnorderedFoaCumulativeStatsPrinter:
class BoostUnorderedFoaPrinter:
def __init__(self, val):
self.val = BoostUnorderedHelpers.maybe_unwrap_reference(val)
self.name = f"{self.val.type.strip_typedefs()}".split("<")[0]
val = BoostUnorderedHelpers.maybe_unwrap_reference(val)
self.table = val["table_"]
self.name = f"{val.type.strip_typedefs()}".split("<")[0]
self.name = self.name.replace("boost::unordered::", "boost::")
self.is_map = self.name.endswith("map")
self.cpo = BoostUnorderedPointerCustomizationPoint(self.val["table_"]["arrays"]["groups_"])
self.cpo = BoostUnorderedPointerCustomizationPoint(self.table["arrays"]["groups_"])
self.groups = self.cpo.to_address(self.table["arrays"]["groups_"])
self.elements = self.cpo.to_address(self.table["arrays"]["elements_"])
self.N = 15 # `self.groups.dereference()["N"]` may be optimized out
self.sentinel_ = 1 # `self.groups.dereference()["sentinel_"]` may be optimized out
def to_string(self):
size = BoostUnorderedHelpers.maybe_unwrap_atomic(self.val["table_"]["size_ctrl"]["size"])
size = BoostUnorderedHelpers.maybe_unwrap_atomic(self.table["size_ctrl"]["size"])
return f"{self.name} with {size} elements"
def display_hint(self):
@@ -191,30 +204,21 @@ class BoostUnorderedFoaPrinter:
m = group["m"]
at = lambda b: BoostUnorderedHelpers.maybe_unwrap_atomic(m[b]["n"])
N = group["N"]
sentinel_ = group["sentinel_"]
if self.is_regular_layout(group):
return pos == N-1 and at(N-1) == sentinel_
return pos == self.N-1 and at(self.N-1) == self.sentinel_
else:
return pos == N-1 and (at(0) & 0x4000400040004000) == 0x4000 and (at(1) & 0x4000400040004000) == 0
return pos == self.N-1 and (at(0) & 0x4000400040004000) == 0x4000 and (at(1) & 0x4000400040004000) == 0
def children(self):
def generator():
table = self.val["table_"]
groups = self.cpo.to_address(table["arrays"]["groups_"])
elements = self.cpo.to_address(table["arrays"]["elements_"])
pc_ = groups.cast(gdb.lookup_type("unsigned char").pointer())
p_ = elements
pc_ = self.groups.cast(gdb.lookup_type("unsigned char").pointer())
p_ = self.elements
first_time = True
mask = 0
n0 = 0
n = 0
count = 0
while p_ != 0:
# This if block mirrors the condition in the begin() call
if (not first_time) or (self.match_occupied(groups.dereference()) & 1):
if (not first_time) or (self.match_occupied(self.groups.dereference()) & 1):
pointer = BoostUnorderedHelpers.maybe_unwrap_foa_element(p_)
value = self.cpo.to_address(pointer).dereference()
if self.is_map:
@@ -228,17 +232,17 @@ class BoostUnorderedFoaPrinter:
count += 1
first_time = False
n0 = pc_.cast(gdb.lookup_type("uintptr_t")) % groups.dereference().type.sizeof
n0 = pc_.cast(gdb.lookup_type("uintptr_t")) % self.groups.dereference().type.sizeof
pc_ = self.cpo.next(pc_, -n0)
mask = (self.match_occupied(pc_.cast(groups.type).dereference()) >> (n0+1)) << (n0+1)
mask = (self.match_occupied(pc_.cast(self.groups.type).dereference()) >> (n0+1)) << (n0+1)
while mask == 0:
pc_ = self.cpo.next(pc_, groups.dereference().type.sizeof)
p_ = self.cpo.next(p_, groups.dereference()["N"])
mask = self.match_occupied(pc_.cast(groups.type).dereference())
pc_ = self.cpo.next(pc_, self.groups.dereference().type.sizeof)
p_ = self.cpo.next(p_, self.N)
mask = self.match_occupied(pc_.cast(self.groups.type).dereference())
n = BoostUnorderedHelpers.countr_zero(mask)
if self.is_sentinel(pc_.cast(groups.type).dereference(), n):
if self.is_sentinel(pc_.cast(self.groups.type).dereference(), n):
p_ = 0
else:
pc_ = self.cpo.next(pc_, n)
@@ -284,7 +288,7 @@ def boost_unordered_build_pretty_printer():
add_template_printer("boost::unordered::concurrent_flat_set", BoostUnorderedFoaPrinter)
add_template_printer("boost::unordered::concurrent_node_map", BoostUnorderedFoaPrinter)
add_template_printer("boost::unordered::concurrent_node_set", BoostUnorderedFoaPrinter)
add_template_printer("boost::unordered::detail::foa::table_iterator", BoostUnorderedFoaIteratorPrinter)
add_concrete_printer("boost::unordered::detail::foa::table_core_cumulative_stats", BoostUnorderedFoaTableCoreCumulativeStatsPrinter)
@@ -301,7 +305,7 @@ gdb.printing.register_pretty_printer(gdb.current_objfile(), boost_unordered_buil
class BoostUnorderedFoaGetStatsMethod(gdb.xmethod.XMethod):
def __init__(self):
gdb.xmethod.XMethod.__init__(self, "get_stats")
def get_worker(self, method_name):
if method_name == "get_stats":
return BoostUnorderedFoaGetStatsWorker()
@@ -312,19 +316,19 @@ class BoostUnorderedFoaGetStatsWorker(gdb.xmethod.XMethodWorker):
def get_result_type(self, obj):
return gdb.lookup_type("boost::unordered::detail::foa::table_core_cumulative_stats")
def __call__(self, obj):
try:
return obj["table_"]["cstats"]
except gdb.error:
print("Error: Binary was compiled without stats. Recompile with `BOOST_UNORDERED_ENABLE_STATS` defined.")
return
class BoostUnorderedFoaMatcher(gdb.xmethod.XMethodMatcher):
def __init__(self):
gdb.xmethod.XMethodMatcher.__init__(self, 'BoostUnorderedFoaMatcher')
self.methods = [BoostUnorderedFoaGetStatsMethod()]
def match(self, class_type, method_name):
template_name = f"{class_type.strip_typedefs()}".split("<")[0]
regex = "^boost::unordered::(unordered|concurrent)_(flat|node)_(map|set)$"
@@ -380,12 +384,12 @@ class MyFancyPtrPrinter:
def boost_to_address(fancy_ptr):
...
return ...
# Equivalent to `operator+()`
def boost_next(raw_ptr, offset):
...
return ...
...
```
"""
@@ -1,7 +1,8 @@
/* Fast open-addressing concurrent hashmap.
*
* Copyright 2023 Christian Mazakas.
* Copyright 2023-2024 Joaquin M Lopez Munoz.
* Copyright 2023-2026 Joaquin M Lopez Munoz.
* Copyright 2026 Braden Ganetsky
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
@@ -189,10 +190,10 @@ namespace boost {
{
}
template <bool avoid_explicit_instantiation = true>
template <typename Key2,
typename std::enable_if<std::is_same<Key, Key2>::value, int>::type = 0>
concurrent_flat_map(
unordered_flat_map<Key, T, Hash, Pred, Allocator>&& other)
unordered_flat_map<Key2, T, Hash, Pred, Allocator>&& other)
: table_(std::move(other.table_))
{
}
@@ -423,8 +424,8 @@ namespace boost {
size_type insert(InputIterator begin, InputIterator end)
{
size_type count_elements = 0;
for (auto pos = begin; pos != end; ++pos, ++count_elements) {
table_.emplace(*pos);
for (auto pos = begin; pos != end; ++pos) {
if (table_.emplace(*pos)) ++count_elements;
}
return count_elements;
}
@@ -1,7 +1,8 @@
/* Fast open-addressing concurrent hashset.
*
* Copyright 2023 Christian Mazakas.
* Copyright 2023-2024 Joaquin M Lopez Munoz.
* Copyright 2023-2026 Joaquin M Lopez Munoz.
* Copyright 2026 Braden Ganetsky
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
@@ -186,10 +187,10 @@ namespace boost {
{
}
template <bool avoid_explicit_instantiation = true>
template <typename Key2,
typename std::enable_if<std::is_same<Key, Key2>::value, int>::type = 0>
concurrent_flat_set(
unordered_flat_set<Key, Hash, Pred, Allocator>&& other)
unordered_flat_set<Key2, Hash, Pred, Allocator>&& other)
: table_(std::move(other.table_))
{
}
@@ -429,8 +430,8 @@ namespace boost {
size_type insert(InputIterator begin, InputIterator end)
{
size_type count_elements = 0;
for (auto pos = begin; pos != end; ++pos, ++count_elements) {
table_.emplace(*pos);
for (auto pos = begin; pos != end; ++pos) {
if (table_.emplace(*pos)) ++count_elements;
}
return count_elements;
}
@@ -1,7 +1,8 @@
/* Fast open-addressing, node-based concurrent hashmap.
*
* Copyright 2023 Christian Mazakas.
* Copyright 2023-2024 Joaquin M Lopez Munoz.
* Copyright 2023-2026 Joaquin M Lopez Munoz.
* Copyright 2026 Braden Ganetsky
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
@@ -197,9 +198,10 @@ namespace boost {
{
}
template <bool avoid_explicit_instantiation = true>
template <typename Key2,
typename std::enable_if<std::is_same<Key, Key2>::value, int>::type = 0>
concurrent_node_map(
unordered_node_map<Key, T, Hash, Pred, Allocator>&& other)
unordered_node_map<Key2, T, Hash, Pred, Allocator>&& other)
: table_(std::move(other.table_))
{
}
@@ -430,8 +432,8 @@ namespace boost {
size_type insert(InputIterator begin, InputIterator end)
{
size_type count_elements = 0;
for (auto pos = begin; pos != end; ++pos, ++count_elements) {
table_.emplace(*pos);
for (auto pos = begin; pos != end; ++pos) {
if (table_.emplace(*pos)) ++count_elements;
}
return count_elements;
}
@@ -1,7 +1,8 @@
/* Fast open-addressing, node-based concurrent hashset.
*
* Copyright 2023 Christian Mazakas.
* Copyright 2023-2024 Joaquin M Lopez Munoz.
* Copyright 2023-2026 Joaquin M Lopez Munoz.
* Copyright 2026 Braden Ganetsky
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
@@ -194,9 +195,10 @@ namespace boost {
{
}
template <bool avoid_explicit_instantiation = true>
template <typename Key2,
typename std::enable_if<std::is_same<Key, Key2>::value, int>::type = 0>
concurrent_node_set(
unordered_node_set<Key, Hash, Pred, Allocator>&& other)
unordered_node_set<Key2, Hash, Pred, Allocator>&& other)
: table_(std::move(other.table_))
{
}
@@ -436,8 +438,8 @@ namespace boost {
size_type insert(InputIterator begin, InputIterator end)
{
size_type count_elements = 0;
for (auto pos = begin; pos != end; ++pos, ++count_elements) {
table_.emplace(*pos);
for (auto pos = begin; pos != end; ++pos) {
if (table_.emplace(*pos)) ++count_elements;
}
return count_elements;
}
+34 -8
View File
@@ -1,4 +1,4 @@
// Copyright (C) 2022-2024 Joaquin M Lopez Munoz.
// Copyright (C) 2022-2025 Joaquin M Lopez Munoz.
// Copyright (C) 2022 Christian Mazakas
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -134,11 +134,37 @@ namespace boost {
namespace unordered {
namespace detail {
template <class ValueType, class VoidPtr> struct node;
// access to node::value_type and node::pointer for incomplete node
template<class Node> struct node_value_type_impl;
template <class ValueType, class VoidPtr>
struct node_value_type_impl<node<ValueType, VoidPtr>>
{
typedef ValueType type;
};
template<class Node> using node_value_type =
typename node_value_type_impl<Node>::type;
template<class Node> struct node_pointer_impl;
template <class ValueType, class VoidPtr>
struct node_pointer_impl<node<ValueType, VoidPtr>>
{
typedef typename boost::pointer_traits<VoidPtr>::template rebind_to<
node<ValueType, VoidPtr>>::type type;
};
template<class Node> using node_pointer =
typename node_pointer_impl<Node>::type;
template <class ValueType, class VoidPtr> struct node
{
typedef ValueType value_type;
typedef typename boost::pointer_traits<VoidPtr>::template rebind_to<
node>::type node_pointer;
typedef node_value_type<node> value_type;
typedef detail::node_pointer<node> node_pointer;
node_pointer next;
opt_storage<value_type> buf;
@@ -304,10 +330,10 @@ namespace boost {
template <class Node> struct grouped_local_bucket_iterator
{
typedef typename Node::node_pointer node_pointer;
typedef detail::node_pointer<Node> node_pointer;
public:
typedef typename Node::value_type value_type;
typedef detail::node_value_type<Node> value_type;
typedef value_type element_type;
typedef value_type* pointer;
typedef value_type& reference;
@@ -370,10 +396,10 @@ namespace boost {
template <class Node> struct const_grouped_local_bucket_iterator
{
typedef typename Node::node_pointer node_pointer;
typedef detail::node_pointer<Node> node_pointer;
public:
typedef typename Node::value_type const value_type;
typedef detail::node_value_type<Node> const value_type;
typedef value_type const element_type;
typedef value_type const* pointer;
typedef value_type const& reference;
+3 -1
View File
@@ -29,7 +29,7 @@
#include <boost/unordered/detail/mulx.hpp>
#include <boost/unordered/detail/static_assert.hpp>
#include <boost/unordered/detail/type_traits.hpp>
#include <boost/unordered/unordered_printers.hpp>
#include <boost/unordered/detail/unordered_printers.hpp>
#include <climits>
#include <cmath>
#include <cstddef>
@@ -923,6 +923,8 @@ inline unsigned int unchecked_countr_zero(int x)
unsigned long r;
_BitScanForward(&r,(unsigned long)x);
return (unsigned int)r;
#elif defined(BOOST_GCC)||defined(BOOST_CLANG)
return (unsigned int)__builtin_ctz((unsigned int)x);
#else
BOOST_UNORDERED_ASSUME(x!=0);
return (unsigned int)boost::core::countr_zero((unsigned int)x);
@@ -21,7 +21,7 @@
#include <boost/unordered/detail/serialize_tracked_address.hpp>
#include <boost/unordered/detail/static_assert.hpp>
#include <boost/unordered/detail/type_traits.hpp>
#include <boost/unordered/unordered_printers.hpp>
#include <boost/unordered/detail/unordered_printers.hpp>
#include <boost/assert.hpp>
#include <boost/core/allocator_traits.hpp>
@@ -969,7 +969,7 @@ namespace boost {
template <class Node, class Bucket> class iterator
{
public:
typedef typename Node::value_type value_type;
typedef typename detail::node_value_type<Node> value_type;
typedef value_type element_type;
typedef value_type* pointer;
typedef value_type& reference;
@@ -1023,7 +1023,7 @@ namespace boost {
}
private:
typedef typename Node::node_pointer node_pointer;
typedef detail::node_pointer<Node> node_pointer;
typedef grouped_bucket_iterator<Bucket> bucket_iterator;
node_pointer p;
@@ -1076,7 +1076,7 @@ namespace boost {
template <class Node, class Bucket> class c_iterator
{
public:
typedef typename Node::value_type value_type;
typedef typename detail::node_value_type<Node> value_type;
typedef value_type const element_type;
typedef value_type const* pointer;
typedef value_type const& reference;
@@ -1131,7 +1131,7 @@ namespace boost {
}
private:
typedef typename Node::node_pointer node_pointer;
typedef detail::node_pointer<Node> node_pointer;
typedef grouped_bucket_iterator<Bucket> bucket_iterator;
node_pointer p;
@@ -1,11 +1,11 @@
// Copyright 2024 Braden Ganetsky
// Copyright 2024-2026 Braden Ganetsky
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
// Generated on 2024-08-25T17:48:54
// Generated on 2026-01-24T00:34:53
#ifndef BOOST_UNORDERED_UNORDERED_PRINTERS_HPP
#define BOOST_UNORDERED_UNORDERED_PRINTERS_HPP
#ifndef BOOST_UNORDERED_DETAIL_UNORDERED_PRINTERS_HPP
#define BOOST_UNORDERED_DETAIL_UNORDERED_PRINTERS_HPP
#ifndef BOOST_ALL_NO_EMBEDDED_GDB_SCRIPTS
#if defined(__ELF__)
@@ -14,7 +14,7 @@
#pragma clang diagnostic ignored "-Woverlength-strings"
#endif
__asm__(".pushsection \".debug_gdb_scripts\", \"MS\",%progbits,1\n"
".ascii \"\\4gdb.inlined-script.BOOST_UNORDERED_UNORDERED_PRINTERS_HPP\\n\"\n"
".ascii \"\\4gdb.inlined-script.BOOST_UNORDERED_DETAIL_UNORDERED_PRINTERS_HPP\\n\"\n"
".ascii \"import gdb.printing\\n\"\n"
".ascii \"import gdb.xmethod\\n\"\n"
".ascii \"import re\\n\"\n"
@@ -29,8 +29,14 @@ __asm__(".pushsection \".debug_gdb_scripts\", \"MS\",%progbits,1\n"
".ascii \" return n\\n\"\n"
".ascii \" def maybe_unwrap_foa_element(e):\\n\"\n"
".ascii \" if f\\\"{e.type.strip_typedefs()}\\\".startswith(\\\"boost::unordered::detail::foa::element_type<\\\"):\\n\"\n"
".ascii \" return e[\\\"p\\\"]\\n\"\n"
".ascii \" # Sometimes the complex typedefs can't be resolved through a pointer\\n\"\n"
".ascii \" if e.type.strip_typedefs().code == gdb.TYPE_CODE_PTR:\\n\"\n"
".ascii \" foa_element = e.dereference()\\n\"\n"
".ascii \" else:\\n\"\n"
".ascii \" foa_element = e\\n\"\n"
".ascii \" if f\\\"{foa_element.type.strip_typedefs()}\\\".startswith(\\\"boost::unordered::detail::foa::element_type<\\\"):\\n\"\n"
".ascii \" return foa_element[\\\"p\\\"]\\n\"\n"
".ascii \" else:\\n\"\n"
".ascii \" return e\\n\"\n"
@@ -58,14 +64,15 @@ __asm__(".pushsection \".debug_gdb_scripts\", \"MS\",%progbits,1\n"
".ascii \"class BoostUnorderedFcaPrinter:\\n\"\n"
".ascii \" def __init__(self, val):\\n\"\n"
".ascii \" self.val = BoostUnorderedHelpers.maybe_unwrap_reference(val)\\n\"\n"
".ascii \" self.name = f\\\"{self.val.type.strip_typedefs()}\\\".split(\\\"<\\\")[0]\\n\"\n"
".ascii \" val = BoostUnorderedHelpers.maybe_unwrap_reference(val)\\n\"\n"
".ascii \" self.table = val[\\\"table_\\\"]\\n\"\n"
".ascii \" self.name = f\\\"{val.type.strip_typedefs()}\\\".split(\\\"<\\\")[0]\\n\"\n"
".ascii \" self.name = self.name.replace(\\\"boost::unordered::\\\", \\\"boost::\\\")\\n\"\n"
".ascii \" self.is_map = self.name.endswith(\\\"map\\\")\\n\"\n"
".ascii \" self.cpo = BoostUnorderedPointerCustomizationPoint(self.val[\\\"table_\\\"][\\\"buckets_\\\"][\\\"buckets\\\"])\\n\"\n"
".ascii \" self.cpo = BoostUnorderedPointerCustomizationPoint(self.table[\\\"buckets_\\\"][\\\"buckets\\\"])\\n\"\n"
".ascii \" def to_string(self):\\n\"\n"
".ascii \" size = self.val[\\\"table_\\\"][\\\"size_\\\"]\\n\"\n"
".ascii \" size = self.table[\\\"size_\\\"]\\n\"\n"
".ascii \" return f\\\"{self.name} with {size} elements\\\"\\n\"\n"
".ascii \" def display_hint(self):\\n\"\n"
@@ -73,7 +80,7 @@ __asm__(".pushsection \".debug_gdb_scripts\", \"MS\",%progbits,1\n"
".ascii \" def children(self):\\n\"\n"
".ascii \" def generator():\\n\"\n"
".ascii \" grouped_buckets = self.val[\\\"table_\\\"][\\\"buckets_\\\"]\\n\"\n"
".ascii \" grouped_buckets = self.table[\\\"buckets_\\\"]\\n\"\n"
".ascii \" size = grouped_buckets[\\\"size_\\\"]\\n\"\n"
".ascii \" buckets = grouped_buckets[\\\"buckets\\\"]\\n\"\n"
@@ -167,14 +174,20 @@ __asm__(".pushsection \".debug_gdb_scripts\", \"MS\",%progbits,1\n"
".ascii \"class BoostUnorderedFoaPrinter:\\n\"\n"
".ascii \" def __init__(self, val):\\n\"\n"
".ascii \" self.val = BoostUnorderedHelpers.maybe_unwrap_reference(val)\\n\"\n"
".ascii \" self.name = f\\\"{self.val.type.strip_typedefs()}\\\".split(\\\"<\\\")[0]\\n\"\n"
".ascii \" val = BoostUnorderedHelpers.maybe_unwrap_reference(val)\\n\"\n"
".ascii \" self.table = val[\\\"table_\\\"]\\n\"\n"
".ascii \" self.name = f\\\"{val.type.strip_typedefs()}\\\".split(\\\"<\\\")[0]\\n\"\n"
".ascii \" self.name = self.name.replace(\\\"boost::unordered::\\\", \\\"boost::\\\")\\n\"\n"
".ascii \" self.is_map = self.name.endswith(\\\"map\\\")\\n\"\n"
".ascii \" self.cpo = BoostUnorderedPointerCustomizationPoint(self.val[\\\"table_\\\"][\\\"arrays\\\"][\\\"groups_\\\"])\\n\"\n"
".ascii \" self.cpo = BoostUnorderedPointerCustomizationPoint(self.table[\\\"arrays\\\"][\\\"groups_\\\"])\\n\"\n"
".ascii \" self.groups = self.cpo.to_address(self.table[\\\"arrays\\\"][\\\"groups_\\\"])\\n\"\n"
".ascii \" self.elements = self.cpo.to_address(self.table[\\\"arrays\\\"][\\\"elements_\\\"])\\n\"\n"
".ascii \" self.N = 15 # `self.groups.dereference()[\\\"N\\\"]` may be optimized out\\n\"\n"
".ascii \" self.sentinel_ = 1 # `self.groups.dereference()[\\\"sentinel_\\\"]` may be optimized out\\n\"\n"
".ascii \" def to_string(self):\\n\"\n"
".ascii \" size = BoostUnorderedHelpers.maybe_unwrap_atomic(self.val[\\\"table_\\\"][\\\"size_ctrl\\\"][\\\"size\\\"])\\n\"\n"
".ascii \" size = BoostUnorderedHelpers.maybe_unwrap_atomic(self.table[\\\"size_ctrl\\\"][\\\"size\\\"])\\n\"\n"
".ascii \" return f\\\"{self.name} with {size} elements\\\"\\n\"\n"
".ascii \" def display_hint(self):\\n\"\n"
@@ -204,30 +217,21 @@ __asm__(".pushsection \".debug_gdb_scripts\", \"MS\",%progbits,1\n"
".ascii \" m = group[\\\"m\\\"]\\n\"\n"
".ascii \" at = lambda b: BoostUnorderedHelpers.maybe_unwrap_atomic(m[b][\\\"n\\\"])\\n\"\n"
".ascii \" N = group[\\\"N\\\"]\\n\"\n"
".ascii \" sentinel_ = group[\\\"sentinel_\\\"]\\n\"\n"
".ascii \" if self.is_regular_layout(group):\\n\"\n"
".ascii \" return pos == N-1 and at(N-1) == sentinel_\\n\"\n"
".ascii \" return pos == self.N-1 and at(self.N-1) == self.sentinel_\\n\"\n"
".ascii \" else:\\n\"\n"
".ascii \" return pos == N-1 and (at(0) & 0x4000400040004000) == 0x4000 and (at(1) & 0x4000400040004000) == 0\\n\"\n"
".ascii \" return pos == self.N-1 and (at(0) & 0x4000400040004000) == 0x4000 and (at(1) & 0x4000400040004000) == 0\\n\"\n"
".ascii \" def children(self):\\n\"\n"
".ascii \" def generator():\\n\"\n"
".ascii \" table = self.val[\\\"table_\\\"]\\n\"\n"
".ascii \" groups = self.cpo.to_address(table[\\\"arrays\\\"][\\\"groups_\\\"])\\n\"\n"
".ascii \" elements = self.cpo.to_address(table[\\\"arrays\\\"][\\\"elements_\\\"])\\n\"\n"
".ascii \" pc_ = groups.cast(gdb.lookup_type(\\\"unsigned char\\\").pointer())\\n\"\n"
".ascii \" p_ = elements\\n\"\n"
".ascii \" pc_ = self.groups.cast(gdb.lookup_type(\\\"unsigned char\\\").pointer())\\n\"\n"
".ascii \" p_ = self.elements\\n\"\n"
".ascii \" first_time = True\\n\"\n"
".ascii \" mask = 0\\n\"\n"
".ascii \" n0 = 0\\n\"\n"
".ascii \" n = 0\\n\"\n"
".ascii \" count = 0\\n\"\n"
".ascii \" while p_ != 0:\\n\"\n"
".ascii \" # This if block mirrors the condition in the begin() call\\n\"\n"
".ascii \" if (not first_time) or (self.match_occupied(groups.dereference()) & 1):\\n\"\n"
".ascii \" if (not first_time) or (self.match_occupied(self.groups.dereference()) & 1):\\n\"\n"
".ascii \" pointer = BoostUnorderedHelpers.maybe_unwrap_foa_element(p_)\\n\"\n"
".ascii \" value = self.cpo.to_address(pointer).dereference()\\n\"\n"
".ascii \" if self.is_map:\\n\"\n"
@@ -241,17 +245,17 @@ __asm__(".pushsection \".debug_gdb_scripts\", \"MS\",%progbits,1\n"
".ascii \" count += 1\\n\"\n"
".ascii \" first_time = False\\n\"\n"
".ascii \" n0 = pc_.cast(gdb.lookup_type(\\\"uintptr_t\\\")) % groups.dereference().type.sizeof\\n\"\n"
".ascii \" n0 = pc_.cast(gdb.lookup_type(\\\"uintptr_t\\\")) % self.groups.dereference().type.sizeof\\n\"\n"
".ascii \" pc_ = self.cpo.next(pc_, -n0)\\n\"\n"
".ascii \" mask = (self.match_occupied(pc_.cast(groups.type).dereference()) >> (n0+1)) << (n0+1)\\n\"\n"
".ascii \" mask = (self.match_occupied(pc_.cast(self.groups.type).dereference()) >> (n0+1)) << (n0+1)\\n\"\n"
".ascii \" while mask == 0:\\n\"\n"
".ascii \" pc_ = self.cpo.next(pc_, groups.dereference().type.sizeof)\\n\"\n"
".ascii \" p_ = self.cpo.next(p_, groups.dereference()[\\\"N\\\"])\\n\"\n"
".ascii \" mask = self.match_occupied(pc_.cast(groups.type).dereference())\\n\"\n"
".ascii \" pc_ = self.cpo.next(pc_, self.groups.dereference().type.sizeof)\\n\"\n"
".ascii \" p_ = self.cpo.next(p_, self.N)\\n\"\n"
".ascii \" mask = self.match_occupied(pc_.cast(self.groups.type).dereference())\\n\"\n"
".ascii \" n = BoostUnorderedHelpers.countr_zero(mask)\\n\"\n"
".ascii \" if self.is_sentinel(pc_.cast(groups.type).dereference(), n):\\n\"\n"
".ascii \" if self.is_sentinel(pc_.cast(self.groups.type).dereference(), n):\\n\"\n"
".ascii \" p_ = 0\\n\"\n"
".ascii \" else:\\n\"\n"
".ascii \" pc_ = self.cpo.next(pc_, n)\\n\"\n"
@@ -411,4 +415,4 @@ __asm__(".pushsection \".debug_gdb_scripts\", \"MS\",%progbits,1\n"
#endif // defined(__ELF__)
#endif // !defined(BOOST_ALL_NO_EMBEDDED_GDB_SCRIPTS)
#endif // !defined(BOOST_UNORDERED_UNORDERED_PRINTERS_HPP)
#endif // !defined(BOOST_UNORDERED_DETAIL_UNORDERED_PRINTERS_HPP)
@@ -1,5 +1,6 @@
// Copyright (C) 2022-2023 Christian Mazakas
// Copyright (C) 2024-2025 Joaquin M Lopez Munoz
// Copyright (C) 2026 Braden Ganetsky
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -182,9 +183,10 @@ namespace boost {
{
}
template <bool avoid_explicit_instantiation = true>
template <typename Key2,
typename std::enable_if<std::is_same<Key, Key2>::value, int>::type = 0>
unordered_flat_map(
concurrent_flat_map<Key, T, Hash, KeyEqual, Allocator>&& other)
concurrent_flat_map<Key2, T, Hash, KeyEqual, Allocator>&& other)
: table_(std::move(other.table_))
{
}
@@ -1,5 +1,6 @@
// Copyright (C) 2022-2023 Christian Mazakas
// Copyright (C) 2024-2025 Joaquin M Lopez Munoz
// Copyright (C) 2026 Braden Ganetsky
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -178,9 +179,10 @@ namespace boost {
{
}
template <bool avoid_explicit_instantiation = true>
template <typename Key2,
typename std::enable_if<std::is_same<Key, Key2>::value, int>::type = 0>
unordered_flat_set(
concurrent_flat_set<Key, Hash, KeyEqual, Allocator>&& other)
concurrent_flat_set<Key2, Hash, KeyEqual, Allocator>&& other)
: table_(std::move(other.table_))
{
}
@@ -1,5 +1,6 @@
// Copyright (C) 2022-2023 Christian Mazakas
// Copyright (C) 2024-2025 Joaquin M Lopez Munoz
// Copyright (C) 2026 Braden Ganetsky
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -189,9 +190,10 @@ namespace boost {
{
}
template <bool avoid_explicit_instantiation = true>
template <typename Key2,
typename std::enable_if<std::is_same<Key, Key2>::value, int>::type = 0>
unordered_node_map(
concurrent_node_map<Key, T, Hash, KeyEqual, Allocator>&& other)
concurrent_node_map<Key2, T, Hash, KeyEqual, Allocator>&& other)
: table_(std::move(other.table_))
{
}
@@ -1,5 +1,6 @@
// Copyright (C) 2022-2023 Christian Mazakas
// Copyright (C) 2024-2025 Joaquin M Lopez Munoz
// Copyright (C) 2026 Braden Ganetsky
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -187,9 +188,10 @@ namespace boost {
{
}
template <bool avoid_explicit_instantiation = true>
template <typename Key2,
typename std::enable_if<std::is_same<Key, Key2>::value, int>::type = 0>
unordered_node_set(
concurrent_node_set<Key, Hash, KeyEqual, Allocator>&& other)
concurrent_node_set<Key2, Hash, KeyEqual, Allocator>&& other)
: table_(std::move(other.table_))
{
}
+9
View File
@@ -163,4 +163,13 @@ cfoa_tests(SOURCES cfoa/rw_spinlock_test6.cpp)
cfoa_tests(SOURCES cfoa/rw_spinlock_test7.cpp)
cfoa_tests(SOURCES cfoa/rw_spinlock_test8.cpp)
# Compile tests
fca_tests(TYPE compile NAME explicit_instantiation_tests SOURCES unordered/explicit_instantiation_tests.cpp)
foa_tests(TYPE compile NAME explicit_instantiation_tests SOURCES unordered/explicit_instantiation_tests.cpp)
cfoa_tests(TYPE compile NAME explicit_instantiation_tests SOURCES cfoa/explicit_instantiation_tests.cpp)
foa_tests(TYPE compile NAME conversion_operator_tests SOURCES unordered/conversion_operator_tests.cpp)
cfoa_tests(TYPE compile NAME conversion_operator_tests SOURCES cfoa/conversion_operator_tests.cpp)
endif()
+5 -4
View File
@@ -12,10 +12,7 @@ import config : requires ;
path-constant TOP : . ;
# Adding -Wundef is blocked on (at least)
# https://github.com/boostorg/type_traits/issues/165
local gcc-flags = -Wsign-promo -Wconversion -Wsign-conversion -Wfloat-equal -Wshadow -Wno-variadic-macros ;
local gcc-flags = -Wsign-promo -Wconversion -Wsign-conversion -Wfloat-equal -Wshadow -Wundef -Wno-variadic-macros ;
local clang-flags = $(gcc-flags) -Wno-c99-extensions ;
local msvc-flags = /wd4494 ;
@@ -169,6 +166,9 @@ compile unordered/explicit_instantiation_tests.cpp :
compile unordered/explicit_instantiation_tests.cpp : <define>BOOST_UNORDERED_FOA_TESTS : foa_explicit_instantiation_tests ;
compile cfoa/explicit_instantiation_tests.cpp : : cfoa_explicit_instantiation_tests ;
compile unordered/conversion_operator_tests.cpp : <define>BOOST_UNORDERED_FOA_TESTS : foa_conversion_operator_tests ;
compile cfoa/conversion_operator_tests.cpp : : cfoa_conversion_operator_tests ;
local FCA_EXCEPTION_TESTS =
constructor_exception_tests
copy_exception_tests
@@ -362,6 +362,7 @@ local CFOA_TESTS =
pmr_allocator_tests
stats_tests
node_handle_allocator_tests
incomplete_tests
;
for local test in $(CFOA_TESTS)
+42
View File
@@ -0,0 +1,42 @@
// Copyright 2026 Braden Ganetsky
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/static_assert.hpp>
#include <boost/unordered/concurrent_flat_map.hpp>
#include <boost/unordered/concurrent_flat_set.hpp>
#include <boost/unordered/concurrent_node_map.hpp>
#include <boost/unordered/concurrent_node_set.hpp>
// Don't include the FOA headers here!
using c_flat_map = boost::unordered::concurrent_flat_map<int, int>;
using c_flat_set = boost::unordered::concurrent_flat_set<int>;
using c_node_map = boost::unordered::concurrent_node_map<int, int>;
using c_node_set = boost::unordered::concurrent_node_set<int>;
struct constrained_template_converter
{
struct dummy
{
};
template <class T, typename std::enable_if<
std::is_constructible<T, dummy>::value, int>::type = 0>
operator T() const
{
return T{};
}
};
// Check whether the corresponding FOA container gets instantiated.
// The FOA headers aren't included, so this would fail to compile if the FOA
// container was instantiated.
BOOST_STATIC_ASSERT(
(!std::is_constructible<c_flat_map, constrained_template_converter>::value));
BOOST_STATIC_ASSERT(
(!std::is_constructible<c_flat_set, constrained_template_converter>::value));
BOOST_STATIC_ASSERT(
(!std::is_constructible<c_node_map, constrained_template_converter>::value));
BOOST_STATIC_ASSERT(
(!std::is_constructible<c_node_set, constrained_template_converter>::value));
int main() { return 0; }
+6
View File
@@ -0,0 +1,6 @@
// Copyright 2025 Joaquin M Lopez Munoz.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_UNORDERED_CFOA_TESTS
#include "../unordered/incomplete_test.cpp"
+14 -6
View File
@@ -1,5 +1,5 @@
// Copyright (C) 2023 Christian Mazakas
// Copyright (C) 2023-2024 Joaquin M Lopez Munoz
// Copyright (C) 2023-2026 Joaquin M Lopez Munoz
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -148,12 +148,18 @@ namespace {
values2.push_back(raii_convertible(v));
}
thread_runner(values2, [&x](boost::span<raii_convertible> s) {
BOOST_TEST_EQ(x.insert(s.begin(), s.end()), s.size());
auto sz = x.size();
std::atomic<std::uint64_t> num_inserts{0};
std::atomic<std::uint64_t> num_attempted_inserts{0};
thread_runner(values2, [&x, &num_inserts, &num_attempted_inserts](boost::span<raii_convertible> s) {
num_inserts += x.insert(s.begin(), s.begin() + s.size() / 2);
num_inserts += x.insert(s.begin(), s.end());
num_attempted_inserts += s.size() + s.size() / 2;
});
BOOST_TEST_EQ(x.size(), sz + num_inserts);
BOOST_TEST_EQ(
raii::default_constructor, value_type_cardinality * values2.size());
raii::default_constructor, value_type_cardinality * num_attempted_inserts);
#if BOOST_WORKAROUND(BOOST_GCC_VERSION, >= 50300) && \
BOOST_WORKAROUND(BOOST_GCC_VERSION, < 50500)
// some versions of old gcc have trouble eliding copies here
@@ -1010,9 +1016,11 @@ namespace {
{
X x;
thread_runner(dummy, [&x, &init_list](boost::span<raii>) {
BOOST_TEST_EQ(x.insert(init_list), init_list.size());
std::atomic<std::uint64_t> num_inserts{0};
thread_runner(dummy, [&x, &init_list, &num_inserts](boost::span<raii>) {
num_inserts += x.insert(init_list);
});
BOOST_TEST_EQ(num_inserts, x.size());
BOOST_TEST_EQ(x.size(), reference_cont.size());
-5
View File
@@ -18,14 +18,9 @@ assert
config
container_hash
core
move
mp11
predef
preprocessor
static_assert
throw_exception
tuple
type_traits
# Secondary dependencies
+31 -2
View File
@@ -11,6 +11,7 @@
#ifndef BOOST_NO_CXX17_HDR_MEMORY_RESOURCE
#include <memory_resource>
#include <new>
namespace test {
class counted_new_delete_resource : public std::pmr::memory_resource
@@ -25,17 +26,45 @@ namespace test {
void* do_allocate(std::size_t bytes, std::size_t alignment) override
{
_count += bytes;
#if defined(__cpp_aligned_new) && __cpp_aligned_new >= 201606L
return ::operator new(bytes, std::align_val_t(alignment));
#else
return ::operator new(bytes);
(void)alignment;
#endif
}
void do_deallocate(
void* p, std::size_t bytes, std::size_t alignment) override
{
_count -= bytes;
#if __cpp_sized_deallocation
#if defined(__cpp_aligned_new) && __cpp_aligned_new >= 201606L
# if defined(__cpp_sized_deallocation) && __cpp_sized_deallocation >= 201309L
::operator delete(p, bytes, std::align_val_t(alignment));
#else
# else
::operator delete(p, std::align_val_t(alignment));
# endif
#else
# if defined(__cpp_sized_deallocation) && __cpp_sized_deallocation >= 201309L
::operator delete(p, bytes);
# else
::operator delete(p);
(void)alignment;
# endif
#endif
}
@@ -0,0 +1,46 @@
// Copyright 2026 Braden Ganetsky
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#if !defined(BOOST_UNORDERED_FOA_TESTS)
#error "This test is only for the FOA-style conatiners"
#endif
#include <boost/static_assert.hpp>
#include <boost/unordered/unordered_flat_map.hpp>
#include <boost/unordered/unordered_flat_set.hpp>
#include <boost/unordered/unordered_node_map.hpp>
#include <boost/unordered/unordered_node_set.hpp>
// Don't include the CFOA headers here!
using flat_map = boost::unordered::unordered_flat_map<int, int>;
using flat_set = boost::unordered::unordered_flat_set<int>;
using node_map = boost::unordered::unordered_node_map<int, int>;
using node_set = boost::unordered::unordered_node_set<int>;
struct constrained_template_converter
{
struct dummy
{
};
template <class T, typename std::enable_if<
std::is_constructible<T, dummy>::value, int>::type = 0>
operator T() const
{
return T{};
}
};
// Check whether the corresponding CFOA container gets instantiated.
// The CFOA headers aren't included, so this would fail to compile if the CFOA
// container was instantiated.
BOOST_STATIC_ASSERT(
(!std::is_constructible<flat_map, constrained_template_converter>::value));
BOOST_STATIC_ASSERT(
(!std::is_constructible<flat_set, constrained_template_converter>::value));
BOOST_STATIC_ASSERT(
(!std::is_constructible<node_map, constrained_template_converter>::value));
BOOST_STATIC_ASSERT(
(!std::is_constructible<node_set, constrained_template_converter>::value));
int main() { return 0; }
+114 -23
View File
@@ -1,17 +1,28 @@
// Copyright 2009 Daniel James.
// Copyright 2022-2023 Christian Mazakas.
// Copyright 2025 Joaquin M Lopez Munoz
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "../helpers/unordered.hpp"
#ifdef BOOST_UNORDERED_CFOA_TESTS
#include <boost/unordered/concurrent_flat_set.hpp>
#include <boost/unordered/concurrent_flat_map.hpp>
#include <boost/unordered/concurrent_node_map.hpp>
#include <boost/unordered/concurrent_node_set.hpp>
#endif
#include <utility>
namespace x {
struct D
{
#ifdef BOOST_UNORDERED_FOA_TESTS
#if defined(BOOST_UNORDERED_CFOA_TESTS)
boost::concurrent_flat_map<D, D> x;
boost::concurrent_node_map<D, D> y;
#elif defined(BOOST_UNORDERED_FOA_TESTS)
boost::unordered_flat_map<D, D> x;
boost::unordered_node_map<D, D> y;
#else
@@ -30,26 +41,36 @@ namespace incomplete_test {
// Declare some instances
#ifdef BOOST_UNORDERED_FOA_TESTS
#if defined(BOOST_UNORDERED_CFOA_TESTS)
typedef boost::concurrent_flat_map<value, value, hash, equals,
allocator<std::pair<value const, value> > >
map1;
typedef boost::concurrent_flat_set<value, hash, equals, allocator<value> > set1;
typedef boost::concurrent_node_map<value, value, hash, equals,
allocator<std::pair<value const, value> > >
map2;
typedef boost::concurrent_node_set<value, hash, equals, allocator<value> >
set2;
#elif defined(BOOST_UNORDERED_FOA_TESTS)
typedef boost::unordered_flat_map<value, value, hash, equals,
allocator<std::pair<value const, value> > >
map;
typedef boost::unordered_flat_set<value, hash, equals, allocator<value> > set;
map1;
typedef boost::unordered_flat_set<value, hash, equals, allocator<value> > set1;
typedef boost::unordered_node_map<value, value, hash, equals,
allocator<std::pair<value const, value> > >
multimap;
map2;
typedef boost::unordered_node_set<value, hash, equals, allocator<value> >
multiset;
set2;
#else
typedef boost::unordered_map<value, value, hash, equals,
allocator<std::pair<value const, value> > >
map;
map1;
typedef boost::unordered_multimap<value, value, hash, equals,
allocator<std::pair<value const, value> > >
multimap;
typedef boost::unordered_set<value, hash, equals, allocator<value> > set;
map2;
typedef boost::unordered_set<value, hash, equals, allocator<value> > set1;
typedef boost::unordered_multiset<value, hash, equals, allocator<value> >
multiset;
set2;
#endif
// Now define the types which are stored as members, as they are needed for
@@ -132,24 +153,60 @@ namespace incomplete_test {
boost::unordered_multiset<struct4, hash, equals, allocator<struct4> > x;
};
#endif
// Now define the value type.
struct value
{
};
// Create some instances.
incomplete_test::map m1;
incomplete_test::multimap m2;
incomplete_test::set s1;
incomplete_test::multiset s2;
incomplete_test::map1 m1;
#ifndef BOOST_UNORDERED_CFOA_TESTS
incomplete_test::map1::iterator itm1;
incomplete_test::map1::const_iterator citm1;
#ifndef BOOST_UNORDERED_FOA_TESTS
incomplete_test::map1::local_iterator litm1;
incomplete_test::map1::const_local_iterator clitm1;
#endif
#endif
incomplete_test::map2 m2;
#ifndef BOOST_UNORDERED_CFOA_TESTS
incomplete_test::map2::iterator itm2;
incomplete_test::map2::const_iterator citm2;
#ifndef BOOST_UNORDERED_FOA_TESTS
incomplete_test::map2::local_iterator litm2;
incomplete_test::map2::const_local_iterator clitm2;
#endif
#endif
incomplete_test::set1 s1;
#ifndef BOOST_UNORDERED_CFOA_TESTS
incomplete_test::set1::iterator its1;
incomplete_test::set1::const_iterator cits1;
#ifndef BOOST_UNORDERED_FOA_TESTS
incomplete_test::set1::local_iterator lits1;
incomplete_test::set1::const_local_iterator clits1;
#endif
#endif
incomplete_test::set2 s2;
#ifndef BOOST_UNORDERED_CFOA_TESTS
incomplete_test::set2::iterator its2;
incomplete_test::set2::const_iterator cits2;
#ifndef BOOST_UNORDERED_FOA_TESTS
incomplete_test::set2::local_iterator lits2;
incomplete_test::set2::const_local_iterator clits2;
#endif
#endif
incomplete_test::struct1 c1;
incomplete_test::struct2 c2;
incomplete_test::struct3 c3;
incomplete_test::struct4 c4;
// Now define the value type.
struct value
{
};
// Now declare, but don't define, the operators required for comparing
// elements.
@@ -171,11 +228,45 @@ namespace incomplete_test {
void use_types()
{
incomplete_test::value x;
m1[x] = x;
m2.insert(std::make_pair(x, x));
s1.insert(x);
s2.insert(x);
m1.insert(std::make_pair(x, x));
#ifndef BOOST_UNORDERED_CFOA_TESTS
itm1 = m1.begin();
citm1 = m1.cbegin();
#ifndef BOOST_UNORDERED_FOA_TESTS
litm1 = m1.begin(0);
clitm1 = m1.cbegin(0);
#endif
#endif
m2.insert(std::make_pair(x, x));
#ifndef BOOST_UNORDERED_CFOA_TESTS
itm2 = m2.begin();
citm2 = m2.cbegin();
#ifndef BOOST_UNORDERED_FOA_TESTS
litm2 = m2.begin(0);
clitm2 = m2.cbegin(0);
#endif
#endif
s1.insert(x);
#ifndef BOOST_UNORDERED_CFOA_TESTS
its1 = s1.begin();
cits1 = s1.cbegin();
#ifndef BOOST_UNORDERED_FOA_TESTS
lits1 = s1.begin(0);
clits1 = s1.cbegin(0);
#endif
#endif
s2.insert(x);
#ifndef BOOST_UNORDERED_CFOA_TESTS
its2 = s2.begin();
cits2 = s2.cbegin();
#ifndef BOOST_UNORDERED_FOA_TESTS
lits2 = s2.begin(0);
clits2 = s2.cbegin(0);
#endif
#endif
c1.x.insert(std::make_pair(c1, c1));
c2.x.insert(std::make_pair(c2, c2));
c3.x.insert(c3);
+5 -5
View File
@@ -1205,7 +1205,7 @@ template <class UnorderedMap> void test_map_non_transparent_erase(UnorderedMap*)
BOOST_TEST_EQ(key::count_, key_count);
}
#if BOOST_UNORDERED_FOA_TESTS
#ifdef BOOST_UNORDERED_FOA_TESTS
typedef boost::unordered_flat_set<int, transparent_hasher,
transparent_key_equal>
transparent_unordered_set;
@@ -1689,14 +1689,14 @@ template <class UnorderedMap> void test_map_transparent_at(UnorderedMap*)
map.at(0) = 7331;
BOOST_TEST_EQ(key::count_, key_count);
BOOST_TEST_THROWS(map.at(4), std::out_of_range)
BOOST_TEST_THROWS(map.at(4), std::out_of_range);
BOOST_TEST_EQ(key::count_, key_count);
UnorderedMap const& m = map;
BOOST_TEST_EQ(m.at(0), 7331);
BOOST_TEST_EQ(key::count_, key_count);
BOOST_TEST_THROWS(m.at(4), std::out_of_range)
BOOST_TEST_THROWS(m.at(4), std::out_of_range);
BOOST_TEST_EQ(key::count_, key_count);
}
@@ -1719,7 +1719,7 @@ template <class UnorderedMap> void test_map_non_transparent_at(UnorderedMap*)
BOOST_TEST_EQ(key::count_, key_count + 1);
key_count = key::count_;
BOOST_TEST_THROWS(map.at(4), std::out_of_range)
BOOST_TEST_THROWS(map.at(4), std::out_of_range);
BOOST_TEST_EQ(key::count_, key_count + 1);
key_count = key::count_;
@@ -1728,7 +1728,7 @@ template <class UnorderedMap> void test_map_non_transparent_at(UnorderedMap*)
BOOST_TEST_EQ(key::count_, key_count + 1);
key_count = key::count_;
BOOST_TEST_THROWS(m.at(4), std::out_of_range)
BOOST_TEST_THROWS(m.at(4), std::out_of_range);
BOOST_TEST_EQ(key::count_, key_count + 1);
}