mirror of
https://github.com/boostorg/unordered.git
synced 2025-06-25 11:51:33 +02:00
Compare commits
548 Commits
svn-trunk
...
boost-1.67
Author | SHA1 | Date | |
---|---|---|---|
741a10f5a8 | |||
c39dd284d2 | |||
4e5c97f3a3 | |||
e10fc0f93b | |||
8207ebe381 | |||
6491f6c10a | |||
cfd4bacc2c | |||
09be9bae04 | |||
c01a8c4629 | |||
cdb0229cf2 | |||
ddf302fcc2 | |||
ca9e9584ba | |||
0d34053870 | |||
66533ace80 | |||
ea599a66b7 | |||
1cc3f680e8 | |||
f7665a2743 | |||
dc9faddf22 | |||
e64c5b34df | |||
57492c1a94 | |||
df8fbca007 | |||
72fb9c7c96 | |||
ce0f16f328 | |||
a477d70f32 | |||
f3476de893 | |||
dea525b2b7 | |||
d55c9565ab | |||
00a4185cf1 | |||
ea28a3f98e | |||
c8facc99a7 | |||
d7ec41f4c6 | |||
9f2063846b | |||
c05c541216 | |||
34e54b35e8 | |||
f12009fc61 | |||
5854090dc7 | |||
7e28fdd45a | |||
daeaf5e98b | |||
4bffd7a85d | |||
7615fabc80 | |||
be0acc575f | |||
9d558b010d | |||
32773fb023 | |||
64441d2b64 | |||
07758b7af8 | |||
92ce66be64 | |||
15befe998e | |||
b50e0d610f | |||
f99dee1917 | |||
6327d174d2 | |||
c2b9b22f67 | |||
311e126ac4 | |||
c037169e1a | |||
9bb861accc | |||
ecd5b239a4 | |||
a600ef6cbb | |||
b90da4a802 | |||
c50ba694a5 | |||
8f7b7ca7b3 | |||
adfc7f4d5d | |||
9e18dc1401 | |||
cf76763ab7 | |||
fb7ef4cf63 | |||
04a0909105 | |||
613f154d47 | |||
978944fab2 | |||
705e69aefd | |||
e58081f6dc | |||
4ac8a45a34 | |||
6b5b968b97 | |||
2ab82ad653 | |||
86df284ad4 | |||
3521c87e17 | |||
32533f7325 | |||
0e19bdf50a | |||
f72b0353d4 | |||
0676b4f4ca | |||
929982357a | |||
5190a5d7f8 | |||
7775aa83df | |||
fc1604f2c8 | |||
5b97fbc292 | |||
4f5a2dabe9 | |||
e0227618bb | |||
ee9a5a2c77 | |||
6fffc738f7 | |||
dc611fc828 | |||
12ee29579d | |||
a897843f6c | |||
80de85f217 | |||
242e91a9fd | |||
ca80237191 | |||
b95ef6de04 | |||
76e7322262 | |||
3c42138e45 | |||
1b0b38a519 | |||
9119a42b7d | |||
8af4b37d14 | |||
31c5b5bfa1 | |||
b6c6bfbe7f | |||
6e074d7165 | |||
0489069419 | |||
597eb5a3fd | |||
3fe259a79e | |||
6ef17a0f0e | |||
47a8c3fc67 | |||
d49d0e90a8 | |||
77bd45b1fa | |||
622dff50df | |||
41f6a051ef | |||
d05619095c | |||
2f8492d720 | |||
7911f491f6 | |||
d84a57441b | |||
b8c754d230 | |||
338a94e577 | |||
2e14c340a8 | |||
35522d3ee0 | |||
8c139940e7 | |||
7b5f73f6c2 | |||
e7a3487df4 | |||
c243895fc0 | |||
451d0f2fc5 | |||
c75b332240 | |||
899248acbf | |||
cae6b121b2 | |||
5f6ee3da9c | |||
bfcdd51b4a | |||
10b736d407 | |||
0b61e6defb | |||
28f529100d | |||
6466ce0b51 | |||
03baef8b28 | |||
f1435d53d4 | |||
20b0c0a6d8 | |||
a1b1df84a0 | |||
408ebd0a0a | |||
e9c4696544 | |||
ea64f2e46e | |||
94a3a9baf9 | |||
da27ae4de6 | |||
ed326e2c87 | |||
bea4c6e29b | |||
61df9479e5 | |||
e3ab7b5d2e | |||
679b73098e | |||
cba643fc51 | |||
1c8edf0298 | |||
07b9a7d60e | |||
9c8980e6a1 | |||
60127d86e0 | |||
0c3c738614 | |||
c8bacbcb00 | |||
b070bb5e49 | |||
e518120104 | |||
84f1ef6d2d | |||
77bf2b5e33 | |||
8229aa6b3c | |||
fc08f62d6a | |||
1254520438 | |||
7941771d61 | |||
4f1c6e1ebf | |||
13ff1e7fb1 | |||
25b0b66e52 | |||
da835e88b8 | |||
b6c229e2bb | |||
19a45e028a | |||
435b7450d4 | |||
a41a0f3a06 | |||
814926ef31 | |||
f6f5ecdc00 | |||
42b6b13943 | |||
cfe4c26f99 | |||
3117611a55 | |||
1e491533fa | |||
a119caaa1b | |||
96f8f85eef | |||
2add451d63 | |||
3effedb728 | |||
b067e65731 | |||
f3b179d451 | |||
de5373413b | |||
fedf533699 | |||
9cd673c71d | |||
85a834cf62 | |||
5167c970af | |||
bf7a65010c | |||
461ac96a2c | |||
5eb10fd0b2 | |||
e2e9959389 | |||
d8969c71fc | |||
ab76814aa6 | |||
1a18cd2196 | |||
e4a00980f8 | |||
af94e6a40e | |||
ee73a53497 | |||
6bdf1ba244 | |||
d47754acac | |||
cee94e9fcb | |||
3ae9930979 | |||
2effcfa195 | |||
8c9080f11f | |||
ef05493c83 | |||
7a0a598649 | |||
cafd236a18 | |||
e0054c7dd0 | |||
3414e6628a | |||
08ce2c98e0 | |||
6d79a322e2 | |||
9e70680044 | |||
7de8c91301 | |||
c333a7f9fc | |||
bc36a06a2d | |||
e62ac22f0b | |||
1092c972c9 | |||
7e5520f974 | |||
2b01bdbc25 | |||
64a3be7d3e | |||
c0e03c3640 | |||
ed8c0f9ecd | |||
2bfc59c461 | |||
727e36e6a6 | |||
09bddd8df4 | |||
f089adc160 | |||
97b68ea05e | |||
972ac220f5 | |||
5d98f3d0f0 | |||
51cd1cd2af | |||
7e940e6e45 | |||
7aa7d8935c | |||
2f4d286a51 | |||
1bc5d87c5d | |||
c2d2be021a | |||
6b32d6bf09 | |||
c18f57f62b | |||
e657f75a17 | |||
d060d3a0e5 | |||
3c8c360f8c | |||
0af2c732ab | |||
68fe365f5b | |||
91bbd5fcb2 | |||
ac6b6bca48 | |||
b6e3f2303f | |||
da370a6a1a | |||
4aa74e5feb | |||
13322fe858 | |||
0645700b33 | |||
d89aadc56c | |||
21a24d6cd7 | |||
9c4c3a754a | |||
5f5f8ef1e4 | |||
958d206bb6 | |||
8fa93cc55b | |||
79cf0c4bfb | |||
81aefde94e | |||
96602df8a8 | |||
c0b72d97b3 | |||
ddee1b686a | |||
2231586033 | |||
13063abce5 | |||
570decf00e | |||
bf5ef9824d | |||
01dcd36c41 | |||
b2f2fdc2f3 | |||
f2af10c746 | |||
3bf664ad31 | |||
67ab88b064 | |||
67f1f65174 | |||
b1dff42434 | |||
57cc6d4bac | |||
e416cafd49 | |||
0aa79ce360 | |||
0a1c9ad4c5 | |||
dd85b16166 | |||
76127b6e42 | |||
03a597983e | |||
33f701dd09 | |||
3db4654b44 | |||
a7546e298e | |||
8a0592a35d | |||
98cce956f9 | |||
a34785fa0d | |||
14ccdbc7b6 | |||
5b5b46ea1c | |||
e3f534a148 | |||
1bcd5b0003 | |||
0d1cfba823 | |||
e986b70981 | |||
9b7b485c33 | |||
c680fa7418 | |||
9772c01161 | |||
6071f9a08b | |||
ad2256b13c | |||
dad0d48c9c | |||
e03a8732a6 | |||
7da307c696 | |||
82438a513b | |||
b5205e58aa | |||
b907cee691 | |||
da6e8e8041 | |||
3fd4495b2f | |||
04607dc9f3 | |||
ece4116329 | |||
74abdd6973 | |||
a316d3fa46 | |||
70ce6b4ae7 | |||
ade302f0a0 | |||
147885fec4 | |||
65aaf27380 | |||
b1588929cc | |||
094fa38360 | |||
71d19820ac | |||
a0dc86ecbc | |||
982685d3a0 | |||
dadb4486ee | |||
d14c1dec59 | |||
21d6d7bc21 | |||
ff0228e752 | |||
b00bc15c3e | |||
50c4cbe06c | |||
573e10665c | |||
d0acb81f2e | |||
e7b20d2877 | |||
588ad6e69f | |||
98462fbcc3 | |||
a93331dd96 | |||
e174af2286 | |||
9decbe0cbd | |||
021817f2b4 | |||
13ff69efbf | |||
8fda9113b8 | |||
b881bcfee3 | |||
1c606980ec | |||
0d6e58d9fd | |||
95e477902e | |||
cc32bfb96f | |||
7c2f11f8e1 | |||
d08dcb7465 | |||
2d1d6ccd75 | |||
7f380028cc | |||
827f77729f | |||
6c81de37f5 | |||
86a8a0429a | |||
4b00548138 | |||
8bb9473443 | |||
da7a5bf269 | |||
7434e116a7 | |||
8f51dc6082 | |||
79deac97dd | |||
9debeadee7 | |||
cae72eec2f | |||
e58370b4ff | |||
e92f7d86c1 | |||
93a33ba15f | |||
ad353c8e3d | |||
09717ffca4 | |||
ce4b840299 | |||
5a8df0ebe4 | |||
6029d1cfd0 | |||
3fe46a1769 | |||
5490bcfe95 | |||
078c562b6c | |||
88612a8be4 | |||
37a6903831 | |||
8017d9e684 | |||
609ae6cb4e | |||
603f785739 | |||
992f9ccf21 | |||
e250fb44f6 | |||
9767d86d97 | |||
7687c99708 | |||
81cc773013 | |||
cdb887e880 | |||
041fee64df | |||
e3dd1f276e | |||
0769ecd70d | |||
2be69b3eb9 | |||
bc601e34d2 | |||
79e39d9d43 | |||
6bc57bd398 | |||
1bca2df642 | |||
59cbe3d483 | |||
21f2522695 | |||
3720b0be58 | |||
413b45a62e | |||
7b8e3d01de | |||
b4a3c6f460 | |||
1d4845d6b8 | |||
c26acdba15 | |||
3f42a56bae | |||
144a0c1791 | |||
cc2b1a1ef1 | |||
84dd473a5d | |||
f014802eb6 | |||
68eb654e7a | |||
3a507b4e39 | |||
0273ec59d7 | |||
9090d87725 | |||
8ccde2e5a1 | |||
31211a607f | |||
56ab93d296 | |||
1d8855da27 | |||
df5a7538b1 | |||
0cedaf7ad6 | |||
b4795f414d | |||
2c9d209eef | |||
a81c86a90e | |||
bf0f90ff03 | |||
7c6f1ef227 | |||
99985bb1b2 | |||
8c5aa5086d | |||
b1232d8061 | |||
2f6b81d8c1 | |||
e1b39bbbfb | |||
6b7cecb9d3 | |||
79dcf7cbe8 | |||
d4702754b7 | |||
98d90f26d7 | |||
b97ceb6442 | |||
c18c645b92 | |||
15cb6d7d1b | |||
2f5d98a0cd | |||
2216c987a0 | |||
86d4d21250 | |||
3eb2355182 | |||
9440395330 | |||
034f2c3779 | |||
e93f5b0971 | |||
8c6f3e910b | |||
78bd2c0736 | |||
4e6ce91dd0 | |||
850d69738b | |||
9c62f83e74 | |||
99fdce0b4d | |||
06b6418044 | |||
57819d1dd9 | |||
80f3376894 | |||
94071cc6e8 | |||
038550a9df | |||
9ca8c691ac | |||
a4881436d2 | |||
70190b3aa2 | |||
8ae166a2c3 | |||
7d0c6d2425 | |||
5995e5521f | |||
59c83ab942 | |||
0a552a47cb | |||
3b5cf359e7 | |||
bea92e8842 | |||
6ca8d5e0d9 | |||
9b9a1d21a6 | |||
a7c0ddb5b3 | |||
c88126e1d2 | |||
0c7c7cc6ad | |||
bd10a8b5aa | |||
0221f1a9bd | |||
34b69e67ee | |||
654fed166a | |||
981f1e2acb | |||
81897a6469 | |||
ced2139eea | |||
0a8037243b | |||
a0ceefc91a | |||
05f7c37f54 | |||
d5971171da | |||
035396e89f | |||
8683332b2c | |||
d77453b7ad | |||
cf9930fe20 | |||
e30a99d2fc | |||
c788780792 | |||
e1416d0a3e | |||
808f1f939f | |||
880d778ab6 | |||
a8cd8cdd0b | |||
fa3d93ddbc | |||
5622afdafa | |||
63d56953af | |||
280b1971b6 | |||
abc556950b | |||
a8f75b7cea | |||
1f111edec8 | |||
8591c1f180 | |||
50e8df5e12 | |||
17ba6c9916 | |||
0618d01f86 | |||
5867994b8c | |||
f6f19aaaaa | |||
a4372314c2 | |||
3fd5635d7d | |||
147181530d | |||
54f9626c12 | |||
dc8e65043b | |||
8b4c480d47 | |||
70ca44b503 | |||
795d9f0aa7 | |||
ec97640b1b | |||
d3ca85bdbd | |||
fe2a6c521b | |||
958738c7af | |||
3fb7d15f5b | |||
2b212d7c49 | |||
aa0e8eedd2 | |||
f962857e68 | |||
02bf8f288e | |||
144d8963a3 | |||
f709c16d70 | |||
a3e57838ed | |||
2221c8334e | |||
584eaad67a | |||
14e09a5456 | |||
06b0b1d31c | |||
3529bc00dc | |||
1e7fe6a2d0 | |||
df1dad5cb6 | |||
1bc3ae3d9d | |||
60ecf12779 | |||
241316e0d9 | |||
9c43533655 | |||
ae09b0dd24 | |||
b018f8b173 | |||
0b4241833d | |||
e911a8011b | |||
f02cc7775d | |||
4e6b5de196 | |||
fb71e0618d | |||
694398f0e1 | |||
ab62d33495 | |||
b475ba05c0 | |||
60e3e96b48 | |||
c0e472755e | |||
6f45d36d97 | |||
2e9cf20cd0 | |||
f7c664a359 | |||
0921f8076d | |||
b8e8ffa242 | |||
07e715fceb | |||
89ab17cce5 | |||
517e39fc23 | |||
93141c26b9 | |||
dd2a994874 | |||
6571648bac | |||
f20f72bade | |||
4e4f99d51f | |||
56b9e0da1a | |||
4f27a146ef | |||
c8d0cb88ad | |||
5a898f2419 |
32
.appveyor.yml
Normal file
32
.appveyor.yml
Normal file
@ -0,0 +1,32 @@
|
||||
# Copyright 2017 Daniel James
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
|
||||
version: 1.0.{build}-{branch}
|
||||
|
||||
shallow_clone: true
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
|
||||
TOOLSET: msvc-10.0,msvc-11.0,msvc-12.0
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
TOOLSET: msvc-14.0
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
TOOLSET: msvc-14.1
|
||||
|
||||
install:
|
||||
- set BOOST_ROOT=c:\projects\boost
|
||||
- cd c:\projects\
|
||||
- python %APPVEYOR_BUILD_FOLDER%\build\download-boost-snapshot.py master
|
||||
- rd /s /q %BOOST_ROOT%\boost\unordered
|
||||
- cd %BOOST_ROOT%\tools\build
|
||||
- cmd /c bootstrap
|
||||
- cd %APPVEYOR_BUILD_FOLDER%
|
||||
- echo. 2>Jamroot.jam
|
||||
|
||||
build: off
|
||||
|
||||
test_script:
|
||||
- cd %APPVEYOR_BUILD_FOLDER%\test
|
||||
- cmd /c %BOOST_ROOT%\tools\build\b2 -j 3 toolset=%TOOLSET% include=%APPVEYOR_BUILD_FOLDER%\include include=%BOOST_ROOT%
|
7
.editorconfig
Normal file
7
.editorconfig
Normal file
@ -0,0 +1,7 @@
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
|
||||
[*.?pp]
|
||||
indent_size = 2
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/doc/html/
|
87
.travis.yml
Normal file
87
.travis.yml
Normal file
@ -0,0 +1,87 @@
|
||||
# Copyright (C) 2016 Daniel James.
|
||||
# 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)
|
||||
|
||||
# Use Trusty to get a reasonably recent version of Boost.
|
||||
sudo: required
|
||||
dist: trusty
|
||||
|
||||
language: c++
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libxml2-utils
|
||||
- g++-multilib
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- compiler: gcc
|
||||
env: |
|
||||
label="gcc C++03/11";
|
||||
user_config="using gcc : : g++-4.8 --coverage -fsanitize=address -Werror ;"
|
||||
enable_coverage=1
|
||||
CXXSTD=03,11
|
||||
- compiler: gcc
|
||||
env: |
|
||||
label="gcc 32 bit C++11";
|
||||
user_config="using gcc : : g++-4.8 -m32 -fsanitize=address -Werror ;"
|
||||
CXXSTD=11
|
||||
- compiler: clang
|
||||
env: |
|
||||
label="clang C++11/17";
|
||||
user_config="using clang : : clang++ -fsanitize=address -Werror ;"
|
||||
CXXSTD=11,17
|
||||
# sanitized=address not available for 32-bit clang on travis.
|
||||
- compiler: clang
|
||||
env: |
|
||||
label="clang 32 bit";
|
||||
user_config="using clang : : clang++ -m32 -Werror ;"
|
||||
CXXSTD=03
|
||||
|
||||
before_install:
|
||||
- if [ -n $enable_coverage ]; then pip install --user cpp-coveralls; fi
|
||||
|
||||
before_script:
|
||||
- export BOOST_VERSION=1.66.0
|
||||
- export BOOST_FILENAME=boost_1_66_0
|
||||
- export BOOST_ROOT=${HOME}/boost
|
||||
- cd ${TRAVIS_BUILD_DIR}
|
||||
- touch Jamroot.jam
|
||||
- cd $HOME
|
||||
- echo $user_config > ~/user-config.jam
|
||||
- cat ~/user-config.jam
|
||||
- |
|
||||
# Pick snapshot to use
|
||||
if [ "$TRAVIS_EVENT_TYPE" == "cron" ]
|
||||
then
|
||||
if [ "$TRAVIS_BRANCH" == "master" ]
|
||||
then
|
||||
snapshot=master
|
||||
else
|
||||
snapshot=develop
|
||||
fi
|
||||
else
|
||||
#snapshot=stable
|
||||
snapshot=master
|
||||
fi
|
||||
|
||||
# Download and extract snapshot
|
||||
echo "Downloading ${download_url}"
|
||||
mkdir $HOME/download
|
||||
cd $HOME/download
|
||||
python ${TRAVIS_BUILD_DIR}/build/download-boost-snapshot.py $snapshot
|
||||
mv * ${BOOST_ROOT}
|
||||
- rm -r ${BOOST_ROOT}/boost/unordered
|
||||
- cd ${BOOST_ROOT}/tools/build
|
||||
- mkdir ${HOME}/opt
|
||||
- bash bootstrap.sh
|
||||
- ./b2 install --prefix=$HOME/opt
|
||||
|
||||
after_success:
|
||||
if [ -n $enable_coverage ]; then coveralls -r ${TRAVIS_BUILD_DIR} -b ${TRAVIS_BUILD_DIR}/test --gcov-options '\-lp' --include include/boost/unordered/ ; fi
|
||||
|
||||
script:
|
||||
- cd ${TRAVIS_BUILD_DIR}/test
|
||||
- ${HOME}/opt/bin/b2 -j 3 cxxstd=$CXXSTD -q include=${BOOST_ROOT} include=${TRAVIS_BUILD_DIR}/include
|
||||
- xmllint --noout ${TRAVIS_BUILD_DIR}/doc/ref.xml
|
38
_clang-format
Normal file
38
_clang-format
Normal file
@ -0,0 +1,38 @@
|
||||
|
||||
# Copyright 2017 Daniel James.
|
||||
# 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)
|
||||
|
||||
# Using clang format 4.0
|
||||
# http://llvm.org/releases/4.0.0/tools/clang/docs/ClangFormatStyleOptions.html
|
||||
|
||||
# Becuase you have to start somewhere.
|
||||
BasedOnStyle: LLVM
|
||||
|
||||
# Basic settings
|
||||
ColumnLimit: 80
|
||||
NamespaceIndentation: All
|
||||
ContinuationIndentWidth: 2
|
||||
IndentWidth: 2
|
||||
UseTab: Never
|
||||
Language: Cpp
|
||||
Standard: Cpp03
|
||||
|
||||
# Code layout
|
||||
AlignAfterOpenBracket: DontAlign
|
||||
AlignTrailingComments: true
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterNamespace: false
|
||||
AfterClass: true
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterControlStatement: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
PointerAlignment: Left
|
||||
|
||||
# Boost specific stuff
|
||||
ForEachMacros: [ BOOST_FOREACH, UNORDERED_AUTO_TEST ]
|
66
build/download-boost-snapshot.py
Normal file
66
build/download-boost-snapshot.py
Normal file
@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import urllib, os, os.path, sys, json, tarfile, zipfile, tempfile
|
||||
|
||||
def download(snapshot):
|
||||
if snapshot == 'stable':
|
||||
# TODO: Default version/filename if not available?
|
||||
downloads = [
|
||||
"https://sourceforge.net/projects/boost/files/boost/%s/%s.tar.bz2/download" %
|
||||
(os.environ['BOOST_VERSION'], os.environ['BOOST_FILENAME'])]
|
||||
else:
|
||||
json_response = urllib.urlopen('https://api.bintray.com/packages/boostorg/%s/snapshot/files' % (snapshot))
|
||||
x = json.load(json_response)
|
||||
|
||||
extension_priorities = { '.bz2': 2, '.gz': 1, '.zip': 0 }
|
||||
file_list = []
|
||||
version_dates = {}
|
||||
for file in x:
|
||||
file_extension = os.path.splitext(file['path'])[1]
|
||||
if (file_extension in extension_priorities):
|
||||
file['priority'] = extension_priorities[file_extension]
|
||||
file_list.append(file)
|
||||
if not file['version'] in version_dates or file['created'] < version_dates[file['version']]:
|
||||
version_dates[file['version']] = file['created']
|
||||
file_list.sort(key=lambda x: (version_dates[x['version']], x['priority']), reverse=True)
|
||||
downloads = ['http://dl.bintray.com/boostorg/%s/%s' % (snapshot, file['path']) for file in file_list]
|
||||
|
||||
filename = ''
|
||||
for download_url in downloads:
|
||||
try:
|
||||
print "Downloading: " + download_url
|
||||
(filename, headers) = urllib.urlretrieve(download_url)
|
||||
|
||||
print "Extracting: " + filename
|
||||
dir = tempfile.mkdtemp()
|
||||
extract(filename, dir)
|
||||
os.remove(filename)
|
||||
files = os.listdir(dir)
|
||||
assert(len(files) == 1)
|
||||
os.rename(os.path.join(dir, files[0]), 'boost')
|
||||
return
|
||||
except IOError:
|
||||
print "Error opening URL: " + download_url
|
||||
|
||||
def extract(filename, path = '.'):
|
||||
if (filename.endswith(".gz")):
|
||||
tar = tarfile.open(filename, "r:gz")
|
||||
tar.extractall(path)
|
||||
tar.close
|
||||
elif (filename.endswith(".bz2")):
|
||||
tar = tarfile.open(filename, "r:bz2")
|
||||
tar.extractall(path)
|
||||
tar.close
|
||||
elif (filename.endswith(".zip")):
|
||||
zip = zipfile.ZipFile(filename, "r")
|
||||
zip.extractall(path)
|
||||
zip.close
|
||||
else:
|
||||
assert False
|
||||
|
||||
if len(sys.argv) == 1:
|
||||
download('stable')
|
||||
elif len(sys.argv) == 2:
|
||||
download(sys.argv[1])
|
||||
else:
|
||||
print "Usage: %s [stable|branch-name]" % (sys.argv[0])
|
@ -9,7 +9,9 @@ using quickbook ;
|
||||
path-constant images_location : ../ ;
|
||||
path-constant admonishment_location : ../../../../doc/src/images ;
|
||||
|
||||
xml unordered : unordered.qbk ;
|
||||
xml unordered : unordered.qbk :
|
||||
<xsl:param>generate.consistent.ids=1 ;
|
||||
|
||||
boostbook standalone : unordered :
|
||||
<xsl:param>chunk.first.sections=1
|
||||
<xsl:param>chunk.section.depth=2
|
||||
@ -21,6 +23,8 @@ boostbook standalone : unordered :
|
||||
<xsl:param>boost.compact.function=0
|
||||
<xsl:param>boost.compact.enum=0
|
||||
|
||||
<xsl:param>generate.consistent.ids=1
|
||||
|
||||
# HTML Options:
|
||||
|
||||
<format>html:<xsl:param>boost.root=../../../..
|
||||
@ -57,3 +61,12 @@ boostbook standalone : unordered :
|
||||
<format>pdf:<xsl:param>boost.url.prefix=http://www.boost.org/doc/libs/release/libs/unordered/doc/html
|
||||
;
|
||||
|
||||
###############################################################################
|
||||
alias boostdoc
|
||||
: unordered
|
||||
:
|
||||
:
|
||||
: ;
|
||||
explicit boostdoc ;
|
||||
alias boostrelease ;
|
||||
explicit boostrelease ;
|
||||
|
@ -17,7 +17,7 @@ the hash function, `Hash`, to the element's key (for `unordered_set` and
|
||||
`unordered_multiset` the key is the whole element, but is referred to as the key
|
||||
so that the same terminology can be used for sets and maps). This returns a
|
||||
value of type `std::size_t`. `std::size_t` has a much greater range of values
|
||||
then the number of buckets, so that container applies another transformation to
|
||||
then the number of buckets, so the container applies another transformation to
|
||||
that value to choose a bucket to place the element in.
|
||||
|
||||
Retrieving the elements for a given key is simple. The same process is applied
|
||||
@ -57,7 +57,7 @@ keep collisions to a minimum.
|
||||
</row>
|
||||
<row>
|
||||
<entry>'''`size_type bucket(key_type const& k) const`'''</entry>
|
||||
<entry>'''Returns the index of the bucket which would contain k'''</entry>
|
||||
<entry>'''Returns the index of the bucket which would contain `k`.'''</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>'''`local_iterator begin(size_type n);`'''</entry>
|
||||
@ -92,7 +92,7 @@ You can also tell the container to change the bucket count (if required) by
|
||||
calling `rehash`.
|
||||
|
||||
The standard leaves a lot of freedom to the implementer to decide how the
|
||||
number of buckets are chosen, but it does make some requirements based on the
|
||||
number of buckets is chosen, but it does make some requirements based on the
|
||||
container's 'load factor', the average number of elements per bucket.
|
||||
Containers also have a 'maximum load factor' which they should try to keep the
|
||||
load factor below.
|
||||
@ -138,7 +138,7 @@ or close to the hint - unless your hint is unreasonably small or large.
|
||||
]
|
||||
[
|
||||
[`void rehash(size_type n)`]
|
||||
[Changes the number of buckets so that there at least n buckets, and
|
||||
[Changes the number of buckets so that there at least `n` buckets, and
|
||||
so that the load factor is less than the maximum load factor.]
|
||||
]
|
||||
|
||||
@ -149,7 +149,7 @@ or close to the hint - unless your hint is unreasonably small or large.
|
||||
It is not specified how member functions other than `rehash` affect
|
||||
the bucket count, although `insert` is only allowed to invalidate iterators
|
||||
when the insertion causes the load factor to be greater than or equal to the
|
||||
maximum load factor. For most implementations this means that insert will only
|
||||
maximum load factor. For most implementations this means that `insert` will only
|
||||
change the number of buckets when this happens. While iterators can be
|
||||
invalidated by calls to `insert` and `rehash`, pointers and references to the
|
||||
container's elements are never invalidated.
|
||||
@ -160,12 +160,9 @@ the expensive rehashing out of the way and let you store iterators, safe in
|
||||
the knowledge that they won't be invalidated. If you are inserting `n`
|
||||
elements into container `x`, you could first call:
|
||||
|
||||
x.rehash((x.size() + n) / x.max_load_factor() + 1);
|
||||
x.rehash((x.size() + n) / x.max_load_factor());
|
||||
|
||||
[blurb Note: `rehash`'s argument is the minimum number of buckets, not the
|
||||
number of elements, which is why the new size is divided by the maximum load factor. The
|
||||
`+ 1` guarantees there is no invalidation; without it, reallocation could occur
|
||||
if the number of bucket exactly divides the target size, since the container is
|
||||
allowed to rehash when the load factor is equal to the maximum load factor.]
|
||||
number of elements, which is why the new size is divided by the maximum load factor.]
|
||||
|
||||
[endsect]
|
||||
|
129
doc/changes.qbk
129
doc/changes.qbk
@ -6,6 +6,8 @@
|
||||
[template ticket[number]'''<ulink
|
||||
url="https://svn.boost.org/trac/boost/ticket/'''[number]'''">'''#[number]'''</ulink>''']
|
||||
|
||||
[template pull_request[number][@https://github.com/boostorg/unordered/pull/[number] GitHub #[number]]]
|
||||
|
||||
[section:changes Change Log]
|
||||
|
||||
[h2 Review Version]
|
||||
@ -47,12 +49,12 @@ First official release.
|
||||
|
||||
[h2 Boost 1.38.0]
|
||||
|
||||
* Use [@boost:/libs/utility/swap.html `boost::swap`].
|
||||
* Use [@boost:/libs/core/swap.html `boost::swap`].
|
||||
* [@https://svn.boost.org/trac/boost/ticket/2237 Ticket 2237]:
|
||||
Document that the equality and inequality operators are undefined for two
|
||||
objects if their equality predicates aren't equivalent. Thanks to Daniel
|
||||
Krügler.
|
||||
* [@https://svn.boost.org/trac/boost/ticket/1710 Ticket 1710]:
|
||||
* [@https://svn.boost.org/trac/boost/ticket/1710 Ticket 1710]:
|
||||
Use a larger prime number list. Thanks to Thorsten Ottosen and Hervé
|
||||
Brönnimann.
|
||||
* Use
|
||||
@ -99,13 +101,13 @@ First official release.
|
||||
has been rewritten to use templates instead of macros for the implementation
|
||||
classes.
|
||||
|
||||
* The container objcet is now smaller thanks to using `boost::compressed_pair`
|
||||
* The container object is now smaller thanks to using `boost::compressed_pair`
|
||||
for EBO and a slightly different function buffer - now using a bool instead
|
||||
of a member pointer.
|
||||
|
||||
* Buckets are allocated lazily which means that constructing an empty container
|
||||
will not allocate any memory.
|
||||
|
||||
|
||||
[h2 Boost 1.42.0]
|
||||
|
||||
* Support instantiating the containers with incomplete value types.
|
||||
@ -170,7 +172,7 @@ C++11 support has resulted in some breaking changes:
|
||||
longer does so. It does emulate the new `piecewise_construct`
|
||||
pair constructors - only you need to use
|
||||
`boost::piecewise_construct`. To use the old emulation of
|
||||
the variadic consturctors define
|
||||
the variadic constructors define
|
||||
`BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT`.
|
||||
|
||||
[h2 Boost 1.49.0]
|
||||
@ -207,7 +209,7 @@ C++11 support has resulted in some breaking changes:
|
||||
* Fix construction/destruction issue when using a C++11 compiler with a
|
||||
C++03 allocator ([ticket 7100]).
|
||||
* Remove a `try..catch` to support compiling without exceptions.
|
||||
* Adjust SFINAE use to try to supprt g++ 3.4 ([ticket 7175]).
|
||||
* Adjust SFINAE use to try to support g++ 3.4 ([ticket 7175]).
|
||||
* Updated to use the new config macros.
|
||||
|
||||
[h2 Boost 1.52.0]
|
||||
@ -239,5 +241,120 @@ C++11 support has resulted in some breaking changes:
|
||||
|
||||
* Avoid some warnings ([ticket 8851], [ticket 8874]).
|
||||
* Avoid exposing some detail functions via. ADL on the iterators.
|
||||
* Follow the standard by only using the allocators' construct and destroy
|
||||
methods to construct and destroy stored elements. Don't use them for internal
|
||||
data like pointers.
|
||||
|
||||
[h2 Boost 1.56.0]
|
||||
|
||||
* Fix some shadowed variable warnings ([ticket 9377]).
|
||||
* Fix allocator use in documentation ([ticket 9719]).
|
||||
* Always use prime number of buckets for integers. Fixes performance
|
||||
regression when inserting consecutive integers, although makes other
|
||||
uses slower ([ticket 9282]).
|
||||
* Only construct elements using allocators, as specified in C++11 standard.
|
||||
|
||||
[h2 Boost 1.57.0]
|
||||
|
||||
* Fix the `pointer` typedef in iterators ([ticket 10672]).
|
||||
* Fix Coverity warning
|
||||
([@https://github.com/boostorg/unordered/pull/2 GitHub #2]).
|
||||
|
||||
[h2 Boost 1.58.0]
|
||||
|
||||
* Remove unnecessary template parameter from const iterators.
|
||||
* Rename private `iterator` typedef in some iterator classes, as it
|
||||
confuses some traits classes.
|
||||
* Fix move assignment with stateful, propagate_on_container_move_assign
|
||||
allocators ([ticket 10777]).
|
||||
* Fix rare exception safety issue in move assignment.
|
||||
* Fix potential overflow when calculating number of buckets to allocate
|
||||
([@https://github.com/boostorg/unordered/pull/4 GitHub #4]).
|
||||
|
||||
[h2 Boost 1.62.0]
|
||||
|
||||
* Remove use of deprecated `boost::iterator`.
|
||||
* Remove `BOOST_NO_STD_DISTANCE` workaround.
|
||||
* Remove `BOOST_UNORDERED_DEPRECATED_EQUALITY` warning.
|
||||
* Simpler implementation of assignment, fixes an exception safety issue
|
||||
for `unordered_multiset` and `unordered_multimap`. Might be a little slower.
|
||||
* Stop using return value SFINAE which some older compilers have issues
|
||||
with.
|
||||
|
||||
[h2 Boost 1.63.0]
|
||||
|
||||
* Check hint iterator in `insert`/`emplace_hint`.
|
||||
* Fix some warnings, mostly in the tests.
|
||||
* Manually write out `emplace_args` for small numbers of arguments -
|
||||
should make template error messages a little more bearable.
|
||||
* Remove superfluous use of `boost::forward` in emplace arguments,
|
||||
which fixes emplacing string literals in old versions of Visual C++.
|
||||
* Fix an exception safety issue in assignment. If bucket allocation
|
||||
throws an exception, it can overwrite the hash and equality functions while
|
||||
leaving the existing elements in place. This would mean that the function
|
||||
objects wouldn't match the container elements, so elements might be in the
|
||||
wrong bucket and equivalent elements would be incorrectly handled.
|
||||
* Various reference documentation improvements.
|
||||
* Better allocator support ([ticket 12459]).
|
||||
* Make the no argument constructors implicit.
|
||||
* Implement missing allocator aware constructors.
|
||||
* Fix assigning the hash/key equality functions for empty containers.
|
||||
* Remove unary/binary_function from the examples in the documentation.
|
||||
They are removed in C++17.
|
||||
* Support 10 constructor arguments in emplace. It was meant to support up to 10
|
||||
arguments, but an off by one error in the preprocessor code meant it only
|
||||
supported up to 9.
|
||||
|
||||
[h2 Boost 1.64.0]
|
||||
* Initial support for new C++17 member functions:
|
||||
`insert_or_assign` and `try_emplace` in `unordered_map`,
|
||||
* Initial support for `merge` and `extract`.
|
||||
Does not include transferring nodes between
|
||||
`unordered_map` and `unordered_multimap` or between `unordered_set` and
|
||||
`unordered_multiset` yet. That will hopefully be in the next version of
|
||||
Boost.
|
||||
|
||||
[h2 Boost 1.65.0]
|
||||
|
||||
* Add deprecated attributes to `quick_erase` and `erase_return_void`.
|
||||
I really will remove them in a future version this time.
|
||||
* Small standards compliance fixes:
|
||||
* `noexpect` specs for `swap` free functions.
|
||||
* Add missing `insert(P&&)` methods.
|
||||
|
||||
[h2 Boost 1.66.0]
|
||||
|
||||
* Simpler move construction implementation.
|
||||
* Documentation fixes ([pull_request 6]).
|
||||
|
||||
[h2 Boost 1.67.0]
|
||||
|
||||
* Improved C++17 support:
|
||||
* Add template deduction guides from the standard.
|
||||
* Use a simple implementation of `optional` in node handles, so
|
||||
that they're closer to the standard.
|
||||
* Add missing `noexcept` specifications to `swap`, `operator=`
|
||||
and node handles, and change the implementation to match.
|
||||
Using `std::allocator_traits::is_always_equal`, or our own
|
||||
implementation when not available, and
|
||||
`boost::is_nothrow_swappable` in the implementation.
|
||||
* Improved C++20 support:
|
||||
* Use `boost::to_address`, which has the proposed C++20 semantics,
|
||||
rather than the old custom implementation.
|
||||
* Add `element_type` to iterators, so that `std::pointer_traits`
|
||||
will work.
|
||||
* Use `std::piecewise_construct` on recent versions of Visual C++,
|
||||
and other uses of the Dinkumware standard library,
|
||||
now using Boost.Predef to check compiler and library versions.
|
||||
* Use `std::iterator_traits` rather than the boost iterator traits
|
||||
in order to remove dependency on Boost.Iterator.
|
||||
* Remove iterators' inheritance from `std::iterator`, which is
|
||||
deprecated in C++17, thanks to Daniela Engert
|
||||
([@https://github.com/boostorg/unordered/pull/7 PR#7]).
|
||||
* Stop using `BOOST_DEDUCED_TYPENAME`.
|
||||
* Update some Boost include paths.
|
||||
* Rename some internal methods, and variables.
|
||||
* Various testing improvements.
|
||||
* Miscellaneous internal changes.
|
||||
|
||||
[endsect]
|
||||
|
@ -60,7 +60,7 @@
|
||||
[Iterators iterate through the container in the order defined by
|
||||
the comparison object.]
|
||||
[Iterators iterate through the container in an arbitrary order, that
|
||||
can change as elements are inserted. Although, equivalent elements
|
||||
can change as elements are inserted, although equivalent elements
|
||||
are always adjacent.]
|
||||
]
|
||||
[
|
||||
|
@ -2,7 +2,13 @@
|
||||
/ 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) ]
|
||||
|
||||
[section:compliance C++11 Compliance]
|
||||
[section:compliance Standard Compliance]
|
||||
|
||||
The intent of Boost.Unordered is to implement a close (but imperfect)
|
||||
implementation of the C++17 standard, that will work with C++98 upwards.
|
||||
The wide compatibility does mean some comprimises have to be made.
|
||||
With a compiler and library that fully support C++11, the differences should
|
||||
be minor.
|
||||
|
||||
[section:move Move emulation]
|
||||
|
||||
@ -51,23 +57,32 @@ Due to imperfect move emulation, some assignments might check
|
||||
`propagate_on_container_copy_assignment` on some compilers and
|
||||
`propagate_on_container_move_assignment` on others.
|
||||
|
||||
The use of the allocator's construct and destruct methods might be a bit
|
||||
surprising.
|
||||
Nodes are constructed and destructed using the allocator, but the elements
|
||||
are stored in aligned space within the node and constructed and destructed
|
||||
by calling the constructor and destructor directly.
|
||||
[endsect]
|
||||
|
||||
In C++11 the allocator's construct function has the signature:
|
||||
[section:construction Construction/Destruction using allocators]
|
||||
|
||||
template <class U, class... Args>
|
||||
void construct(U* p, Args&&... args);
|
||||
The following support is required for full use of C++11 style
|
||||
construction/destruction:
|
||||
|
||||
which supports calling `construct` for the contained object, but
|
||||
most existing allocators don't support this. If member function detection
|
||||
was good enough then with old allocators it would fall back to calling
|
||||
the element's constructor directly but in general, detection isn't good
|
||||
enough to do this which is why Boost.Unordered just calls the constructor
|
||||
directly every time. In most cases this will work okay.
|
||||
* Variadic templates.
|
||||
* Piecewise construction of `std::pair`.
|
||||
* Either `std::allocator_traits` or expression SFINAE.
|
||||
|
||||
This is detected using Boost.Config. The macro
|
||||
`BOOST_UNORDERED_CXX11_CONSTRUCTION` will be set to 1 if it is found, or 0
|
||||
otherwise.
|
||||
|
||||
When this is the case `allocator_traits::construct` and
|
||||
`allocator_traits::destroy` will always be used, apart from when piecewise
|
||||
constructing a `std::pair` using `boost::tuple` (see [link
|
||||
unordered.compliance.pairs below]), but that should be easily avoided.
|
||||
|
||||
When support is not available `allocator_traits::construct` and
|
||||
`allocator_traits::destroy` are never called.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:pointer_traits Pointer Traits]
|
||||
|
||||
`pointer_traits` aren't used. Instead, pointer types are obtained from
|
||||
rebound allocators, this can cause problems if the allocator can't be
|
||||
@ -77,6 +92,7 @@ is used to obtain a const pointer.
|
||||
|
||||
[endsect]
|
||||
|
||||
[#unordered.compliance.pairs]
|
||||
[section:pairs Pairs]
|
||||
|
||||
Since the containers use `std::pair` they're limited to the version
|
||||
@ -101,7 +117,7 @@ first part of the pair, and the remaining for the second part.
|
||||
|
||||
When swapping, `Pred` and `Hash` are not currently swapped by calling
|
||||
`swap`, their copy constructors are used. As a consequence when swapping
|
||||
an exception may be throw from their copy constructor.
|
||||
an exception may be thrown from their copy constructor.
|
||||
|
||||
Variadic constructor arguments for `emplace` are only used when both
|
||||
rvalue references and variadic template parameters are available.
|
||||
|
@ -54,14 +54,14 @@ order to work with non-C++11 compilers and libraries.
|
||||
class Key, class Mapped,
|
||||
class Hash = ``[classref boost::hash]``<Key>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Alloc = std::allocator<Key> >
|
||||
class Alloc = std::allocator<std::pair<Key const, Mapped> > >
|
||||
class ``[classref boost::unordered_map unordered_map]``;
|
||||
|
||||
template<
|
||||
class Key, class Mapped,
|
||||
class Hash = ``[classref boost::hash]``<Key>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Alloc = std::allocator<Key> >
|
||||
class Alloc = std::allocator<std::pair<Key const, Mapped> > >
|
||||
class ``[classref boost::unordered_multimap unordered_multimap]``;
|
||||
}
|
||||
|
||||
@ -84,7 +84,7 @@ can be in any order. For example, it might be:
|
||||
one,1
|
||||
three,3
|
||||
|
||||
To store an object in an unordered associative container requires both an
|
||||
To store an object in an unordered associative container requires both a
|
||||
key equality function and a hash function. The default function objects in
|
||||
the standard containers support a few basic types including integer types,
|
||||
floating point types, pointer types, and the standard strings. Since
|
||||
|
@ -13,7 +13,7 @@ containers in the draft standard, so the interface was fixed. But there are
|
||||
still some implementation decisions to make. The priorities are
|
||||
conformance to the standard and portability.
|
||||
|
||||
The [@http://en.wikipedia.org/wiki/Hash_table wikipedia article on hash tables]
|
||||
The [@http://en.wikipedia.org/wiki/Hash_table Wikipedia article on hash tables]
|
||||
has a good summary of the implementation issues for hash tables in general.
|
||||
|
||||
[h2 Data Structure]
|
||||
@ -23,7 +23,7 @@ standard pretty much requires that the hash table uses chained addressing.
|
||||
|
||||
It would be conceivable to write a hash table that uses another method. For
|
||||
example, it could use open addressing, and use the lookup chain to act as a
|
||||
bucket but there are a some serious problems with this:
|
||||
bucket but there are some serious problems with this:
|
||||
|
||||
* The draft standard requires that pointers to elements aren't invalidated, so
|
||||
the elements can't be stored in one array, but will need a layer of
|
||||
@ -89,7 +89,7 @@ is that the required modulus operation is fairly expensive. This is what the
|
||||
containers do in most cases.
|
||||
|
||||
Using a power of 2 allows for much quicker selection of the bucket
|
||||
to use, but at the expense of loosing the upper bits of the hash value.
|
||||
to use, but at the expense of losing the upper bits of the hash value.
|
||||
For some specially designed hash functions it is possible to do this and
|
||||
still get a good result but as the containers can take arbitrary hash
|
||||
functions this can't be relied on.
|
||||
@ -100,7 +100,7 @@ knowledge of the number of bits in the hash value, so it isn't portable enough
|
||||
to use as a default. It can applicable in certain cases so the containers
|
||||
have a policy based implementation that can use this alternative technique.
|
||||
|
||||
Currently this is only done on 64 bit architecures, where prime number
|
||||
Currently this is only done on 64 bit architectures, where prime number
|
||||
modulus can be expensive. Although this varies depending on the architecture,
|
||||
so I probably should revisit it.
|
||||
|
||||
|
573
doc/ref.php
573
doc/ref.php
@ -7,6 +7,10 @@ function echo_unordered_docs(
|
||||
$name = 'unordered_'.
|
||||
($equivalent_keys ? 'multi' : '').
|
||||
($map ? 'map' : 'set');
|
||||
// For merge....
|
||||
$node_partner = 'unordered_'.
|
||||
($equivalent_keys ? '' : 'multi').
|
||||
($map ? 'map' : 'set');
|
||||
|
||||
if ($map)
|
||||
{
|
||||
@ -189,10 +193,36 @@ EOL;
|
||||
<para>A const_local_iterator object can be used to iterate through a single bucket.</para>
|
||||
</description>
|
||||
</typedef>
|
||||
<typedef name="node_type">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
<description>
|
||||
<para>See <classname>node_handle_<?php echo $map ? 'map' : 'set'; ?></classname> for details.</para>
|
||||
</description>
|
||||
</typedef>
|
||||
<?php if (!$equivalent_keys): ?>
|
||||
<typedef name="insert_return_type">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
<description>
|
||||
Structure returned by inserting <code>node_type</code>.
|
||||
</description>
|
||||
</typedef>
|
||||
<?php endif; ?>
|
||||
<constructor>
|
||||
<postconditions>
|
||||
<code><methodname>size</methodname>() == 0</code>
|
||||
</postconditions>
|
||||
<description>
|
||||
<para>Constructs an empty container using hasher() as the hash function, key_equal() as the key equality predicate, allocator_type() as the allocator and a maximum load factor of 1.0.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para>If the defaults are used, <code>hasher</code>, <code>key_equal</code> and
|
||||
<code>allocator_type</code> need to be <code>DefaultConstructible</code>.
|
||||
</para>
|
||||
</requires>
|
||||
</constructor>
|
||||
<constructor specifiers="explicit">
|
||||
<parameter name="n">
|
||||
<paramtype>size_type</paramtype>
|
||||
<default><emphasis>implementation-defined</emphasis></default>
|
||||
</parameter>
|
||||
<parameter name="hf">
|
||||
<paramtype>hasher const&</paramtype>
|
||||
@ -246,7 +276,12 @@ EOL;
|
||||
<default>allocator_type()</default>
|
||||
</parameter>
|
||||
<description>
|
||||
<para>Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0 and inserts the elements from [f, l) into it.</para>
|
||||
<para>Constructs an empty container with at least <code>n</code> buckets,
|
||||
using <code>hf</code> as the hash function,
|
||||
<code>eq</code> as the key equality predicate,
|
||||
<code>a</code> as the allocator and a maximum load factor of 1.0
|
||||
and inserts the elements from [f, l) into it.
|
||||
</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para>If the defaults are used, <code>hasher</code>, <code>key_equal</code> and
|
||||
@ -310,6 +345,168 @@ EOL;
|
||||
<para>Constructs an container, copying <code>x</code>'s contained elements, hash function, predicate, maximum load factor, but using allocator <code>a</code>.</para>
|
||||
</description>
|
||||
</constructor>
|
||||
<constructor>
|
||||
<parameter name="x">
|
||||
<paramtype><?php echo $name; ?> &&</paramtype>
|
||||
</parameter>
|
||||
<parameter name="a">
|
||||
<paramtype>Allocator const&</paramtype>
|
||||
</parameter>
|
||||
<description>
|
||||
<para>Construct a container moving <code>x</code>'s contained elements, and having the hash function, predicate and maximum load factor, but using allocate <code>a</code>.</para>
|
||||
</description>
|
||||
<notes>
|
||||
<para>This is implemented using Boost.Move.</para>
|
||||
</notes>
|
||||
<requires>
|
||||
<para>
|
||||
<code>value_type</code> is move insertable.
|
||||
</para>
|
||||
</requires>
|
||||
</constructor>
|
||||
<constructor>
|
||||
<parameter name="il">
|
||||
<paramtype>initializer_list<value_type></paramtype>
|
||||
</parameter>
|
||||
<parameter name="n">
|
||||
<paramtype>size_type</paramtype>
|
||||
<default><emphasis>implementation-defined</emphasis></default>
|
||||
</parameter>
|
||||
<parameter name="hf">
|
||||
<paramtype>hasher const&</paramtype>
|
||||
<default>hasher()</default>
|
||||
</parameter>
|
||||
<parameter name="eq">
|
||||
<paramtype>key_equal const&</paramtype>
|
||||
<default>key_equal()</default>
|
||||
</parameter>
|
||||
<parameter name="a">
|
||||
<paramtype>allocator_type const&</paramtype>
|
||||
<default>allocator_type()</default>
|
||||
</parameter>
|
||||
<description>
|
||||
<para>Constructs an empty container with at least <code>n</code> buckets,
|
||||
using <code>hf</code> as the hash function,
|
||||
<code>eq</code> as the key equality predicate,
|
||||
<code>a</code> as the allocator and a maximum load factor of 1.0
|
||||
and inserts the elements from <code>il</code> into it.
|
||||
</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para>If the defaults are used, <code>hasher</code>, <code>key_equal</code> and
|
||||
<code>allocator_type</code> need to be <code>DefaultConstructible</code>.
|
||||
</para>
|
||||
</requires>
|
||||
</constructor>
|
||||
<constructor>
|
||||
<parameter name="n">
|
||||
<paramtype>size_type</paramtype>
|
||||
</parameter>
|
||||
<parameter name="a">
|
||||
<paramtype>allocator_type const&</paramtype>
|
||||
</parameter>
|
||||
<postconditions>
|
||||
<code><methodname>size</methodname>() == 0</code>
|
||||
</postconditions>
|
||||
<description>
|
||||
<para>Constructs an empty container with at least <code>n</code> buckets,
|
||||
using <code>hf</code> as the hash function,
|
||||
the default hash function and key equality predicate,
|
||||
<code>a</code> as the allocator and a maximum load factor of 1.0.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>hasher</code> and <code>key_equal</code> need to be <code>DefaultConstructible</code>.
|
||||
</para>
|
||||
</requires>
|
||||
</constructor>
|
||||
<constructor>
|
||||
<parameter name="n">
|
||||
<paramtype>size_type</paramtype>
|
||||
</parameter>
|
||||
<parameter name="hf">
|
||||
<paramtype>hasher const&</paramtype>
|
||||
</parameter>
|
||||
<parameter name="a">
|
||||
<paramtype>allocator_type const&</paramtype>
|
||||
</parameter>
|
||||
<postconditions>
|
||||
<code><methodname>size</methodname>() == 0</code>
|
||||
</postconditions>
|
||||
<description>
|
||||
<para>Constructs an empty container with at least <code>n</code> buckets,
|
||||
using <code>hf</code> as the hash function,
|
||||
the default key equality predicate,
|
||||
<code>a</code> as the allocator and a maximum load factor of 1.0.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>key_equal</code> needs to be <code>DefaultConstructible</code>.
|
||||
</para>
|
||||
</requires>
|
||||
</constructor>
|
||||
<constructor>
|
||||
<template>
|
||||
<template-type-parameter name="InputIterator">
|
||||
</template-type-parameter>
|
||||
</template>
|
||||
<parameter name="f">
|
||||
<paramtype>InputIterator</paramtype>
|
||||
</parameter>
|
||||
<parameter name="l">
|
||||
<paramtype>InputIterator</paramtype>
|
||||
</parameter>
|
||||
<parameter name="n">
|
||||
<paramtype>size_type</paramtype>
|
||||
</parameter>
|
||||
<parameter name="a">
|
||||
<paramtype>allocator_type const&</paramtype>
|
||||
</parameter>
|
||||
<description>
|
||||
<para>Constructs an empty container with at least <code>n</code> buckets,
|
||||
using <code>a</code> as the allocator, with the
|
||||
default hash function and key equality predicate
|
||||
and a maximum load factor of 1.0
|
||||
and inserts the elements from [f, l) into it.
|
||||
</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>hasher</code>, <code>key_equal</code> need to be <code>DefaultConstructible</code>.
|
||||
</para>
|
||||
</requires>
|
||||
</constructor>
|
||||
<constructor>
|
||||
<template>
|
||||
<template-type-parameter name="InputIterator">
|
||||
</template-type-parameter>
|
||||
</template>
|
||||
<parameter name="f">
|
||||
<paramtype>InputIterator</paramtype>
|
||||
</parameter>
|
||||
<parameter name="l">
|
||||
<paramtype>InputIterator</paramtype>
|
||||
</parameter>
|
||||
<parameter name="n">
|
||||
<paramtype>size_type</paramtype>
|
||||
</parameter>
|
||||
<parameter name="hf">
|
||||
<paramtype>hasher const&</paramtype>
|
||||
</parameter>
|
||||
<parameter name="a">
|
||||
<paramtype>allocator_type const&</paramtype>
|
||||
</parameter>
|
||||
<description>
|
||||
<para>Constructs an empty container with at least <code>n</code> buckets,
|
||||
using <code>hf</code> as the hash function,
|
||||
<code>a</code> as the allocator, with the
|
||||
default key equality predicate
|
||||
and a maximum load factor of 1.0
|
||||
and inserts the elements from [f, l) into it.
|
||||
</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>key_equal</code> needs to be <code>DefaultConstructible</code>.
|
||||
</para>
|
||||
</requires>
|
||||
</constructor>
|
||||
<destructor>
|
||||
<notes>
|
||||
<para>The destructor is applied to every element, and all memory is deallocated</para>
|
||||
@ -358,6 +555,21 @@ EOL;
|
||||
</para>
|
||||
</requires>
|
||||
</method>
|
||||
<method name="operator=">
|
||||
<parameter>
|
||||
<paramtype>initializer_list<value_type></paramtype>
|
||||
</parameter>
|
||||
<type><?php echo $name; ?>&</type>
|
||||
<description>
|
||||
<para>Assign from values in initializer list. All existing elements are either overwritten by the new elements or destroyed.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para>
|
||||
<code>value_type</code> is <code>CopyInsertable</code> into the container and
|
||||
<code>CopyAssignable</code>.
|
||||
</para>
|
||||
</requires>
|
||||
</method>
|
||||
<method name="get_allocator" cv="const">
|
||||
<type>allocator_type</type>
|
||||
</method>
|
||||
@ -639,6 +851,54 @@ EOL;
|
||||
<paramtype>InputIterator</paramtype>
|
||||
</parameter>
|
||||
<type>void</type>
|
||||
<description>
|
||||
<para>Inserts a range of elements into the container.
|
||||
<?php if (!$equivalent_keys): ?>
|
||||
Elements are inserted if and only if there is no element in the container with an equivalent <?php echo $key_name; ?>.
|
||||
<?php endif; ?>
|
||||
</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>EmplaceConstructible</code> into
|
||||
<code>X</code> from <code>*first</code>.</para>
|
||||
</requires>
|
||||
<throws>
|
||||
<para>When inserting a single element, if an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
|
||||
</throws>
|
||||
<notes>
|
||||
<para>Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.</para>
|
||||
<para>Pointers and references to elements are never invalidated.</para>
|
||||
</notes>
|
||||
</method>
|
||||
<method name="insert">
|
||||
<parameter name="il">
|
||||
<paramtype>initializer_list<value_type></paramtype>
|
||||
</parameter>
|
||||
<type>void</type>
|
||||
<description>
|
||||
<para>Inserts a range of elements into the container.
|
||||
<?php if (!$equivalent_keys): ?>
|
||||
Elements are inserted if and only if there is no element in the container with an equivalent <?php echo $key_name; ?>.
|
||||
<?php endif; ?>
|
||||
</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>EmplaceConstructible</code> into
|
||||
<code>X</code> from <code>*first</code>.</para>
|
||||
</requires>
|
||||
<throws>
|
||||
<para>When inserting a single element, if an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
|
||||
</throws>
|
||||
<notes>
|
||||
<para>Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.</para>
|
||||
<para>Pointers and references to elements are never invalidated.</para>
|
||||
</notes>
|
||||
</method>
|
||||
<method name="insert">
|
||||
<parameter name="il">
|
||||
<paramtype>initializer_list<value_type></paramtype>
|
||||
</parameter>
|
||||
<type>void</type>
|
||||
<description>
|
||||
<para>Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent <?php echo $key_name; ?>.</para>
|
||||
</description>
|
||||
@ -654,6 +914,138 @@ EOL;
|
||||
<para>Pointers and references to elements are never invalidated.</para>
|
||||
</notes>
|
||||
</method>
|
||||
<method name="extract">
|
||||
<parameter name="position">
|
||||
<paramtype>const_iterator</paramtype>
|
||||
</parameter>
|
||||
<type>node_type</type>
|
||||
<description>
|
||||
<para>Removes the element pointed to by <code>position</code>.</para>
|
||||
</description>
|
||||
<returns>
|
||||
<para>A <code>node_type</code> owning the element.</para>
|
||||
</returns>
|
||||
<notes>
|
||||
<para>
|
||||
In C++17 a node extracted using this method can be inserted into a compatible <code><?php echo $node_partner; ?></code>,
|
||||
but that is not supported yet.
|
||||
</para>
|
||||
</notes>
|
||||
</method>
|
||||
<method name="extract">
|
||||
<parameter name="k">
|
||||
<paramtype>key_type const&</paramtype>
|
||||
</parameter>
|
||||
<type>node_type</type>
|
||||
<description>
|
||||
<para>Removes an element with key equivalent to <code>k</code>.</para>
|
||||
</description>
|
||||
<returns>
|
||||
<para>A <code>node_type</code> owning the element if found, otherwise an empty <code>node_type</code>.</para>
|
||||
</returns>
|
||||
<throws>
|
||||
<para>Only throws an exception if it is thrown by <code>hasher</code> or <code>key_equal</code>.</para>
|
||||
</throws>
|
||||
<notes>
|
||||
<para>
|
||||
In C++17 a node extracted using this method can be inserted into a compatible <code><?php echo $node_partner; ?></code>,
|
||||
but that is not supported yet.
|
||||
</para>
|
||||
</notes>
|
||||
</method>
|
||||
<method name="insert">
|
||||
<parameter name="nh">
|
||||
<paramtype>node_type&&</paramtype>
|
||||
</parameter>
|
||||
<type><?php echo $equivalent_keys ? 'iterator' : 'insert_return_type' ?></type>
|
||||
<description>
|
||||
<para>If <code>nh</code> is empty, has no affect.</para>
|
||||
<?php if ($equivalent_keys): ?>
|
||||
<para>Otherwise inserts the element owned by <code>nh</code></para>
|
||||
<?php else: ?>
|
||||
<para>Otherwise inserts the element owned by <code>nh</code>
|
||||
if and only if there is no element in the container with an equivalent <?php echo $key_name; ?>.
|
||||
</para>
|
||||
<?php endif ?>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>nh</code> is empty or <code>nh.get_allocator()</code> is equal to the container's allocator.</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<?php if ($equivalent_keys): ?>
|
||||
<para>If <code>nh</code> was empty, returns <code>end()</code>.</para>
|
||||
<para>Otherwise returns an iterator pointing to the newly inserted element.</para>
|
||||
<?php else: ?>
|
||||
<para>If <code>nh</code> was empty, returns an <code>insert_return_type</code> with:
|
||||
<code>inserted</code> equal to <code>false</code>,
|
||||
<code>position</code> equal to <code>end()</code> and
|
||||
<code>node</code> empty.</para>
|
||||
<para>Otherwise if there was already an element with an equivalent key, returns an <code>insert_return_type</code> with:
|
||||
<code>inserted</code> equal to <code>false</code>,
|
||||
<code>position</code> pointing to a matching element and
|
||||
<code>node</code> contains the node from <code>nh</code>.</para>
|
||||
<para>Otherwise if the insertion succeeded, returns an <code>insert_return_type</code> with:
|
||||
<code>inserted</code> equal to <code>true</code>,
|
||||
<code>position</code> pointing to the newly inserted element and
|
||||
<code>node</code> empty.</para>
|
||||
<?php endif; ?>
|
||||
</returns>
|
||||
<throws>
|
||||
<para>If an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
|
||||
</throws>
|
||||
<notes>
|
||||
<para>Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.</para>
|
||||
<para>Pointers and references to elements are never invalidated.</para>
|
||||
<para>In C++17 this can be used to insert a node extracted from a compatible <code><?php echo $node_partner; ?></code>,
|
||||
but that is not supported yet.</para>
|
||||
</notes>
|
||||
</method>
|
||||
<method name="insert">
|
||||
<parameter name="hint">
|
||||
<paramtype>const_iterator</paramtype>
|
||||
</parameter>
|
||||
<parameter name="nh">
|
||||
<paramtype>node_type&&</paramtype>
|
||||
</parameter>
|
||||
<type>iterator</type>
|
||||
<description>
|
||||
<para>If <code>nh</code> is empty, has no affect.</para>
|
||||
<?php if ($equivalent_keys): ?>
|
||||
<para>Otherwise inserts the element owned by <code>nh</code></para>
|
||||
<?php else: ?>
|
||||
<para>Otherwise inserts the element owned by <code>nh</code>
|
||||
if and only if there is no element in the container with an equivalent <?php echo $key_name; ?>.
|
||||
</para>
|
||||
<para>If there is already an element in the container with an equivalent <?php echo $key_name; ?>
|
||||
has no effect on <code>nh</code> (i.e. <code>nh</code> still contains the node.)</para>
|
||||
<?php endif ?>
|
||||
<para>hint is a suggestion to where the element should be inserted.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>nh</code> is empty or <code>nh.get_allocator()</code> is equal to the container's allocator.</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<?php if ($equivalent_keys): ?>
|
||||
<para>If <code>nh</code> was empty, returns <code>end()</code>.</para>
|
||||
<para>Otherwise returns an iterator pointing to the newly inserted element.</para>
|
||||
<?php else: ?>
|
||||
<para>If <code>nh</code> was empty returns <code>end()</code>.</para>
|
||||
<para>If there was already an element in the container with an equivalent <?php echo $key_name; ?>
|
||||
returns an iterator pointing to that.</para>
|
||||
<para>Otherwise returns an iterator pointing to the newly inserted element.</para>
|
||||
<?php endif; ?>
|
||||
</returns>
|
||||
<throws>
|
||||
<para>If an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
|
||||
</throws>
|
||||
<notes>
|
||||
<para>The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same <?php echo $key_name; ?>. </para>
|
||||
<para>Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.</para>
|
||||
<para>Pointers and references to elements are never invalidated.</para>
|
||||
<para>In C++17 this can be used to insert a node extracted from a compatible <code><?php echo $node_partner; ?></code>,
|
||||
but that is not supported yet.</para>
|
||||
</notes>
|
||||
</method>
|
||||
<method name="erase">
|
||||
<parameter name="position">
|
||||
<paramtype>const_iterator</paramtype>
|
||||
@ -785,6 +1177,74 @@ EOL;
|
||||
the equality predieate and hash function are swapped using their copy constructors.</para>
|
||||
</notes>
|
||||
</method>
|
||||
<method name="merge">
|
||||
<template>
|
||||
<template-type-parameter name="H2">
|
||||
</template-type-parameter>
|
||||
<template-type-parameter name="P2">
|
||||
</template-type-parameter>
|
||||
</template>
|
||||
<parameter name="source">
|
||||
<?php if ($map): ?>
|
||||
<paramtype><?php echo $name; ?><Key, Mapped, H2, P2, Alloc>&</paramtype>
|
||||
<?php else: ?>
|
||||
<paramtype><?php echo $name; ?><Value, H2, P2, Alloc>&</paramtype>
|
||||
<?php endif; ?>
|
||||
</parameter>
|
||||
<notes>
|
||||
<para>Does not support merging with a compatible <code><?php echo $node_partner; ?></code> yet.</para>
|
||||
</notes>
|
||||
</method>
|
||||
<method name="merge">
|
||||
<template>
|
||||
<template-type-parameter name="H2">
|
||||
</template-type-parameter>
|
||||
<template-type-parameter name="P2">
|
||||
</template-type-parameter>
|
||||
</template>
|
||||
<parameter name="source">
|
||||
<?php if ($map): ?>
|
||||
<paramtype><?php echo $name; ?><Key, Mapped, H2, P2, Alloc>&&</paramtype>
|
||||
<?php else: ?>
|
||||
<paramtype><?php echo $name; ?><Value, H2, P2, Alloc>&&</paramtype>
|
||||
<?php endif; ?>
|
||||
</parameter>
|
||||
<notes>
|
||||
<para>Does not support merging with a compatible <code><?php echo $node_partner; ?></code> yet.</para>
|
||||
</notes>
|
||||
</method>
|
||||
<?php /*
|
||||
<method name="merge">
|
||||
<template>
|
||||
<template-type-parameter name="H2">
|
||||
</template-type-parameter>
|
||||
<template-type-parameter name="P2">
|
||||
</template-type-parameter>
|
||||
</template>
|
||||
<parameter name="source">
|
||||
<?php if ($map): ?>
|
||||
<paramtype><?php echo $node_partner; ?><Key, Mapped, H2, P2, Alloc>&</paramtype>
|
||||
<?php else: ?>
|
||||
<paramtype><?php echo $node_partner; ?><Value, H2, P2, Alloc>&</paramtype>
|
||||
<?php endif; ?>
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="merge">
|
||||
<template>
|
||||
<template-type-parameter name="H2">
|
||||
</template-type-parameter>
|
||||
<template-type-parameter name="P2">
|
||||
</template-type-parameter>
|
||||
</template>
|
||||
<parameter name="source">
|
||||
<?php if ($map): ?>
|
||||
<paramtype><?php echo $node_partner; ?><Key, Mapped, H2, P2, Alloc>&&</paramtype>
|
||||
<?php else: ?>
|
||||
<paramtype><?php echo $node_partner; ?><Value, H2, P2, Alloc>&&</paramtype>
|
||||
<?php endif; ?>
|
||||
</parameter>
|
||||
</method>
|
||||
*/ ?>
|
||||
</method-group>
|
||||
<method-group name="observers">
|
||||
<method name="hash_function" cv="const">
|
||||
@ -1194,6 +1654,113 @@ EOL;
|
||||
<?php
|
||||
}
|
||||
|
||||
function echo_node_handle_docs($map)
|
||||
{
|
||||
$type = $map ? 'map' : 'set';
|
||||
$name = 'node_handle_'.$type;
|
||||
$full_type = "{$name}<ImplementationDefined>";
|
||||
?>
|
||||
<namespace name="unordered">
|
||||
<class name="<?php echo $name ?>">
|
||||
<template pack="true">
|
||||
<template-type-parameter name="ImplementationDefined"/>
|
||||
</template>
|
||||
<purpose>
|
||||
<para>
|
||||
An object that owns a single element extracted from an
|
||||
<classname>unordered_<?php echo $type ?></classname> or an
|
||||
<classname>unordered_multi<?php echo $type ?></classname>, that
|
||||
can then be inserted into a compatible container type.
|
||||
</para>
|
||||
<para>
|
||||
The name and template parameters of this type are implementation
|
||||
defined, and should be obtained using the <code>node_type</code>
|
||||
member typedef from the appropriate container.
|
||||
</para>
|
||||
</purpose>
|
||||
<?php if ($map): ?>
|
||||
<typedef name="key_type">
|
||||
<type>typename Container::key_type</type>
|
||||
</typedef>
|
||||
<typedef name="mapped_type">
|
||||
<type>typename Container::mapped_type</type>
|
||||
</typedef>
|
||||
<?php else: ?>
|
||||
<typedef name="value_type">
|
||||
<type>typename Container::value_type></type>
|
||||
</typedef>
|
||||
<?php endif ?>
|
||||
<typedef name="allocator_type">
|
||||
<type>typename Container::allocator_type></type>
|
||||
</typedef>
|
||||
<constructor specifiers="constexpr" cv="noexcept">
|
||||
</constructor>
|
||||
<destructor/>
|
||||
<constructor cv="noexcept">
|
||||
<parameter>
|
||||
<paramtype><?php echo $name; ?> &&</paramtype>
|
||||
</parameter>
|
||||
</constructor>
|
||||
<method name="operator=">
|
||||
<parameter>
|
||||
<paramtype><?php echo $name; ?>&&</paramtype>
|
||||
</parameter>
|
||||
<type><?php echo $name; ?>&</type>
|
||||
</method>
|
||||
<?php if ($map): ?>
|
||||
<method name="key" cv="const">
|
||||
<type>key_type&</type>
|
||||
</method>
|
||||
<method name="mapped" cv="const">
|
||||
<type>mapped_type&</type>
|
||||
</method>
|
||||
<?php else: ?>
|
||||
<method name="value" cv="const">
|
||||
<type>value_type&</type>
|
||||
</method>
|
||||
<?php endif; ?>
|
||||
<method name="get_allocator" cv="const">
|
||||
<type>allocator_type</type>
|
||||
</method>
|
||||
<method name="operator bool" specifiers="explicit" cv="const noexcept">
|
||||
</method>
|
||||
<method name="empty" cv="const noexcept">
|
||||
<type>bool</type>
|
||||
</method>
|
||||
<method name="swap" cv="noexcept(ator_traits::propagate_on_container_swap::value)">
|
||||
<parameter>
|
||||
<paramtype><?php echo $name; ?>&</paramtype>
|
||||
</parameter>
|
||||
<type>void</type>
|
||||
<notes>
|
||||
<para>
|
||||
In C++17 is also <code>noexcept</code> if <code>ator_traits::is_always_equal::value</code> is true.
|
||||
But we don't support that trait yet.
|
||||
</para>
|
||||
</notes>
|
||||
</method>
|
||||
<free-function-group name="swap" cv="noexcept(noexcept(x.swap(y)))">
|
||||
<function name="swap">
|
||||
<template pack="true">
|
||||
<template-type-parameter name="ImplementationDefined"/>
|
||||
</template>
|
||||
<parameter name="x">
|
||||
<paramtype><?php echo $full_type; ?>&</paramtype>
|
||||
</parameter>
|
||||
<parameter name="y">
|
||||
<paramtype><?php echo $full_type; ?>&</paramtype>
|
||||
</parameter>
|
||||
<type>void</type>
|
||||
<effects>
|
||||
<para><code>x.swap(y)</code></para>
|
||||
</effects>
|
||||
</function>
|
||||
</free-function-group>
|
||||
</class>
|
||||
</namespace>
|
||||
<?php
|
||||
}
|
||||
|
||||
?>
|
||||
<!--
|
||||
Copyright Daniel James 2006-2009
|
||||
@ -1205,6 +1772,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<?php
|
||||
echo_unordered_docs(false, false);
|
||||
echo_unordered_docs(false, true);
|
||||
echo_node_handle_docs(false);
|
||||
?>
|
||||
</namespace>
|
||||
</header>
|
||||
@ -1213,6 +1781,7 @@ echo_unordered_docs(false, true);
|
||||
<?php
|
||||
echo_unordered_docs(true, false);
|
||||
echo_unordered_docs(true, true);
|
||||
echo_node_handle_docs(true);
|
||||
?>
|
||||
</namespace>
|
||||
</header>
|
||||
|
1694
doc/ref.xml
1694
doc/ref.xml
File diff suppressed because it is too large
Load Diff
@ -4,13 +4,12 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include "../../examples/fnv1.hpp"
|
||||
|
||||
//[case_insensitive_functions
|
||||
struct iequal_to
|
||||
: std::binary_function<std::string, std::string, bool>
|
||||
{
|
||||
bool operator()(std::string const& x,
|
||||
std::string const& y) const
|
||||
@ -20,7 +19,6 @@
|
||||
};
|
||||
|
||||
struct ihash
|
||||
: std::unary_function<std::string, std::size_t>
|
||||
{
|
||||
std::size_t operator()(std::string const& x) const
|
||||
{
|
||||
|
@ -4,7 +4,7 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
//[point_example1
|
||||
struct point {
|
||||
@ -18,7 +18,6 @@
|
||||
}
|
||||
|
||||
struct point_hash
|
||||
: std::unary_function<point, std::size_t>
|
||||
{
|
||||
std::size_t operator()(point const& p) const
|
||||
{
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
//[point_example2
|
||||
struct point {
|
||||
|
@ -3,7 +3,8 @@
|
||||
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ]
|
||||
|
||||
[library Boost.Unordered
|
||||
[quickbook 1.5]
|
||||
[quickbook 1.7]
|
||||
[compatibility-mode 1.5]
|
||||
[authors [James, Daniel]]
|
||||
[copyright 2003 2004 Jeremy B. Maitin-Shepard]
|
||||
[copyright 2005 2006 2007 2008 Daniel James]
|
||||
|
@ -19,7 +19,6 @@
|
||||
namespace hash_examples
|
||||
{
|
||||
struct iequal_to
|
||||
: std::binary_function<std::string, std::string, bool>
|
||||
{
|
||||
iequal_to() {}
|
||||
explicit iequal_to(std::locale const& l) : locale_(l) {}
|
||||
@ -34,7 +33,6 @@ namespace hash_examples
|
||||
};
|
||||
|
||||
struct ihash
|
||||
: std::unary_function<std::string, std::size_t>
|
||||
{
|
||||
ihash() {}
|
||||
explicit ihash(std::locale const& l) : locale_(l) {}
|
||||
|
@ -4,7 +4,7 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include "./case_insensitive.hpp"
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
struct word_info {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,889 +0,0 @@
|
||||
|
||||
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
||||
// Copyright (C) 2005-2011 Daniel James
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/unordered/detail/util.hpp>
|
||||
#include <boost/unordered/detail/allocate.hpp>
|
||||
#include <boost/type_traits/aligned_storage.hpp>
|
||||
#include <boost/type_traits/alignment_of.hpp>
|
||||
#include <boost/type_traits/is_nothrow_move_constructible.hpp>
|
||||
#include <boost/type_traits/is_nothrow_move_assignable.hpp>
|
||||
#include <boost/swap.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/limits.hpp>
|
||||
#include <boost/iterator.hpp>
|
||||
|
||||
namespace boost { namespace unordered { namespace detail {
|
||||
|
||||
template <typename Types> struct table;
|
||||
template <typename NodePointer> struct bucket;
|
||||
struct ptr_bucket;
|
||||
template <typename Types> struct table_impl;
|
||||
template <typename Types> struct grouped_table_impl;
|
||||
|
||||
}}}
|
||||
|
||||
// The 'iterator_detail' namespace was a misguided attempt at avoiding ADL
|
||||
// in the detail namespace. It didn't work because the template parameters
|
||||
// were in detail. I'm not changing it at the moment to be safe. I might
|
||||
// do in the future if I change the iterator types.
|
||||
namespace boost { namespace unordered { namespace iterator_detail {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Iterators
|
||||
//
|
||||
// all no throw
|
||||
|
||||
template <typename Node> struct iterator;
|
||||
template <typename Node, typename ConstNodePointer> struct c_iterator;
|
||||
template <typename Node, typename Policy> struct l_iterator;
|
||||
template <typename Node, typename ConstNodePointer, typename Policy>
|
||||
struct cl_iterator;
|
||||
|
||||
// Local Iterators
|
||||
//
|
||||
// all no throw
|
||||
|
||||
template <typename Node, typename Policy>
|
||||
struct l_iterator
|
||||
: public boost::iterator<
|
||||
std::forward_iterator_tag,
|
||||
typename Node::value_type,
|
||||
std::ptrdiff_t,
|
||||
typename Node::node_pointer,
|
||||
typename Node::value_type&>
|
||||
{
|
||||
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
|
||||
template <typename Node2, typename ConstNodePointer, typename Policy2>
|
||||
friend struct boost::unordered::iterator_detail::cl_iterator;
|
||||
private:
|
||||
#endif
|
||||
typedef typename Node::node_pointer node_pointer;
|
||||
typedef boost::unordered::iterator_detail::iterator<Node> iterator;
|
||||
node_pointer ptr_;
|
||||
std::size_t bucket_;
|
||||
std::size_t bucket_count_;
|
||||
|
||||
public:
|
||||
|
||||
typedef typename Node::value_type value_type;
|
||||
|
||||
l_iterator() BOOST_NOEXCEPT : ptr_() {}
|
||||
|
||||
l_iterator(iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT
|
||||
: ptr_(x.node_), bucket_(b), bucket_count_(c) {}
|
||||
|
||||
value_type& operator*() const {
|
||||
return ptr_->value();
|
||||
}
|
||||
|
||||
value_type* operator->() const {
|
||||
return ptr_->value_ptr();
|
||||
}
|
||||
|
||||
l_iterator& operator++() {
|
||||
ptr_ = static_cast<node_pointer>(ptr_->next_);
|
||||
if (ptr_ && Policy::to_bucket(bucket_count_, ptr_->hash_)
|
||||
!= bucket_)
|
||||
ptr_ = node_pointer();
|
||||
return *this;
|
||||
}
|
||||
|
||||
l_iterator operator++(int) {
|
||||
l_iterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator==(l_iterator x) const BOOST_NOEXCEPT {
|
||||
return ptr_ == x.ptr_;
|
||||
}
|
||||
|
||||
bool operator!=(l_iterator x) const BOOST_NOEXCEPT {
|
||||
return ptr_ != x.ptr_;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Node, typename ConstNodePointer, typename Policy>
|
||||
struct cl_iterator
|
||||
: public boost::iterator<
|
||||
std::forward_iterator_tag,
|
||||
typename Node::value_type,
|
||||
std::ptrdiff_t,
|
||||
ConstNodePointer,
|
||||
typename Node::value_type const&>
|
||||
{
|
||||
friend struct boost::unordered::iterator_detail::l_iterator
|
||||
<Node, Policy>;
|
||||
private:
|
||||
|
||||
typedef typename Node::node_pointer node_pointer;
|
||||
typedef boost::unordered::iterator_detail::iterator<Node> iterator;
|
||||
node_pointer ptr_;
|
||||
std::size_t bucket_;
|
||||
std::size_t bucket_count_;
|
||||
|
||||
public:
|
||||
|
||||
typedef typename Node::value_type value_type;
|
||||
|
||||
cl_iterator() BOOST_NOEXCEPT : ptr_() {}
|
||||
|
||||
cl_iterator(iterator x, std::size_t b, std::size_t c) BOOST_NOEXCEPT :
|
||||
ptr_(x.node_), bucket_(b), bucket_count_(c) {}
|
||||
|
||||
cl_iterator(boost::unordered::iterator_detail::l_iterator<
|
||||
Node, Policy> const& x) BOOST_NOEXCEPT :
|
||||
ptr_(x.ptr_), bucket_(x.bucket_), bucket_count_(x.bucket_count_)
|
||||
{}
|
||||
|
||||
value_type const& operator*() const {
|
||||
return ptr_->value();
|
||||
}
|
||||
|
||||
value_type const* operator->() const {
|
||||
return ptr_->value_ptr();
|
||||
}
|
||||
|
||||
cl_iterator& operator++() {
|
||||
ptr_ = static_cast<node_pointer>(ptr_->next_);
|
||||
if (ptr_ && Policy::to_bucket(bucket_count_, ptr_->hash_)
|
||||
!= bucket_)
|
||||
ptr_ = node_pointer();
|
||||
return *this;
|
||||
}
|
||||
|
||||
cl_iterator operator++(int) {
|
||||
cl_iterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
friend bool operator==(cl_iterator const& x, cl_iterator const& y)
|
||||
BOOST_NOEXCEPT
|
||||
{
|
||||
return x.ptr_ == y.ptr_;
|
||||
}
|
||||
|
||||
friend bool operator!=(cl_iterator const& x, cl_iterator const& y)
|
||||
BOOST_NOEXCEPT
|
||||
{
|
||||
return x.ptr_ != y.ptr_;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Node>
|
||||
struct iterator
|
||||
: public boost::iterator<
|
||||
std::forward_iterator_tag,
|
||||
typename Node::value_type,
|
||||
std::ptrdiff_t,
|
||||
typename Node::node_pointer,
|
||||
typename Node::value_type&>
|
||||
{
|
||||
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
|
||||
template <typename, typename>
|
||||
friend struct boost::unordered::iterator_detail::c_iterator;
|
||||
template <typename, typename>
|
||||
friend struct boost::unordered::iterator_detail::l_iterator;
|
||||
template <typename, typename, typename>
|
||||
friend struct boost::unordered::iterator_detail::cl_iterator;
|
||||
template <typename>
|
||||
friend struct boost::unordered::detail::table;
|
||||
template <typename>
|
||||
friend struct boost::unordered::detail::table_impl;
|
||||
template <typename>
|
||||
friend struct boost::unordered::detail::grouped_table_impl;
|
||||
private:
|
||||
#endif
|
||||
typedef typename Node::node_pointer node_pointer;
|
||||
node_pointer node_;
|
||||
|
||||
public:
|
||||
|
||||
typedef typename Node::value_type value_type;
|
||||
|
||||
iterator() BOOST_NOEXCEPT : node_() {}
|
||||
|
||||
explicit iterator(typename Node::link_pointer x) BOOST_NOEXCEPT :
|
||||
node_(static_cast<node_pointer>(x)) {}
|
||||
|
||||
value_type& operator*() const {
|
||||
return node_->value();
|
||||
}
|
||||
|
||||
value_type* operator->() const {
|
||||
return &node_->value();
|
||||
}
|
||||
|
||||
iterator& operator++() {
|
||||
node_ = static_cast<node_pointer>(node_->next_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator++(int) {
|
||||
iterator tmp(node_);
|
||||
node_ = static_cast<node_pointer>(node_->next_);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator==(iterator const& x) const BOOST_NOEXCEPT {
|
||||
return node_ == x.node_;
|
||||
}
|
||||
|
||||
bool operator!=(iterator const& x) const BOOST_NOEXCEPT {
|
||||
return node_ != x.node_;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Node, typename ConstNodePointer>
|
||||
struct c_iterator
|
||||
: public boost::iterator<
|
||||
std::forward_iterator_tag,
|
||||
typename Node::value_type,
|
||||
std::ptrdiff_t,
|
||||
ConstNodePointer,
|
||||
typename Node::value_type const&>
|
||||
{
|
||||
friend struct boost::unordered::iterator_detail::iterator<Node>;
|
||||
|
||||
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
|
||||
template <typename>
|
||||
friend struct boost::unordered::detail::table;
|
||||
template <typename>
|
||||
friend struct boost::unordered::detail::table_impl;
|
||||
template <typename>
|
||||
friend struct boost::unordered::detail::grouped_table_impl;
|
||||
|
||||
private:
|
||||
#endif
|
||||
typedef typename Node::node_pointer node_pointer;
|
||||
typedef boost::unordered::iterator_detail::iterator<Node> iterator;
|
||||
node_pointer node_;
|
||||
|
||||
public:
|
||||
|
||||
typedef typename Node::value_type value_type;
|
||||
|
||||
c_iterator() BOOST_NOEXCEPT : node_() {}
|
||||
|
||||
explicit c_iterator(typename Node::link_pointer x) BOOST_NOEXCEPT :
|
||||
node_(static_cast<node_pointer>(x)) {}
|
||||
|
||||
c_iterator(iterator const& x) BOOST_NOEXCEPT : node_(x.node_) {}
|
||||
|
||||
value_type const& operator*() const {
|
||||
return node_->value();
|
||||
}
|
||||
|
||||
value_type const* operator->() const {
|
||||
return &node_->value();
|
||||
}
|
||||
|
||||
c_iterator& operator++() {
|
||||
node_ = static_cast<node_pointer>(node_->next_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
c_iterator operator++(int) {
|
||||
c_iterator tmp(node_);
|
||||
node_ = static_cast<node_pointer>(node_->next_);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
friend bool operator==(c_iterator const& x, c_iterator const& y)
|
||||
BOOST_NOEXCEPT
|
||||
{
|
||||
return x.node_ == y.node_;
|
||||
}
|
||||
|
||||
friend bool operator!=(c_iterator const& x, c_iterator const& y)
|
||||
BOOST_NOEXCEPT
|
||||
{
|
||||
return x.node_ != y.node_;
|
||||
}
|
||||
};
|
||||
}}}
|
||||
|
||||
namespace boost { namespace unordered { namespace detail {
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Node construction
|
||||
|
||||
template <typename NodeAlloc>
|
||||
struct node_constructor
|
||||
{
|
||||
private:
|
||||
|
||||
typedef NodeAlloc node_allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<NodeAlloc>
|
||||
node_allocator_traits;
|
||||
typedef typename node_allocator_traits::value_type node;
|
||||
typedef typename node_allocator_traits::pointer node_pointer;
|
||||
typedef typename node::value_type value_type;
|
||||
|
||||
protected:
|
||||
|
||||
node_allocator& alloc_;
|
||||
node_pointer node_;
|
||||
bool node_constructed_;
|
||||
bool value_constructed_;
|
||||
|
||||
public:
|
||||
|
||||
node_constructor(node_allocator& n) :
|
||||
alloc_(n),
|
||||
node_(),
|
||||
node_constructed_(false),
|
||||
value_constructed_(false)
|
||||
{
|
||||
}
|
||||
|
||||
~node_constructor();
|
||||
|
||||
void construct();
|
||||
|
||||
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
|
||||
void construct_with_value(BOOST_UNORDERED_EMPLACE_ARGS)
|
||||
{
|
||||
construct();
|
||||
boost::unordered::detail::func::construct_value_impl(
|
||||
alloc_, node_->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD);
|
||||
value_constructed_ = true;
|
||||
}
|
||||
|
||||
template <typename A0>
|
||||
void construct_with_value2(BOOST_FWD_REF(A0) a0)
|
||||
{
|
||||
construct();
|
||||
boost::unordered::detail::func::construct_value_impl(
|
||||
alloc_, node_->value_ptr(),
|
||||
BOOST_UNORDERED_EMPLACE_ARGS1(boost::forward<A0>(a0)));
|
||||
value_constructed_ = true;
|
||||
}
|
||||
|
||||
value_type const& value() const {
|
||||
BOOST_ASSERT(node_ && node_constructed_ && value_constructed_);
|
||||
return node_->value();
|
||||
}
|
||||
|
||||
// no throw
|
||||
node_pointer release()
|
||||
{
|
||||
BOOST_ASSERT(node_ && node_constructed_);
|
||||
node_pointer p = node_;
|
||||
node_ = node_pointer();
|
||||
return p;
|
||||
}
|
||||
|
||||
private:
|
||||
node_constructor(node_constructor const&);
|
||||
node_constructor& operator=(node_constructor const&);
|
||||
};
|
||||
|
||||
template <typename Alloc>
|
||||
node_constructor<Alloc>::~node_constructor()
|
||||
{
|
||||
if (node_) {
|
||||
if (value_constructed_) {
|
||||
boost::unordered::detail::func::destroy_value_impl(alloc_,
|
||||
node_->value_ptr());
|
||||
}
|
||||
|
||||
if (node_constructed_) {
|
||||
node_allocator_traits::destroy(alloc_,
|
||||
boost::addressof(*node_));
|
||||
}
|
||||
|
||||
node_allocator_traits::deallocate(alloc_, node_, 1);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Alloc>
|
||||
void node_constructor<Alloc>::construct()
|
||||
{
|
||||
if(!node_) {
|
||||
node_constructed_ = false;
|
||||
value_constructed_ = false;
|
||||
|
||||
node_ = node_allocator_traits::allocate(alloc_, 1);
|
||||
|
||||
node_allocator_traits::construct(alloc_,
|
||||
boost::addressof(*node_), node());
|
||||
node_->init(node_);
|
||||
node_constructed_ = true;
|
||||
}
|
||||
else {
|
||||
BOOST_ASSERT(node_constructed_);
|
||||
|
||||
if (value_constructed_)
|
||||
{
|
||||
boost::unordered::detail::func::destroy_value_impl(alloc_,
|
||||
node_->value_ptr());
|
||||
value_constructed_ = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Node Holder
|
||||
//
|
||||
// Temporary store for nodes. Deletes any that aren't used.
|
||||
|
||||
template <typename NodeAlloc>
|
||||
struct node_holder : private node_constructor<NodeAlloc>
|
||||
{
|
||||
private:
|
||||
typedef node_constructor<NodeAlloc> base;
|
||||
|
||||
typedef NodeAlloc node_allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<NodeAlloc>
|
||||
node_allocator_traits;
|
||||
typedef typename node_allocator_traits::value_type node;
|
||||
typedef typename node_allocator_traits::pointer node_pointer;
|
||||
typedef typename node::value_type value_type;
|
||||
typedef typename node::link_pointer link_pointer;
|
||||
typedef boost::unordered::iterator_detail::iterator<node> iterator;
|
||||
|
||||
node_pointer nodes_;
|
||||
|
||||
public:
|
||||
|
||||
template <typename Table>
|
||||
explicit node_holder(Table& b) :
|
||||
base(b.node_alloc()),
|
||||
nodes_()
|
||||
{
|
||||
if (b.size_) {
|
||||
typename Table::link_pointer prev = b.get_previous_start();
|
||||
nodes_ = static_cast<node_pointer>(prev->next_);
|
||||
prev->next_ = link_pointer();
|
||||
b.size_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
~node_holder();
|
||||
|
||||
void node_for_assignment()
|
||||
{
|
||||
if (!this->node_ && nodes_) {
|
||||
this->node_ = nodes_;
|
||||
nodes_ = static_cast<node_pointer>(nodes_->next_);
|
||||
this->node_->init(this->node_);
|
||||
this->node_->next_ = link_pointer();
|
||||
|
||||
this->node_constructed_ = true;
|
||||
this->value_constructed_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void assign_impl(T const& v) {
|
||||
if (this->node_ && this->value_constructed_) {
|
||||
this->node_->value() = v;
|
||||
}
|
||||
else {
|
||||
this->construct_with_value2(v);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
inline void assign_impl(std::pair<T1 const, T2> const& v) {
|
||||
this->construct_with_value2(v);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void move_assign_impl(T& v) {
|
||||
if (this->node_ && this->value_constructed_) {
|
||||
this->node_->value() = boost::move(v);
|
||||
}
|
||||
else {
|
||||
this->construct_with_value2(boost::move(v));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
inline void move_assign_impl(std::pair<T1 const, T2>& v) {
|
||||
this->construct_with_value2(boost::move(v));
|
||||
}
|
||||
|
||||
node_pointer copy_of(value_type const& v)
|
||||
{
|
||||
node_for_assignment();
|
||||
assign_impl(v);
|
||||
return base::release();
|
||||
}
|
||||
|
||||
node_pointer move_copy_of(value_type& v)
|
||||
{
|
||||
node_for_assignment();
|
||||
move_assign_impl(v);
|
||||
return base::release();
|
||||
}
|
||||
|
||||
iterator begin() const
|
||||
{
|
||||
return iterator(nodes_);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Alloc>
|
||||
node_holder<Alloc>::~node_holder()
|
||||
{
|
||||
while (nodes_) {
|
||||
node_pointer p = nodes_;
|
||||
nodes_ = static_cast<node_pointer>(p->next_);
|
||||
|
||||
boost::unordered::detail::func::destroy_value_impl(this->alloc_,
|
||||
p->value_ptr());
|
||||
node_allocator_traits::destroy(this->alloc_, boost::addressof(*p));
|
||||
node_allocator_traits::deallocate(this->alloc_, p, 1);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Bucket
|
||||
|
||||
template <typename NodePointer>
|
||||
struct bucket
|
||||
{
|
||||
typedef NodePointer link_pointer;
|
||||
link_pointer next_;
|
||||
|
||||
bucket() : next_() {}
|
||||
|
||||
link_pointer first_from_start()
|
||||
{
|
||||
return next_;
|
||||
}
|
||||
|
||||
enum { extra_node = true };
|
||||
};
|
||||
|
||||
struct ptr_bucket
|
||||
{
|
||||
typedef ptr_bucket* link_pointer;
|
||||
link_pointer next_;
|
||||
|
||||
ptr_bucket() : next_(0) {}
|
||||
|
||||
link_pointer first_from_start()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
enum { extra_node = false };
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Hash Policy
|
||||
|
||||
template <typename SizeT>
|
||||
struct prime_policy
|
||||
{
|
||||
template <typename Hash, typename T>
|
||||
static inline SizeT apply_hash(Hash const& hf, T const& x) {
|
||||
return hf(x);
|
||||
}
|
||||
|
||||
static inline SizeT to_bucket(SizeT bucket_count, SizeT hash) {
|
||||
return hash % bucket_count;
|
||||
}
|
||||
|
||||
static inline SizeT new_bucket_count(SizeT min) {
|
||||
return boost::unordered::detail::next_prime(min);
|
||||
}
|
||||
|
||||
static inline SizeT prev_bucket_count(SizeT max) {
|
||||
return boost::unordered::detail::prev_prime(max);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename SizeT>
|
||||
struct mix64_policy
|
||||
{
|
||||
template <typename Hash, typename T>
|
||||
static inline SizeT apply_hash(Hash const& hf, T const& x) {
|
||||
SizeT key = hf(x);
|
||||
key = (~key) + (key << 21); // key = (key << 21) - key - 1;
|
||||
key = key ^ (key >> 24);
|
||||
key = (key + (key << 3)) + (key << 8); // key * 265
|
||||
key = key ^ (key >> 14);
|
||||
key = (key + (key << 2)) + (key << 4); // key * 21
|
||||
key = key ^ (key >> 28);
|
||||
key = key + (key << 31);
|
||||
return key;
|
||||
}
|
||||
|
||||
static inline SizeT to_bucket(SizeT bucket_count, SizeT hash) {
|
||||
return hash & (bucket_count - 1);
|
||||
}
|
||||
|
||||
static inline SizeT new_bucket_count(SizeT min) {
|
||||
if (min <= 4) return 4;
|
||||
--min;
|
||||
min |= min >> 1;
|
||||
min |= min >> 2;
|
||||
min |= min >> 4;
|
||||
min |= min >> 8;
|
||||
min |= min >> 16;
|
||||
min |= min >> 32;
|
||||
return min + 1;
|
||||
}
|
||||
|
||||
static inline SizeT prev_bucket_count(SizeT max) {
|
||||
max |= max >> 1;
|
||||
max |= max >> 2;
|
||||
max |= max >> 4;
|
||||
max |= max >> 8;
|
||||
max |= max >> 16;
|
||||
max |= max >> 32;
|
||||
return (max >> 1) + 1;
|
||||
}
|
||||
};
|
||||
|
||||
template <int digits, int radix>
|
||||
struct pick_policy_impl {
|
||||
typedef prime_policy<std::size_t> type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct pick_policy_impl<64, 2> {
|
||||
typedef mix64_policy<std::size_t> type;
|
||||
};
|
||||
|
||||
struct pick_policy :
|
||||
pick_policy_impl<
|
||||
std::numeric_limits<std::size_t>::digits,
|
||||
std::numeric_limits<std::size_t>::radix> {};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Functions
|
||||
|
||||
// Assigning and swapping the equality and hash function objects
|
||||
// needs strong exception safety. To implement that normally we'd
|
||||
// require one of them to be known to not throw and the other to
|
||||
// guarantee strong exception safety. Unfortunately they both only
|
||||
// have basic exception safety. So to acheive strong exception
|
||||
// safety we have storage space for two copies, and assign the new
|
||||
// copies to the unused space. Then switch to using that to use
|
||||
// them. This is implemented in 'set_hash_functions' which
|
||||
// atomically assigns the new function objects in a strongly
|
||||
// exception safe manner.
|
||||
|
||||
template <class H, class P, bool NoThrowMoveAssign>
|
||||
class set_hash_functions;
|
||||
|
||||
template <class H, class P>
|
||||
class functions
|
||||
{
|
||||
public:
|
||||
static const bool nothrow_move_assignable =
|
||||
boost::is_nothrow_move_assignable<H>::value &&
|
||||
boost::is_nothrow_move_assignable<P>::value;
|
||||
static const bool nothrow_move_constructible =
|
||||
boost::is_nothrow_move_constructible<H>::value &&
|
||||
boost::is_nothrow_move_constructible<P>::value;
|
||||
|
||||
private:
|
||||
friend class boost::unordered::detail::set_hash_functions<H, P,
|
||||
nothrow_move_assignable>;
|
||||
functions& operator=(functions const&);
|
||||
|
||||
typedef compressed<H, P> function_pair;
|
||||
|
||||
typedef typename boost::aligned_storage<
|
||||
sizeof(function_pair),
|
||||
boost::alignment_of<function_pair>::value>::type aligned_function;
|
||||
|
||||
bool current_; // The currently active functions.
|
||||
aligned_function funcs_[2];
|
||||
|
||||
function_pair const& current() const {
|
||||
return *static_cast<function_pair const*>(
|
||||
static_cast<void const*>(&funcs_[current_]));
|
||||
}
|
||||
|
||||
function_pair& current() {
|
||||
return *static_cast<function_pair*>(
|
||||
static_cast<void*>(&funcs_[current_]));
|
||||
}
|
||||
|
||||
void construct(bool which, H const& hf, P const& eq)
|
||||
{
|
||||
new((void*) &funcs_[which]) function_pair(hf, eq);
|
||||
}
|
||||
|
||||
void construct(bool which, function_pair const& f,
|
||||
boost::unordered::detail::false_type =
|
||||
boost::unordered::detail::false_type())
|
||||
{
|
||||
new((void*) &funcs_[which]) function_pair(f);
|
||||
}
|
||||
|
||||
void construct(bool which, function_pair& f,
|
||||
boost::unordered::detail::true_type)
|
||||
{
|
||||
new((void*) &funcs_[which]) function_pair(f,
|
||||
boost::unordered::detail::move_tag());
|
||||
}
|
||||
|
||||
void destroy(bool which)
|
||||
{
|
||||
boost::unordered::detail::func::destroy((function_pair*)(&funcs_[which]));
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
typedef boost::unordered::detail::set_hash_functions<H, P,
|
||||
nothrow_move_assignable> set_hash_functions;
|
||||
|
||||
functions(H const& hf, P const& eq)
|
||||
: current_(false)
|
||||
{
|
||||
construct(current_, hf, eq);
|
||||
}
|
||||
|
||||
functions(functions const& bf)
|
||||
: current_(false)
|
||||
{
|
||||
construct(current_, bf.current());
|
||||
}
|
||||
|
||||
functions(functions& bf, boost::unordered::detail::move_tag)
|
||||
: current_(false)
|
||||
{
|
||||
construct(current_, bf.current(),
|
||||
boost::unordered::detail::integral_constant<bool,
|
||||
nothrow_move_constructible>());
|
||||
}
|
||||
|
||||
~functions() {
|
||||
this->destroy(current_);
|
||||
}
|
||||
|
||||
H const& hash_function() const {
|
||||
return current().first();
|
||||
}
|
||||
|
||||
P const& key_eq() const {
|
||||
return current().second();
|
||||
}
|
||||
};
|
||||
|
||||
template <class H, class P>
|
||||
class set_hash_functions<H, P, false>
|
||||
{
|
||||
set_hash_functions(set_hash_functions const&);
|
||||
set_hash_functions& operator=(set_hash_functions const&);
|
||||
|
||||
typedef functions<H, P> functions_type;
|
||||
|
||||
functions_type& functions_;
|
||||
bool tmp_functions_;
|
||||
|
||||
public:
|
||||
|
||||
set_hash_functions(functions_type& f, H const& h, P const& p)
|
||||
: functions_(f),
|
||||
tmp_functions_(!f.current_)
|
||||
{
|
||||
f.construct(tmp_functions_, h, p);
|
||||
}
|
||||
|
||||
set_hash_functions(functions_type& f, functions_type const& other)
|
||||
: functions_(f),
|
||||
tmp_functions_(!f.current_)
|
||||
{
|
||||
f.construct(tmp_functions_, other.current());
|
||||
}
|
||||
|
||||
~set_hash_functions()
|
||||
{
|
||||
functions_.destroy(tmp_functions_);
|
||||
}
|
||||
|
||||
void commit()
|
||||
{
|
||||
functions_.current_ = tmp_functions_;
|
||||
tmp_functions_ = !tmp_functions_;
|
||||
}
|
||||
};
|
||||
|
||||
template <class H, class P>
|
||||
class set_hash_functions<H, P, true>
|
||||
{
|
||||
set_hash_functions(set_hash_functions const&);
|
||||
set_hash_functions& operator=(set_hash_functions const&);
|
||||
|
||||
typedef functions<H, P> functions_type;
|
||||
|
||||
functions_type& functions_;
|
||||
H hash_;
|
||||
P pred_;
|
||||
|
||||
public:
|
||||
|
||||
set_hash_functions(functions_type& f, H const& h, P const& p) :
|
||||
functions_(f),
|
||||
hash_(h),
|
||||
pred_(p) {}
|
||||
|
||||
set_hash_functions(functions_type& f, functions_type const& other) :
|
||||
functions_(f),
|
||||
hash_(other.hash_function()),
|
||||
pred_(other.key_eq()) {}
|
||||
|
||||
void commit()
|
||||
{
|
||||
functions_.current().first() = boost::move(hash_);
|
||||
functions_.current().second() = boost::move(pred_);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// rvalue parameters when type can't be a BOOST_RV_REF(T) parameter
|
||||
// e.g. for int
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
# define BOOST_UNORDERED_RV_REF(T) BOOST_RV_REF(T)
|
||||
#else
|
||||
struct please_ignore_this_overload {
|
||||
typedef please_ignore_this_overload type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct rv_ref_impl {
|
||||
typedef BOOST_RV_REF(T) type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct rv_ref :
|
||||
boost::detail::if_true<
|
||||
boost::is_class<T>::value
|
||||
>::BOOST_NESTED_TEMPLATE then <
|
||||
boost::unordered::detail::rv_ref_impl<T>,
|
||||
please_ignore_this_overload
|
||||
>::type
|
||||
{};
|
||||
|
||||
# define BOOST_UNORDERED_RV_REF(T) \
|
||||
typename boost::unordered::detail::rv_ref<T>::type
|
||||
#endif
|
||||
}}}
|
||||
|
||||
#endif
|
@ -1,681 +0,0 @@
|
||||
|
||||
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
||||
// Copyright (C) 2005-2011 Daniel James
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/unordered/detail/table.hpp>
|
||||
#include <boost/unordered/detail/extract_key.hpp>
|
||||
|
||||
namespace boost { namespace unordered { namespace detail {
|
||||
|
||||
template <typename A, typename T> struct grouped_node;
|
||||
template <typename T> struct grouped_ptr_node;
|
||||
template <typename Types> struct grouped_table_impl;
|
||||
|
||||
template <typename A, typename T>
|
||||
struct grouped_node :
|
||||
boost::unordered::detail::value_base<T>
|
||||
{
|
||||
typedef typename ::boost::unordered::detail::rebind_wrap<
|
||||
A, grouped_node<A, T> >::type allocator;
|
||||
typedef typename ::boost::unordered::detail::
|
||||
allocator_traits<allocator>::pointer node_pointer;
|
||||
typedef node_pointer link_pointer;
|
||||
|
||||
link_pointer next_;
|
||||
node_pointer group_prev_;
|
||||
std::size_t hash_;
|
||||
|
||||
grouped_node() :
|
||||
next_(),
|
||||
group_prev_(),
|
||||
hash_(0)
|
||||
{}
|
||||
|
||||
void init(node_pointer self)
|
||||
{
|
||||
group_prev_ = self;
|
||||
}
|
||||
|
||||
private:
|
||||
grouped_node& operator=(grouped_node const&);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct grouped_ptr_node :
|
||||
boost::unordered::detail::value_base<T>,
|
||||
boost::unordered::detail::ptr_bucket
|
||||
{
|
||||
typedef boost::unordered::detail::ptr_bucket bucket_base;
|
||||
typedef grouped_ptr_node<T>* node_pointer;
|
||||
typedef ptr_bucket* link_pointer;
|
||||
|
||||
node_pointer group_prev_;
|
||||
std::size_t hash_;
|
||||
|
||||
grouped_ptr_node() :
|
||||
bucket_base(),
|
||||
group_prev_(0),
|
||||
hash_(0)
|
||||
{}
|
||||
|
||||
void init(node_pointer self)
|
||||
{
|
||||
group_prev_ = self;
|
||||
}
|
||||
|
||||
private:
|
||||
grouped_ptr_node& operator=(grouped_ptr_node const&);
|
||||
};
|
||||
|
||||
// If the allocator uses raw pointers use grouped_ptr_node
|
||||
// Otherwise use grouped_node.
|
||||
|
||||
template <typename A, typename T, typename NodePtr, typename BucketPtr>
|
||||
struct pick_grouped_node2
|
||||
{
|
||||
typedef boost::unordered::detail::grouped_node<A, T> node;
|
||||
|
||||
typedef typename boost::unordered::detail::allocator_traits<
|
||||
typename boost::unordered::detail::rebind_wrap<A, node>::type
|
||||
>::pointer node_pointer;
|
||||
|
||||
typedef boost::unordered::detail::bucket<node_pointer> bucket;
|
||||
typedef node_pointer link_pointer;
|
||||
};
|
||||
|
||||
template <typename A, typename T>
|
||||
struct pick_grouped_node2<A, T,
|
||||
boost::unordered::detail::grouped_ptr_node<T>*,
|
||||
boost::unordered::detail::ptr_bucket*>
|
||||
{
|
||||
typedef boost::unordered::detail::grouped_ptr_node<T> node;
|
||||
typedef boost::unordered::detail::ptr_bucket bucket;
|
||||
typedef bucket* link_pointer;
|
||||
};
|
||||
|
||||
template <typename A, typename T>
|
||||
struct pick_grouped_node
|
||||
{
|
||||
typedef boost::unordered::detail::allocator_traits<
|
||||
typename boost::unordered::detail::rebind_wrap<A,
|
||||
boost::unordered::detail::grouped_ptr_node<T> >::type
|
||||
> tentative_node_traits;
|
||||
|
||||
typedef boost::unordered::detail::allocator_traits<
|
||||
typename boost::unordered::detail::rebind_wrap<A,
|
||||
boost::unordered::detail::ptr_bucket >::type
|
||||
> tentative_bucket_traits;
|
||||
|
||||
typedef pick_grouped_node2<A, T,
|
||||
typename tentative_node_traits::pointer,
|
||||
typename tentative_bucket_traits::pointer> pick;
|
||||
|
||||
typedef typename pick::node node;
|
||||
typedef typename pick::bucket bucket;
|
||||
typedef typename pick::link_pointer link_pointer;
|
||||
};
|
||||
|
||||
template <typename A, typename T, typename H, typename P>
|
||||
struct multiset
|
||||
{
|
||||
typedef boost::unordered::detail::multiset<A, T, H, P> types;
|
||||
|
||||
typedef A allocator;
|
||||
typedef T value_type;
|
||||
typedef H hasher;
|
||||
typedef P key_equal;
|
||||
typedef T key_type;
|
||||
|
||||
typedef boost::unordered::detail::allocator_traits<allocator> traits;
|
||||
typedef boost::unordered::detail::pick_grouped_node<allocator,
|
||||
value_type> pick;
|
||||
typedef typename pick::node node;
|
||||
typedef typename pick::bucket bucket;
|
||||
typedef typename pick::link_pointer link_pointer;
|
||||
|
||||
typedef boost::unordered::detail::grouped_table_impl<types> table;
|
||||
typedef boost::unordered::detail::set_extractor<value_type> extractor;
|
||||
|
||||
typedef boost::unordered::detail::pick_policy::type policy;
|
||||
};
|
||||
|
||||
template <typename A, typename K, typename M, typename H, typename P>
|
||||
struct multimap
|
||||
{
|
||||
typedef boost::unordered::detail::multimap<A, K, M, H, P> types;
|
||||
|
||||
typedef A allocator;
|
||||
typedef std::pair<K const, M> value_type;
|
||||
typedef H hasher;
|
||||
typedef P key_equal;
|
||||
typedef K key_type;
|
||||
|
||||
typedef boost::unordered::detail::allocator_traits<allocator> traits;
|
||||
typedef boost::unordered::detail::pick_grouped_node<allocator,
|
||||
value_type> pick;
|
||||
typedef typename pick::node node;
|
||||
typedef typename pick::bucket bucket;
|
||||
typedef typename pick::link_pointer link_pointer;
|
||||
|
||||
typedef boost::unordered::detail::grouped_table_impl<types> table;
|
||||
typedef boost::unordered::detail::map_extractor<key_type, value_type>
|
||||
extractor;
|
||||
|
||||
typedef boost::unordered::detail::pick_policy::type policy;
|
||||
};
|
||||
|
||||
template <typename Types>
|
||||
struct grouped_table_impl : boost::unordered::detail::table<Types>
|
||||
{
|
||||
typedef boost::unordered::detail::table<Types> table;
|
||||
typedef typename table::value_type value_type;
|
||||
typedef typename table::bucket bucket;
|
||||
typedef typename table::policy policy;
|
||||
typedef typename table::node_pointer node_pointer;
|
||||
typedef typename table::node_allocator node_allocator;
|
||||
typedef typename table::node_allocator_traits node_allocator_traits;
|
||||
typedef typename table::bucket_pointer bucket_pointer;
|
||||
typedef typename table::link_pointer link_pointer;
|
||||
typedef typename table::hasher hasher;
|
||||
typedef typename table::key_equal key_equal;
|
||||
typedef typename table::key_type key_type;
|
||||
typedef typename table::node_constructor node_constructor;
|
||||
typedef typename table::extractor extractor;
|
||||
typedef typename table::iterator iterator;
|
||||
typedef typename table::c_iterator c_iterator;
|
||||
|
||||
// Constructors
|
||||
|
||||
grouped_table_impl(std::size_t n,
|
||||
hasher const& hf,
|
||||
key_equal const& eq,
|
||||
node_allocator const& a)
|
||||
: table(n, hf, eq, a)
|
||||
{}
|
||||
|
||||
grouped_table_impl(grouped_table_impl const& x)
|
||||
: table(x, node_allocator_traits::
|
||||
select_on_container_copy_construction(x.node_alloc()))
|
||||
{
|
||||
this->init(x);
|
||||
}
|
||||
|
||||
grouped_table_impl(grouped_table_impl const& x,
|
||||
node_allocator const& a)
|
||||
: table(x, a)
|
||||
{
|
||||
this->init(x);
|
||||
}
|
||||
|
||||
grouped_table_impl(grouped_table_impl& x,
|
||||
boost::unordered::detail::move_tag m)
|
||||
: table(x, m)
|
||||
{}
|
||||
|
||||
grouped_table_impl(grouped_table_impl& x,
|
||||
node_allocator const& a,
|
||||
boost::unordered::detail::move_tag m)
|
||||
: table(x, a, m)
|
||||
{
|
||||
this->move_init(x);
|
||||
}
|
||||
|
||||
// Accessors
|
||||
|
||||
template <class Key, class Pred>
|
||||
iterator find_node_impl(
|
||||
std::size_t key_hash,
|
||||
Key const& k,
|
||||
Pred const& eq) const
|
||||
{
|
||||
std::size_t bucket_index = this->hash_to_bucket(key_hash);
|
||||
iterator n = this->begin(bucket_index);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (!n.node_) return n;
|
||||
|
||||
std::size_t node_hash = n.node_->hash_;
|
||||
if (key_hash == node_hash)
|
||||
{
|
||||
if (eq(k, this->get_key(*n)))
|
||||
return n;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this->hash_to_bucket(node_hash) != bucket_index)
|
||||
return iterator();
|
||||
}
|
||||
|
||||
n = iterator(n.node_->group_prev_->next_);
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t count(key_type const& k) const
|
||||
{
|
||||
iterator n = this->find_node(k);
|
||||
if (!n.node_) return 0;
|
||||
|
||||
std::size_t x = 0;
|
||||
node_pointer it = n.node_;
|
||||
do {
|
||||
it = it->group_prev_;
|
||||
++x;
|
||||
} while(it != n.node_);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
std::pair<iterator, iterator>
|
||||
equal_range(key_type const& k) const
|
||||
{
|
||||
iterator n = this->find_node(k);
|
||||
return std::make_pair(
|
||||
n, n.node_ ? iterator(n.node_->group_prev_->next_) : n);
|
||||
}
|
||||
|
||||
// Equality
|
||||
|
||||
bool equals(grouped_table_impl const& other) const
|
||||
{
|
||||
if(this->size_ != other.size_) return false;
|
||||
|
||||
for(iterator n1 = this->begin(); n1.node_;)
|
||||
{
|
||||
iterator n2 = other.find_matching_node(n1);
|
||||
if (!n2.node_) return false;
|
||||
iterator end1(n1.node_->group_prev_->next_);
|
||||
iterator end2(n2.node_->group_prev_->next_);
|
||||
if (!group_equals(n1, end1, n2, end2)) return false;
|
||||
n1 = end1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool group_equals(iterator n1, iterator end1,
|
||||
iterator n2, iterator end2)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
if (*n1 != *n2) break;
|
||||
|
||||
++n1;
|
||||
++n2;
|
||||
|
||||
if (n1 == end1) return n2 == end2;
|
||||
if (n2 == end2) return false;
|
||||
}
|
||||
|
||||
for(iterator n1a = n1, n2a = n2;;)
|
||||
{
|
||||
++n1a;
|
||||
++n2a;
|
||||
|
||||
if (n1a == end1)
|
||||
{
|
||||
if (n2a == end2) break;
|
||||
else return false;
|
||||
}
|
||||
|
||||
if (n2a == end2) return false;
|
||||
}
|
||||
|
||||
iterator start = n1;
|
||||
for(;n1 != end1; ++n1)
|
||||
{
|
||||
value_type const& v = *n1;
|
||||
if (find(start, n1, v)) continue;
|
||||
std::size_t matches = count_equal(n2, end2, v);
|
||||
if (!matches) return false;
|
||||
iterator next = n1;
|
||||
++next;
|
||||
if (matches != 1 + count_equal(next, end1, v)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool find(iterator n, iterator end, value_type const& v)
|
||||
{
|
||||
for(;n != end; ++n)
|
||||
if (*n == v)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::size_t count_equal(iterator n, iterator end,
|
||||
value_type const& v)
|
||||
{
|
||||
std::size_t count = 0;
|
||||
for(;n != end; ++n)
|
||||
if (*n == v) ++count;
|
||||
return count;
|
||||
}
|
||||
|
||||
// Emplace/Insert
|
||||
|
||||
static inline void add_after_node(
|
||||
node_pointer n,
|
||||
node_pointer pos)
|
||||
{
|
||||
n->next_ = pos->group_prev_->next_;
|
||||
n->group_prev_ = pos->group_prev_;
|
||||
pos->group_prev_->next_ = n;
|
||||
pos->group_prev_ = n;
|
||||
}
|
||||
|
||||
inline iterator add_node(
|
||||
node_constructor& a,
|
||||
std::size_t key_hash,
|
||||
iterator pos)
|
||||
{
|
||||
node_pointer n = a.release();
|
||||
n->hash_ = key_hash;
|
||||
if (pos.node_) {
|
||||
this->add_after_node(n, pos.node_);
|
||||
if (n->next_) {
|
||||
std::size_t next_bucket = this->hash_to_bucket(
|
||||
static_cast<node_pointer>(n->next_)->hash_);
|
||||
if (next_bucket != this->hash_to_bucket(key_hash)) {
|
||||
this->get_bucket(next_bucket)->next_ = n;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
bucket_pointer b = this->get_bucket(
|
||||
this->hash_to_bucket(key_hash));
|
||||
|
||||
if (!b->next_)
|
||||
{
|
||||
link_pointer start_node = this->get_previous_start();
|
||||
|
||||
if (start_node->next_) {
|
||||
this->get_bucket(this->hash_to_bucket(
|
||||
static_cast<node_pointer>(start_node->next_)->hash_
|
||||
))->next_ = n;
|
||||
}
|
||||
|
||||
b->next_ = start_node;
|
||||
n->next_ = start_node->next_;
|
||||
start_node->next_ = n;
|
||||
}
|
||||
else
|
||||
{
|
||||
n->next_ = b->next_->next_;
|
||||
b->next_->next_ = n;
|
||||
}
|
||||
}
|
||||
++this->size_;
|
||||
return iterator(n);
|
||||
}
|
||||
|
||||
iterator emplace_impl(node_constructor& a)
|
||||
{
|
||||
key_type const& k = this->get_key(a.value());
|
||||
std::size_t key_hash = this->hash(k);
|
||||
iterator position = this->find_node(key_hash, k);
|
||||
|
||||
// reserve has basic exception safety if the hash function
|
||||
// throws, strong otherwise.
|
||||
this->reserve_for_insert(this->size_ + 1);
|
||||
return this->add_node(a, key_hash, position);
|
||||
}
|
||||
|
||||
void emplace_impl_no_rehash(node_constructor& a)
|
||||
{
|
||||
key_type const& k = this->get_key(a.value());
|
||||
std::size_t key_hash = this->hash(k);
|
||||
this->add_node(a, key_hash, this->find_node(key_hash, k));
|
||||
}
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
# if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
iterator emplace(boost::unordered::detail::emplace_args1<
|
||||
boost::unordered::detail::please_ignore_this_overload> const&)
|
||||
{
|
||||
BOOST_ASSERT(false);
|
||||
return iterator();
|
||||
}
|
||||
# else
|
||||
iterator emplace(
|
||||
boost::unordered::detail::please_ignore_this_overload const&)
|
||||
{
|
||||
BOOST_ASSERT(false);
|
||||
return iterator();
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
|
||||
iterator emplace(BOOST_UNORDERED_EMPLACE_ARGS)
|
||||
{
|
||||
node_constructor a(this->node_alloc());
|
||||
a.construct_with_value(BOOST_UNORDERED_EMPLACE_FORWARD);
|
||||
|
||||
return iterator(emplace_impl(a));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Insert range methods
|
||||
|
||||
// if hash function throws, or inserting > 1 element, basic exception
|
||||
// safety. Strong otherwise
|
||||
template <class I>
|
||||
typename boost::unordered::detail::enable_if_forward<I, void>::type
|
||||
insert_range(I i, I j)
|
||||
{
|
||||
if(i == j) return;
|
||||
|
||||
std::size_t distance = boost::unordered::detail::distance(i, j);
|
||||
if(distance == 1) {
|
||||
node_constructor a(this->node_alloc());
|
||||
a.construct_with_value2(*i);
|
||||
emplace_impl(a);
|
||||
}
|
||||
else {
|
||||
// Only require basic exception safety here
|
||||
this->reserve_for_insert(this->size_ + distance);
|
||||
|
||||
node_constructor a(this->node_alloc());
|
||||
for (; i != j; ++i) {
|
||||
a.construct_with_value2(*i);
|
||||
emplace_impl_no_rehash(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class I>
|
||||
typename boost::unordered::detail::disable_if_forward<I, void>::type
|
||||
insert_range(I i, I j)
|
||||
{
|
||||
node_constructor a(this->node_alloc());
|
||||
for (; i != j; ++i) {
|
||||
a.construct_with_value2(*i);
|
||||
emplace_impl(a);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Erase
|
||||
//
|
||||
// no throw
|
||||
|
||||
std::size_t erase_key(key_type const& k)
|
||||
{
|
||||
if(!this->size_) return 0;
|
||||
|
||||
std::size_t key_hash = this->hash(k);
|
||||
std::size_t bucket_index = this->hash_to_bucket(key_hash);
|
||||
link_pointer prev = this->get_previous_start(bucket_index);
|
||||
if (!prev) return 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (!prev->next_) return 0;
|
||||
std::size_t node_hash =
|
||||
static_cast<node_pointer>(prev->next_)->hash_;
|
||||
if (this->hash_to_bucket(node_hash) != bucket_index)
|
||||
return 0;
|
||||
if (node_hash == key_hash &&
|
||||
this->key_eq()(k, this->get_key(
|
||||
static_cast<node_pointer>(prev->next_)->value())))
|
||||
break;
|
||||
prev = static_cast<node_pointer>(prev->next_)->group_prev_;
|
||||
}
|
||||
|
||||
node_pointer first_node = static_cast<node_pointer>(prev->next_);
|
||||
link_pointer end = first_node->group_prev_->next_;
|
||||
|
||||
std::size_t count = this->delete_nodes(prev, end);
|
||||
this->fix_bucket(bucket_index, prev);
|
||||
return count;
|
||||
}
|
||||
|
||||
iterator erase(c_iterator r)
|
||||
{
|
||||
BOOST_ASSERT(r.node_);
|
||||
iterator next(r.node_);
|
||||
++next;
|
||||
erase_nodes(r.node_, next.node_);
|
||||
return next;
|
||||
}
|
||||
|
||||
iterator erase_range(c_iterator r1, c_iterator r2)
|
||||
{
|
||||
if (r1 == r2) return iterator(r2.node_);
|
||||
erase_nodes(r1.node_, r2.node_);
|
||||
return iterator(r2.node_);
|
||||
}
|
||||
|
||||
link_pointer erase_nodes(node_pointer begin, node_pointer end)
|
||||
{
|
||||
std::size_t bucket_index = this->hash_to_bucket(begin->hash_);
|
||||
|
||||
// Split the groups containing 'begin' and 'end'.
|
||||
// And get the pointer to the node before begin while
|
||||
// we're at it.
|
||||
link_pointer prev = split_groups(begin, end);
|
||||
|
||||
// If we don't have a 'prev' it means that begin is at the
|
||||
// beginning of a block, so search through the blocks in the
|
||||
// same bucket.
|
||||
if (!prev) {
|
||||
prev = this->get_previous_start(bucket_index);
|
||||
while (prev->next_ != begin)
|
||||
prev = static_cast<node_pointer>(prev->next_)->group_prev_;
|
||||
}
|
||||
|
||||
// Delete the nodes.
|
||||
do {
|
||||
link_pointer group_end =
|
||||
static_cast<node_pointer>(prev->next_)->group_prev_->next_;
|
||||
this->delete_nodes(prev, group_end);
|
||||
bucket_index = this->fix_bucket(bucket_index, prev);
|
||||
} while(prev->next_ != end);
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
static link_pointer split_groups(node_pointer begin, node_pointer end)
|
||||
{
|
||||
node_pointer prev = begin->group_prev_;
|
||||
if (prev->next_ != begin) prev = node_pointer();
|
||||
|
||||
if (end) {
|
||||
node_pointer first = end;
|
||||
while (first != begin && first->group_prev_->next_ == first) {
|
||||
first = first->group_prev_;
|
||||
}
|
||||
|
||||
boost::swap(first->group_prev_, end->group_prev_);
|
||||
if (first == begin) return prev;
|
||||
}
|
||||
|
||||
if (prev) {
|
||||
node_pointer first = prev;
|
||||
while (first->group_prev_->next_ == first) {
|
||||
first = first->group_prev_;
|
||||
}
|
||||
boost::swap(first->group_prev_, begin->group_prev_);
|
||||
}
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// fill_buckets
|
||||
|
||||
template <class NodeCreator>
|
||||
static void fill_buckets(iterator n, table& dst,
|
||||
NodeCreator& creator)
|
||||
{
|
||||
link_pointer prev = dst.get_previous_start();
|
||||
|
||||
while (n.node_) {
|
||||
std::size_t key_hash = n.node_->hash_;
|
||||
iterator group_end(n.node_->group_prev_->next_);
|
||||
|
||||
node_pointer first_node = creator.create(*n);
|
||||
node_pointer end = first_node;
|
||||
first_node->hash_ = key_hash;
|
||||
prev->next_ = first_node;
|
||||
++dst.size_;
|
||||
|
||||
for (++n; n != group_end; ++n)
|
||||
{
|
||||
end = creator.create(*n);
|
||||
end->hash_ = key_hash;
|
||||
add_after_node(end, first_node);
|
||||
++dst.size_;
|
||||
}
|
||||
|
||||
prev = place_in_bucket(dst, prev, end);
|
||||
}
|
||||
}
|
||||
|
||||
// strong otherwise exception safety
|
||||
void rehash_impl(std::size_t num_buckets)
|
||||
{
|
||||
BOOST_ASSERT(this->buckets_);
|
||||
|
||||
this->create_buckets(num_buckets);
|
||||
link_pointer prev = this->get_previous_start();
|
||||
while (prev->next_)
|
||||
prev = place_in_bucket(*this, prev,
|
||||
static_cast<node_pointer>(prev->next_)->group_prev_);
|
||||
}
|
||||
|
||||
// Iterate through the nodes placing them in the correct buckets.
|
||||
// pre: prev->next_ is not null.
|
||||
static link_pointer place_in_bucket(table& dst,
|
||||
link_pointer prev, node_pointer end)
|
||||
{
|
||||
bucket_pointer b = dst.get_bucket(dst.hash_to_bucket(end->hash_));
|
||||
|
||||
if (!b->next_) {
|
||||
b->next_ = prev;
|
||||
return end;
|
||||
}
|
||||
else {
|
||||
link_pointer next = end->next_;
|
||||
end->next_ = b->next_->next_;
|
||||
b->next_->next_ = prev->next_;
|
||||
prev->next_ = next;
|
||||
return prev;
|
||||
}
|
||||
}
|
||||
};
|
||||
}}}
|
||||
|
||||
#endif
|
@ -1,188 +0,0 @@
|
||||
|
||||
// Copyright (C) 2005-2011 Daniel James
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_EXTRACT_KEY_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_DETAIL_EXTRACT_KEY_HPP_INCLUDED
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/unordered/detail/table.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
namespace detail {
|
||||
|
||||
// key extractors
|
||||
//
|
||||
// no throw
|
||||
//
|
||||
// 'extract_key' is called with the emplace parameters to return a
|
||||
// key if available or 'no_key' is one isn't and will need to be
|
||||
// constructed. This could be done by overloading the emplace implementation
|
||||
// for the different cases, but that's a bit tricky on compilers without
|
||||
// variadic templates.
|
||||
|
||||
struct no_key {
|
||||
no_key() {}
|
||||
template <class T> no_key(T const&) {}
|
||||
};
|
||||
|
||||
template <typename Key, typename T>
|
||||
struct is_key {
|
||||
template <typename T2>
|
||||
static choice1::type test(T2 const&);
|
||||
static choice2::type test(Key const&);
|
||||
|
||||
enum { value = sizeof(test(boost::unordered::detail::make<T>())) ==
|
||||
sizeof(choice2::type) };
|
||||
|
||||
typedef typename boost::detail::if_true<value>::
|
||||
BOOST_NESTED_TEMPLATE then<Key const&, no_key>::type type;
|
||||
};
|
||||
|
||||
template <class ValueType>
|
||||
struct set_extractor
|
||||
{
|
||||
typedef ValueType value_type;
|
||||
typedef ValueType key_type;
|
||||
|
||||
static key_type const& extract(key_type const& v)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
static no_key extract()
|
||||
{
|
||||
return no_key();
|
||||
}
|
||||
|
||||
template <class Arg>
|
||||
static no_key extract(Arg const&)
|
||||
{
|
||||
return no_key();
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
template <class Arg1, class Arg2, class... Args>
|
||||
static no_key extract(Arg1 const&, Arg2 const&, Args const&...)
|
||||
{
|
||||
return no_key();
|
||||
}
|
||||
#else
|
||||
template <class Arg1, class Arg2>
|
||||
static no_key extract(Arg1 const&, Arg2 const&)
|
||||
{
|
||||
return no_key();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <class Key, class ValueType>
|
||||
struct map_extractor
|
||||
{
|
||||
typedef ValueType value_type;
|
||||
typedef typename boost::remove_const<Key>::type key_type;
|
||||
|
||||
static key_type const& extract(value_type const& v)
|
||||
{
|
||||
return v.first;
|
||||
}
|
||||
|
||||
template <class Second>
|
||||
static key_type const& extract(std::pair<key_type, Second> const& v)
|
||||
{
|
||||
return v.first;
|
||||
}
|
||||
|
||||
template <class Second>
|
||||
static key_type const& extract(
|
||||
std::pair<key_type const, Second> const& v)
|
||||
{
|
||||
return v.first;
|
||||
}
|
||||
|
||||
template <class Arg1>
|
||||
static key_type const& extract(key_type const& k, Arg1 const&)
|
||||
{
|
||||
return k;
|
||||
}
|
||||
|
||||
static no_key extract()
|
||||
{
|
||||
return no_key();
|
||||
}
|
||||
|
||||
template <class Arg>
|
||||
static no_key extract(Arg const&)
|
||||
{
|
||||
return no_key();
|
||||
}
|
||||
|
||||
template <class Arg1, class Arg2>
|
||||
static no_key extract(Arg1 const&, Arg2 const&)
|
||||
{
|
||||
return no_key();
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
template <class Arg1, class Arg2, class Arg3, class... Args>
|
||||
static no_key extract(Arg1 const&, Arg2 const&, Arg3 const&,
|
||||
Args const&...)
|
||||
{
|
||||
return no_key();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
|
||||
#define BOOST_UNORDERED_KEY_FROM_TUPLE(namespace_) \
|
||||
template <typename T2> \
|
||||
static no_key extract(boost::unordered::piecewise_construct_t, \
|
||||
namespace_ tuple<> const&, T2 const&) \
|
||||
{ \
|
||||
return no_key(); \
|
||||
} \
|
||||
\
|
||||
template <typename T, typename T2> \
|
||||
static typename is_key<key_type, T>::type \
|
||||
extract(boost::unordered::piecewise_construct_t, \
|
||||
namespace_ tuple<T> const& k, T2 const&) \
|
||||
{ \
|
||||
return typename is_key<key_type, T>::type( \
|
||||
namespace_ get<0>(k)); \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define BOOST_UNORDERED_KEY_FROM_TUPLE(namespace_) \
|
||||
static no_key extract(boost::unordered::piecewise_construct_t, \
|
||||
namespace_ tuple<> const&) \
|
||||
{ \
|
||||
return no_key(); \
|
||||
} \
|
||||
\
|
||||
template <typename T> \
|
||||
static typename is_key<key_type, T>::type \
|
||||
extract(boost::unordered::piecewise_construct_t, \
|
||||
namespace_ tuple<T> const& k) \
|
||||
{ \
|
||||
return typename is_key<key_type, T>::type( \
|
||||
namespace_ get<0>(k)); \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
BOOST_UNORDERED_KEY_FROM_TUPLE(boost::)
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
BOOST_UNORDERED_KEY_FROM_TUPLE(std::)
|
||||
#endif
|
||||
};
|
||||
}}}
|
||||
|
||||
#endif
|
@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright (C) 2008-2011 Daniel James.
|
||||
// Copyright (C) 2008-2016 Daniel James.
|
||||
// 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)
|
||||
|
||||
@ -11,13 +11,53 @@
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace unordered
|
||||
{
|
||||
struct piecewise_construct_t {};
|
||||
#include <boost/predef.h>
|
||||
|
||||
#if defined(BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT)
|
||||
// Already defined.
|
||||
#elif defined(BOOST_LIBSTDCXX11)
|
||||
// https://github.com/gcc-mirror/gcc/blob/gcc-4_6-branch/libstdc++-v3/include/bits/stl_pair.h#L70
|
||||
#if BOOST_LIBSTDCXX_VERSION > 40600
|
||||
#define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1
|
||||
#endif
|
||||
#elif BOOST_LIB_STD_CXX
|
||||
// https://github.com/llvm-mirror/libcxx/blob/release_30/include/utility#L206
|
||||
#if BOOST_LIB_STD_CXX >= BOOST_VERSION_NUMBER(3, 0, 0)
|
||||
#define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1
|
||||
#endif
|
||||
#elif defined(BOOST_LIB_STD_DINKUMWARE)
|
||||
// Apparently C++11 standard supported in Visual Studio 2012
|
||||
// https://msdn.microsoft.com/en-us/library/hh567368.aspx#stl
|
||||
// 2012 = VC+11 = BOOST_MSVC 1700 Hopefully!
|
||||
// I have no idea when Dinkumware added it, probably a lot
|
||||
// earlier than this check.
|
||||
#if BOOST_LIB_STD_DINKUMWARE >= BOOST_VERSION_NUMBER(6, 50, 0) || \
|
||||
BOOST_COMP_MSVC >= BOOST_VERSION_NUMBER(17, 0, 0)
|
||||
#define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Assume that an unknown library does not support piecewise construction.
|
||||
#if !defined(BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT)
|
||||
#define BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT 0
|
||||
#endif
|
||||
|
||||
#if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT
|
||||
#include <utility>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
#if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT
|
||||
using std::piecewise_construct_t;
|
||||
using std::piecewise_construct;
|
||||
#else
|
||||
struct piecewise_construct_t
|
||||
{
|
||||
};
|
||||
const piecewise_construct_t piecewise_construct = piecewise_construct_t();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
4952
include/boost/unordered/detail/implementation.hpp
Normal file
4952
include/boost/unordered/detail/implementation.hpp
Normal file
File diff suppressed because it is too large
Load Diff
67
include/boost/unordered/detail/map.hpp
Normal file
67
include/boost/unordered/detail/map.hpp
Normal file
@ -0,0 +1,67 @@
|
||||
|
||||
// Copyright (C) 2005-2016 Daniel James
|
||||
// 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 <boost/unordered/detail/implementation.hpp>
|
||||
#include <boost/unordered/unordered_map_fwd.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
namespace detail {
|
||||
template <typename A, typename K, typename M, typename H, typename P>
|
||||
struct map
|
||||
{
|
||||
typedef boost::unordered::detail::map<A, K, M, H, P> types;
|
||||
|
||||
typedef std::pair<K const, M> value_type;
|
||||
typedef H hasher;
|
||||
typedef P key_equal;
|
||||
typedef K const const_key_type;
|
||||
|
||||
typedef
|
||||
typename ::boost::unordered::detail::rebind_wrap<A, value_type>::type
|
||||
value_allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<value_allocator>
|
||||
value_allocator_traits;
|
||||
|
||||
typedef boost::unordered::detail::pick_node<A, value_type> pick;
|
||||
typedef typename pick::node node;
|
||||
typedef typename pick::bucket bucket;
|
||||
typedef typename pick::link_pointer link_pointer;
|
||||
|
||||
typedef boost::unordered::detail::table<types> table;
|
||||
typedef boost::unordered::detail::map_extractor<value_type> extractor;
|
||||
|
||||
typedef typename boost::unordered::detail::pick_policy<K>::type policy;
|
||||
|
||||
typedef boost::unordered::iterator_detail::iterator<node> iterator;
|
||||
typedef boost::unordered::iterator_detail::c_iterator<node> c_iterator;
|
||||
typedef boost::unordered::iterator_detail::l_iterator<node> l_iterator;
|
||||
typedef boost::unordered::iterator_detail::cl_iterator<node>
|
||||
cl_iterator;
|
||||
|
||||
typedef boost::unordered::node_handle_map<node, K, M, A> node_type;
|
||||
typedef boost::unordered::insert_return_type_map<node, K, M, A>
|
||||
insert_return_type;
|
||||
};
|
||||
|
||||
template <typename K, typename M, typename H, typename P, typename A>
|
||||
class instantiate_map
|
||||
{
|
||||
typedef boost::unordered_map<K, M, H, P, A> container;
|
||||
container x;
|
||||
typename container::node_type node_type;
|
||||
typename container::insert_return_type insert_return_type;
|
||||
};
|
||||
|
||||
template <typename K, typename M, typename H, typename P, typename A>
|
||||
class instantiate_multimap
|
||||
{
|
||||
typedef boost::unordered_multimap<K, M, H, P, A> container;
|
||||
container x;
|
||||
typename container::node_type node_type;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
66
include/boost/unordered/detail/set.hpp
Normal file
66
include/boost/unordered/detail/set.hpp
Normal file
@ -0,0 +1,66 @@
|
||||
|
||||
// Copyright (C) 2005-2016 Daniel James
|
||||
// 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 <boost/unordered/detail/implementation.hpp>
|
||||
#include <boost/unordered/unordered_set_fwd.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
namespace detail {
|
||||
template <typename A, typename T, typename H, typename P> struct set
|
||||
{
|
||||
typedef boost::unordered::detail::set<A, T, H, P> types;
|
||||
|
||||
typedef T value_type;
|
||||
typedef H hasher;
|
||||
typedef P key_equal;
|
||||
typedef T const const_key_type;
|
||||
|
||||
typedef
|
||||
typename ::boost::unordered::detail::rebind_wrap<A, value_type>::type
|
||||
value_allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<value_allocator>
|
||||
value_allocator_traits;
|
||||
|
||||
typedef boost::unordered::detail::pick_node<A, value_type> pick;
|
||||
typedef typename pick::node node;
|
||||
typedef typename pick::bucket bucket;
|
||||
typedef typename pick::link_pointer link_pointer;
|
||||
|
||||
typedef boost::unordered::detail::table<types> table;
|
||||
typedef boost::unordered::detail::set_extractor<value_type> extractor;
|
||||
|
||||
typedef typename boost::unordered::detail::pick_policy<T>::type policy;
|
||||
|
||||
typedef boost::unordered::iterator_detail::c_iterator<node> iterator;
|
||||
typedef boost::unordered::iterator_detail::c_iterator<node> c_iterator;
|
||||
typedef boost::unordered::iterator_detail::cl_iterator<node> l_iterator;
|
||||
typedef boost::unordered::iterator_detail::cl_iterator<node>
|
||||
cl_iterator;
|
||||
|
||||
typedef boost::unordered::node_handle_set<node, T, A> node_type;
|
||||
typedef boost::unordered::insert_return_type_set<node, T, A>
|
||||
insert_return_type;
|
||||
};
|
||||
|
||||
template <typename T, typename H, typename P, typename A>
|
||||
class instantiate_set
|
||||
{
|
||||
typedef boost::unordered_set<T, H, P, A> container;
|
||||
container x;
|
||||
typename container::node_type node_type;
|
||||
typename container::insert_return_type insert_return_type;
|
||||
};
|
||||
|
||||
template <typename T, typename H, typename P, typename A>
|
||||
class instantiate_multiset
|
||||
{
|
||||
typedef boost::unordered_multiset<T, H, P, A> container;
|
||||
container x;
|
||||
typename container::node_type node_type;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1,868 +0,0 @@
|
||||
|
||||
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
||||
// Copyright (C) 2005-2011 Daniel James
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_DETAIL_ALL_HPP_INCLUDED
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/unordered/detail/buckets.hpp>
|
||||
#include <boost/unordered/detail/util.hpp>
|
||||
#include <boost/type_traits/aligned_storage.hpp>
|
||||
#include <boost/type_traits/alignment_of.hpp>
|
||||
#include <cmath>
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_UNORDERED_DEPRECATED_EQUALITY)
|
||||
|
||||
#if defined(__EDG__)
|
||||
#elif defined(_MSC_VER) || defined(__BORLANDC__) || defined(__DMC__)
|
||||
#pragma message("Warning: BOOST_UNORDERED_DEPRECATED_EQUALITY is no longer supported.")
|
||||
#elif defined(__GNUC__) || defined(__HP_aCC) || \
|
||||
defined(__SUNPRO_CC) || defined(__IBMCPP__)
|
||||
#warning "BOOST_UNORDERED_DEPRECATED_EQUALITY is no longer supported."
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
namespace boost { namespace unordered { namespace detail {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// convert double to std::size_t
|
||||
|
||||
inline std::size_t double_to_size(double f)
|
||||
{
|
||||
return f >= static_cast<double>(
|
||||
(std::numeric_limits<std::size_t>::max)()) ?
|
||||
(std::numeric_limits<std::size_t>::max)() :
|
||||
static_cast<std::size_t>(f);
|
||||
}
|
||||
|
||||
// The space used to store values in a node.
|
||||
|
||||
template <typename ValueType>
|
||||
struct value_base
|
||||
{
|
||||
typedef ValueType value_type;
|
||||
|
||||
typename boost::aligned_storage<
|
||||
sizeof(value_type),
|
||||
boost::alignment_of<value_type>::value>::type data_;
|
||||
|
||||
void* address() {
|
||||
return this;
|
||||
}
|
||||
|
||||
value_type& value() {
|
||||
return *(ValueType*) this;
|
||||
}
|
||||
|
||||
value_type* value_ptr() {
|
||||
return (ValueType*) this;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
value_base& operator=(value_base const&);
|
||||
};
|
||||
|
||||
template <typename NodeAlloc>
|
||||
struct copy_nodes
|
||||
{
|
||||
typedef boost::unordered::detail::allocator_traits<NodeAlloc>
|
||||
node_allocator_traits;
|
||||
|
||||
node_constructor<NodeAlloc> constructor;
|
||||
|
||||
explicit copy_nodes(NodeAlloc& a) : constructor(a) {}
|
||||
|
||||
typename node_allocator_traits::pointer create(
|
||||
typename node_allocator_traits::value_type::value_type const& v)
|
||||
{
|
||||
constructor.construct_with_value2(v);
|
||||
return constructor.release();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename NodeAlloc>
|
||||
struct move_nodes
|
||||
{
|
||||
typedef boost::unordered::detail::allocator_traits<NodeAlloc>
|
||||
node_allocator_traits;
|
||||
|
||||
node_constructor<NodeAlloc> constructor;
|
||||
|
||||
explicit move_nodes(NodeAlloc& a) : constructor(a) {}
|
||||
|
||||
typename node_allocator_traits::pointer create(
|
||||
typename node_allocator_traits::value_type::value_type& v)
|
||||
{
|
||||
constructor.construct_with_value2(boost::move(v));
|
||||
return constructor.release();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Buckets>
|
||||
struct assign_nodes
|
||||
{
|
||||
node_holder<typename Buckets::node_allocator> holder;
|
||||
|
||||
explicit assign_nodes(Buckets& b) : holder(b) {}
|
||||
|
||||
typename Buckets::node_pointer create(
|
||||
typename Buckets::value_type const& v)
|
||||
{
|
||||
return holder.copy_of(v);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Buckets>
|
||||
struct move_assign_nodes
|
||||
{
|
||||
node_holder<typename Buckets::node_allocator> holder;
|
||||
|
||||
explicit move_assign_nodes(Buckets& b) : holder(b) {}
|
||||
|
||||
typename Buckets::node_pointer create(
|
||||
typename Buckets::value_type& v)
|
||||
{
|
||||
return holder.move_copy_of(v);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Types>
|
||||
struct table :
|
||||
boost::unordered::detail::functions<
|
||||
typename Types::hasher,
|
||||
typename Types::key_equal>
|
||||
{
|
||||
private:
|
||||
table(table const&);
|
||||
table& operator=(table const&);
|
||||
public:
|
||||
typedef typename Types::node node;
|
||||
typedef typename Types::bucket bucket;
|
||||
typedef typename Types::hasher hasher;
|
||||
typedef typename Types::key_equal key_equal;
|
||||
typedef typename Types::key_type key_type;
|
||||
typedef typename Types::extractor extractor;
|
||||
typedef typename Types::value_type value_type;
|
||||
typedef typename Types::table table_impl;
|
||||
typedef typename Types::link_pointer link_pointer;
|
||||
typedef typename Types::policy policy;
|
||||
|
||||
typedef boost::unordered::detail::functions<
|
||||
typename Types::hasher,
|
||||
typename Types::key_equal> functions;
|
||||
typedef typename functions::set_hash_functions set_hash_functions;
|
||||
|
||||
typedef typename Types::allocator allocator;
|
||||
typedef typename boost::unordered::detail::
|
||||
rebind_wrap<allocator, node>::type node_allocator;
|
||||
typedef typename boost::unordered::detail::
|
||||
rebind_wrap<allocator, bucket>::type bucket_allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<node_allocator>
|
||||
node_allocator_traits;
|
||||
typedef boost::unordered::detail::allocator_traits<bucket_allocator>
|
||||
bucket_allocator_traits;
|
||||
typedef typename node_allocator_traits::pointer
|
||||
node_pointer;
|
||||
typedef typename node_allocator_traits::const_pointer
|
||||
const_node_pointer;
|
||||
typedef typename bucket_allocator_traits::pointer
|
||||
bucket_pointer;
|
||||
typedef boost::unordered::detail::node_constructor<node_allocator>
|
||||
node_constructor;
|
||||
|
||||
typedef boost::unordered::iterator_detail::
|
||||
iterator<node> iterator;
|
||||
typedef boost::unordered::iterator_detail::
|
||||
c_iterator<node, const_node_pointer> c_iterator;
|
||||
typedef boost::unordered::iterator_detail::
|
||||
l_iterator<node, policy> l_iterator;
|
||||
typedef boost::unordered::iterator_detail::
|
||||
cl_iterator<node, const_node_pointer, policy> cl_iterator;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Members
|
||||
|
||||
boost::unordered::detail::compressed<bucket_allocator, node_allocator>
|
||||
allocators_;
|
||||
std::size_t bucket_count_;
|
||||
std::size_t size_;
|
||||
float mlf_;
|
||||
std::size_t max_load_;
|
||||
bucket_pointer buckets_;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Data access
|
||||
|
||||
bucket_allocator const& bucket_alloc() const
|
||||
{
|
||||
return allocators_.first();
|
||||
}
|
||||
|
||||
node_allocator const& node_alloc() const
|
||||
{
|
||||
return allocators_.second();
|
||||
}
|
||||
|
||||
bucket_allocator& bucket_alloc()
|
||||
{
|
||||
return allocators_.first();
|
||||
}
|
||||
|
||||
node_allocator& node_alloc()
|
||||
{
|
||||
return allocators_.second();
|
||||
}
|
||||
|
||||
std::size_t max_bucket_count() const
|
||||
{
|
||||
// -1 to account for the start bucket.
|
||||
return policy::prev_bucket_count(
|
||||
bucket_allocator_traits::max_size(bucket_alloc()) - 1);
|
||||
}
|
||||
|
||||
bucket_pointer get_bucket(std::size_t bucket_index) const
|
||||
{
|
||||
BOOST_ASSERT(buckets_);
|
||||
return buckets_ + static_cast<std::ptrdiff_t>(bucket_index);
|
||||
}
|
||||
|
||||
link_pointer get_previous_start() const
|
||||
{
|
||||
return get_bucket(bucket_count_)->first_from_start();
|
||||
}
|
||||
|
||||
link_pointer get_previous_start(std::size_t bucket_index) const
|
||||
{
|
||||
return get_bucket(bucket_index)->next_;
|
||||
}
|
||||
|
||||
iterator begin() const
|
||||
{
|
||||
return size_ ? iterator(get_previous_start()->next_) : iterator();
|
||||
}
|
||||
|
||||
iterator begin(std::size_t bucket_index) const
|
||||
{
|
||||
if (!size_) return iterator();
|
||||
link_pointer prev = get_previous_start(bucket_index);
|
||||
return prev ? iterator(prev->next_) : iterator();
|
||||
}
|
||||
|
||||
std::size_t hash_to_bucket(std::size_t hash) const
|
||||
{
|
||||
return policy::to_bucket(bucket_count_, hash);
|
||||
}
|
||||
|
||||
float load_factor() const
|
||||
{
|
||||
BOOST_ASSERT(bucket_count_ != 0);
|
||||
return static_cast<float>(size_)
|
||||
/ static_cast<float>(bucket_count_);
|
||||
}
|
||||
|
||||
std::size_t bucket_size(std::size_t index) const
|
||||
{
|
||||
iterator it = begin(index);
|
||||
if (!it.node_) return 0;
|
||||
|
||||
std::size_t count = 0;
|
||||
while(it.node_ && hash_to_bucket(it.node_->hash_) == index)
|
||||
{
|
||||
++count;
|
||||
++it;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Load methods
|
||||
|
||||
std::size_t max_size() const
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
// size < mlf_ * count
|
||||
return boost::unordered::detail::double_to_size(ceil(
|
||||
static_cast<double>(mlf_) *
|
||||
static_cast<double>(max_bucket_count())
|
||||
)) - 1;
|
||||
}
|
||||
|
||||
void recalculate_max_load()
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
// From 6.3.1/13:
|
||||
// Only resize when size >= mlf_ * count
|
||||
max_load_ = buckets_ ? boost::unordered::detail::double_to_size(ceil(
|
||||
static_cast<double>(mlf_) *
|
||||
static_cast<double>(bucket_count_)
|
||||
)) : 0;
|
||||
|
||||
}
|
||||
|
||||
void max_load_factor(float z)
|
||||
{
|
||||
BOOST_ASSERT(z > 0);
|
||||
mlf_ = (std::max)(z, minimum_max_load_factor);
|
||||
recalculate_max_load();
|
||||
}
|
||||
|
||||
std::size_t min_buckets_for_size(std::size_t size) const
|
||||
{
|
||||
BOOST_ASSERT(mlf_ >= minimum_max_load_factor);
|
||||
|
||||
using namespace std;
|
||||
|
||||
// From 6.3.1/13:
|
||||
// size < mlf_ * count
|
||||
// => count > size / mlf_
|
||||
//
|
||||
// Or from rehash post-condition:
|
||||
// count > size / mlf_
|
||||
|
||||
return policy::new_bucket_count(
|
||||
boost::unordered::detail::double_to_size(floor(
|
||||
static_cast<double>(size) /
|
||||
static_cast<double>(mlf_))) + 1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Constructors
|
||||
|
||||
table(std::size_t num_buckets,
|
||||
hasher const& hf,
|
||||
key_equal const& eq,
|
||||
node_allocator const& a) :
|
||||
functions(hf, eq),
|
||||
allocators_(a,a),
|
||||
bucket_count_(policy::new_bucket_count(num_buckets)),
|
||||
size_(0),
|
||||
mlf_(1.0f),
|
||||
max_load_(0),
|
||||
buckets_()
|
||||
{}
|
||||
|
||||
table(table const& x, node_allocator const& a) :
|
||||
functions(x),
|
||||
allocators_(a,a),
|
||||
bucket_count_(x.min_buckets_for_size(x.size_)),
|
||||
size_(0),
|
||||
mlf_(x.mlf_),
|
||||
max_load_(0),
|
||||
buckets_()
|
||||
{}
|
||||
|
||||
table(table& x, boost::unordered::detail::move_tag m) :
|
||||
functions(x, m),
|
||||
allocators_(x.allocators_, m),
|
||||
bucket_count_(x.bucket_count_),
|
||||
size_(x.size_),
|
||||
mlf_(x.mlf_),
|
||||
max_load_(x.max_load_),
|
||||
buckets_(x.buckets_)
|
||||
{
|
||||
x.buckets_ = bucket_pointer();
|
||||
x.size_ = 0;
|
||||
x.max_load_ = 0;
|
||||
}
|
||||
|
||||
table(table& x, node_allocator const& a,
|
||||
boost::unordered::detail::move_tag m) :
|
||||
functions(x, m),
|
||||
allocators_(a, a),
|
||||
bucket_count_(x.bucket_count_),
|
||||
size_(0),
|
||||
mlf_(x.mlf_),
|
||||
max_load_(x.max_load_),
|
||||
buckets_()
|
||||
{}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Initialisation.
|
||||
|
||||
void init(table const& x)
|
||||
{
|
||||
if (x.size_) {
|
||||
create_buckets(bucket_count_);
|
||||
copy_nodes<node_allocator> copy(node_alloc());
|
||||
table_impl::fill_buckets(x.begin(), *this, copy);
|
||||
}
|
||||
}
|
||||
|
||||
void move_init(table& x)
|
||||
{
|
||||
if(node_alloc() == x.node_alloc()) {
|
||||
move_buckets_from(x);
|
||||
}
|
||||
else if(x.size_) {
|
||||
// TODO: Could pick new bucket size?
|
||||
create_buckets(bucket_count_);
|
||||
|
||||
move_nodes<node_allocator> move(node_alloc());
|
||||
node_holder<node_allocator> nodes(x);
|
||||
table_impl::fill_buckets(nodes.begin(), *this, move);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Create buckets
|
||||
|
||||
void create_buckets(std::size_t new_count)
|
||||
{
|
||||
boost::unordered::detail::array_constructor<bucket_allocator>
|
||||
constructor(bucket_alloc());
|
||||
|
||||
// Creates an extra bucket to act as the start node.
|
||||
constructor.construct(bucket(), new_count + 1);
|
||||
|
||||
if (buckets_)
|
||||
{
|
||||
// Copy the nodes to the new buckets, including the dummy
|
||||
// node if there is one.
|
||||
(constructor.get() +
|
||||
static_cast<std::ptrdiff_t>(new_count))->next_ =
|
||||
(buckets_ + static_cast<std::ptrdiff_t>(
|
||||
bucket_count_))->next_;
|
||||
destroy_buckets();
|
||||
}
|
||||
else if (bucket::extra_node)
|
||||
{
|
||||
node_constructor a(node_alloc());
|
||||
a.construct();
|
||||
|
||||
(constructor.get() +
|
||||
static_cast<std::ptrdiff_t>(new_count))->next_ =
|
||||
a.release();
|
||||
}
|
||||
|
||||
bucket_count_ = new_count;
|
||||
buckets_ = constructor.release();
|
||||
recalculate_max_load();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Swap and Move
|
||||
|
||||
void swap_allocators(table& other, false_type)
|
||||
{
|
||||
boost::unordered::detail::func::ignore_unused_variable_warning(other);
|
||||
|
||||
// According to 23.2.1.8, if propagate_on_container_swap is
|
||||
// false the behaviour is undefined unless the allocators
|
||||
// are equal.
|
||||
BOOST_ASSERT(node_alloc() == other.node_alloc());
|
||||
}
|
||||
|
||||
void swap_allocators(table& other, true_type)
|
||||
{
|
||||
allocators_.swap(other.allocators_);
|
||||
}
|
||||
|
||||
// Only swaps the allocators if propagate_on_container_swap
|
||||
void swap(table& x)
|
||||
{
|
||||
set_hash_functions op1(*this, x);
|
||||
set_hash_functions op2(x, *this);
|
||||
|
||||
// I think swap can throw if Propagate::value,
|
||||
// since the allocators' swap can throw. Not sure though.
|
||||
swap_allocators(x,
|
||||
boost::unordered::detail::integral_constant<bool,
|
||||
allocator_traits<node_allocator>::
|
||||
propagate_on_container_swap::value>());
|
||||
|
||||
boost::swap(buckets_, x.buckets_);
|
||||
boost::swap(bucket_count_, x.bucket_count_);
|
||||
boost::swap(size_, x.size_);
|
||||
std::swap(mlf_, x.mlf_);
|
||||
std::swap(max_load_, x.max_load_);
|
||||
op1.commit();
|
||||
op2.commit();
|
||||
}
|
||||
|
||||
void move_buckets_from(table& other)
|
||||
{
|
||||
BOOST_ASSERT(node_alloc() == other.node_alloc());
|
||||
BOOST_ASSERT(!buckets_);
|
||||
buckets_ = other.buckets_;
|
||||
bucket_count_ = other.bucket_count_;
|
||||
size_ = other.size_;
|
||||
other.buckets_ = bucket_pointer();
|
||||
other.size_ = 0;
|
||||
other.max_load_ = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Delete/destruct
|
||||
|
||||
~table()
|
||||
{
|
||||
delete_buckets();
|
||||
}
|
||||
|
||||
void delete_node(link_pointer prev)
|
||||
{
|
||||
node_pointer n = static_cast<node_pointer>(prev->next_);
|
||||
prev->next_ = n->next_;
|
||||
|
||||
boost::unordered::detail::func::destroy_value_impl(node_alloc(),
|
||||
n->value_ptr());
|
||||
node_allocator_traits::destroy(node_alloc(),
|
||||
boost::addressof(*n));
|
||||
node_allocator_traits::deallocate(node_alloc(), n, 1);
|
||||
--size_;
|
||||
}
|
||||
|
||||
std::size_t delete_nodes(link_pointer prev, link_pointer end)
|
||||
{
|
||||
BOOST_ASSERT(prev->next_ != end);
|
||||
|
||||
std::size_t count = 0;
|
||||
|
||||
do {
|
||||
delete_node(prev);
|
||||
++count;
|
||||
} while (prev->next_ != end);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void delete_buckets()
|
||||
{
|
||||
if(buckets_) {
|
||||
if (size_) delete_nodes(get_previous_start(), link_pointer());
|
||||
|
||||
if (bucket::extra_node) {
|
||||
node_pointer n = static_cast<node_pointer>(
|
||||
get_bucket(bucket_count_)->next_);
|
||||
node_allocator_traits::destroy(node_alloc(),
|
||||
boost::addressof(*n));
|
||||
node_allocator_traits::deallocate(node_alloc(), n, 1);
|
||||
}
|
||||
|
||||
destroy_buckets();
|
||||
buckets_ = bucket_pointer();
|
||||
max_load_ = 0;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(!size_);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
if (!size_) return;
|
||||
|
||||
delete_nodes(get_previous_start(), link_pointer());
|
||||
clear_buckets();
|
||||
|
||||
BOOST_ASSERT(!size_);
|
||||
}
|
||||
|
||||
void clear_buckets()
|
||||
{
|
||||
bucket_pointer end = get_bucket(bucket_count_);
|
||||
for(bucket_pointer it = buckets_; it != end; ++it)
|
||||
{
|
||||
it->next_ = node_pointer();
|
||||
}
|
||||
}
|
||||
|
||||
void destroy_buckets()
|
||||
{
|
||||
bucket_pointer end = get_bucket(bucket_count_ + 1);
|
||||
for(bucket_pointer it = buckets_; it != end; ++it)
|
||||
{
|
||||
bucket_allocator_traits::destroy(bucket_alloc(),
|
||||
boost::addressof(*it));
|
||||
}
|
||||
|
||||
bucket_allocator_traits::deallocate(bucket_alloc(),
|
||||
buckets_, bucket_count_ + 1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Fix buckets after delete
|
||||
//
|
||||
|
||||
std::size_t fix_bucket(std::size_t bucket_index, link_pointer prev)
|
||||
{
|
||||
link_pointer end = prev->next_;
|
||||
std::size_t bucket_index2 = bucket_index;
|
||||
|
||||
if (end)
|
||||
{
|
||||
bucket_index2 = hash_to_bucket(
|
||||
static_cast<node_pointer>(end)->hash_);
|
||||
|
||||
// If begin and end are in the same bucket, then
|
||||
// there's nothing to do.
|
||||
if (bucket_index == bucket_index2) return bucket_index2;
|
||||
|
||||
// Update the bucket containing end.
|
||||
get_bucket(bucket_index2)->next_ = prev;
|
||||
}
|
||||
|
||||
// Check if this bucket is now empty.
|
||||
bucket_pointer this_bucket = get_bucket(bucket_index);
|
||||
if (this_bucket->next_ == prev)
|
||||
this_bucket->next_ = link_pointer();
|
||||
|
||||
return bucket_index2;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Assignment
|
||||
|
||||
void assign(table const& x)
|
||||
{
|
||||
if (this != boost::addressof(x))
|
||||
{
|
||||
assign(x,
|
||||
boost::unordered::detail::integral_constant<bool,
|
||||
allocator_traits<node_allocator>::
|
||||
propagate_on_container_copy_assignment::value>());
|
||||
}
|
||||
}
|
||||
|
||||
void assign(table const& x, false_type)
|
||||
{
|
||||
// Strong exception safety.
|
||||
set_hash_functions new_func_this(*this, x);
|
||||
new_func_this.commit();
|
||||
mlf_ = x.mlf_;
|
||||
recalculate_max_load();
|
||||
|
||||
if (!size_ && !x.size_) return;
|
||||
|
||||
if (x.size_ >= max_load_) {
|
||||
create_buckets(min_buckets_for_size(x.size_));
|
||||
}
|
||||
else {
|
||||
clear_buckets();
|
||||
}
|
||||
|
||||
// assign_nodes takes ownership of the container's elements,
|
||||
// assigning to them if possible, and deleting any that are
|
||||
// left over.
|
||||
assign_nodes<table> assign(*this);
|
||||
table_impl::fill_buckets(x.begin(), *this, assign);
|
||||
}
|
||||
|
||||
void assign(table const& x, true_type)
|
||||
{
|
||||
if (node_alloc() == x.node_alloc()) {
|
||||
allocators_.assign(x.allocators_);
|
||||
assign(x, false_type());
|
||||
}
|
||||
else {
|
||||
set_hash_functions new_func_this(*this, x);
|
||||
|
||||
// Delete everything with current allocators before assigning
|
||||
// the new ones.
|
||||
delete_buckets();
|
||||
allocators_.assign(x.allocators_);
|
||||
|
||||
// Copy over other data, all no throw.
|
||||
new_func_this.commit();
|
||||
mlf_ = x.mlf_;
|
||||
bucket_count_ = min_buckets_for_size(x.size_);
|
||||
max_load_ = 0;
|
||||
|
||||
// Finally copy the elements.
|
||||
if (x.size_) {
|
||||
create_buckets(bucket_count_);
|
||||
copy_nodes<node_allocator> copy(node_alloc());
|
||||
table_impl::fill_buckets(x.begin(), *this, copy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void move_assign(table& x)
|
||||
{
|
||||
if (this != boost::addressof(x))
|
||||
{
|
||||
move_assign(x,
|
||||
boost::unordered::detail::integral_constant<bool,
|
||||
allocator_traits<node_allocator>::
|
||||
propagate_on_container_move_assignment::value>());
|
||||
}
|
||||
}
|
||||
|
||||
void move_assign(table& x, true_type)
|
||||
{
|
||||
delete_buckets();
|
||||
allocators_.move_assign(x.allocators_);
|
||||
move_assign_no_alloc(x);
|
||||
}
|
||||
|
||||
void move_assign(table& x, false_type)
|
||||
{
|
||||
if (node_alloc() == x.node_alloc()) {
|
||||
delete_buckets();
|
||||
move_assign_no_alloc(x);
|
||||
}
|
||||
else {
|
||||
set_hash_functions new_func_this(*this, x);
|
||||
new_func_this.commit();
|
||||
mlf_ = x.mlf_;
|
||||
recalculate_max_load();
|
||||
|
||||
if (!size_ && !x.size_) return;
|
||||
|
||||
if (x.size_ >= max_load_) {
|
||||
create_buckets(min_buckets_for_size(x.size_));
|
||||
}
|
||||
else {
|
||||
clear_buckets();
|
||||
}
|
||||
|
||||
// move_assign_nodes takes ownership of the container's
|
||||
// elements, assigning to them if possible, and deleting
|
||||
// any that are left over.
|
||||
move_assign_nodes<table> assign(*this);
|
||||
node_holder<node_allocator> nodes(x);
|
||||
table_impl::fill_buckets(nodes.begin(), *this, assign);
|
||||
}
|
||||
}
|
||||
|
||||
void move_assign_no_alloc(table& x)
|
||||
{
|
||||
set_hash_functions new_func_this(*this, x);
|
||||
// No throw from here.
|
||||
mlf_ = x.mlf_;
|
||||
max_load_ = x.max_load_;
|
||||
move_buckets_from(x);
|
||||
new_func_this.commit();
|
||||
}
|
||||
|
||||
// Accessors
|
||||
|
||||
key_type const& get_key(value_type const& x) const
|
||||
{
|
||||
return extractor::extract(x);
|
||||
}
|
||||
|
||||
std::size_t hash(key_type const& k) const
|
||||
{
|
||||
return policy::apply_hash(this->hash_function(), k);
|
||||
}
|
||||
|
||||
// Find Node
|
||||
|
||||
template <typename Key, typename Hash, typename Pred>
|
||||
iterator generic_find_node(
|
||||
Key const& k,
|
||||
Hash const& hf,
|
||||
Pred const& eq) const
|
||||
{
|
||||
return static_cast<table_impl const*>(this)->
|
||||
find_node_impl(policy::apply_hash(hf, k), k, eq);
|
||||
}
|
||||
|
||||
iterator find_node(
|
||||
std::size_t key_hash,
|
||||
key_type const& k) const
|
||||
{
|
||||
return static_cast<table_impl const*>(this)->
|
||||
find_node_impl(key_hash, k, this->key_eq());
|
||||
}
|
||||
|
||||
iterator find_node(key_type const& k) const
|
||||
{
|
||||
return static_cast<table_impl const*>(this)->
|
||||
find_node_impl(hash(k), k, this->key_eq());
|
||||
}
|
||||
|
||||
iterator find_matching_node(iterator n) const
|
||||
{
|
||||
// TODO: Does this apply to C++11?
|
||||
//
|
||||
// For some stupid reason, I decided to support equality comparison
|
||||
// when different hash functions are used. So I can't use the hash
|
||||
// value from the node here.
|
||||
|
||||
return find_node(get_key(*n));
|
||||
}
|
||||
|
||||
// Reserve and rehash
|
||||
|
||||
void reserve_for_insert(std::size_t);
|
||||
void rehash(std::size_t);
|
||||
void reserve(std::size_t);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Reserve & Rehash
|
||||
|
||||
// basic exception safety
|
||||
template <typename Types>
|
||||
inline void table<Types>::reserve_for_insert(std::size_t size)
|
||||
{
|
||||
if (!buckets_) {
|
||||
create_buckets((std::max)(bucket_count_,
|
||||
min_buckets_for_size(size)));
|
||||
}
|
||||
// According to the standard this should be 'size >= max_load_',
|
||||
// but I think this is better, defect report filed.
|
||||
else if(size > max_load_) {
|
||||
std::size_t num_buckets
|
||||
= min_buckets_for_size((std::max)(size,
|
||||
size_ + (size_ >> 1)));
|
||||
|
||||
if (num_buckets != bucket_count_)
|
||||
static_cast<table_impl*>(this)->rehash_impl(num_buckets);
|
||||
}
|
||||
}
|
||||
|
||||
// if hash function throws, basic exception safety
|
||||
// strong otherwise.
|
||||
|
||||
template <typename Types>
|
||||
inline void table<Types>::rehash(std::size_t min_buckets)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
if(!size_) {
|
||||
delete_buckets();
|
||||
bucket_count_ = policy::new_bucket_count(min_buckets);
|
||||
}
|
||||
else {
|
||||
min_buckets = policy::new_bucket_count((std::max)(min_buckets,
|
||||
boost::unordered::detail::double_to_size(floor(
|
||||
static_cast<double>(size_) /
|
||||
static_cast<double>(mlf_))) + 1));
|
||||
|
||||
if(min_buckets != bucket_count_)
|
||||
static_cast<table_impl*>(this)->rehash_impl(min_buckets);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Types>
|
||||
inline void table<Types>::reserve(std::size_t num_elements)
|
||||
{
|
||||
rehash(static_cast<std::size_t>(
|
||||
std::ceil(static_cast<double>(num_elements) / mlf_)));
|
||||
}
|
||||
}}}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,621 +0,0 @@
|
||||
|
||||
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
||||
// Copyright (C) 2005-2011 Daniel James
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/unordered/detail/table.hpp>
|
||||
#include <boost/unordered/detail/extract_key.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace boost { namespace unordered { namespace detail {
|
||||
|
||||
template <typename A, typename T> struct unique_node;
|
||||
template <typename T> struct ptr_node;
|
||||
template <typename Types> struct table_impl;
|
||||
|
||||
template <typename A, typename T>
|
||||
struct unique_node :
|
||||
boost::unordered::detail::value_base<T>
|
||||
{
|
||||
typedef typename ::boost::unordered::detail::rebind_wrap<
|
||||
A, unique_node<A, T> >::type::pointer node_pointer;
|
||||
typedef node_pointer link_pointer;
|
||||
|
||||
link_pointer next_;
|
||||
std::size_t hash_;
|
||||
|
||||
unique_node() :
|
||||
next_(),
|
||||
hash_(0)
|
||||
{}
|
||||
|
||||
void init(node_pointer)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
unique_node& operator=(unique_node const&);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ptr_node :
|
||||
boost::unordered::detail::value_base<T>,
|
||||
boost::unordered::detail::ptr_bucket
|
||||
{
|
||||
typedef boost::unordered::detail::ptr_bucket bucket_base;
|
||||
typedef ptr_node<T>* node_pointer;
|
||||
typedef ptr_bucket* link_pointer;
|
||||
|
||||
std::size_t hash_;
|
||||
|
||||
ptr_node() :
|
||||
bucket_base(),
|
||||
hash_(0)
|
||||
{}
|
||||
|
||||
void init(node_pointer)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
ptr_node& operator=(ptr_node const&);
|
||||
};
|
||||
|
||||
// If the allocator uses raw pointers use ptr_node
|
||||
// Otherwise use node.
|
||||
|
||||
template <typename A, typename T, typename NodePtr, typename BucketPtr>
|
||||
struct pick_node2
|
||||
{
|
||||
typedef boost::unordered::detail::unique_node<A, T> node;
|
||||
|
||||
typedef typename boost::unordered::detail::allocator_traits<
|
||||
typename boost::unordered::detail::rebind_wrap<A, node>::type
|
||||
>::pointer node_pointer;
|
||||
|
||||
typedef boost::unordered::detail::bucket<node_pointer> bucket;
|
||||
typedef node_pointer link_pointer;
|
||||
};
|
||||
|
||||
template <typename A, typename T>
|
||||
struct pick_node2<A, T,
|
||||
boost::unordered::detail::ptr_node<T>*,
|
||||
boost::unordered::detail::ptr_bucket*>
|
||||
{
|
||||
typedef boost::unordered::detail::ptr_node<T> node;
|
||||
typedef boost::unordered::detail::ptr_bucket bucket;
|
||||
typedef bucket* link_pointer;
|
||||
};
|
||||
|
||||
template <typename A, typename T>
|
||||
struct pick_node
|
||||
{
|
||||
typedef boost::unordered::detail::allocator_traits<
|
||||
typename boost::unordered::detail::rebind_wrap<A,
|
||||
boost::unordered::detail::ptr_node<T> >::type
|
||||
> tentative_node_traits;
|
||||
|
||||
typedef boost::unordered::detail::allocator_traits<
|
||||
typename boost::unordered::detail::rebind_wrap<A,
|
||||
boost::unordered::detail::ptr_bucket >::type
|
||||
> tentative_bucket_traits;
|
||||
|
||||
typedef pick_node2<A, T,
|
||||
typename tentative_node_traits::pointer,
|
||||
typename tentative_bucket_traits::pointer> pick;
|
||||
|
||||
typedef typename pick::node node;
|
||||
typedef typename pick::bucket bucket;
|
||||
typedef typename pick::link_pointer link_pointer;
|
||||
};
|
||||
|
||||
template <typename A, typename T, typename H, typename P>
|
||||
struct set
|
||||
{
|
||||
typedef boost::unordered::detail::set<A, T, H, P> types;
|
||||
|
||||
typedef A allocator;
|
||||
typedef T value_type;
|
||||
typedef H hasher;
|
||||
typedef P key_equal;
|
||||
typedef T key_type;
|
||||
|
||||
typedef boost::unordered::detail::allocator_traits<allocator> traits;
|
||||
typedef boost::unordered::detail::pick_node<allocator, value_type> pick;
|
||||
typedef typename pick::node node;
|
||||
typedef typename pick::bucket bucket;
|
||||
typedef typename pick::link_pointer link_pointer;
|
||||
|
||||
typedef boost::unordered::detail::table_impl<types> table;
|
||||
typedef boost::unordered::detail::set_extractor<value_type> extractor;
|
||||
|
||||
typedef boost::unordered::detail::pick_policy::type policy;
|
||||
};
|
||||
|
||||
template <typename A, typename K, typename M, typename H, typename P>
|
||||
struct map
|
||||
{
|
||||
typedef boost::unordered::detail::map<A, K, M, H, P> types;
|
||||
|
||||
typedef A allocator;
|
||||
typedef std::pair<K const, M> value_type;
|
||||
typedef H hasher;
|
||||
typedef P key_equal;
|
||||
typedef K key_type;
|
||||
|
||||
typedef boost::unordered::detail::allocator_traits<allocator>
|
||||
traits;
|
||||
typedef boost::unordered::detail::pick_node<allocator, value_type> pick;
|
||||
typedef typename pick::node node;
|
||||
typedef typename pick::bucket bucket;
|
||||
typedef typename pick::link_pointer link_pointer;
|
||||
|
||||
typedef boost::unordered::detail::table_impl<types> table;
|
||||
typedef boost::unordered::detail::map_extractor<key_type, value_type>
|
||||
extractor;
|
||||
|
||||
typedef boost::unordered::detail::pick_policy::type policy;
|
||||
};
|
||||
|
||||
template <typename Types>
|
||||
struct table_impl : boost::unordered::detail::table<Types>
|
||||
{
|
||||
typedef boost::unordered::detail::table<Types> table;
|
||||
typedef typename table::value_type value_type;
|
||||
typedef typename table::bucket bucket;
|
||||
typedef typename table::policy policy;
|
||||
typedef typename table::node_pointer node_pointer;
|
||||
typedef typename table::node_allocator node_allocator;
|
||||
typedef typename table::node_allocator_traits node_allocator_traits;
|
||||
typedef typename table::bucket_pointer bucket_pointer;
|
||||
typedef typename table::link_pointer link_pointer;
|
||||
typedef typename table::hasher hasher;
|
||||
typedef typename table::key_equal key_equal;
|
||||
typedef typename table::key_type key_type;
|
||||
typedef typename table::node_constructor node_constructor;
|
||||
typedef typename table::extractor extractor;
|
||||
typedef typename table::iterator iterator;
|
||||
typedef typename table::c_iterator c_iterator;
|
||||
|
||||
typedef std::pair<iterator, bool> emplace_return;
|
||||
|
||||
// Constructors
|
||||
|
||||
table_impl(std::size_t n,
|
||||
hasher const& hf,
|
||||
key_equal const& eq,
|
||||
node_allocator const& a)
|
||||
: table(n, hf, eq, a)
|
||||
{}
|
||||
|
||||
table_impl(table_impl const& x)
|
||||
: table(x, node_allocator_traits::
|
||||
select_on_container_copy_construction(x.node_alloc()))
|
||||
{
|
||||
this->init(x);
|
||||
}
|
||||
|
||||
table_impl(table_impl const& x,
|
||||
node_allocator const& a)
|
||||
: table(x, a)
|
||||
{
|
||||
this->init(x);
|
||||
}
|
||||
|
||||
table_impl(table_impl& x,
|
||||
boost::unordered::detail::move_tag m)
|
||||
: table(x, m)
|
||||
{}
|
||||
|
||||
table_impl(table_impl& x,
|
||||
node_allocator const& a,
|
||||
boost::unordered::detail::move_tag m)
|
||||
: table(x, a, m)
|
||||
{
|
||||
this->move_init(x);
|
||||
}
|
||||
|
||||
// Accessors
|
||||
|
||||
template <class Key, class Pred>
|
||||
iterator find_node_impl(
|
||||
std::size_t key_hash,
|
||||
Key const& k,
|
||||
Pred const& eq) const
|
||||
{
|
||||
std::size_t bucket_index = this->hash_to_bucket(key_hash);
|
||||
iterator n = this->begin(bucket_index);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (!n.node_) return n;
|
||||
|
||||
std::size_t node_hash = n.node_->hash_;
|
||||
if (key_hash == node_hash)
|
||||
{
|
||||
if (eq(k, this->get_key(*n)))
|
||||
return n;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this->hash_to_bucket(node_hash) != bucket_index)
|
||||
return iterator();
|
||||
}
|
||||
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t count(key_type const& k) const
|
||||
{
|
||||
return this->find_node(k).node_ ? 1 : 0;
|
||||
}
|
||||
|
||||
value_type& at(key_type const& k) const
|
||||
{
|
||||
if (this->size_) {
|
||||
iterator it = this->find_node(k);
|
||||
if (it.node_) return *it;
|
||||
}
|
||||
|
||||
boost::throw_exception(
|
||||
std::out_of_range("Unable to find key in unordered_map."));
|
||||
}
|
||||
|
||||
std::pair<iterator, iterator>
|
||||
equal_range(key_type const& k) const
|
||||
{
|
||||
iterator n = this->find_node(k);
|
||||
iterator n2 = n;
|
||||
if (n2.node_) ++n2;
|
||||
return std::make_pair(n, n2);
|
||||
}
|
||||
|
||||
// equals
|
||||
|
||||
bool equals(table_impl const& other) const
|
||||
{
|
||||
if(this->size_ != other.size_) return false;
|
||||
|
||||
for(iterator n1 = this->begin(); n1.node_; ++n1)
|
||||
{
|
||||
iterator n2 = other.find_matching_node(n1);
|
||||
|
||||
if (!n2.node_ || *n1 != *n2)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Emplace/Insert
|
||||
|
||||
inline iterator add_node(
|
||||
node_constructor& a,
|
||||
std::size_t key_hash)
|
||||
{
|
||||
node_pointer n = a.release();
|
||||
n->hash_ = key_hash;
|
||||
|
||||
bucket_pointer b = this->get_bucket(this->hash_to_bucket(key_hash));
|
||||
|
||||
if (!b->next_)
|
||||
{
|
||||
link_pointer start_node = this->get_previous_start();
|
||||
|
||||
if (start_node->next_) {
|
||||
this->get_bucket(this->hash_to_bucket(
|
||||
static_cast<node_pointer>(start_node->next_)->hash_)
|
||||
)->next_ = n;
|
||||
}
|
||||
|
||||
b->next_ = start_node;
|
||||
n->next_ = start_node->next_;
|
||||
start_node->next_ = n;
|
||||
}
|
||||
else
|
||||
{
|
||||
n->next_ = b->next_->next_;
|
||||
b->next_->next_ = n;
|
||||
}
|
||||
|
||||
++this->size_;
|
||||
return iterator(n);
|
||||
}
|
||||
|
||||
value_type& operator[](key_type const& k)
|
||||
{
|
||||
std::size_t key_hash = this->hash(k);
|
||||
iterator pos = this->find_node(key_hash, k);
|
||||
|
||||
if (pos.node_) return *pos;
|
||||
|
||||
// Create the node before rehashing in case it throws an
|
||||
// exception (need strong safety in such a case).
|
||||
node_constructor a(this->node_alloc());
|
||||
a.construct_with_value(BOOST_UNORDERED_EMPLACE_ARGS3(
|
||||
boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(k),
|
||||
boost::make_tuple()));
|
||||
|
||||
this->reserve_for_insert(this->size_ + 1);
|
||||
return *add_node(a, key_hash);
|
||||
}
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
# if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
emplace_return emplace(boost::unordered::detail::emplace_args1<
|
||||
boost::unordered::detail::please_ignore_this_overload> const&)
|
||||
{
|
||||
BOOST_ASSERT(false);
|
||||
return emplace_return(this->begin(), false);
|
||||
}
|
||||
# else
|
||||
emplace_return emplace(
|
||||
boost::unordered::detail::please_ignore_this_overload const&)
|
||||
{
|
||||
BOOST_ASSERT(false);
|
||||
return emplace_return(this->begin(), false);
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
|
||||
emplace_return emplace(BOOST_UNORDERED_EMPLACE_ARGS)
|
||||
{
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
return emplace_impl(
|
||||
extractor::extract(BOOST_UNORDERED_EMPLACE_FORWARD),
|
||||
BOOST_UNORDERED_EMPLACE_FORWARD);
|
||||
#else
|
||||
return emplace_impl(
|
||||
extractor::extract(args.a0, args.a1),
|
||||
BOOST_UNORDERED_EMPLACE_FORWARD);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
template <typename A0>
|
||||
emplace_return emplace(
|
||||
boost::unordered::detail::emplace_args1<A0> const& args)
|
||||
{
|
||||
return emplace_impl(extractor::extract(args.a0), args);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
|
||||
emplace_return emplace_impl(key_type const& k,
|
||||
BOOST_UNORDERED_EMPLACE_ARGS)
|
||||
{
|
||||
std::size_t key_hash = this->hash(k);
|
||||
iterator pos = this->find_node(key_hash, k);
|
||||
|
||||
if (pos.node_) return emplace_return(pos, false);
|
||||
|
||||
// Create the node before rehashing in case it throws an
|
||||
// exception (need strong safety in such a case).
|
||||
node_constructor a(this->node_alloc());
|
||||
a.construct_with_value(BOOST_UNORDERED_EMPLACE_FORWARD);
|
||||
|
||||
// reserve has basic exception safety if the hash function
|
||||
// throws, strong otherwise.
|
||||
this->reserve_for_insert(this->size_ + 1);
|
||||
return emplace_return(this->add_node(a, key_hash), true);
|
||||
}
|
||||
|
||||
emplace_return emplace_impl_with_node(node_constructor& a)
|
||||
{
|
||||
key_type const& k = this->get_key(a.value());
|
||||
std::size_t key_hash = this->hash(k);
|
||||
iterator pos = this->find_node(key_hash, k);
|
||||
|
||||
if (pos.node_) return emplace_return(pos, false);
|
||||
|
||||
// reserve has basic exception safety if the hash function
|
||||
// throws, strong otherwise.
|
||||
this->reserve_for_insert(this->size_ + 1);
|
||||
return emplace_return(this->add_node(a, key_hash), true);
|
||||
}
|
||||
|
||||
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
|
||||
emplace_return emplace_impl(no_key, BOOST_UNORDERED_EMPLACE_ARGS)
|
||||
{
|
||||
// Don't have a key, so construct the node first in order
|
||||
// to be able to lookup the position.
|
||||
node_constructor a(this->node_alloc());
|
||||
a.construct_with_value(BOOST_UNORDERED_EMPLACE_FORWARD);
|
||||
return emplace_impl_with_node(a);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Insert range methods
|
||||
//
|
||||
// if hash function throws, or inserting > 1 element, basic exception
|
||||
// safety strong otherwise
|
||||
|
||||
template <class InputIt>
|
||||
void insert_range(InputIt i, InputIt j)
|
||||
{
|
||||
if(i != j)
|
||||
return insert_range_impl(extractor::extract(*i), i, j);
|
||||
}
|
||||
|
||||
template <class InputIt>
|
||||
void insert_range_impl(key_type const& k, InputIt i, InputIt j)
|
||||
{
|
||||
node_constructor a(this->node_alloc());
|
||||
|
||||
insert_range_impl2(a, k, i, j);
|
||||
|
||||
while(++i != j) {
|
||||
// Note: can't use get_key as '*i' might not be value_type - it
|
||||
// could be a pair with first_types as key_type without const or
|
||||
// a different second_type.
|
||||
//
|
||||
// TODO: Might be worth storing the value_type instead of the
|
||||
// key here. Could be more efficient if '*i' is expensive. Could
|
||||
// be less efficient if copying the full value_type is
|
||||
// expensive.
|
||||
insert_range_impl2(a, extractor::extract(*i), i, j);
|
||||
}
|
||||
}
|
||||
|
||||
template <class InputIt>
|
||||
void insert_range_impl2(node_constructor& a, key_type const& k,
|
||||
InputIt i, InputIt j)
|
||||
{
|
||||
// No side effects in this initial code
|
||||
std::size_t key_hash = this->hash(k);
|
||||
iterator pos = this->find_node(key_hash, k);
|
||||
|
||||
if (!pos.node_) {
|
||||
a.construct_with_value2(*i);
|
||||
if(this->size_ + 1 > this->max_load_)
|
||||
this->reserve_for_insert(this->size_ +
|
||||
boost::unordered::detail::insert_size(i, j));
|
||||
|
||||
// Nothing after this point can throw.
|
||||
this->add_node(a, key_hash);
|
||||
}
|
||||
}
|
||||
|
||||
template <class InputIt>
|
||||
void insert_range_impl(no_key, InputIt i, InputIt j)
|
||||
{
|
||||
node_constructor a(this->node_alloc());
|
||||
|
||||
do {
|
||||
a.construct_with_value2(*i);
|
||||
emplace_impl_with_node(a);
|
||||
} while(++i != j);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Erase
|
||||
//
|
||||
// no throw
|
||||
|
||||
std::size_t erase_key(key_type const& k)
|
||||
{
|
||||
if(!this->size_) return 0;
|
||||
|
||||
std::size_t key_hash = this->hash(k);
|
||||
std::size_t bucket_index = this->hash_to_bucket(key_hash);
|
||||
link_pointer prev = this->get_previous_start(bucket_index);
|
||||
if (!prev) return 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (!prev->next_) return 0;
|
||||
std::size_t node_hash =
|
||||
static_cast<node_pointer>(prev->next_)->hash_;
|
||||
if (this->hash_to_bucket(node_hash) != bucket_index)
|
||||
return 0;
|
||||
if (node_hash == key_hash &&
|
||||
this->key_eq()(k, this->get_key(
|
||||
static_cast<node_pointer>(prev->next_)->value())))
|
||||
break;
|
||||
prev = prev->next_;
|
||||
}
|
||||
|
||||
link_pointer end = static_cast<node_pointer>(prev->next_)->next_;
|
||||
|
||||
std::size_t count = this->delete_nodes(prev, end);
|
||||
this->fix_bucket(bucket_index, prev);
|
||||
return count;
|
||||
}
|
||||
|
||||
iterator erase(c_iterator r)
|
||||
{
|
||||
BOOST_ASSERT(r.node_);
|
||||
iterator next(r.node_);
|
||||
++next;
|
||||
erase_nodes(r.node_, next.node_);
|
||||
return next;
|
||||
}
|
||||
|
||||
iterator erase_range(c_iterator r1, c_iterator r2)
|
||||
{
|
||||
if (r1 == r2) return iterator(r2.node_);
|
||||
erase_nodes(r1.node_, r2.node_);
|
||||
return iterator(r2.node_);
|
||||
}
|
||||
|
||||
void erase_nodes(node_pointer begin, node_pointer end)
|
||||
{
|
||||
std::size_t bucket_index = this->hash_to_bucket(begin->hash_);
|
||||
|
||||
// Find the node before begin.
|
||||
link_pointer prev = this->get_previous_start(bucket_index);
|
||||
while(prev->next_ != begin) prev = prev->next_;
|
||||
|
||||
// Delete the nodes.
|
||||
do {
|
||||
this->delete_node(prev);
|
||||
bucket_index = this->fix_bucket(bucket_index, prev);
|
||||
} while (prev->next_ != end);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// fill_buckets
|
||||
|
||||
template <class NodeCreator>
|
||||
static void fill_buckets(iterator n, table& dst,
|
||||
NodeCreator& creator)
|
||||
{
|
||||
link_pointer prev = dst.get_previous_start();
|
||||
|
||||
while (n.node_) {
|
||||
node_pointer node = creator.create(*n);
|
||||
node->hash_ = n.node_->hash_;
|
||||
prev->next_ = node;
|
||||
++dst.size_;
|
||||
++n;
|
||||
|
||||
prev = place_in_bucket(dst, prev);
|
||||
}
|
||||
}
|
||||
|
||||
// strong otherwise exception safety
|
||||
void rehash_impl(std::size_t num_buckets)
|
||||
{
|
||||
BOOST_ASSERT(this->buckets_);
|
||||
|
||||
this->create_buckets(num_buckets);
|
||||
link_pointer prev = this->get_previous_start();
|
||||
while (prev->next_)
|
||||
prev = place_in_bucket(*this, prev);
|
||||
}
|
||||
|
||||
// Iterate through the nodes placing them in the correct buckets.
|
||||
// pre: prev->next_ is not null.
|
||||
static link_pointer place_in_bucket(table& dst, link_pointer prev)
|
||||
{
|
||||
node_pointer n = static_cast<node_pointer>(prev->next_);
|
||||
bucket_pointer b = dst.get_bucket(dst.hash_to_bucket(n->hash_));
|
||||
|
||||
if (!b->next_) {
|
||||
b->next_ = prev;
|
||||
return n;
|
||||
}
|
||||
else {
|
||||
prev->next_ = n->next_;
|
||||
n->next_ = b->next_->next_;
|
||||
b->next_->next_ = n;
|
||||
return prev;
|
||||
}
|
||||
}
|
||||
};
|
||||
}}}
|
||||
|
||||
#endif
|
@ -1,266 +0,0 @@
|
||||
|
||||
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
||||
// Copyright (C) 2005-2011 Daniel James
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_UTIL_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_DETAIL_UTIL_HPP_INCLUDED
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/type_traits/is_empty.hpp>
|
||||
#include <boost/iterator/iterator_categories.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/detail/select_type.hpp>
|
||||
#include <boost/move/move.hpp>
|
||||
#include <boost/preprocessor/seq/size.hpp>
|
||||
#include <boost/preprocessor/seq/enum.hpp>
|
||||
#include <boost/swap.hpp>
|
||||
|
||||
namespace boost { namespace unordered { namespace detail {
|
||||
|
||||
static const float minimum_max_load_factor = 1e-3f;
|
||||
static const std::size_t default_bucket_count = 11;
|
||||
struct move_tag {};
|
||||
struct empty_emplace {};
|
||||
|
||||
namespace func {
|
||||
template <class T>
|
||||
inline void ignore_unused_variable_warning(T const&) {}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// iterator SFINAE
|
||||
|
||||
template <typename I>
|
||||
struct is_forward :
|
||||
boost::is_convertible<
|
||||
typename boost::iterator_traversal<I>::type,
|
||||
boost::forward_traversal_tag>
|
||||
{};
|
||||
|
||||
template <typename I, typename ReturnType>
|
||||
struct enable_if_forward :
|
||||
boost::enable_if_c<
|
||||
boost::unordered::detail::is_forward<I>::value,
|
||||
ReturnType>
|
||||
{};
|
||||
|
||||
template <typename I, typename ReturnType>
|
||||
struct disable_if_forward :
|
||||
boost::disable_if_c<
|
||||
boost::unordered::detail::is_forward<I>::value,
|
||||
ReturnType>
|
||||
{};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// primes
|
||||
|
||||
#define BOOST_UNORDERED_PRIMES \
|
||||
(17ul)(29ul)(37ul)(53ul)(67ul)(79ul) \
|
||||
(97ul)(131ul)(193ul)(257ul)(389ul)(521ul)(769ul) \
|
||||
(1031ul)(1543ul)(2053ul)(3079ul)(6151ul)(12289ul)(24593ul) \
|
||||
(49157ul)(98317ul)(196613ul)(393241ul)(786433ul) \
|
||||
(1572869ul)(3145739ul)(6291469ul)(12582917ul)(25165843ul) \
|
||||
(50331653ul)(100663319ul)(201326611ul)(402653189ul)(805306457ul) \
|
||||
(1610612741ul)(3221225473ul)(4294967291ul)
|
||||
|
||||
template<class T> struct prime_list_template
|
||||
{
|
||||
static std::size_t const value[];
|
||||
|
||||
#if !defined(SUNPRO_CC)
|
||||
static std::ptrdiff_t const length;
|
||||
#else
|
||||
static std::ptrdiff_t const length
|
||||
= BOOST_PP_SEQ_SIZE(BOOST_UNORDERED_PRIMES);
|
||||
#endif
|
||||
};
|
||||
|
||||
template<class T>
|
||||
std::size_t const prime_list_template<T>::value[] = {
|
||||
BOOST_PP_SEQ_ENUM(BOOST_UNORDERED_PRIMES)
|
||||
};
|
||||
|
||||
#if !defined(SUNPRO_CC)
|
||||
template<class T>
|
||||
std::ptrdiff_t const prime_list_template<T>::length
|
||||
= BOOST_PP_SEQ_SIZE(BOOST_UNORDERED_PRIMES);
|
||||
#endif
|
||||
|
||||
#undef BOOST_UNORDERED_PRIMES
|
||||
|
||||
typedef prime_list_template<std::size_t> prime_list;
|
||||
|
||||
// no throw
|
||||
inline std::size_t next_prime(std::size_t num) {
|
||||
std::size_t const* const prime_list_begin = prime_list::value;
|
||||
std::size_t const* const prime_list_end = prime_list_begin +
|
||||
prime_list::length;
|
||||
std::size_t const* bound =
|
||||
std::lower_bound(prime_list_begin, prime_list_end, num);
|
||||
if(bound == prime_list_end)
|
||||
bound--;
|
||||
return *bound;
|
||||
}
|
||||
|
||||
// no throw
|
||||
inline std::size_t prev_prime(std::size_t num) {
|
||||
std::size_t const* const prime_list_begin = prime_list::value;
|
||||
std::size_t const* const prime_list_end = prime_list_begin +
|
||||
prime_list::length;
|
||||
std::size_t const* bound =
|
||||
std::upper_bound(prime_list_begin,prime_list_end, num);
|
||||
if(bound != prime_list_begin)
|
||||
bound--;
|
||||
return *bound;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// insert_size/initial_size
|
||||
|
||||
#if !defined(BOOST_NO_STD_DISTANCE)
|
||||
|
||||
using ::std::distance;
|
||||
|
||||
#else
|
||||
|
||||
template <class ForwardIterator>
|
||||
inline std::size_t distance(ForwardIterator i, ForwardIterator j) {
|
||||
std::size_t x;
|
||||
std::distance(i, j, x);
|
||||
return x;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template <class I>
|
||||
inline typename
|
||||
boost::unordered::detail::enable_if_forward<I, std::size_t>::type
|
||||
insert_size(I i, I j)
|
||||
{
|
||||
return std::distance(i, j);
|
||||
}
|
||||
|
||||
template <class I>
|
||||
inline typename
|
||||
boost::unordered::detail::disable_if_forward<I, std::size_t>::type
|
||||
insert_size(I, I)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <class I>
|
||||
inline std::size_t initial_size(I i, I j,
|
||||
std::size_t num_buckets =
|
||||
boost::unordered::detail::default_bucket_count)
|
||||
{
|
||||
// TODO: Why +1?
|
||||
return (std::max)(
|
||||
boost::unordered::detail::insert_size(i, j) + 1,
|
||||
num_buckets);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// compressed
|
||||
|
||||
template <typename T, int Index>
|
||||
struct compressed_base : private T
|
||||
{
|
||||
compressed_base(T const& x) : T(x) {}
|
||||
compressed_base(T& x, move_tag) : T(boost::move(x)) {}
|
||||
|
||||
T& get() { return *this; }
|
||||
T const& get() const { return *this; }
|
||||
};
|
||||
|
||||
template <typename T, int Index>
|
||||
struct uncompressed_base
|
||||
{
|
||||
uncompressed_base(T const& x) : value_(x) {}
|
||||
uncompressed_base(T& x, move_tag) : value_(boost::move(x)) {}
|
||||
|
||||
T& get() { return value_; }
|
||||
T const& get() const { return value_; }
|
||||
private:
|
||||
T value_;
|
||||
};
|
||||
|
||||
template <typename T, int Index>
|
||||
struct generate_base
|
||||
: boost::detail::if_true<
|
||||
boost::is_empty<T>::value
|
||||
>:: BOOST_NESTED_TEMPLATE then<
|
||||
boost::unordered::detail::compressed_base<T, Index>,
|
||||
boost::unordered::detail::uncompressed_base<T, Index>
|
||||
>
|
||||
{};
|
||||
|
||||
template <typename T1, typename T2>
|
||||
struct compressed
|
||||
: private boost::unordered::detail::generate_base<T1, 1>::type,
|
||||
private boost::unordered::detail::generate_base<T2, 2>::type
|
||||
{
|
||||
typedef typename generate_base<T1, 1>::type base1;
|
||||
typedef typename generate_base<T2, 2>::type base2;
|
||||
|
||||
typedef T1 first_type;
|
||||
typedef T2 second_type;
|
||||
|
||||
first_type& first() {
|
||||
return static_cast<base1*>(this)->get();
|
||||
}
|
||||
|
||||
first_type const& first() const {
|
||||
return static_cast<base1 const*>(this)->get();
|
||||
}
|
||||
|
||||
second_type& second() {
|
||||
return static_cast<base2*>(this)->get();
|
||||
}
|
||||
|
||||
second_type const& second() const {
|
||||
return static_cast<base2 const*>(this)->get();
|
||||
}
|
||||
|
||||
template <typename First, typename Second>
|
||||
compressed(First const& x1, Second const& x2)
|
||||
: base1(x1), base2(x2) {}
|
||||
|
||||
compressed(compressed const& x)
|
||||
: base1(x.first()), base2(x.second()) {}
|
||||
|
||||
compressed(compressed& x, move_tag m)
|
||||
: base1(x.first(), m), base2(x.second(), m) {}
|
||||
|
||||
void assign(compressed const& x)
|
||||
{
|
||||
first() = x.first();
|
||||
second() = x.second();
|
||||
}
|
||||
|
||||
void move_assign(compressed& x)
|
||||
{
|
||||
first() = boost::move(x.first());
|
||||
second() = boost::move(x.second());
|
||||
}
|
||||
|
||||
void swap(compressed& x)
|
||||
{
|
||||
boost::swap(first(), x.first());
|
||||
boost::swap(second(), x.second());
|
||||
}
|
||||
|
||||
private:
|
||||
// Prevent assignment just to make use of assign or
|
||||
// move_assign explicit.
|
||||
compressed& operator=(compressed const&);
|
||||
};
|
||||
}}}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -11,55 +11,54 @@
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <boost/functional/hash_fwd.hpp>
|
||||
#include <boost/unordered/detail/fwd.hpp>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace unordered
|
||||
{
|
||||
template <class K,
|
||||
class T,
|
||||
class H = boost::hash<K>,
|
||||
class P = std::equal_to<K>,
|
||||
class A = std::allocator<std::pair<const K, T> > >
|
||||
class unordered_map;
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
template <class K, class T, class H = boost::hash<K>,
|
||||
class P = std::equal_to<K>,
|
||||
class A = std::allocator<std::pair<const K, T> > >
|
||||
class unordered_map;
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
inline bool operator==(unordered_map<K, T, H, P, A> const&,
|
||||
unordered_map<K, T, H, P, A> const&);
|
||||
template <class K, class T, class H, class P, class A>
|
||||
inline bool operator!=(unordered_map<K, T, H, P, A> const&,
|
||||
unordered_map<K, T, H, P, A> const&);
|
||||
template <class K, class T, class H, class P, class A>
|
||||
inline void swap(unordered_map<K, T, H, P, A>&,
|
||||
unordered_map<K, T, H, P, A>&);
|
||||
template <class K, class T, class H, class P, class A>
|
||||
inline bool operator==(
|
||||
unordered_map<K, T, H, P, A> const&, unordered_map<K, T, H, P, A> const&);
|
||||
template <class K, class T, class H, class P, class A>
|
||||
inline bool operator!=(
|
||||
unordered_map<K, T, H, P, A> const&, unordered_map<K, T, H, P, A> const&);
|
||||
template <class K, class T, class H, class P, class A>
|
||||
inline void swap(
|
||||
unordered_map<K, T, H, P, A>& m1, unordered_map<K, T, H, P, A>& m2)
|
||||
BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m1.swap(m2)));
|
||||
|
||||
template <class K,
|
||||
class T,
|
||||
class H = boost::hash<K>,
|
||||
class P = std::equal_to<K>,
|
||||
class A = std::allocator<std::pair<const K, T> > >
|
||||
class unordered_multimap;
|
||||
template <class K, class T, class H = boost::hash<K>,
|
||||
class P = std::equal_to<K>,
|
||||
class A = std::allocator<std::pair<const K, T> > >
|
||||
class unordered_multimap;
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
inline bool operator==(unordered_multimap<K, T, H, P, A> const&,
|
||||
unordered_multimap<K, T, H, P, A> const&);
|
||||
template <class K, class T, class H, class P, class A>
|
||||
inline bool operator!=(unordered_multimap<K, T, H, P, A> const&,
|
||||
unordered_multimap<K, T, H, P, A> const&);
|
||||
template <class K, class T, class H, class P, class A>
|
||||
inline void swap(unordered_multimap<K, T, H, P, A>&,
|
||||
unordered_multimap<K, T, H, P, A>&);
|
||||
}
|
||||
template <class K, class T, class H, class P, class A>
|
||||
inline bool operator==(unordered_multimap<K, T, H, P, A> const&,
|
||||
unordered_multimap<K, T, H, P, A> const&);
|
||||
template <class K, class T, class H, class P, class A>
|
||||
inline bool operator!=(unordered_multimap<K, T, H, P, A> const&,
|
||||
unordered_multimap<K, T, H, P, A> const&);
|
||||
template <class K, class T, class H, class P, class A>
|
||||
inline void swap(unordered_multimap<K, T, H, P, A>& m1,
|
||||
unordered_multimap<K, T, H, P, A>& m2)
|
||||
BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m1.swap(m2)));
|
||||
|
||||
using boost::unordered::unordered_map;
|
||||
using boost::unordered::unordered_multimap;
|
||||
using boost::unordered::swap;
|
||||
using boost::unordered::operator==;
|
||||
using boost::unordered::operator!=;
|
||||
template <class N, class K, class T, class A> class node_handle_map;
|
||||
template <class N, class K, class T, class A> struct insert_return_type_map;
|
||||
}
|
||||
|
||||
using boost::unordered::unordered_map;
|
||||
using boost::unordered::unordered_multimap;
|
||||
using boost::unordered::swap;
|
||||
using boost::unordered::operator==;
|
||||
using boost::unordered::operator!=;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -11,53 +11,52 @@
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <boost/functional/hash_fwd.hpp>
|
||||
#include <boost/unordered/detail/fwd.hpp>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace unordered
|
||||
{
|
||||
template <class T,
|
||||
class H = boost::hash<T>,
|
||||
class P = std::equal_to<T>,
|
||||
class A = std::allocator<T> >
|
||||
class unordered_set;
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
template <class T, class H = boost::hash<T>, class P = std::equal_to<T>,
|
||||
class A = std::allocator<T> >
|
||||
class unordered_set;
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
inline bool operator==(unordered_set<T, H, P, A> const&,
|
||||
unordered_set<T, H, P, A> const&);
|
||||
template <class T, class H, class P, class A>
|
||||
inline bool operator!=(unordered_set<T, H, P, A> const&,
|
||||
unordered_set<T, H, P, A> const&);
|
||||
template <class T, class H, class P, class A>
|
||||
inline void swap(unordered_set<T, H, P, A> &m1,
|
||||
unordered_set<T, H, P, A> &m2);
|
||||
template <class T, class H, class P, class A>
|
||||
inline bool operator==(
|
||||
unordered_set<T, H, P, A> const&, unordered_set<T, H, P, A> const&);
|
||||
template <class T, class H, class P, class A>
|
||||
inline bool operator!=(
|
||||
unordered_set<T, H, P, A> const&, unordered_set<T, H, P, A> const&);
|
||||
template <class T, class H, class P, class A>
|
||||
inline void swap(
|
||||
unordered_set<T, H, P, A>& m1, unordered_set<T, H, P, A>& m2)
|
||||
BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m1.swap(m2)));
|
||||
|
||||
template <class T,
|
||||
class H = boost::hash<T>,
|
||||
class P = std::equal_to<T>,
|
||||
class A = std::allocator<T> >
|
||||
class unordered_multiset;
|
||||
template <class T, class H = boost::hash<T>, class P = std::equal_to<T>,
|
||||
class A = std::allocator<T> >
|
||||
class unordered_multiset;
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
inline bool operator==(unordered_multiset<T, H, P, A> const&,
|
||||
unordered_multiset<T, H, P, A> const&);
|
||||
template <class T, class H, class P, class A>
|
||||
inline bool operator!=(unordered_multiset<T, H, P, A> const&,
|
||||
unordered_multiset<T, H, P, A> const&);
|
||||
template <class T, class H, class P, class A>
|
||||
inline void swap(unordered_multiset<T, H, P, A> &m1,
|
||||
unordered_multiset<T, H, P, A> &m2);
|
||||
}
|
||||
template <class T, class H, class P, class A>
|
||||
inline bool operator==(unordered_multiset<T, H, P, A> const&,
|
||||
unordered_multiset<T, H, P, A> const&);
|
||||
template <class T, class H, class P, class A>
|
||||
inline bool operator!=(unordered_multiset<T, H, P, A> const&,
|
||||
unordered_multiset<T, H, P, A> const&);
|
||||
template <class T, class H, class P, class A>
|
||||
inline void swap(
|
||||
unordered_multiset<T, H, P, A>& m1, unordered_multiset<T, H, P, A>& m2)
|
||||
BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m1.swap(m2)));
|
||||
|
||||
using boost::unordered::unordered_set;
|
||||
using boost::unordered::unordered_multiset;
|
||||
using boost::unordered::swap;
|
||||
using boost::unordered::operator==;
|
||||
using boost::unordered::operator!=;
|
||||
template <class N, class T, class A> class node_handle_set;
|
||||
template <class N, class T, class A> struct insert_return_type_set;
|
||||
}
|
||||
|
||||
using boost::unordered::unordered_set;
|
||||
using boost::unordered::unordered_multiset;
|
||||
using boost::unordered::swap;
|
||||
using boost::unordered::operator==;
|
||||
using boost::unordered::operator!=;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
44
meta/explicit-failures-markup.xml
Normal file
44
meta/explicit-failures-markup.xml
Normal file
@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2017-2018 Daniel James
|
||||
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)
|
||||
-->
|
||||
<explicit-failures-markup>
|
||||
<!-- unordered -->
|
||||
<library name="unordered">
|
||||
<mark-expected-failures>
|
||||
<test name="unnecessary_copy_tests"/>
|
||||
<toolset name="borland-*"/>
|
||||
<toolset name="sun-*"/>
|
||||
<note author="Daniel James">
|
||||
This tests whether inserting elements creates as few copies as I think
|
||||
is possible. If this fails it just means that the container might be
|
||||
a little inefficient.
|
||||
</note>
|
||||
</mark-expected-failures>
|
||||
|
||||
<mark-expected-failures>
|
||||
<test name="compile_map_unordered_allocator"/>
|
||||
<toolset name="msvc-7.1"/>
|
||||
<note author="Daniel James">
|
||||
This test fail because it's using unordered's internal
|
||||
allocator traits, which doesn't work on Visual C++ 7.1.
|
||||
It normally uses the one from Boost.Container by default.
|
||||
</note>
|
||||
</mark-expected-failures>
|
||||
|
||||
<mark-expected-failures>
|
||||
<test name="noexcept_tests"/>
|
||||
<toolset name="gcc-4.3c+"/>
|
||||
<note author="Daniel James">
|
||||
boost::is_nothrow_move_constructible and
|
||||
boost::is_nothrow_move_assignable don't seem to work on this
|
||||
compiler. I'd hope that anyone wanting noexcept support would
|
||||
use a more recent compiler anyway.
|
||||
</note>
|
||||
</mark-expected-failures>
|
||||
</library>
|
||||
</explicit-failures-markup>
|
||||
|
17
meta/libraries.json
Normal file
17
meta/libraries.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"key": "unordered",
|
||||
"name": "Unordered",
|
||||
"authors": [
|
||||
"Daniel James"
|
||||
],
|
||||
"maintainers": [
|
||||
"Daniel James <dnljms -at- gmail.com>"
|
||||
],
|
||||
"description": "Unordered associative containers.",
|
||||
"std": [
|
||||
"tr1"
|
||||
],
|
||||
"category": [
|
||||
"Containers"
|
||||
]
|
||||
}
|
@ -5,5 +5,93 @@
|
||||
|
||||
import testing ;
|
||||
|
||||
build-project unordered ;
|
||||
build-project exception ;
|
||||
project unordered-test/unordered
|
||||
: requirements
|
||||
<warnings>all
|
||||
<toolset>intel:<warnings>on
|
||||
# Would be nice to define -Wundef, but I'm getting warnings from
|
||||
# Boost.Preprocessor on trunk.
|
||||
<toolset>gcc:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow"
|
||||
<toolset>darwin:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal -Wshadow"
|
||||
<toolset>clang:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wsign-conversion -Wconversion -Wfloat-equal -Wshadow"
|
||||
<toolset>msvc:<cxxflags>"/wd4494"
|
||||
<toolset>gcc:<c++-template-depth>500
|
||||
;
|
||||
|
||||
#alias framework : /boost/test//boost_unit_test_framework ;
|
||||
alias framework : ;
|
||||
|
||||
test-suite unordered
|
||||
:
|
||||
[ run unordered/fwd_set_test.cpp ]
|
||||
[ run unordered/fwd_map_test.cpp ]
|
||||
[ run unordered/allocator_traits.cpp ]
|
||||
[ run unordered/minimal_allocator.cpp ]
|
||||
[ run unordered/compile_set.cpp ]
|
||||
[ run unordered/compile_map.cpp ]
|
||||
[ run unordered/compile_map.cpp : :
|
||||
: <define>BOOST_UNORDERED_USE_ALLOCATOR_TRAITS=0
|
||||
: compile_map_unordered_allocator ]
|
||||
[ run unordered/noexcept_tests.cpp ]
|
||||
[ run unordered/link_test_1.cpp unordered/link_test_2.cpp ]
|
||||
[ run unordered/incomplete_test.cpp ]
|
||||
[ run unordered/simple_tests.cpp ]
|
||||
[ run unordered/equivalent_keys_tests.cpp ]
|
||||
[ run unordered/constructor_tests.cpp ]
|
||||
[ run unordered/copy_tests.cpp ]
|
||||
[ run unordered/move_tests.cpp ]
|
||||
[ run unordered/assign_tests.cpp ]
|
||||
[ run unordered/insert_tests.cpp ]
|
||||
[ run unordered/insert_stable_tests.cpp ]
|
||||
[ run unordered/insert_hint_tests.cpp ]
|
||||
[ run unordered/emplace_tests.cpp ]
|
||||
[ run unordered/unnecessary_copy_tests.cpp ]
|
||||
[ run unordered/erase_tests.cpp : : : <define>BOOST_UNORDERED_SUPPRESS_DEPRECATED ]
|
||||
[ run unordered/erase_equiv_tests.cpp ]
|
||||
[ run unordered/extract_tests.cpp ]
|
||||
[ run unordered/node_handle_tests.cpp ]
|
||||
[ run unordered/merge_tests.cpp ]
|
||||
[ compile-fail unordered/insert_node_type_fail.cpp : <define>UNORDERED_TEST_MAP : insert_node_type_fail_map ]
|
||||
[ compile-fail unordered/insert_node_type_fail.cpp : <define>UNORDERED_TEST_MULTIMAP : insert_node_type_fail_multimap ]
|
||||
[ compile-fail unordered/insert_node_type_fail.cpp : <define>UNORDERED_TEST_SET : insert_node_type_fail_set ]
|
||||
[ compile-fail unordered/insert_node_type_fail.cpp : <define>UNORDERED_TEST_MULTISET : insert_node_type_fail_multiset ]
|
||||
[ run unordered/find_tests.cpp ]
|
||||
[ run unordered/at_tests.cpp ]
|
||||
[ run unordered/bucket_tests.cpp ]
|
||||
[ run unordered/load_factor_tests.cpp ]
|
||||
[ run unordered/rehash_tests.cpp ]
|
||||
[ run unordered/equality_tests.cpp ]
|
||||
[ run unordered/swap_tests.cpp ]
|
||||
[ run unordered/detail_tests.cpp ]
|
||||
[ run unordered/deduction_tests.cpp ]
|
||||
|
||||
[ run unordered/compile_set.cpp : :
|
||||
: <define>BOOST_UNORDERED_USE_MOVE
|
||||
: bmove_compile_set ]
|
||||
[ run unordered/compile_map.cpp : :
|
||||
: <define>BOOST_UNORDERED_USE_MOVE
|
||||
: bmove_compile_map ]
|
||||
[ run unordered/copy_tests.cpp : :
|
||||
: <define>BOOST_UNORDERED_USE_MOVE
|
||||
: bmove_copy ]
|
||||
[ run unordered/move_tests.cpp : :
|
||||
: <define>BOOST_UNORDERED_USE_MOVE
|
||||
: bmove_move ]
|
||||
[ run unordered/assign_tests.cpp : :
|
||||
: <define>BOOST_UNORDERED_USE_MOVE
|
||||
: bmove_assign ]
|
||||
;
|
||||
|
||||
test-suite unordered-exception
|
||||
:
|
||||
[ run exception/constructor_exception_tests.cpp framework ]
|
||||
[ run exception/copy_exception_tests.cpp framework ]
|
||||
[ run exception/assign_exception_tests.cpp framework ]
|
||||
[ run exception/move_assign_exception_tests.cpp framework ]
|
||||
[ run exception/insert_exception_tests.cpp framework ]
|
||||
[ run exception/erase_exception_tests.cpp framework ]
|
||||
[ run exception/rehash_exception_tests.cpp framework ]
|
||||
[ run exception/swap_exception_tests.cpp framework : : :
|
||||
<define>BOOST_UNORDERED_SWAP_METHOD=2 ]
|
||||
[ run exception/merge_exception_tests.cpp framework ]
|
||||
;
|
||||
|
@ -1,34 +0,0 @@
|
||||
|
||||
# Copyright 2006-2008 Daniel James.
|
||||
# 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 testing ;
|
||||
|
||||
#alias framework : /boost/test//boost_unit_test_framework ;
|
||||
alias framework : ;
|
||||
|
||||
project unordered-test/exception-tests
|
||||
: requirements
|
||||
<warnings>all
|
||||
<toolset>intel:<warnings>on
|
||||
<toolset>gcc:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter"
|
||||
<toolset>darwin:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter"
|
||||
#<toolset>gcc:<define>_GLIBCXX_DEBUG
|
||||
#<toolset>darwin:<define>_GLIBCXX_DEBUG
|
||||
#<toolset>msvc:<warnings-as-errors>on
|
||||
#<toolset>gcc:<warnings-as-errors>on
|
||||
#<toolset>darwin:<warnings-as-errors>on
|
||||
;
|
||||
|
||||
test-suite unordered-exception
|
||||
:
|
||||
[ run constructor_exception_tests.cpp framework ]
|
||||
[ run copy_exception_tests.cpp framework ]
|
||||
[ run assign_exception_tests.cpp framework ]
|
||||
[ run insert_exception_tests.cpp framework ]
|
||||
[ run erase_exception_tests.cpp framework ]
|
||||
[ run rehash_exception_tests.cpp framework ]
|
||||
[ run swap_exception_tests.cpp framework : : :
|
||||
<define>BOOST_UNORDERED_SWAP_METHOD=2 ]
|
||||
;
|
@ -4,109 +4,182 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include "./containers.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(disable:4512) // assignment operator could not be generated
|
||||
#pragma warning(disable : 4512) // assignment operator could not be generated
|
||||
#endif
|
||||
|
||||
test::seed_t initialize_seed(12847);
|
||||
|
||||
template <class T>
|
||||
struct self_assign_base : public test::exception_base
|
||||
template <class T> struct self_assign_base : public test::exception_base
|
||||
{
|
||||
test::random_values<T> values;
|
||||
self_assign_base(int count = 0) : values(count) {}
|
||||
test::random_values<T> values;
|
||||
self_assign_base(std::size_t count = 0) : values(count, test::limited_range)
|
||||
{
|
||||
}
|
||||
|
||||
typedef T data_type;
|
||||
T init() const { return T(values.begin(), values.end()); }
|
||||
void run(T& x) const { x = x; }
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const
|
||||
{ test::check_equivalent_keys(x); }
|
||||
typedef T data_type;
|
||||
T init() const { return T(values.begin(), values.end()); }
|
||||
|
||||
void run(T& x) const
|
||||
{
|
||||
x = x;
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const
|
||||
{
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct self_assign_test1 : self_assign_base<T> {};
|
||||
|
||||
template <class T>
|
||||
struct self_assign_test2 : self_assign_base<T>
|
||||
template <class T> struct self_assign_test1 : self_assign_base<T>
|
||||
{
|
||||
self_assign_test2() : self_assign_base<T>(100) {}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct assign_base : public test::exception_base
|
||||
template <class T> struct self_assign_test2 : self_assign_base<T>
|
||||
{
|
||||
const test::random_values<T> x_values, y_values;
|
||||
T x,y;
|
||||
self_assign_test2() : self_assign_base<T>(100) {}
|
||||
};
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME T::hasher hasher;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
|
||||
template <class T> struct assign_base : public test::exception_base
|
||||
{
|
||||
test::random_values<T> x_values, y_values;
|
||||
T x, y;
|
||||
|
||||
assign_base(unsigned int count1, unsigned int count2, int tag1, int tag2,
|
||||
float mlf1 = 1.0, float mlf2 = 1.0) :
|
||||
x_values(count1),
|
||||
y_values(count2),
|
||||
x(x_values.begin(), x_values.end(), 0, hasher(tag1), key_equal(tag1),
|
||||
allocator_type(tag1)),
|
||||
y(y_values.begin(), y_values.end(), 0, hasher(tag2), key_equal(tag2),
|
||||
allocator_type(tag2))
|
||||
{
|
||||
x.max_load_factor(mlf1);
|
||||
y.max_load_factor(mlf2);
|
||||
}
|
||||
|
||||
typedef T data_type;
|
||||
T init() const { return T(x); }
|
||||
void run(T& x1) const { x1 = y; }
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x1) const
|
||||
{
|
||||
test::check_equivalent_keys(x1);
|
||||
|
||||
// If the container is empty at the point of the exception, the
|
||||
// internal structure is hidden, this exposes it.
|
||||
T& y = const_cast<T&>(x1);
|
||||
if (x_values.size()) {
|
||||
y.emplace(*x_values.begin());
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
typedef typename T::hasher hasher;
|
||||
typedef typename T::key_equal key_equal;
|
||||
typedef typename T::allocator_type allocator_type;
|
||||
|
||||
assign_base(int tag1, int tag2, float mlf1 = 1.0, float mlf2 = 1.0)
|
||||
: x_values(), y_values(),
|
||||
x(0, hasher(tag1), key_equal(tag1), allocator_type(tag1)),
|
||||
y(0, hasher(tag2), key_equal(tag2), allocator_type(tag2))
|
||||
{
|
||||
x.max_load_factor(mlf1);
|
||||
y.max_load_factor(mlf2);
|
||||
}
|
||||
|
||||
typedef T data_type;
|
||||
T init() const { return T(x); }
|
||||
|
||||
void run(T& x1) const
|
||||
{
|
||||
x1 = y;
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x1, y_values);
|
||||
test::check_equivalent_keys(x1);
|
||||
}
|
||||
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x1) const
|
||||
{
|
||||
test::check_equivalent_keys(x1);
|
||||
|
||||
// If the container is empty at the point of the exception, the
|
||||
// internal structure is hidden, this exposes it, at the cost of
|
||||
// messing up the data.
|
||||
if (x_values.size()) {
|
||||
T& x2 = const_cast<T&>(x1);
|
||||
x2.emplace(*x_values.begin());
|
||||
test::check_equivalent_keys(x2);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct assign_test1 : assign_base<T>
|
||||
template <class T> struct assign_values : assign_base<T>
|
||||
{
|
||||
assign_test1() : assign_base<T>(0, 0, 0, 0) {}
|
||||
assign_values(unsigned int count1, unsigned int count2, int tag1, int tag2,
|
||||
test::random_generator gen = test::default_generator, float mlf1 = 1.0,
|
||||
float mlf2 = 1.0)
|
||||
: assign_base<T>(tag1, tag2, mlf1, mlf2)
|
||||
{
|
||||
this->x_values.fill(count1, gen);
|
||||
this->y_values.fill(count2, gen);
|
||||
this->x.insert(this->x_values.begin(), this->x_values.end());
|
||||
this->y.insert(this->y_values.begin(), this->y_values.end());
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct assign_test2 : assign_base<T>
|
||||
template <class T> struct assign_test1 : assign_values<T>
|
||||
{
|
||||
assign_test2() : assign_base<T>(60, 0, 0, 0) {}
|
||||
assign_test1() : assign_values<T>(0, 0, 0, 0) {}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct assign_test3 : assign_base<T>
|
||||
template <class T> struct assign_test2 : assign_values<T>
|
||||
{
|
||||
assign_test3() : assign_base<T>(0, 60, 0, 0) {}
|
||||
assign_test2() : assign_values<T>(60, 0, 0, 0) {}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct assign_test4 : assign_base<T>
|
||||
template <class T> struct assign_test2a : assign_values<T>
|
||||
{
|
||||
assign_test4() : assign_base<T>(10, 10, 1, 2) {}
|
||||
assign_test2a() : assign_values<T>(60, 0, 0, 0, test::limited_range) {}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct assign_test5 : assign_base<T>
|
||||
template <class T> struct assign_test3 : assign_values<T>
|
||||
{
|
||||
assign_test5() : assign_base<T>(5, 60, 0, 0, 1.0, 0.1) {}
|
||||
assign_test3() : assign_values<T>(0, 60, 0, 0) {}
|
||||
};
|
||||
|
||||
EXCEPTION_TESTS(
|
||||
template <class T> struct assign_test3a : assign_values<T>
|
||||
{
|
||||
assign_test3a() : assign_values<T>(0, 60, 0, 0, test::limited_range) {}
|
||||
};
|
||||
|
||||
template <class T> struct assign_test4 : assign_values<T>
|
||||
{
|
||||
assign_test4() : assign_values<T>(10, 10, 1, 2) {}
|
||||
};
|
||||
|
||||
template <class T> struct assign_test4a : assign_values<T>
|
||||
{
|
||||
assign_test4a() : assign_values<T>(10, 100, 1, 2) {}
|
||||
};
|
||||
|
||||
template <class T> struct assign_test4b : assign_values<T>
|
||||
{
|
||||
assign_test4b() : assign_values<T>(10, 100, 1, 2, test::limited_range) {}
|
||||
};
|
||||
|
||||
template <class T> struct assign_test5 : assign_values<T>
|
||||
{
|
||||
assign_test5()
|
||||
: assign_values<T>(5, 60, 0, 0, test::default_generator, 1.0f, 0.1f)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template <class T> struct equivalent_test1 : assign_base<T>
|
||||
{
|
||||
equivalent_test1() : assign_base<T>(0, 0)
|
||||
{
|
||||
test::random_values<T> x_values2(10);
|
||||
this->x_values.insert(x_values2.begin(), x_values2.end());
|
||||
this->x_values.insert(x_values2.begin(), x_values2.end());
|
||||
test::random_values<T> y_values2(10);
|
||||
this->y_values.insert(y_values2.begin(), y_values2.end());
|
||||
this->y_values.insert(y_values2.begin(), y_values2.end());
|
||||
this->x.insert(this->x_values.begin(), this->x_values.end());
|
||||
this->y.insert(this->y_values.begin(), this->y_values.end());
|
||||
}
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
EXCEPTION_TESTS_REPEAT(5,
|
||||
(self_assign_test1)(self_assign_test2)
|
||||
(assign_test1)(assign_test2)(assign_test3)(assign_test4)(assign_test5),
|
||||
(assign_test1)(assign_test2)(assign_test2a)
|
||||
(assign_test3)(assign_test3a)
|
||||
(assign_test4)(assign_test4a)(assign_test4b)
|
||||
(assign_test5)
|
||||
(equivalent_test1),
|
||||
CONTAINER_SEQ)
|
||||
// clang-format on
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -4,8 +4,11 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include "./containers.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
|
||||
#include "../helpers/input_iterator.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
|
||||
template <typename T> inline void avoid_unused_warning(T const&) {}
|
||||
|
||||
@ -13,165 +16,197 @@ test::seed_t initialize_seed(91274);
|
||||
|
||||
struct objects
|
||||
{
|
||||
test::exception::object obj;
|
||||
test::exception::hash hash;
|
||||
test::exception::equal_to equal_to;
|
||||
test::exception::allocator<test::exception::object> allocator;
|
||||
test::exception::object obj;
|
||||
test::exception::hash hash;
|
||||
test::exception::equal_to equal_to;
|
||||
test::exception::allocator<test::exception::object> allocator;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct construct_test1 : public objects, test::exception_base
|
||||
template <class T> struct construct_test1 : public objects, test::exception_base
|
||||
{
|
||||
void run() const {
|
||||
T x;
|
||||
avoid_unused_warning(x);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T x;
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
BOOST_TEST(x.empty());
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct construct_test2 : public objects, test::exception_base
|
||||
template <class T> struct construct_test2 : public objects, test::exception_base
|
||||
{
|
||||
void run() const {
|
||||
T x(300);
|
||||
avoid_unused_warning(x);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T x(300);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
BOOST_TEST(x.empty());
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct construct_test3 : public objects, test::exception_base
|
||||
template <class T> struct construct_test3 : public objects, test::exception_base
|
||||
{
|
||||
void run() const {
|
||||
T x(0, hash);
|
||||
avoid_unused_warning(x);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T x(0, hash);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
BOOST_TEST(x.empty());
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct construct_test4 : public objects, test::exception_base
|
||||
template <class T> struct construct_test4 : public objects, test::exception_base
|
||||
{
|
||||
void run() const {
|
||||
T x(0, hash, equal_to);
|
||||
avoid_unused_warning(x);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T x(0, hash, equal_to);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
BOOST_TEST(x.empty());
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct construct_test5 : public objects, test::exception_base
|
||||
template <class T> struct construct_test5 : public objects, test::exception_base
|
||||
{
|
||||
void run() const {
|
||||
T x(50, hash, equal_to, allocator);
|
||||
avoid_unused_warning(x);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T x(50, hash, equal_to, allocator);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
BOOST_TEST(x.empty());
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct construct_test6 : public objects, test::exception_base
|
||||
template <class T> struct construct_test6 : public objects, test::exception_base
|
||||
{
|
||||
void run() const {
|
||||
T x(allocator);
|
||||
avoid_unused_warning(x);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T x(allocator);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
BOOST_TEST(x.empty());
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct range : public test::exception_base
|
||||
template <class T> struct range : public test::exception_base
|
||||
{
|
||||
test::random_values<T> values;
|
||||
test::random_values<T> values;
|
||||
|
||||
range() : values(5) {}
|
||||
range(unsigned int count) : values(count) {}
|
||||
range() : values(5, test::limited_range) {}
|
||||
range(unsigned int count) : values(count, test::limited_range) {}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct range_construct_test1 : public range<T>, objects
|
||||
template <class T> struct range_construct_test1 : public range<T>, objects
|
||||
{
|
||||
void run() const {
|
||||
T x(this->values.begin(), this->values.end());
|
||||
avoid_unused_warning(x);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T x(this->values.begin(), this->values.end());
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, this->values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct range_construct_test2 : public range<T>, objects
|
||||
template <class T> struct range_construct_test2 : public range<T>, objects
|
||||
{
|
||||
void run() const {
|
||||
T x(this->values.begin(), this->values.end(), 0);
|
||||
avoid_unused_warning(x);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T x(this->values.begin(), this->values.end(), 0);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, this->values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct range_construct_test3 : public range<T>, objects
|
||||
template <class T> struct range_construct_test3 : public range<T>, objects
|
||||
{
|
||||
void run() const {
|
||||
T x(this->values.begin(), this->values.end(), 0, hash);
|
||||
avoid_unused_warning(x);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T x(this->values.begin(), this->values.end(), 0, hash);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, this->values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct range_construct_test4 : public range<T>, objects
|
||||
template <class T> struct range_construct_test4 : public range<T>, objects
|
||||
{
|
||||
void run() const {
|
||||
T x(this->values.begin(), this->values.end(), 100, hash, equal_to);
|
||||
avoid_unused_warning(x);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T x(this->values.begin(), this->values.end(), 100, hash, equal_to);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, this->values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
// Need to run at least one test with a fairly large number
|
||||
// of objects in case it triggers a rehash.
|
||||
template <class T>
|
||||
struct range_construct_test5 : public range<T>, objects
|
||||
template <class T> struct range_construct_test5 : public range<T>, objects
|
||||
{
|
||||
range_construct_test5() : range<T>(60) {}
|
||||
range_construct_test5() : range<T>(60) {}
|
||||
|
||||
void run() const {
|
||||
T x(this->values.begin(), this->values.end(), 0,
|
||||
hash, equal_to, allocator);
|
||||
avoid_unused_warning(x);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T x(this->values.begin(), this->values.end(), 0, hash, equal_to, allocator);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, this->values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct input_range_construct_test : public range<T>, objects
|
||||
template <class T> struct input_range_construct_test : public range<T>, objects
|
||||
{
|
||||
input_range_construct_test() : range<T>(60) {}
|
||||
input_range_construct_test() : range<T>(60) {}
|
||||
|
||||
void run() const {
|
||||
BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
|
||||
begin = this->values.begin(), end = this->values.end();
|
||||
T x(test::input_iterator(begin), test::input_iterator(end),
|
||||
0, hash, equal_to, allocator);
|
||||
avoid_unused_warning(x);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
typename test::random_values<T>::const_iterator begin =
|
||||
this->values.begin(),
|
||||
end = this->values.end();
|
||||
T x(test::input_iterator(begin), test::input_iterator(end), 0, hash,
|
||||
equal_to, allocator);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, this->values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct copy_range_construct_test : public range<T>, objects
|
||||
template <class T> struct copy_range_construct_test : public range<T>, objects
|
||||
{
|
||||
copy_range_construct_test() : range<T>(60) {}
|
||||
copy_range_construct_test() : range<T>(60) {}
|
||||
|
||||
void run() const {
|
||||
T x(test::copy_iterator(this->values.begin()),
|
||||
test::copy_iterator(this->values.end()),
|
||||
0, hash, equal_to, allocator);
|
||||
avoid_unused_warning(x);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T x(test::copy_iterator(this->values.begin()),
|
||||
test::copy_iterator(this->values.end()), 0, hash, equal_to, allocator);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, this->values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
EXCEPTION_TESTS(
|
||||
(construct_test1)
|
||||
(construct_test2)
|
||||
(construct_test3)
|
||||
(construct_test4)
|
||||
(construct_test5)
|
||||
(construct_test6)
|
||||
(range_construct_test1)
|
||||
(range_construct_test2)
|
||||
(range_construct_test3)
|
||||
(range_construct_test4)
|
||||
(range_construct_test5)
|
||||
(input_range_construct_test)
|
||||
(copy_range_construct_test),
|
||||
CONTAINER_SEQ)
|
||||
(construct_test1)(construct_test2)(construct_test3)(construct_test4)
|
||||
(construct_test5)(construct_test6)(range_construct_test1)
|
||||
(range_construct_test2)(range_construct_test3)(range_construct_test4)
|
||||
(range_construct_test5)(input_range_construct_test)
|
||||
(copy_range_construct_test),
|
||||
CONTAINER_SEQ)
|
||||
// clang-format on
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -3,33 +3,42 @@
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include "../objects/exception.hpp"
|
||||
|
||||
typedef boost::unordered_set<test::exception::object, test::exception::hash,
|
||||
test::exception::equal_to,
|
||||
test::exception::allocator<test::exception::object> >
|
||||
test_set;
|
||||
typedef boost::unordered_multiset<test::exception::object,
|
||||
test::exception::hash, test::exception::equal_to,
|
||||
test::exception::allocator2<test::exception::object> >
|
||||
test_multiset;
|
||||
typedef boost::unordered_map<test::exception::object, test::exception::object,
|
||||
test::exception::hash, test::exception::equal_to,
|
||||
test::exception::allocator2<test::exception::object> >
|
||||
test_map;
|
||||
typedef boost::unordered_multimap<test::exception::object,
|
||||
test::exception::object, test::exception::hash, test::exception::equal_to,
|
||||
test::exception::allocator<test::exception::object> >
|
||||
test_multimap;
|
||||
typedef boost::unordered_set<
|
||||
test::exception::object,
|
||||
test::exception::hash,
|
||||
test::exception::equal_to,
|
||||
test::exception::allocator<test::exception::object> > test_set;
|
||||
std::pair<test::exception::object, test::exception::object>,
|
||||
test::exception::hash, test::exception::equal_to,
|
||||
test::exception::allocator<test::exception::object> >
|
||||
test_pair_set;
|
||||
typedef boost::unordered_multiset<
|
||||
test::exception::object,
|
||||
test::exception::hash,
|
||||
test::exception::equal_to,
|
||||
test::exception::allocator2<test::exception::object> > test_multiset;
|
||||
typedef boost::unordered_map<
|
||||
test::exception::object,
|
||||
test::exception::object,
|
||||
test::exception::hash,
|
||||
test::exception::equal_to,
|
||||
test::exception::allocator2<test::exception::object> > test_map;
|
||||
typedef boost::unordered_multimap<
|
||||
test::exception::object,
|
||||
test::exception::object,
|
||||
test::exception::hash,
|
||||
test::exception::equal_to,
|
||||
test::exception::allocator<test::exception::object> > test_multimap;
|
||||
std::pair<test::exception::object, test::exception::object>,
|
||||
test::exception::hash, test::exception::equal_to,
|
||||
test::exception::allocator2<test::exception::object> >
|
||||
test_pair_multiset;
|
||||
|
||||
#define CONTAINER_SEQ (test_set)(test_multiset)(test_map)(test_multimap)
|
||||
#define CONTAINER_PAIR_SEQ \
|
||||
(test_pair_set)(test_pair_multiset)(test_map)(test_multimap)
|
||||
|
@ -4,67 +4,107 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include "./containers.hpp"
|
||||
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
|
||||
template <typename T> inline void avoid_unused_warning(T const&) {}
|
||||
|
||||
test::seed_t initialize_seed(73041);
|
||||
|
||||
template <class T>
|
||||
struct copy_test1 : public test::exception_base
|
||||
template <class T> struct copy_test1 : public test::exception_base
|
||||
{
|
||||
T x;
|
||||
T x;
|
||||
|
||||
void run() const {
|
||||
T y(x);
|
||||
avoid_unused_warning(y);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T y(x);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
BOOST_TEST(y.empty());
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct copy_test2 : public test::exception_base
|
||||
template <class T> struct copy_test2 : public test::exception_base
|
||||
{
|
||||
test::random_values<T> values;
|
||||
T x;
|
||||
test::random_values<T> values;
|
||||
T x;
|
||||
|
||||
copy_test2() : values(5), x(values.begin(), values.end()) {}
|
||||
copy_test2() : values(5, test::limited_range), x(values.begin(), values.end())
|
||||
{
|
||||
}
|
||||
|
||||
void run() const {
|
||||
T y(x);
|
||||
avoid_unused_warning(y);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T y(x);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(y, this->values);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct copy_test3 : public test::exception_base
|
||||
template <class T> struct copy_test3 : public test::exception_base
|
||||
{
|
||||
test::random_values<T> values;
|
||||
T x;
|
||||
test::random_values<T> values;
|
||||
T x;
|
||||
|
||||
copy_test3() : values(100), x(values.begin(), values.end()) {}
|
||||
copy_test3() : values(100), x(values.begin(), values.end()) {}
|
||||
|
||||
void run() const {
|
||||
T y(x);
|
||||
avoid_unused_warning(y);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T y(x);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(y, this->values);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct copy_with_allocator_test : public test::exception_base
|
||||
template <class T> struct copy_test3a : public test::exception_base
|
||||
{
|
||||
test::random_values<T> values;
|
||||
T x;
|
||||
test::exception::allocator<test::exception::object> allocator;
|
||||
test::random_values<T> values;
|
||||
T x;
|
||||
|
||||
copy_with_allocator_test() : values(100), x(values.begin(), values.end()) {}
|
||||
copy_test3a()
|
||||
: values(100, test::limited_range), x(values.begin(), values.end())
|
||||
{
|
||||
}
|
||||
|
||||
void run() const {
|
||||
T y(x, allocator);
|
||||
avoid_unused_warning(y);
|
||||
}
|
||||
void run() const
|
||||
{
|
||||
T y(x);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(y, this->values);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T> struct copy_with_allocator_test : public test::exception_base
|
||||
{
|
||||
test::random_values<T> values;
|
||||
T x;
|
||||
test::exception::allocator<test::exception::object> allocator;
|
||||
|
||||
copy_with_allocator_test() : values(100), x(values.begin(), values.end()) {}
|
||||
|
||||
void run() const
|
||||
{
|
||||
T y(x, allocator);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(y, this->values);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
EXCEPTION_TESTS(
|
||||
(copy_test1)(copy_test2)(copy_test3)(copy_with_allocator_test),
|
||||
(copy_test1)(copy_test2)(copy_test3)(copy_test3a)(copy_with_allocator_test),
|
||||
CONTAINER_SEQ)
|
||||
// clang-format on
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -4,52 +4,52 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include "./containers.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
|
||||
#include "../helpers/helpers.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
|
||||
test::seed_t initialize_seed(835193);
|
||||
|
||||
template <class T>
|
||||
struct erase_test_base : public test::exception_base
|
||||
template <class T> struct erase_test_base : public test::exception_base
|
||||
{
|
||||
test::random_values<T> values;
|
||||
erase_test_base(unsigned int count = 5) : values(count) {}
|
||||
test::random_values<T> values;
|
||||
erase_test_base(unsigned int count = 5) : values(count, test::limited_range)
|
||||
{
|
||||
}
|
||||
|
||||
typedef T data_type;
|
||||
typedef T data_type;
|
||||
|
||||
data_type init() const {
|
||||
return T(values.begin(), values.end());
|
||||
}
|
||||
data_type init() const { return T(values.begin(), values.end()); }
|
||||
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const {
|
||||
std::string scope(test::scope);
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const
|
||||
{
|
||||
std::string scope(test::scope);
|
||||
|
||||
BOOST_TEST(scope.find("hash::") != std::string::npos ||
|
||||
scope.find("equal_to::") != std::string::npos ||
|
||||
scope == "operator==(object, object)");
|
||||
BOOST_TEST(scope.find("hash::") != std::string::npos ||
|
||||
scope.find("equal_to::") != std::string::npos ||
|
||||
scope == "operator==(object, object)");
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct erase_by_key_test1 : public erase_test_base<T>
|
||||
template <class T> struct erase_by_key_test1 : public erase_test_base<T>
|
||||
{
|
||||
void run(T& x) const
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
test::random_values<T>::const_iterator iterator;
|
||||
void run(T& x) const
|
||||
{
|
||||
typedef typename test::random_values<T>::const_iterator iterator;
|
||||
|
||||
for(iterator it = this->values.begin(), end = this->values.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
x.erase(test::get_key<T>(*it));
|
||||
}
|
||||
for (iterator it = this->values.begin(), end = this->values.end();
|
||||
it != end; ++it) {
|
||||
x.erase(test::get_key<T>(*it));
|
||||
}
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
BOOST_TEST(x.empty());
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
EXCEPTION_TESTS(
|
||||
(erase_by_key_test1),
|
||||
CONTAINER_SEQ)
|
||||
EXCEPTION_TESTS((erase_by_key_test1), CONTAINER_SEQ)
|
||||
RUN_TESTS()
|
||||
|
@ -2,246 +2,415 @@
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// 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 "./containers.hpp"
|
||||
#include <string>
|
||||
#include "../helpers/random_values.hpp"
|
||||
|
||||
#include "../helpers/helpers.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/strong.hpp"
|
||||
#include <boost/utility.hpp>
|
||||
#include "../helpers/tracker.hpp"
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
|
||||
test::seed_t initialize_seed(747373);
|
||||
|
||||
template <class T>
|
||||
struct insert_test_base : public test::exception_base
|
||||
// Fill in a container so that it's about to rehash
|
||||
template <typename T> void rehash_prep(T& x)
|
||||
{
|
||||
test::random_values<T> values;
|
||||
insert_test_base(unsigned int count = 5) : values(count) {}
|
||||
using namespace std;
|
||||
typedef typename T::size_type size_type;
|
||||
|
||||
typedef T data_type;
|
||||
typedef test::strong<T> strong_type;
|
||||
x.max_load_factor(0.25);
|
||||
size_type bucket_count = x.bucket_count();
|
||||
size_type initial_elements = static_cast<size_type>(
|
||||
ceil((double)bucket_count * (double)x.max_load_factor()) - 1);
|
||||
test::random_values<T> v(initial_elements);
|
||||
x.insert(v.begin(), v.end());
|
||||
BOOST_TEST(bucket_count == x.bucket_count());
|
||||
}
|
||||
|
||||
data_type init() const {
|
||||
return T();
|
||||
// Overload to generate inserters that need type information.
|
||||
|
||||
template <typename Inserter, typename T>
|
||||
Inserter generate(Inserter inserter, T&)
|
||||
{
|
||||
return inserter;
|
||||
}
|
||||
|
||||
// Get the iterator returned from an insert/emplace.
|
||||
|
||||
template <typename T> T get_iterator(T const& x) { return x; }
|
||||
|
||||
template <typename T> T get_iterator(std::pair<T, bool> const& x)
|
||||
{
|
||||
return x.first;
|
||||
}
|
||||
|
||||
// Generic insert exception test for typical single element inserts..
|
||||
|
||||
template <typename T, typename Inserter, typename Values>
|
||||
void insert_exception_test_impl(T x, Inserter insert, Values const& v)
|
||||
{
|
||||
test::strong<T> strong;
|
||||
|
||||
test::ordered<T> tracker;
|
||||
tracker.insert(x.begin(), x.end());
|
||||
|
||||
try {
|
||||
ENABLE_EXCEPTIONS;
|
||||
|
||||
for (typename Values::const_iterator it = v.begin(); it != v.end(); ++it) {
|
||||
strong.store(x, test::detail::tracker.count_allocations);
|
||||
insert(x, it);
|
||||
}
|
||||
} catch (...) {
|
||||
test::check_equivalent_keys(x);
|
||||
insert.exception_check(x, strong);
|
||||
throw;
|
||||
}
|
||||
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(
|
||||
T const& x, strong_type const& strong) const
|
||||
{
|
||||
std::string scope(test::scope);
|
||||
test::check_equivalent_keys(x);
|
||||
insert.track(tracker, v.begin(), v.end());
|
||||
tracker.compare(x);
|
||||
}
|
||||
|
||||
if(scope.find("hash::operator()") == std::string::npos)
|
||||
strong.test(x, test::detail::tracker.count_allocations);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
// Simple insert exception test
|
||||
|
||||
template <typename T, typename Inserter>
|
||||
void insert_exception_test(T*, Inserter insert, test::random_generator gen)
|
||||
{
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
test::random_values<T> v(10, gen);
|
||||
T x;
|
||||
|
||||
EXCEPTION_LOOP(insert_exception_test_impl(x, generate(insert, x), v));
|
||||
}
|
||||
}
|
||||
|
||||
// Insert into a container which is about to hit its max load, so that it
|
||||
// rehashes.
|
||||
|
||||
template <typename T, typename Inserter>
|
||||
void insert_rehash_exception_test(
|
||||
T*, Inserter insert, test::random_generator gen)
|
||||
{
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
T x;
|
||||
rehash_prep(x);
|
||||
|
||||
test::random_values<T> v2(5, gen);
|
||||
EXCEPTION_LOOP(insert_exception_test_impl(x, generate(insert, x), v2));
|
||||
}
|
||||
}
|
||||
|
||||
// Various methods for inserting a single element
|
||||
|
||||
struct inserter_base
|
||||
{
|
||||
template <typename T> void exception_check(T& x, test::strong<T>& strong)
|
||||
{
|
||||
std::string scope(test::scope);
|
||||
|
||||
if (scope.find("hash::operator()") == std::string::npos)
|
||||
strong.test(x, test::detail::tracker.count_allocations);
|
||||
}
|
||||
|
||||
template <typename T, typename Iterator>
|
||||
void track(T& tracker, Iterator begin, Iterator end)
|
||||
{
|
||||
tracker.insert(begin, end);
|
||||
}
|
||||
};
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
|
||||
template <class T>
|
||||
struct emplace_test1 : public insert_test_base<T>
|
||||
struct insert_lvalue_type : inserter_base
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
|
||||
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
x.insert(*it);
|
||||
}
|
||||
} insert_lvalue;
|
||||
|
||||
void run(T& x, strong_type& strong) const {
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
|
||||
it = this->values.begin(), end = this->values.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
strong.store(x, test::detail::tracker.count_allocations);
|
||||
x.emplace(*it);
|
||||
}
|
||||
}
|
||||
struct insert_lvalue_begin_type : inserter_base
|
||||
{
|
||||
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
x.insert(x.begin(), *it);
|
||||
}
|
||||
} insert_lvalue_begin;
|
||||
|
||||
struct insert_lvalue_end_type : inserter_base
|
||||
{
|
||||
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
x.insert(x.end(), *it);
|
||||
}
|
||||
} insert_lvalue_end;
|
||||
|
||||
template <typename T> struct insert_lvalue_pos_type_impl : inserter_base
|
||||
{
|
||||
typename T::iterator pos;
|
||||
|
||||
insert_lvalue_pos_type_impl(T& x) : pos(x.begin()) {}
|
||||
|
||||
template <typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
pos = get_iterator(x.insert(pos, *it));
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
struct insert_test1 : public insert_test_base<T>
|
||||
struct insert_lvalue_pos_type
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
|
||||
template <typename T>
|
||||
friend insert_lvalue_pos_type_impl<T> generate(insert_lvalue_pos_type, T& x)
|
||||
{
|
||||
return insert_lvalue_pos_type_impl<T>(x);
|
||||
}
|
||||
} insert_lvalue_pos;
|
||||
|
||||
void run(T& x, strong_type& strong) const {
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
|
||||
it = this->values.begin(), end = this->values.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
strong.store(x, test::detail::tracker.count_allocations);
|
||||
x.insert(*it);
|
||||
}
|
||||
}
|
||||
struct insert_single_item_range_type : inserter_base
|
||||
{
|
||||
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
x.insert(it, test::next(it));
|
||||
}
|
||||
} insert_single_item_range;
|
||||
|
||||
struct emplace_lvalue_type : inserter_base
|
||||
{
|
||||
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
x.emplace(*it);
|
||||
}
|
||||
} emplace_lvalue;
|
||||
|
||||
struct emplace_lvalue_begin_type : inserter_base
|
||||
{
|
||||
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
x.emplace_hint(x.begin(), *it);
|
||||
}
|
||||
} emplace_lvalue_begin;
|
||||
|
||||
struct emplace_lvalue_end_type : inserter_base
|
||||
{
|
||||
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
x.emplace_hint(x.end(), *it);
|
||||
}
|
||||
} emplace_lvalue_end;
|
||||
|
||||
template <typename T> struct emplace_lvalue_pos_type_impl : inserter_base
|
||||
{
|
||||
typename T::iterator pos;
|
||||
|
||||
emplace_lvalue_pos_type_impl(T& x) : pos(x.begin()) {}
|
||||
|
||||
template <typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
pos = get_iterator(x.emplace_hint(pos, *it));
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct insert_test2 : public insert_test_base<T>
|
||||
struct emplace_lvalue_pos_type
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
|
||||
template <typename T>
|
||||
friend emplace_lvalue_pos_type_impl<T> generate(emplace_lvalue_pos_type, T& x)
|
||||
{
|
||||
return emplace_lvalue_pos_type_impl<T>(x);
|
||||
}
|
||||
} emplace_lvalue_pos;
|
||||
|
||||
void run(T& x, strong_type& strong) const {
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
|
||||
it = this->values.begin(), end = this->values.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
strong.store(x, test::detail::tracker.count_allocations);
|
||||
x.insert(x.begin(), *it);
|
||||
}
|
||||
// Run the exception tests in various combinations.
|
||||
|
||||
test_set* test_set_;
|
||||
test_multiset* test_multiset_;
|
||||
test_map* test_map_;
|
||||
test_multimap* test_multimap_;
|
||||
|
||||
using test::default_generator;
|
||||
using test::limited_range;
|
||||
using test::generate_collisions;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_TEST(insert_exception_test,
|
||||
((test_set_)(test_multiset_)(test_map_)(test_multimap_))
|
||||
((insert_lvalue)(insert_lvalue_begin)(insert_lvalue_end)
|
||||
(insert_lvalue_pos)(insert_single_item_range)
|
||||
(emplace_lvalue)(emplace_lvalue_begin)(emplace_lvalue_end)
|
||||
(emplace_lvalue_pos)
|
||||
)
|
||||
((default_generator)(limited_range)(generate_collisions))
|
||||
)
|
||||
|
||||
UNORDERED_TEST(insert_rehash_exception_test,
|
||||
((test_set_)(test_multiset_)(test_map_)(test_multimap_))
|
||||
((insert_lvalue)(insert_lvalue_begin)(insert_lvalue_end)
|
||||
(insert_lvalue_pos)(insert_single_item_range)
|
||||
(emplace_lvalue)(emplace_lvalue_begin)(emplace_lvalue_end)
|
||||
(emplace_lvalue_pos)
|
||||
)
|
||||
((default_generator)(limited_range)(generate_collisions))
|
||||
)
|
||||
// clang-format on
|
||||
|
||||
// Repeat insert tests with pairs
|
||||
|
||||
struct pair_emplace_type : inserter_base
|
||||
{
|
||||
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
x.emplace(boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(it->first), boost::make_tuple(it->second));
|
||||
}
|
||||
} pair_emplace;
|
||||
|
||||
struct pair_emplace2_type : inserter_base
|
||||
{
|
||||
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
x.emplace_hint(x.begin(), boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(it->first),
|
||||
boost::make_tuple(it->second.tag1_, it->second.tag2_));
|
||||
}
|
||||
} pair_emplace2;
|
||||
|
||||
test_pair_set* test_pair_set_;
|
||||
test_pair_multiset* test_pair_multiset_;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_TEST(insert_exception_test,
|
||||
((test_pair_set_)(test_pair_multiset_)(test_map_)(test_multimap_))
|
||||
((pair_emplace)(pair_emplace2))
|
||||
((default_generator)(limited_range)(generate_collisions))
|
||||
)
|
||||
UNORDERED_TEST(insert_rehash_exception_test,
|
||||
((test_pair_set_)(test_pair_multiset_)(test_map_)(test_multimap_))
|
||||
((pair_emplace)(pair_emplace2))
|
||||
((default_generator)(limited_range)(generate_collisions))
|
||||
)
|
||||
// clang-format on
|
||||
|
||||
// Test inserting using operator[]
|
||||
|
||||
struct try_emplace_type : inserter_base
|
||||
{
|
||||
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
x.try_emplace(it->first, it->second);
|
||||
}
|
||||
} try_emplace;
|
||||
|
||||
struct try_emplace2_type : inserter_base
|
||||
{
|
||||
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
x.try_emplace(it->first, it->second.tag1_, it->second.tag2_);
|
||||
}
|
||||
} try_emplace2;
|
||||
|
||||
struct map_inserter_base
|
||||
{
|
||||
template <typename T> void exception_check(T& x, test::strong<T>& strong)
|
||||
{
|
||||
std::string scope(test::scope);
|
||||
|
||||
if (scope.find("hash::operator()") == std::string::npos &&
|
||||
scope.find("::operator=") == std::string::npos)
|
||||
strong.test(x, test::detail::tracker.count_allocations);
|
||||
}
|
||||
|
||||
template <typename T, typename Iterator>
|
||||
void track(T& tracker, Iterator begin, Iterator end)
|
||||
{
|
||||
for (; begin != end; ++begin) {
|
||||
tracker[begin->first] = begin->second;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct insert_test3 : public insert_test_base<T>
|
||||
struct map_insert_operator_type : map_inserter_base
|
||||
{
|
||||
void run(T& x) const {
|
||||
x.insert(this->values.begin(), this->values.end());
|
||||
}
|
||||
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
x[it->first] = it->second;
|
||||
}
|
||||
} map_insert_operator;
|
||||
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const {
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct insert_test4 : public insert_test_base<T>
|
||||
struct map_insert_or_assign_type : map_inserter_base
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
|
||||
template <typename T, typename Iterator> void operator()(T& x, Iterator it)
|
||||
{
|
||||
x.insert_or_assign(it->first, it->second);
|
||||
}
|
||||
} map_insert_or_assign;
|
||||
|
||||
void run(T& x, strong_type& strong) const {
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
|
||||
it = this->values.begin(), end = this->values.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
strong.store(x, test::detail::tracker.count_allocations);
|
||||
x.insert(it, boost::next(it));
|
||||
}
|
||||
}
|
||||
};
|
||||
// clang-format off
|
||||
UNORDERED_TEST(insert_exception_test,
|
||||
((test_map_))
|
||||
((try_emplace)(try_emplace2)(map_insert_operator)(map_insert_or_assign))
|
||||
((default_generator)(limited_range)(generate_collisions))
|
||||
)
|
||||
UNORDERED_TEST(insert_rehash_exception_test,
|
||||
((test_map_))
|
||||
((try_emplace)(try_emplace2)(map_insert_operator)(map_insert_or_assign))
|
||||
((default_generator)(limited_range)(generate_collisions))
|
||||
)
|
||||
// clang-format on
|
||||
|
||||
template <class T>
|
||||
struct insert_test_rehash1 : public insert_test_base<T>
|
||||
// Range insert tests
|
||||
|
||||
template <typename T, typename Values>
|
||||
void insert_range_exception_test_impl(T x, Values const& v)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
|
||||
test::ordered<T> tracker;
|
||||
tracker.insert(x.begin(), x.end());
|
||||
|
||||
insert_test_rehash1() : insert_test_base<T>(1000) {}
|
||||
try {
|
||||
ENABLE_EXCEPTIONS;
|
||||
x.insert(v.begin(), v.end());
|
||||
} catch (...) {
|
||||
test::check_equivalent_keys(x);
|
||||
throw;
|
||||
}
|
||||
|
||||
T init() const {
|
||||
using namespace std;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::size_type size_type;
|
||||
test::check_equivalent_keys(x);
|
||||
tracker.insert(v.begin(), v.end());
|
||||
tracker.compare(x);
|
||||
}
|
||||
|
||||
T x;
|
||||
x.max_load_factor(0.25);
|
||||
size_type bucket_count = x.bucket_count();
|
||||
size_type initial_elements = static_cast<size_type>(
|
||||
ceil(bucket_count * (double) x.max_load_factor()) - 1);
|
||||
BOOST_TEST(initial_elements < this->values.size());
|
||||
x.insert(this->values.begin(),
|
||||
boost::next(this->values.begin(), initial_elements));
|
||||
BOOST_TEST(bucket_count == x.bucket_count());
|
||||
return x;
|
||||
}
|
||||
|
||||
void run(T& x, strong_type& strong) const {
|
||||
BOOST_DEDUCED_TYPENAME T::size_type bucket_count = x.bucket_count();
|
||||
int count = 0;
|
||||
BOOST_DEDUCED_TYPENAME T::const_iterator pos = x.cbegin();
|
||||
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
|
||||
it = boost::next(this->values.begin(), x.size()),
|
||||
end = this->values.end();
|
||||
it != end && count < 10; ++it, ++count)
|
||||
{
|
||||
strong.store(x, test::detail::tracker.count_allocations);
|
||||
pos = x.insert(pos, *it);
|
||||
}
|
||||
|
||||
// This isn't actually a failure, but it means the test isn't doing its
|
||||
// job.
|
||||
BOOST_TEST(x.bucket_count() != bucket_count);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct insert_test_rehash2 : public insert_test_rehash1<T>
|
||||
template <typename T>
|
||||
void insert_range_exception_test(T*, test::random_generator gen)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
test::random_values<T> v(10, gen);
|
||||
T x;
|
||||
|
||||
void run(T& x, strong_type& strong) const {
|
||||
BOOST_DEDUCED_TYPENAME T::size_type bucket_count = x.bucket_count();
|
||||
int count = 0;
|
||||
EXCEPTION_LOOP(insert_range_exception_test_impl(x, v));
|
||||
}
|
||||
}
|
||||
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
|
||||
it = boost::next(this->values.begin(), x.size()),
|
||||
end = this->values.end();
|
||||
it != end && count < 10; ++it, ++count)
|
||||
{
|
||||
strong.store(x, test::detail::tracker.count_allocations);
|
||||
x.insert(*it);
|
||||
}
|
||||
|
||||
// This isn't actually a failure, but it means the test isn't doing its
|
||||
// job.
|
||||
BOOST_TEST(x.bucket_count() != bucket_count);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct insert_test_rehash3 : public insert_test_base<T>
|
||||
template <typename T>
|
||||
void insert_range_rehash_exception_test(T*, test::random_generator gen)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME T::size_type mutable
|
||||
rehash_bucket_count, original_bucket_count;
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
T x;
|
||||
rehash_prep(x);
|
||||
|
||||
insert_test_rehash3() : insert_test_base<T>(1000) {}
|
||||
test::random_values<T> v2(5, gen);
|
||||
EXCEPTION_LOOP(insert_range_exception_test_impl(x, v2));
|
||||
}
|
||||
}
|
||||
|
||||
T init() const {
|
||||
using namespace std;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::size_type size_type;
|
||||
// clang-format off
|
||||
UNORDERED_TEST(insert_range_exception_test,
|
||||
((test_set_)(test_multiset_)(test_map_)(test_multimap_))
|
||||
((default_generator)(limited_range)(generate_collisions))
|
||||
)
|
||||
|
||||
T x;
|
||||
x.max_load_factor(0.25);
|
||||
UNORDERED_TEST(insert_range_rehash_exception_test,
|
||||
((test_set_)(test_multiset_)(test_map_)(test_multimap_))
|
||||
((default_generator)(limited_range)(generate_collisions))
|
||||
)
|
||||
// clang-format on
|
||||
|
||||
original_bucket_count = x.bucket_count();
|
||||
rehash_bucket_count = static_cast<size_type>(
|
||||
ceil(original_bucket_count * (double) x.max_load_factor())) - 1;
|
||||
|
||||
size_type initial_elements =
|
||||
rehash_bucket_count > 5 ? rehash_bucket_count - 5 : 1;
|
||||
|
||||
BOOST_TEST(initial_elements < this->values.size());
|
||||
x.insert(this->values.begin(),
|
||||
boost::next(this->values.begin(), initial_elements));
|
||||
BOOST_TEST(original_bucket_count == x.bucket_count());
|
||||
return x;
|
||||
}
|
||||
|
||||
void run(T& x) const {
|
||||
BOOST_DEDUCED_TYPENAME T::size_type bucket_count = x.bucket_count();
|
||||
|
||||
x.insert(boost::next(this->values.begin(), x.size()),
|
||||
boost::next(this->values.begin(), x.size() + 20));
|
||||
|
||||
// This isn't actually a failure, but it means the test isn't doing its
|
||||
// job.
|
||||
BOOST_TEST(x.bucket_count() != bucket_count);
|
||||
}
|
||||
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const {
|
||||
if(x.size() < rehash_bucket_count) {
|
||||
//BOOST_TEST(x.bucket_count() == original_bucket_count);
|
||||
}
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
#define BASIC_TESTS \
|
||||
(insert_test1)(insert_test2)(insert_test3)(insert_test4) \
|
||||
(insert_test_rehash1)(insert_test_rehash2)(insert_test_rehash3)
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
#define ALL_TESTS (emplace_test1)BASIC_TESTS
|
||||
#else
|
||||
#define ALL_TESTS BASIC_TESTS
|
||||
#endif
|
||||
|
||||
|
||||
EXCEPTION_TESTS(ALL_TESTS, CONTAINER_SEQ)
|
||||
RUN_TESTS()
|
||||
|
108
test/exception/merge_exception_tests.cpp
Normal file
108
test/exception/merge_exception_tests.cpp
Normal file
@ -0,0 +1,108 @@
|
||||
|
||||
// Copyright 2017-2018 Daniel James.
|
||||
// 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/exception_test.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/metafunctions.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "./containers.hpp"
|
||||
|
||||
template <typename T1, typename T2> void merge_exception_test(T1 x, T2 y)
|
||||
{
|
||||
std::size_t size = x.size() + y.size();
|
||||
|
||||
try {
|
||||
ENABLE_EXCEPTIONS;
|
||||
x.merge(y);
|
||||
} catch (...) {
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_equivalent_keys(y);
|
||||
throw;
|
||||
}
|
||||
|
||||
// Not a full check, just want to make sure the merge completed.
|
||||
BOOST_TEST(size == x.size() + y.size());
|
||||
if (y.size()) {
|
||||
BOOST_TEST(test::has_unique_keys<T1>::value);
|
||||
for (typename T2::iterator it = y.begin(); it != y.end(); ++it) {
|
||||
BOOST_TEST(x.find(test::get_key<T2>(*it)) != x.end());
|
||||
}
|
||||
}
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
void merge_exception_test(T1 const*, T2 const*, std::size_t count12, int tag12,
|
||||
test::random_generator gen1, test::random_generator gen2)
|
||||
{
|
||||
std::size_t count1 = count12 / 256;
|
||||
std::size_t count2 = count12 % 256;
|
||||
int tag1 = tag12 / 256;
|
||||
int tag2 = tag12 % 256;
|
||||
test::random_values<T1> v1(count1, gen1);
|
||||
test::random_values<T2> v2(count2, gen2);
|
||||
T1 x(v1.begin(), v1.end(), 0, test::exception::hash(tag1),
|
||||
test::exception::equal_to(tag1));
|
||||
T2 y(v2.begin(), v2.end(), 0, test::exception::hash(tag2),
|
||||
test::exception::equal_to(tag2));
|
||||
|
||||
EXCEPTION_LOOP(merge_exception_test(x, y))
|
||||
}
|
||||
|
||||
boost::unordered_set<test::exception::object, test::exception::hash,
|
||||
test::exception::equal_to,
|
||||
test::exception::allocator<test::exception::object> >* test_set_;
|
||||
boost::unordered_multiset<test::exception::object, test::exception::hash,
|
||||
test::exception::equal_to,
|
||||
test::exception::allocator<test::exception::object> >* test_multiset_;
|
||||
boost::unordered_map<test::exception::object, test::exception::object,
|
||||
test::exception::hash, test::exception::equal_to,
|
||||
test::exception::allocator2<test::exception::object> >* test_map_;
|
||||
boost::unordered_multimap<test::exception::object, test::exception::object,
|
||||
test::exception::hash, test::exception::equal_to,
|
||||
test::exception::allocator2<test::exception::object> >* test_multimap_;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
using test::limited_range;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_MULTI_TEST(set_merge, merge_exception_test,
|
||||
((test_set_)(test_multiset_))
|
||||
((test_set_)(test_multiset_))
|
||||
((0x0000)(0x6400)(0x0064)(0x0a64)(0x3232))
|
||||
((0x0000)(0x0001)(0x0102))
|
||||
((default_generator)(limited_range))
|
||||
((default_generator)(limited_range))
|
||||
)
|
||||
UNORDERED_MULTI_TEST(map_merge, merge_exception_test,
|
||||
((test_map_)(test_multimap_))
|
||||
((test_map_)(test_multimap_))
|
||||
((0x0000)(0x6400)(0x0064)(0x0a64)(0x3232))
|
||||
((0x0101)(0x0200)(0x0201))
|
||||
((default_generator)(limited_range))
|
||||
((default_generator)(limited_range))
|
||||
)
|
||||
// Run fewer generate_collisions tests, as they're slow.
|
||||
UNORDERED_MULTI_TEST(set_merge_collisions, merge_exception_test,
|
||||
((test_set_)(test_multiset_))
|
||||
((test_set_)(test_multiset_))
|
||||
((0x0a0a))
|
||||
((0x0202)(0x0100)(0x0201))
|
||||
((generate_collisions))
|
||||
((generate_collisions))
|
||||
)
|
||||
UNORDERED_MULTI_TEST(map_merge_collisions, merge_exception_test,
|
||||
((test_map_)(test_multimap_))
|
||||
((test_map_)(test_multimap_))
|
||||
((0x0a0a))
|
||||
((0x0000)(0x0002)(0x0102))
|
||||
((generate_collisions))
|
||||
((generate_collisions))
|
||||
)
|
||||
// clang-format on
|
||||
|
||||
RUN_TESTS_QUIET()
|
132
test/exception/move_assign_exception_tests.cpp
Normal file
132
test/exception/move_assign_exception_tests.cpp
Normal file
@ -0,0 +1,132 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// 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 "./containers.hpp"
|
||||
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning( \
|
||||
disable : 4512) // move_assignment operator could not be generated
|
||||
#endif
|
||||
|
||||
test::seed_t initialize_seed(12847);
|
||||
|
||||
template <class T> struct move_assign_base : public test::exception_base
|
||||
{
|
||||
test::random_values<T> x_values, y_values;
|
||||
T x, y;
|
||||
|
||||
typedef typename T::hasher hasher;
|
||||
typedef typename T::key_equal key_equal;
|
||||
typedef typename T::allocator_type allocator_type;
|
||||
|
||||
move_assign_base(int tag1, int tag2, float mlf1 = 1.0, float mlf2 = 1.0)
|
||||
: x_values(), y_values(),
|
||||
x(0, hasher(tag1), key_equal(tag1), allocator_type(tag1)),
|
||||
y(0, hasher(tag2), key_equal(tag2), allocator_type(tag2))
|
||||
{
|
||||
x.max_load_factor(mlf1);
|
||||
y.max_load_factor(mlf2);
|
||||
}
|
||||
|
||||
typedef T data_type;
|
||||
T init() const { return T(x); }
|
||||
void run(T& x1) const
|
||||
{
|
||||
test::exceptions_enable disable_exceptions(false);
|
||||
T y1 = y;
|
||||
disable_exceptions.release();
|
||||
x1 = boost::move(y1);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x1, y_values);
|
||||
test::check_equivalent_keys(x1);
|
||||
}
|
||||
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x1) const
|
||||
{
|
||||
test::check_equivalent_keys(x1);
|
||||
|
||||
// If the container is empty at the point of the exception, the
|
||||
// internal structure is hidden, this exposes it, at the cost of
|
||||
// messing up the data.
|
||||
if (x_values.size()) {
|
||||
T& x2 = const_cast<T&>(x1);
|
||||
x2.emplace(*x_values.begin());
|
||||
test::check_equivalent_keys(x2);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class T> struct move_assign_values : move_assign_base<T>
|
||||
{
|
||||
move_assign_values(unsigned int count1, unsigned int count2, int tag1,
|
||||
int tag2, float mlf1 = 1.0, float mlf2 = 1.0)
|
||||
: move_assign_base<T>(tag1, tag2, mlf1, mlf2)
|
||||
{
|
||||
this->x_values.fill(count1, test::limited_range);
|
||||
this->y_values.fill(count2, test::limited_range);
|
||||
this->x.insert(this->x_values.begin(), this->x_values.end());
|
||||
this->y.insert(this->y_values.begin(), this->y_values.end());
|
||||
}
|
||||
};
|
||||
|
||||
template <class T> struct move_assign_test1 : move_assign_values<T>
|
||||
{
|
||||
move_assign_test1() : move_assign_values<T>(0, 0, 0, 0) {}
|
||||
};
|
||||
|
||||
template <class T> struct move_assign_test2 : move_assign_values<T>
|
||||
{
|
||||
move_assign_test2() : move_assign_values<T>(60, 0, 0, 0) {}
|
||||
};
|
||||
|
||||
template <class T> struct move_assign_test3 : move_assign_values<T>
|
||||
{
|
||||
move_assign_test3() : move_assign_values<T>(0, 60, 0, 0) {}
|
||||
};
|
||||
|
||||
template <class T> struct move_assign_test4 : move_assign_values<T>
|
||||
{
|
||||
move_assign_test4() : move_assign_values<T>(10, 10, 1, 2) {}
|
||||
};
|
||||
|
||||
template <class T> struct move_assign_test4a : move_assign_values<T>
|
||||
{
|
||||
move_assign_test4a() : move_assign_values<T>(10, 100, 1, 2) {}
|
||||
};
|
||||
|
||||
template <class T> struct move_assign_test5 : move_assign_values<T>
|
||||
{
|
||||
move_assign_test5() : move_assign_values<T>(5, 60, 0, 0, 1.0f, 0.1f) {}
|
||||
};
|
||||
|
||||
template <class T> struct equivalent_test1 : move_assign_base<T>
|
||||
{
|
||||
equivalent_test1() : move_assign_base<T>(0, 0)
|
||||
{
|
||||
test::random_values<T> x_values2(10, test::limited_range);
|
||||
this->x_values.insert(x_values2.begin(), x_values2.end());
|
||||
this->x_values.insert(x_values2.begin(), x_values2.end());
|
||||
test::random_values<T> y_values2(10, test::limited_range);
|
||||
this->y_values.insert(y_values2.begin(), y_values2.end());
|
||||
this->y_values.insert(y_values2.begin(), y_values2.end());
|
||||
this->x.insert(this->x_values.begin(), this->x_values.end());
|
||||
this->y.insert(this->y_values.begin(), this->y_values.end());
|
||||
}
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
EXCEPTION_TESTS(
|
||||
(move_assign_test1)(move_assign_test2)(move_assign_test3)
|
||||
(move_assign_test4)(move_assign_test4a)(move_assign_test5)
|
||||
(equivalent_test1),
|
||||
CONTAINER_SEQ)
|
||||
// clang-format on
|
||||
|
||||
RUN_TESTS()
|
@ -4,82 +4,130 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include "./containers.hpp"
|
||||
#include <string>
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/strong.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/strong.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
#include <string>
|
||||
|
||||
test::seed_t initialize_seed(3298597);
|
||||
|
||||
template <class T>
|
||||
struct rehash_test_base : public test::exception_base
|
||||
template <class T> struct rehash_test_base : public test::exception_base
|
||||
{
|
||||
test::random_values<T> values;
|
||||
unsigned int n;
|
||||
rehash_test_base(unsigned int count = 100, unsigned int n = 0)
|
||||
: values(count), n(n)
|
||||
{}
|
||||
test::random_values<T> values;
|
||||
unsigned int n;
|
||||
rehash_test_base(unsigned int count = 100, unsigned int n_ = 0)
|
||||
: values(count, test::limited_range), n(n_)
|
||||
{
|
||||
}
|
||||
|
||||
typedef T data_type;
|
||||
typedef test::strong<T> strong_type;
|
||||
typedef T data_type;
|
||||
typedef test::strong<T> strong_type;
|
||||
|
||||
data_type init() const {
|
||||
T x(values.begin(), values.end(), n);
|
||||
return x;
|
||||
}
|
||||
data_type init() const
|
||||
{
|
||||
T x(values.begin(), values.end(), n);
|
||||
return x;
|
||||
}
|
||||
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x,
|
||||
strong_type const& strong) const
|
||||
{
|
||||
std::string scope(test::scope);
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(
|
||||
T const& x, strong_type const& strong) const
|
||||
{
|
||||
std::string scope(test::scope);
|
||||
|
||||
if(scope.find("hash::operator()") == std::string::npos &&
|
||||
scope.find("equal_to::operator()") == std::string::npos &&
|
||||
scope != "operator==(object, object)")
|
||||
strong.test(x);
|
||||
if (scope.find("hash::operator()") == std::string::npos &&
|
||||
scope.find("equal_to::operator()") == std::string::npos &&
|
||||
scope != "operator==(object, object)")
|
||||
strong.test(x);
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct rehash_test0 : rehash_test_base<T>
|
||||
template <class T> struct rehash_test0 : rehash_test_base<T>
|
||||
{
|
||||
rehash_test0() : rehash_test_base<T>(0) {}
|
||||
void run(T& x) const { x.rehash(0); }
|
||||
rehash_test0() : rehash_test_base<T>(0) {}
|
||||
void run(T& x) const
|
||||
{
|
||||
x.rehash(0);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, this->values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct rehash_test1 : rehash_test_base<T>
|
||||
template <class T> struct rehash_test1 : rehash_test_base<T>
|
||||
{
|
||||
rehash_test1() : rehash_test_base<T>(0) {}
|
||||
void run(T& x) const { x.rehash(200); }
|
||||
rehash_test1() : rehash_test_base<T>(0) {}
|
||||
void run(T& x) const
|
||||
{
|
||||
x.rehash(200);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, this->values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct rehash_test2 : rehash_test_base<T>
|
||||
template <class T> struct rehash_test2 : rehash_test_base<T>
|
||||
{
|
||||
rehash_test2() : rehash_test_base<T>(0, 200) {}
|
||||
void run(T& x) const { x.rehash(0); }
|
||||
rehash_test2() : rehash_test_base<T>(0, 200) {}
|
||||
void run(T& x) const
|
||||
{
|
||||
x.rehash(0);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, this->values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct rehash_test3 : rehash_test_base<T>
|
||||
template <class T> struct rehash_test3 : rehash_test_base<T>
|
||||
{
|
||||
rehash_test3() : rehash_test_base<T>(10, 0) {}
|
||||
void run(T& x) const { x.rehash(200); }
|
||||
rehash_test3() : rehash_test_base<T>(10, 0) {}
|
||||
void run(T& x) const
|
||||
{
|
||||
x.rehash(200);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, this->values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct rehash_test4 : rehash_test_base<T>
|
||||
template <class T> struct rehash_test4 : rehash_test_base<T>
|
||||
{
|
||||
rehash_test4() : rehash_test_base<T>(10, 200) {}
|
||||
void run(T& x) const { x.rehash(0); }
|
||||
rehash_test4() : rehash_test_base<T>(10, 200) {}
|
||||
void run(T& x) const
|
||||
{
|
||||
x.rehash(0);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, this->values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T> struct rehash_test5 : rehash_test_base<T>
|
||||
{
|
||||
rehash_test5() : rehash_test_base<T>(200, 10) {}
|
||||
void run(T& x) const
|
||||
{
|
||||
x.rehash(0);
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, this->values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
EXCEPTION_TESTS(
|
||||
(rehash_test0)(rehash_test1)(rehash_test2)(rehash_test3)(rehash_test4),
|
||||
CONTAINER_SEQ)
|
||||
(rehash_test0)(rehash_test1)(rehash_test2)(rehash_test3)(rehash_test4)
|
||||
(rehash_test5),
|
||||
CONTAINER_SEQ)
|
||||
// clang-format on
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -4,122 +4,142 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include "./containers.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(disable:4512) // assignment operator could not be generated
|
||||
#pragma warning(disable : 4512) // assignment operator could not be generated
|
||||
#endif
|
||||
|
||||
test::seed_t initialize_seed(9387);
|
||||
|
||||
template <class T>
|
||||
struct self_swap_base : public test::exception_base
|
||||
template <class T> struct self_swap_base : public test::exception_base
|
||||
{
|
||||
test::random_values<T> values;
|
||||
self_swap_base(int count = 0) : values(count) {}
|
||||
test::random_values<T> values;
|
||||
self_swap_base(std::size_t count = 0) : values(count, test::limited_range) {}
|
||||
|
||||
typedef T data_type;
|
||||
T init() const { return T(values.begin(), values.end()); }
|
||||
void run(T& x) const { x.swap(x); }
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const {
|
||||
std::string scope(test::scope);
|
||||
typedef T data_type;
|
||||
T init() const { return T(values.begin(), values.end()); }
|
||||
|
||||
// TODO: In C++11 exceptions are only allowed in the swap function.
|
||||
BOOST_TEST(
|
||||
scope == "hash::hash(hash)" ||
|
||||
scope == "hash::operator=(hash)" ||
|
||||
scope == "equal_to::equal_to(equal_to)" ||
|
||||
scope == "equal_to::operator=(equal_to)");
|
||||
void run(T& x) const
|
||||
{
|
||||
x.swap(x);
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(x, this->values);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const
|
||||
{
|
||||
std::string scope(test::scope);
|
||||
|
||||
// TODO: In C++11 exceptions are only allowed in the swap function.
|
||||
BOOST_TEST(scope == "hash::hash(hash)" ||
|
||||
scope == "hash::operator=(hash)" ||
|
||||
scope == "equal_to::equal_to(equal_to)" ||
|
||||
scope == "equal_to::operator=(equal_to)");
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct self_swap_test1 : self_swap_base<T> {};
|
||||
|
||||
template <class T>
|
||||
struct self_swap_test2 : self_swap_base<T>
|
||||
template <class T> struct self_swap_test1 : self_swap_base<T>
|
||||
{
|
||||
self_swap_test2() : self_swap_base<T>(100) {}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct swap_base : public test::exception_base
|
||||
template <class T> struct self_swap_test2 : self_swap_base<T>
|
||||
{
|
||||
const test::random_values<T> x_values, y_values;
|
||||
const T initial_x, initial_y;
|
||||
self_swap_test2() : self_swap_base<T>(100) {}
|
||||
};
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME T::hasher hasher;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
|
||||
template <class T> struct swap_base : public test::exception_base
|
||||
{
|
||||
const test::random_values<T> x_values, y_values;
|
||||
const T initial_x, initial_y;
|
||||
|
||||
swap_base(unsigned int count1, unsigned int count2, int tag1, int tag2)
|
||||
: x_values(count1), y_values(count2),
|
||||
typedef typename T::hasher hasher;
|
||||
typedef typename T::key_equal key_equal;
|
||||
typedef typename T::allocator_type allocator_type;
|
||||
|
||||
swap_base(unsigned int count1, unsigned int count2, int tag1, int tag2)
|
||||
: x_values(count1, test::limited_range),
|
||||
y_values(count2, test::limited_range),
|
||||
initial_x(x_values.begin(), x_values.end(), 0, hasher(tag1),
|
||||
key_equal(tag1), allocator_type(tag1)),
|
||||
key_equal(tag1), allocator_type(tag1)),
|
||||
initial_y(y_values.begin(), y_values.end(), 0, hasher(tag2),
|
||||
key_equal(tag2), allocator_type(
|
||||
T::allocator_type::propagate_on_container_swap::value ?
|
||||
tag2 : tag1))
|
||||
{}
|
||||
key_equal(tag2),
|
||||
allocator_type(T::allocator_type::propagate_on_container_swap::value
|
||||
? tag2
|
||||
: tag1))
|
||||
{
|
||||
}
|
||||
|
||||
struct data_type {
|
||||
data_type(T const& x, T const& y)
|
||||
: x(x), y(y) {}
|
||||
struct data_type
|
||||
{
|
||||
data_type(T const& x_, T const& y_) : x(x_), y(y_) {}
|
||||
|
||||
T x, y;
|
||||
};
|
||||
T x, y;
|
||||
};
|
||||
|
||||
data_type init() const { return data_type(initial_x, initial_y); }
|
||||
data_type init() const { return data_type(initial_x, initial_y); }
|
||||
|
||||
void run(data_type& d) const {
|
||||
try {
|
||||
d.x.swap(d.y);
|
||||
} catch (std::runtime_error) {}
|
||||
void run(data_type& d) const
|
||||
{
|
||||
try {
|
||||
d.x.swap(d.y);
|
||||
} catch (std::runtime_error&) {
|
||||
}
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(data_type const& d) const {
|
||||
std::string scope(test::scope);
|
||||
|
||||
// TODO: In C++11 exceptions are only allowed in the swap function.
|
||||
BOOST_TEST(
|
||||
scope == "hash::hash(hash)" ||
|
||||
scope == "hash::operator=(hash)" ||
|
||||
scope == "equal_to::equal_to(equal_to)" ||
|
||||
scope == "equal_to::operator=(equal_to)");
|
||||
|
||||
test::check_equivalent_keys(d.x);
|
||||
test::check_equivalent_keys(d.y);
|
||||
}
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_container(d.x, this->y_values);
|
||||
test::check_equivalent_keys(d.x);
|
||||
test::check_container(d.y, this->x_values);
|
||||
test::check_equivalent_keys(d.y);
|
||||
}
|
||||
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(data_type const& d) const
|
||||
{
|
||||
std::string scope(test::scope);
|
||||
|
||||
// TODO: In C++11 exceptions are only allowed in the swap function.
|
||||
BOOST_TEST(scope == "hash::hash(hash)" ||
|
||||
scope == "hash::operator=(hash)" ||
|
||||
scope == "equal_to::equal_to(equal_to)" ||
|
||||
scope == "equal_to::operator=(equal_to)");
|
||||
|
||||
test::check_equivalent_keys(d.x);
|
||||
test::check_equivalent_keys(d.y);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct swap_test1 : swap_base<T>
|
||||
template <class T> struct swap_test1 : swap_base<T>
|
||||
{
|
||||
swap_test1() : swap_base<T>(0, 0, 0, 0) {}
|
||||
swap_test1() : swap_base<T>(0, 0, 0, 0) {}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct swap_test2 : swap_base<T>
|
||||
template <class T> struct swap_test2 : swap_base<T>
|
||||
{
|
||||
swap_test2() : swap_base<T>(60, 0, 0, 0) {}
|
||||
swap_test2() : swap_base<T>(60, 0, 0, 0) {}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct swap_test3 : swap_base<T>
|
||||
template <class T> struct swap_test3 : swap_base<T>
|
||||
{
|
||||
swap_test3() : swap_base<T>(0, 60, 0, 0) {}
|
||||
swap_test3() : swap_base<T>(0, 60, 0, 0) {}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct swap_test4 : swap_base<T>
|
||||
template <class T> struct swap_test4 : swap_base<T>
|
||||
{
|
||||
swap_test4() : swap_base<T>(10, 10, 1, 2) {}
|
||||
swap_test4() : swap_base<T>(10, 10, 1, 2) {}
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
EXCEPTION_TESTS(
|
||||
(self_swap_test1)(self_swap_test2)
|
||||
(swap_test1)(swap_test2)(swap_test3)(swap_test4),
|
||||
CONTAINER_SEQ)
|
||||
(self_swap_test1)(self_swap_test2)
|
||||
(swap_test1)(swap_test2)(swap_test3)(swap_test4),
|
||||
CONTAINER_SEQ)
|
||||
// clang-format on
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -7,32 +7,27 @@
|
||||
#define BOOST_UNORDERED_TEST_HELPERS_CHECK_RETURN_TYPE_HEADER
|
||||
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
|
||||
namespace test
|
||||
{
|
||||
template <class T1>
|
||||
struct check_return_type
|
||||
namespace test {
|
||||
template <class T1> struct check_return_type
|
||||
{
|
||||
template <class T2> static void equals(T2)
|
||||
{
|
||||
template <class T2>
|
||||
static void equals(T2)
|
||||
{
|
||||
BOOST_STATIC_ASSERT((boost::is_same<T1, T2>::value));
|
||||
}
|
||||
BOOST_STATIC_ASSERT((boost::is_same<T1, T2>::value));
|
||||
}
|
||||
|
||||
template <class T2>
|
||||
static void equals_ref(T2&)
|
||||
{
|
||||
BOOST_STATIC_ASSERT((boost::is_same<T1, T2>::value));
|
||||
}
|
||||
template <class T2> static void equals_ref(T2&)
|
||||
{
|
||||
BOOST_STATIC_ASSERT((boost::is_same<T1, T2>::value));
|
||||
}
|
||||
|
||||
template <class T2>
|
||||
static void convertible(T2)
|
||||
{
|
||||
BOOST_STATIC_ASSERT((boost::is_convertible<T2, T1>::value));
|
||||
}
|
||||
};
|
||||
template <class T2> static void convertible(T2)
|
||||
{
|
||||
BOOST_STATIC_ASSERT((boost::is_convertible<T2, T1>::value));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -6,74 +6,84 @@
|
||||
#if !defined(BOOST_UNORDERED_TEST_HELPERS_COUNT_HEAD)
|
||||
#define BOOST_UNORDERED_TEST_HELPERS_COUNT_HEAD
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
namespace test {
|
||||
struct object_count {
|
||||
int instances;
|
||||
int constructions;
|
||||
struct object_count
|
||||
{
|
||||
int instances;
|
||||
int constructions;
|
||||
|
||||
object_count() : instances(0), constructions(0) {}
|
||||
void reset() { *this = object_count(); }
|
||||
object_count() : instances(0), constructions(0) {}
|
||||
void reset() { *this = object_count(); }
|
||||
|
||||
void construct() {
|
||||
++instances;
|
||||
++constructions;
|
||||
}
|
||||
|
||||
void destruct() {
|
||||
if(instances == 0) {
|
||||
BOOST_ERROR("Unbalanced constructions.");
|
||||
}
|
||||
else {
|
||||
--instances;
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(object_count const& x) const {
|
||||
return instances == x.instances &&
|
||||
constructions == x.constructions;
|
||||
}
|
||||
|
||||
bool operator!=(object_count const& x) const {
|
||||
return !(*this == x);
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& out,
|
||||
object_count const& c)
|
||||
{
|
||||
out
|
||||
<< "[instances: "
|
||||
<< c.instances
|
||||
<< ", constructions: "
|
||||
<< c.constructions
|
||||
<< "]";
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
// This won't be a problem as I'm only using a single compile unit
|
||||
// in each test (this is actually require by the minimal test
|
||||
// framework).
|
||||
//
|
||||
// boostinspect:nounnamed
|
||||
namespace {
|
||||
object_count global_object_count;
|
||||
}
|
||||
|
||||
struct counted_object
|
||||
void construct()
|
||||
{
|
||||
counted_object() { global_object_count.construct(); }
|
||||
counted_object(counted_object const&) { global_object_count.construct(); }
|
||||
~counted_object() { global_object_count.destruct(); }
|
||||
};
|
||||
++instances;
|
||||
++constructions;
|
||||
}
|
||||
|
||||
struct check_instances {
|
||||
int instances;
|
||||
|
||||
check_instances() : instances(global_object_count.instances) {}
|
||||
~check_instances() { BOOST_TEST(global_object_count.instances == instances); }
|
||||
};
|
||||
void destruct()
|
||||
{
|
||||
if (instances == 0) {
|
||||
BOOST_ERROR("Unbalanced constructions.");
|
||||
} else {
|
||||
--instances;
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(object_count const& x) const
|
||||
{
|
||||
return instances == x.instances && constructions == x.constructions;
|
||||
}
|
||||
|
||||
bool operator!=(object_count const& x) const { return !(*this == x); }
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& out, object_count const& c)
|
||||
{
|
||||
out << "[instances: " << c.instances
|
||||
<< ", constructions: " << c.constructions << "]";
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
// This won't be a problem as I'm only using a single compile unit
|
||||
// in each test (this is actually require by the minimal test
|
||||
// framework).
|
||||
//
|
||||
// boostinspect:nounnamed
|
||||
namespace {
|
||||
object_count global_object_count;
|
||||
}
|
||||
|
||||
struct counted_object
|
||||
{
|
||||
counted_object() { global_object_count.construct(); }
|
||||
counted_object(counted_object const&) { global_object_count.construct(); }
|
||||
~counted_object() { global_object_count.destruct(); }
|
||||
};
|
||||
|
||||
struct check_instances
|
||||
{
|
||||
int instances_;
|
||||
int constructions_;
|
||||
|
||||
check_instances()
|
||||
: instances_(global_object_count.instances),
|
||||
constructions_(global_object_count.constructions)
|
||||
{
|
||||
}
|
||||
~check_instances()
|
||||
{
|
||||
BOOST_TEST(global_object_count.instances == instances_);
|
||||
}
|
||||
|
||||
int instances() const { return global_object_count.instances - instances_; }
|
||||
int constructions() const
|
||||
{
|
||||
return global_object_count.constructions - constructions_;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -6,93 +6,91 @@
|
||||
#if !defined(BOOST_UNORDERED_TESTS_EQUIVALENT_HEADER)
|
||||
#define BOOST_UNORDERED_TESTS_EQUIVALENT_HEADER
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <algorithm>
|
||||
#include "./metafunctions.hpp"
|
||||
#include "./fwd.hpp"
|
||||
#include "./list.hpp"
|
||||
#include "./metafunctions.hpp"
|
||||
#include <algorithm>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
|
||||
namespace test {
|
||||
template <class T1, class T2>
|
||||
bool equivalent_impl(T1 const& x, T2 const& y, base_type)
|
||||
{
|
||||
return x == y;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool equivalent_impl(
|
||||
boost::hash<T> const&, boost::hash<T> const&, derived_type)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool equivalent_impl(
|
||||
std::equal_to<T> const&, std::equal_to<T> const&, derived_type)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T1, class T2, class T3, class T4>
|
||||
bool equivalent_impl(
|
||||
std::pair<T1, T2> const& x1, std::pair<T3, T4> const& x2, derived_type)
|
||||
{
|
||||
return equivalent_impl(x1.first, x2.first, derived) &&
|
||||
equivalent_impl(x1.second, x2.second, derived);
|
||||
}
|
||||
|
||||
struct equivalent_type
|
||||
{
|
||||
equivalent_type() {}
|
||||
|
||||
namespace test
|
||||
{
|
||||
template <class T1, class T2>
|
||||
bool equivalent_impl(T1 const& x, T2 const& y, base_type) {
|
||||
return x == y;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool equivalent_impl(boost::hash<T> const&, boost::hash<T> const&,
|
||||
derived_type)
|
||||
bool operator()(T1 const& x, T2 const& y) const
|
||||
{
|
||||
return true;
|
||||
return equivalent_impl(x, y, derived);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
bool equivalent_impl(std::equal_to<T> const&, std::equal_to<T> const&,
|
||||
derived_type)
|
||||
const equivalent_type equivalent;
|
||||
|
||||
template <class Container> class unordered_equivalence_tester
|
||||
{
|
||||
typename Container::size_type size_;
|
||||
typename Container::hasher hasher_;
|
||||
typename Container::key_equal key_equal_;
|
||||
float max_load_factor_;
|
||||
|
||||
typedef test::list<typename Container::value_type> value_list;
|
||||
value_list values_;
|
||||
|
||||
public:
|
||||
unordered_equivalence_tester(Container const& x)
|
||||
: size_(x.size()), hasher_(x.hash_function()), key_equal_(x.key_eq()),
|
||||
max_load_factor_(x.max_load_factor()), values_(x.begin(), x.end())
|
||||
{
|
||||
return true;
|
||||
values_.sort();
|
||||
}
|
||||
|
||||
template <class T1, class T2, class T3, class T4>
|
||||
bool equivalent_impl(std::pair<T1, T2> const& x1,
|
||||
std::pair<T3, T4> const& x2, derived_type) {
|
||||
return equivalent_impl(x1.first, x2.first, derived) &&
|
||||
equivalent_impl(x1.second, x2.second, derived);
|
||||
}
|
||||
|
||||
struct equivalent_type {
|
||||
template <class T1, class T2>
|
||||
bool operator()(T1 const& x, T2 const& y) {
|
||||
return equivalent_impl(x, y, derived);
|
||||
}
|
||||
};
|
||||
|
||||
// This won't be a problem as I'm only using a single compile unit
|
||||
// in each test (this is actually require by the minimal test
|
||||
// framework).
|
||||
//
|
||||
// boostinspect:nounnamed
|
||||
namespace {
|
||||
equivalent_type equivalent;
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
class unordered_equivalence_tester
|
||||
bool operator()(Container const& x) const
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME Container::size_type size_;
|
||||
BOOST_DEDUCED_TYPENAME Container::hasher hasher_;
|
||||
BOOST_DEDUCED_TYPENAME Container::key_equal key_equal_;
|
||||
float max_load_factor_;
|
||||
if (!((size_ == x.size()) &&
|
||||
(test::equivalent(hasher_, x.hash_function())) &&
|
||||
(test::equivalent(key_equal_, x.key_eq())) &&
|
||||
(max_load_factor_ == x.max_load_factor()) &&
|
||||
(values_.size() == x.size())))
|
||||
return false;
|
||||
|
||||
typedef test::list<BOOST_DEDUCED_TYPENAME Container::value_type>
|
||||
value_list;
|
||||
value_list values_;
|
||||
public:
|
||||
unordered_equivalence_tester(Container const &x)
|
||||
: size_(x.size()),
|
||||
hasher_(x.hash_function()), key_equal_(x.key_eq()),
|
||||
max_load_factor_(x.max_load_factor()),
|
||||
values_(x.begin(), x.end())
|
||||
{
|
||||
values_.sort();
|
||||
}
|
||||
value_list copy(x.begin(), x.end());
|
||||
copy.sort();
|
||||
return values_ == copy;
|
||||
}
|
||||
|
||||
bool operator()(Container const& x) const
|
||||
{
|
||||
if(!((size_ == x.size()) &&
|
||||
(test::equivalent(hasher_, x.hash_function())) &&
|
||||
(test::equivalent(key_equal_, x.key_eq())) &&
|
||||
(max_load_factor_ == x.max_load_factor()) &&
|
||||
(values_.size() == x.size()))) return false;
|
||||
|
||||
value_list copy(x.begin(), x.end());
|
||||
copy.sort();
|
||||
return values_ == copy;
|
||||
}
|
||||
private:
|
||||
unordered_equivalence_tester();
|
||||
};
|
||||
private:
|
||||
unordered_equivalence_tester();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -6,246 +6,343 @@
|
||||
#if !defined(BOOST_UNORDERED_EXCEPTION_TEST_HEADER)
|
||||
#define BOOST_UNORDERED_EXCEPTION_TEST_HEADER
|
||||
|
||||
#include "./count.hpp"
|
||||
#include "./test.hpp"
|
||||
|
||||
#include <boost/preprocessor/seq/for_each_product.hpp>
|
||||
#include <boost/preprocessor/seq/elem.hpp>
|
||||
#include <boost/preprocessor/cat.hpp>
|
||||
#include <boost/preprocessor/seq/elem.hpp>
|
||||
#include <boost/preprocessor/seq/for_each_product.hpp>
|
||||
|
||||
# define UNORDERED_EXCEPTION_TEST_CASE(name, test_func, type) \
|
||||
UNORDERED_AUTO_TEST(name) \
|
||||
{ \
|
||||
test_func< type > fixture; \
|
||||
::test::lightweight::exception_safety( \
|
||||
fixture, BOOST_STRINGIZE(test_func<type>)); \
|
||||
} \
|
||||
#define UNORDERED_EXCEPTION_TEST_CASE(name, test_func, type) \
|
||||
UNORDERED_AUTO_TEST (name) { \
|
||||
test_func<type> fixture; \
|
||||
::test::lightweight::exception_safety( \
|
||||
fixture, BOOST_STRINGIZE(test_func<type>)); \
|
||||
}
|
||||
|
||||
# define UNORDERED_EXCEPTION_TEST_CASE_REPEAT(name, test_func, n, type) \
|
||||
UNORDERED_AUTO_TEST(name) \
|
||||
{ \
|
||||
for (unsigned i = 0; i < n; ++i) { \
|
||||
test_func< type > fixture; \
|
||||
::test::lightweight::exception_safety( \
|
||||
fixture, BOOST_STRINGIZE(test_func<type>)); \
|
||||
} \
|
||||
} \
|
||||
#define UNORDERED_EXCEPTION_TEST_CASE_REPEAT(name, test_func, n, type) \
|
||||
UNORDERED_AUTO_TEST (name) { \
|
||||
for (unsigned i = 0; i < n; ++i) { \
|
||||
test_func<type> fixture; \
|
||||
::test::lightweight::exception_safety( \
|
||||
fixture, BOOST_STRINGIZE(test_func<type>)); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
# define UNORDERED_EPOINT_IMPL ::test::lightweight::epoint
|
||||
#define UNORDERED_EPOINT_IMPL ::test::lightweight::epoint
|
||||
|
||||
#define UNORDERED_EXCEPTION_TEST_POSTFIX RUN_TESTS()
|
||||
|
||||
#define EXCEPTION_TESTS(test_seq, param_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH_PRODUCT(EXCEPTION_TESTS_OP, \
|
||||
(test_seq)((1))(param_seq))
|
||||
#define EXCEPTION_TESTS(test_seq, param_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH_PRODUCT(EXCEPTION_TESTS_OP, (test_seq)((1))(param_seq))
|
||||
|
||||
#define EXCEPTION_TESTS_REPEAT(n, test_seq, param_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH_PRODUCT(EXCEPTION_TESTS_OP, \
|
||||
(test_seq)((n))(param_seq))
|
||||
#define EXCEPTION_TESTS_REPEAT(n, test_seq, param_seq) \
|
||||
BOOST_PP_SEQ_FOR_EACH_PRODUCT(EXCEPTION_TESTS_OP, (test_seq)((n))(param_seq))
|
||||
|
||||
#define EXCEPTION_TESTS_OP(r, product) \
|
||||
UNORDERED_EXCEPTION_TEST_CASE_REPEAT( \
|
||||
BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(0, product), \
|
||||
BOOST_PP_CAT(_, BOOST_PP_SEQ_ELEM(2, product)) \
|
||||
), \
|
||||
BOOST_PP_SEQ_ELEM(0, product), \
|
||||
BOOST_PP_SEQ_ELEM(1, product), \
|
||||
BOOST_PP_SEQ_ELEM(2, product) \
|
||||
) \
|
||||
#define EXCEPTION_TESTS_OP(r, product) \
|
||||
UNORDERED_EXCEPTION_TEST_CASE_REPEAT( \
|
||||
BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(0, product), \
|
||||
BOOST_PP_CAT(_, BOOST_PP_SEQ_ELEM(2, product))), \
|
||||
BOOST_PP_SEQ_ELEM(0, product), BOOST_PP_SEQ_ELEM(1, product), \
|
||||
BOOST_PP_SEQ_ELEM(2, product))
|
||||
|
||||
#define UNORDERED_SCOPE(scope_name) \
|
||||
for(::test::scope_guard unordered_test_guard( \
|
||||
BOOST_STRINGIZE(scope_name)); \
|
||||
!unordered_test_guard.dismissed(); \
|
||||
unordered_test_guard.dismiss()) \
|
||||
#define UNORDERED_SCOPE(scope_name) \
|
||||
for (::test::scope_guard unordered_test_guard(BOOST_STRINGIZE(scope_name)); \
|
||||
!unordered_test_guard.dismissed(); unordered_test_guard.dismiss())
|
||||
|
||||
#define UNORDERED_EPOINT(name) \
|
||||
if(::test::exceptions_enabled) { \
|
||||
UNORDERED_EPOINT_IMPL(name); \
|
||||
} \
|
||||
#define UNORDERED_EPOINT(name) \
|
||||
if (::test::exceptions_enabled) { \
|
||||
UNORDERED_EPOINT_IMPL(name); \
|
||||
}
|
||||
|
||||
#define ENABLE_EXCEPTIONS \
|
||||
::test::exceptions_enable BOOST_PP_CAT( \
|
||||
ENABLE_EXCEPTIONS_, __LINE__)(true) \
|
||||
#define ENABLE_EXCEPTIONS \
|
||||
::test::exceptions_enable BOOST_PP_CAT(ENABLE_EXCEPTIONS_, __LINE__)(true)
|
||||
|
||||
#define DISABLE_EXCEPTIONS \
|
||||
::test::exceptions_enable BOOST_PP_CAT( \
|
||||
ENABLE_EXCEPTIONS_, __LINE__)(false) \
|
||||
#define DISABLE_EXCEPTIONS \
|
||||
::test::exceptions_enable BOOST_PP_CAT(ENABLE_EXCEPTIONS_, __LINE__)(false)
|
||||
|
||||
namespace test {
|
||||
static char const* scope = "";
|
||||
bool exceptions_enabled = false;
|
||||
static char const* scope = "";
|
||||
bool exceptions_enabled = false;
|
||||
|
||||
class scope_guard {
|
||||
scope_guard& operator=(scope_guard const&);
|
||||
scope_guard(scope_guard const&);
|
||||
class scope_guard
|
||||
{
|
||||
scope_guard& operator=(scope_guard const&);
|
||||
scope_guard(scope_guard const&);
|
||||
|
||||
char const* old_scope_;
|
||||
char const* scope_;
|
||||
bool dismissed_;
|
||||
public:
|
||||
scope_guard(char const* name)
|
||||
: old_scope_(scope),
|
||||
scope_(name),
|
||||
dismissed_(false)
|
||||
{
|
||||
scope = scope_;
|
||||
}
|
||||
char const* old_scope_;
|
||||
char const* scope_;
|
||||
bool dismissed_;
|
||||
|
||||
~scope_guard() {
|
||||
if(dismissed_) scope = old_scope_;
|
||||
}
|
||||
|
||||
void dismiss() {
|
||||
dismissed_ = true;
|
||||
}
|
||||
|
||||
bool dismissed() const {
|
||||
return dismissed_;
|
||||
}
|
||||
};
|
||||
|
||||
class exceptions_enable
|
||||
public:
|
||||
scope_guard(char const* name)
|
||||
: old_scope_(scope), scope_(name), dismissed_(false)
|
||||
{
|
||||
exceptions_enable& operator=(exceptions_enable const&);
|
||||
exceptions_enable(exceptions_enable const&);
|
||||
|
||||
bool old_value_;
|
||||
public:
|
||||
exceptions_enable(bool enable)
|
||||
: old_value_(exceptions_enabled)
|
||||
{
|
||||
exceptions_enabled = enable;
|
||||
}
|
||||
|
||||
~exceptions_enable()
|
||||
{
|
||||
exceptions_enabled = old_value_;
|
||||
}
|
||||
};
|
||||
|
||||
struct exception_base {
|
||||
struct data_type {};
|
||||
struct strong_type {
|
||||
template <class T> void store(T const&) {}
|
||||
template <class T> void test(T const&) const {}
|
||||
};
|
||||
data_type init() const { return data_type(); }
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION() const {}
|
||||
};
|
||||
|
||||
template <class T, class P1, class P2, class T2>
|
||||
inline void call_ignore_extra_parameters(
|
||||
void (T::*fn)() const, T2 const& obj,
|
||||
P1&, P2&)
|
||||
{
|
||||
(obj.*fn)();
|
||||
scope = scope_;
|
||||
}
|
||||
|
||||
template <class T, class P1, class P2, class T2>
|
||||
inline void call_ignore_extra_parameters(
|
||||
void (T::*fn)(P1&) const, T2 const& obj,
|
||||
P1& p1, P2&)
|
||||
~scope_guard()
|
||||
{
|
||||
(obj.*fn)(p1);
|
||||
if (dismissed_)
|
||||
scope = old_scope_;
|
||||
}
|
||||
|
||||
template <class T, class P1, class P2, class T2>
|
||||
inline void call_ignore_extra_parameters(
|
||||
void (T::*fn)(P1&, P2&) const, T2 const& obj,
|
||||
P1& p1, P2& p2)
|
||||
void dismiss() { dismissed_ = true; }
|
||||
|
||||
bool dismissed() const { return dismissed_; }
|
||||
};
|
||||
|
||||
class exceptions_enable
|
||||
{
|
||||
exceptions_enable& operator=(exceptions_enable const&);
|
||||
exceptions_enable(exceptions_enable const&);
|
||||
|
||||
bool old_value_;
|
||||
bool released_;
|
||||
|
||||
public:
|
||||
exceptions_enable(bool enable)
|
||||
: old_value_(exceptions_enabled), released_(false)
|
||||
{
|
||||
(obj.*fn)(p1, p2);
|
||||
exceptions_enabled = enable;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T const& constant(T const& x) {
|
||||
return x;
|
||||
~exceptions_enable()
|
||||
{
|
||||
if (!released_) {
|
||||
exceptions_enabled = old_value_;
|
||||
released_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void release()
|
||||
{
|
||||
if (!released_) {
|
||||
exceptions_enabled = old_value_;
|
||||
released_ = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct exception_base
|
||||
{
|
||||
struct data_type
|
||||
{
|
||||
};
|
||||
struct strong_type
|
||||
{
|
||||
template <class T> void store(T const&) {}
|
||||
template <class T> void test(T const&) const {}
|
||||
};
|
||||
data_type init() const { return data_type(); }
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION() const {}
|
||||
};
|
||||
|
||||
template <class T, class P1, class P2, class T2>
|
||||
inline void call_ignore_extra_parameters(
|
||||
void (T::*fn)() const, T2 const& obj, P1&, P2&)
|
||||
{
|
||||
(obj.*fn)();
|
||||
}
|
||||
|
||||
template <class T, class P1, class P2, class T2>
|
||||
inline void call_ignore_extra_parameters(
|
||||
void (T::*fn)(P1&) const, T2 const& obj, P1& p1, P2&)
|
||||
{
|
||||
(obj.*fn)(p1);
|
||||
}
|
||||
|
||||
template <class T, class P1, class P2, class T2>
|
||||
inline void call_ignore_extra_parameters(
|
||||
void (T::*fn)(P1&, P2&) const, T2 const& obj, P1& p1, P2& p2)
|
||||
{
|
||||
(obj.*fn)(p1, p2);
|
||||
}
|
||||
|
||||
template <class T> T const& constant(T const& x) { return x; }
|
||||
|
||||
template <class Test> class test_runner
|
||||
{
|
||||
Test const& test_;
|
||||
bool exception_in_check_;
|
||||
|
||||
test_runner(test_runner const&);
|
||||
test_runner& operator=(test_runner const&);
|
||||
|
||||
public:
|
||||
test_runner(Test const& t) : test_(t), exception_in_check_(false) {}
|
||||
void run()
|
||||
{
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::check_instances check;
|
||||
test::scope = "";
|
||||
typename Test::data_type x(test_.init());
|
||||
typename Test::strong_type strong;
|
||||
strong.store(x);
|
||||
try {
|
||||
ENABLE_EXCEPTIONS;
|
||||
call_ignore_extra_parameters<Test, typename Test::data_type,
|
||||
typename Test::strong_type>(&Test::run, test_, x, strong);
|
||||
} catch (...) {
|
||||
try {
|
||||
DISABLE_EXCEPTIONS;
|
||||
call_ignore_extra_parameters<Test, typename Test::data_type const,
|
||||
typename Test::strong_type const>(
|
||||
&Test::check, test_, constant(x), constant(strong));
|
||||
} catch (...) {
|
||||
exception_in_check_ = true;
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
void end()
|
||||
{
|
||||
if (exception_in_check_) {
|
||||
BOOST_ERROR("Unexcpected exception in test_runner check call.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Quick exception testing based on lightweight test
|
||||
|
||||
namespace lightweight {
|
||||
static int iteration;
|
||||
static int count;
|
||||
|
||||
struct test_exception
|
||||
{
|
||||
char const* name;
|
||||
test_exception(char const* n) : name(n) {}
|
||||
};
|
||||
|
||||
struct test_failure
|
||||
{
|
||||
};
|
||||
|
||||
void epoint(char const* name)
|
||||
{
|
||||
++count;
|
||||
if (count == iteration) {
|
||||
throw test_exception(name);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Test>
|
||||
class test_runner
|
||||
void exception_safety(Test const& f, char const* /*name*/)
|
||||
{
|
||||
Test const& test_;
|
||||
test_runner<Test> runner(f);
|
||||
|
||||
test_runner(test_runner const&);
|
||||
test_runner& operator=(test_runner const&);
|
||||
public:
|
||||
test_runner(Test const& t) : test_(t) {}
|
||||
void operator()() const {
|
||||
DISABLE_EXCEPTIONS;
|
||||
test::scope = "";
|
||||
BOOST_DEDUCED_TYPENAME Test::data_type x(test_.init());
|
||||
BOOST_DEDUCED_TYPENAME Test::strong_type strong;
|
||||
strong.store(x);
|
||||
try {
|
||||
ENABLE_EXCEPTIONS;
|
||||
call_ignore_extra_parameters<
|
||||
Test,
|
||||
BOOST_DEDUCED_TYPENAME Test::data_type,
|
||||
BOOST_DEDUCED_TYPENAME Test::strong_type
|
||||
>(&Test::run, test_, x, strong);
|
||||
}
|
||||
catch(...) {
|
||||
call_ignore_extra_parameters<
|
||||
Test,
|
||||
BOOST_DEDUCED_TYPENAME Test::data_type const,
|
||||
BOOST_DEDUCED_TYPENAME Test::strong_type const
|
||||
>(&Test::check, test_, constant(x), constant(strong));
|
||||
throw;
|
||||
}
|
||||
iteration = 0;
|
||||
bool success = false;
|
||||
unsigned int failure_count = 0;
|
||||
char const* error_msg = 0;
|
||||
do {
|
||||
int error_count = boost::detail::test_errors();
|
||||
++iteration;
|
||||
count = 0;
|
||||
|
||||
try {
|
||||
runner.run();
|
||||
success = true;
|
||||
} catch (test_failure) {
|
||||
error_msg = "test_failure caught.";
|
||||
break;
|
||||
} catch (test_exception e) {
|
||||
if (error_count != boost::detail::test_errors()) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM
|
||||
<< "Iteration: " << iteration
|
||||
<< " Error found for epoint: " << e.name << std::endl;
|
||||
}
|
||||
} catch (...) {
|
||||
error_msg = "Unexpected exception.";
|
||||
break;
|
||||
}
|
||||
|
||||
if (error_count != boost::detail::test_errors()) {
|
||||
++failure_count;
|
||||
}
|
||||
} while (!success && failure_count < 5);
|
||||
|
||||
if (error_msg) {
|
||||
BOOST_ERROR(error_msg);
|
||||
}
|
||||
runner.end();
|
||||
}
|
||||
|
||||
//
|
||||
// An alternative way to run exception tests.
|
||||
// See merge_exception_tests.cpp for an example.
|
||||
|
||||
struct exception_looper
|
||||
{
|
||||
bool success;
|
||||
unsigned int failure_count;
|
||||
char const* error_msg;
|
||||
int error_count;
|
||||
|
||||
exception_looper() : success(false), failure_count(0), error_msg(0) {}
|
||||
|
||||
void start() { iteration = 0; }
|
||||
|
||||
bool loop_condition() const
|
||||
{
|
||||
return !error_msg && !success && failure_count < 5;
|
||||
}
|
||||
|
||||
void start_iteration()
|
||||
{
|
||||
error_count = boost::detail::test_errors();
|
||||
++iteration;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
void successful_run() { success = true; }
|
||||
|
||||
void test_failure_caught(test_failure const&)
|
||||
{
|
||||
error_msg = "test_failure caught.";
|
||||
}
|
||||
|
||||
void test_exception_caught(test_exception const& e)
|
||||
{
|
||||
if (error_count != boost::detail::test_errors()) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM
|
||||
<< "Iteration: " << iteration
|
||||
<< " Error found for epoint: " << e.name << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void unexpected_exception_caught()
|
||||
{
|
||||
error_msg = "Unexpected exception.";
|
||||
}
|
||||
|
||||
void end()
|
||||
{
|
||||
if (error_msg) {
|
||||
BOOST_ERROR(error_msg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Quick exception testing based on lightweight test
|
||||
|
||||
namespace lightweight {
|
||||
static int iteration;
|
||||
static int count;
|
||||
|
||||
struct test_exception {
|
||||
char const* name;
|
||||
test_exception(char const* n) : name(n) {}
|
||||
};
|
||||
|
||||
struct test_failure {
|
||||
};
|
||||
|
||||
void epoint(char const* name) {
|
||||
++count;
|
||||
if(count == iteration) {
|
||||
throw test_exception(name);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Test>
|
||||
void exception_safety(Test const& f, char const* /*name*/) {
|
||||
test_runner<Test> runner(f);
|
||||
|
||||
iteration = 0;
|
||||
bool success = false;
|
||||
do {
|
||||
++iteration;
|
||||
count = 0;
|
||||
|
||||
try {
|
||||
runner();
|
||||
success = true;
|
||||
}
|
||||
catch(test_failure) {
|
||||
BOOST_ERROR("test_failure caught.");
|
||||
break;
|
||||
}
|
||||
catch(test_exception) {
|
||||
continue;
|
||||
}
|
||||
catch(...) {
|
||||
BOOST_ERROR("Unexpected exception.");
|
||||
break;
|
||||
}
|
||||
} while(!success);
|
||||
}
|
||||
}
|
||||
#define EXCEPTION_LOOP(op) \
|
||||
test::lightweight::exception_looper looper; \
|
||||
looper.start(); \
|
||||
while (looper.loop_condition()) { \
|
||||
looper.start_iteration(); \
|
||||
try { \
|
||||
op; \
|
||||
looper.successful_run(); \
|
||||
} catch (test::lightweight::test_failure e) { \
|
||||
looper.test_failure_caught(e); \
|
||||
} catch (test::lightweight::test_exception e) { \
|
||||
looper.test_exception_caught(e); \
|
||||
} catch (...) { \
|
||||
looper.unexpected_exception_caught(); \
|
||||
} \
|
||||
} \
|
||||
looper.end();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -8,17 +8,25 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace test
|
||||
{
|
||||
int generate(int const*);
|
||||
char generate(char const*);
|
||||
signed char generate(signed char const*);
|
||||
std::string generate(std::string*);
|
||||
float generate(float const*);
|
||||
namespace test {
|
||||
typedef enum {
|
||||
default_generator,
|
||||
generate_collisions,
|
||||
limited_range
|
||||
} random_generator;
|
||||
|
||||
struct base_type {} base;
|
||||
struct derived_type : base_type {} derived;
|
||||
int generate(int const*, random_generator);
|
||||
char generate(char const*, random_generator);
|
||||
signed char generate(signed char const*, random_generator);
|
||||
std::string generate(std::string const*, random_generator);
|
||||
float generate(float const*, random_generator);
|
||||
|
||||
struct base_type
|
||||
{
|
||||
} base;
|
||||
struct derived_type : base_type
|
||||
{
|
||||
} derived;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -11,60 +11,83 @@
|
||||
#if !defined(BOOST_UNORDERED_TEST_HELPERS_GENERATORS_HEADER)
|
||||
#define BOOST_UNORDERED_TEST_HELPERS_GENERATORS_HEADER
|
||||
|
||||
#include "./fwd.hpp"
|
||||
#include <boost/type_traits/add_const.hpp>
|
||||
#include <cstdlib>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <stdexcept>
|
||||
#include <cstdlib>
|
||||
#include <boost/type_traits/add_const.hpp>
|
||||
#include "./fwd.hpp"
|
||||
|
||||
namespace test
|
||||
{
|
||||
struct seed_t {
|
||||
seed_t(unsigned int x) {
|
||||
using namespace std;
|
||||
srand(x);
|
||||
}
|
||||
};
|
||||
|
||||
inline int generate(int const*)
|
||||
namespace test {
|
||||
struct seed_t
|
||||
{
|
||||
seed_t(unsigned int x)
|
||||
{
|
||||
using namespace std;
|
||||
return rand();
|
||||
using namespace std;
|
||||
srand(x);
|
||||
}
|
||||
};
|
||||
|
||||
std::size_t random_value(std::size_t max)
|
||||
{
|
||||
using namespace std;
|
||||
return static_cast<std::size_t>(rand()) % max;
|
||||
}
|
||||
|
||||
inline int generate(int const*, random_generator g)
|
||||
{
|
||||
using namespace std;
|
||||
int value = rand();
|
||||
if (g == limited_range) {
|
||||
value = value % 100;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
inline char generate(char const*, random_generator)
|
||||
{
|
||||
using namespace std;
|
||||
return static_cast<char>((rand() >> 1) % (128 - 32) + 32);
|
||||
}
|
||||
|
||||
inline signed char generate(signed char const*, random_generator)
|
||||
{
|
||||
using namespace std;
|
||||
return static_cast<signed char>(rand());
|
||||
}
|
||||
|
||||
inline std::string generate(std::string const*, random_generator g)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
char* char_ptr = 0;
|
||||
|
||||
std::string result;
|
||||
|
||||
if (g == limited_range) {
|
||||
std::size_t length = test::random_value(2) + 2;
|
||||
|
||||
char const* strings[] = {"'vZh(3~ms", "%m", "_Y%U", "N'Y", "4,J_J"};
|
||||
for (std::size_t i = 0; i < length; ++i) {
|
||||
result += strings[random_value(sizeof(strings) / sizeof(strings[0]))];
|
||||
}
|
||||
} else {
|
||||
std::size_t length = test::random_value(10) + 1;
|
||||
for (std::size_t i = 0; i < length; ++i) {
|
||||
result += generate(char_ptr, g);
|
||||
}
|
||||
}
|
||||
|
||||
inline char generate(char const*)
|
||||
{
|
||||
using namespace std;
|
||||
return static_cast<char>((rand() >> 1) % (128-32) + 32);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline signed char generate(signed char const*)
|
||||
{
|
||||
using namespace std;
|
||||
return static_cast<signed char>(rand());
|
||||
}
|
||||
|
||||
inline std::string generate(std::string const*)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
char* char_ptr = 0;
|
||||
|
||||
std::string result;
|
||||
|
||||
int length = rand() % 10;
|
||||
for(int i = 0; i < length; ++i)
|
||||
result += generate(char_ptr);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
float generate(float const*)
|
||||
{
|
||||
using namespace std;
|
||||
return (float) rand() / (float) RAND_MAX;
|
||||
}
|
||||
float generate(float const*, random_generator g)
|
||||
{
|
||||
using namespace std;
|
||||
int x = 0;
|
||||
int value = generate(&x, g);
|
||||
return (float)value / (float)RAND_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -6,38 +6,51 @@
|
||||
#if !defined(BOOST_UNORDERED_TEST_HELPERS_HEADER)
|
||||
#define BOOST_UNORDERED_TEST_HELPERS_HEADER
|
||||
|
||||
namespace test
|
||||
{
|
||||
template <class Container>
|
||||
struct get_key_impl
|
||||
#include <iterator>
|
||||
|
||||
namespace test {
|
||||
template <class Container> struct get_key_impl
|
||||
{
|
||||
typedef typename Container::key_type key_type;
|
||||
|
||||
static key_type const& get_key(key_type const& x) { return x; }
|
||||
|
||||
template <class T>
|
||||
static key_type const& get_key(std::pair<key_type, T> const& x, char = 0)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME Container::key_type key_type;
|
||||
|
||||
static key_type const& get_key(key_type const& x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static key_type const& get_key(
|
||||
std::pair<key_type, T> const& x, char = 0)
|
||||
{
|
||||
return x.first;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static key_type const& get_key(std::pair<key_type const, T> const& x,
|
||||
unsigned char = 0)
|
||||
{
|
||||
return x.first;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Container, class T>
|
||||
inline BOOST_DEDUCED_TYPENAME Container::key_type const& get_key(T const& x)
|
||||
{
|
||||
return get_key_impl<Container>::get_key(x);
|
||||
return x.first;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static key_type const& get_key(
|
||||
std::pair<key_type const, T> const& x, unsigned char = 0)
|
||||
{
|
||||
return x.first;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Container, class T>
|
||||
inline typename Container::key_type const& get_key(T const& x)
|
||||
{
|
||||
return get_key_impl<Container>::get_key(x);
|
||||
}
|
||||
|
||||
// test::next
|
||||
//
|
||||
// Increments an iterator by 1 or a given value.
|
||||
// Like boost::next, but simpler.
|
||||
// Mainly because boost::next uses an MPL file
|
||||
// which causes warnings.
|
||||
|
||||
template <typename Iterator> Iterator next(Iterator it) { return ++it; }
|
||||
|
||||
template <typename Iterator, typename IntType>
|
||||
Iterator next(Iterator it, IntType x)
|
||||
{
|
||||
std::advance(it,
|
||||
static_cast<typename std::iterator_traits<Iterator>::difference_type>(x));
|
||||
return it;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -7,159 +7,159 @@
|
||||
#define BOOST_UNORDERED_TEST_HELPERS_INPUT_ITERATOR_HEADER
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/iterator.hpp>
|
||||
#include <boost/iterator/iterator_traits.hpp>
|
||||
#include <iterator>
|
||||
|
||||
namespace test
|
||||
{
|
||||
template <class Iterator>
|
||||
struct proxy
|
||||
namespace test {
|
||||
template <class Iterator> struct proxy
|
||||
{
|
||||
typedef typename Iterator::value_type value_type;
|
||||
|
||||
explicit proxy(value_type const& v) : v_(v) {}
|
||||
proxy(proxy const& x) : v_(x.v_) {}
|
||||
operator value_type const&() const { return v_; }
|
||||
|
||||
value_type v_;
|
||||
|
||||
private:
|
||||
proxy& operator=(proxy const&);
|
||||
};
|
||||
|
||||
template <class Iterator> struct input_iterator_adaptor
|
||||
{
|
||||
typedef typename std::iterator_traits<Iterator>::value_type value_type;
|
||||
typedef typename std::iterator_traits<Iterator>::pointer pointer;
|
||||
typedef proxy<Iterator> reference;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::input_iterator_tag iterator_category;
|
||||
|
||||
input_iterator_adaptor() : base_() {}
|
||||
explicit input_iterator_adaptor(Iterator& it) : base_(&it) {}
|
||||
proxy<Iterator> operator*() const { return proxy<Iterator>(**base_); }
|
||||
value_type* operator->() const { return &**base_; }
|
||||
input_iterator_adaptor& operator++()
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME Iterator::value_type value_type;
|
||||
|
||||
explicit proxy(value_type const& v) : v_(v) {}
|
||||
proxy(proxy const& x) : v_(x.v_) {}
|
||||
operator value_type const&() const { return v_; }
|
||||
|
||||
value_type v_;
|
||||
private:
|
||||
proxy& operator=(proxy const&);
|
||||
};
|
||||
|
||||
template <class Iterator>
|
||||
struct input_iterator_adaptor
|
||||
: public boost::iterator<
|
||||
std::input_iterator_tag,
|
||||
BOOST_DEDUCED_TYPENAME boost::iterator_value<Iterator>::type,
|
||||
std::ptrdiff_t,
|
||||
BOOST_DEDUCED_TYPENAME boost::iterator_pointer<Iterator>::type,
|
||||
proxy<Iterator>
|
||||
>
|
||||
++*base_;
|
||||
return *this;
|
||||
}
|
||||
// input_iterator_adaptor operator++(int) {
|
||||
//}
|
||||
bool operator==(input_iterator_adaptor const& x) const
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::iterator_value<Iterator>::type
|
||||
value_type;
|
||||
|
||||
input_iterator_adaptor()
|
||||
: base_() {}
|
||||
explicit input_iterator_adaptor(Iterator& it)
|
||||
: base_(&it) {}
|
||||
proxy<Iterator> operator*() const {
|
||||
return proxy<Iterator>(**base_);
|
||||
}
|
||||
value_type* operator->() const {
|
||||
return &**base_;
|
||||
}
|
||||
input_iterator_adaptor& operator++() {
|
||||
++*base_; return *this;
|
||||
}
|
||||
//input_iterator_adaptor operator++(int) {
|
||||
//}
|
||||
bool operator==(input_iterator_adaptor const& x) const {
|
||||
return *base_ == *x.base_;
|
||||
}
|
||||
bool operator!=(input_iterator_adaptor const& x) const {
|
||||
return *base_ != *x.base_;
|
||||
}
|
||||
private:
|
||||
Iterator* base_;
|
||||
};
|
||||
|
||||
template <class Iterator>
|
||||
input_iterator_adaptor<Iterator> input_iterator(Iterator& it)
|
||||
return *base_ == *x.base_;
|
||||
}
|
||||
bool operator!=(input_iterator_adaptor const& x) const
|
||||
{
|
||||
return input_iterator_adaptor<Iterator>(it);
|
||||
return *base_ != *x.base_;
|
||||
}
|
||||
|
||||
template <class Iterator>
|
||||
struct copy_iterator_adaptor
|
||||
: public boost::iterator<
|
||||
BOOST_DEDUCED_TYPENAME boost::iterator_category<Iterator>::type,
|
||||
BOOST_DEDUCED_TYPENAME boost::iterator_value<Iterator>::type,
|
||||
BOOST_DEDUCED_TYPENAME boost::iterator_difference<Iterator>::type,
|
||||
BOOST_DEDUCED_TYPENAME boost::iterator_pointer<Iterator>::type,
|
||||
proxy<Iterator>
|
||||
>
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::iterator_value<Iterator>::type
|
||||
value_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME boost::iterator_difference<Iterator>::type
|
||||
difference_type;
|
||||
|
||||
copy_iterator_adaptor()
|
||||
: base_() {}
|
||||
explicit copy_iterator_adaptor(Iterator const& it)
|
||||
: base_(it) {}
|
||||
value_type operator*() const {
|
||||
return *base_;
|
||||
}
|
||||
value_type* operator->() const {
|
||||
return &*base_;
|
||||
}
|
||||
value_type operator[](difference_type d) {
|
||||
return base_[d];
|
||||
}
|
||||
copy_iterator_adaptor& operator++() {
|
||||
++base_; return *this;
|
||||
}
|
||||
copy_iterator_adaptor operator++(int) {
|
||||
copy_iterator_adaptor tmp(*this); ++base_; return tmp;
|
||||
}
|
||||
copy_iterator_adaptor& operator--() {
|
||||
--base_; return *this;
|
||||
}
|
||||
copy_iterator_adaptor operator--(int) {
|
||||
copy_iterator_adaptor tmp(*this); --base_; return tmp;
|
||||
}
|
||||
copy_iterator_adaptor operator+=(difference_type x) {
|
||||
base_ += x;
|
||||
return *this;
|
||||
}
|
||||
copy_iterator_adaptor operator-=(difference_type x) {
|
||||
base_ -= x;
|
||||
return *this;
|
||||
}
|
||||
copy_iterator_adaptor operator+(difference_type n) {
|
||||
return copy_iterator_adaptor(base_+n);
|
||||
}
|
||||
copy_iterator_adaptor operator-(difference_type n) {
|
||||
return copy_iterator_adaptor(base_-n);
|
||||
}
|
||||
friend copy_iterator_adaptor operator+(
|
||||
difference_type n, copy_iterator_adaptor x) {
|
||||
return x+n;
|
||||
}
|
||||
difference_type operator-(copy_iterator_adaptor const& other) {
|
||||
return base_-other.base_;
|
||||
}
|
||||
bool operator==(copy_iterator_adaptor const& x) const {
|
||||
return base_ == x.base_;
|
||||
}
|
||||
bool operator!=(copy_iterator_adaptor const& x) const {
|
||||
return base_ != x.base_;
|
||||
}
|
||||
bool operator<(copy_iterator_adaptor const& x) const {
|
||||
return base_ < x.base_;
|
||||
}
|
||||
bool operator>(copy_iterator_adaptor const& x) const {
|
||||
return base_ > x.base_;
|
||||
}
|
||||
bool operator<=(copy_iterator_adaptor const& x) const {
|
||||
return base_ <= x.base_;
|
||||
}
|
||||
bool operator>=(copy_iterator_adaptor const& x) const {
|
||||
return base_ >= x.base_;
|
||||
}
|
||||
private:
|
||||
Iterator base_;
|
||||
};
|
||||
private:
|
||||
Iterator* base_;
|
||||
};
|
||||
|
||||
template <class Iterator>
|
||||
copy_iterator_adaptor<Iterator> copy_iterator(Iterator const& it)
|
||||
template <class Iterator>
|
||||
input_iterator_adaptor<Iterator> input_iterator(Iterator& it)
|
||||
{
|
||||
return input_iterator_adaptor<Iterator>(it);
|
||||
}
|
||||
|
||||
template <class Iterator> struct copy_iterator_adaptor
|
||||
{
|
||||
typedef typename std::iterator_traits<Iterator>::value_type value_type;
|
||||
typedef
|
||||
typename std::iterator_traits<Iterator>::difference_type difference_type;
|
||||
typedef typename std::iterator_traits<Iterator>::iterator_category
|
||||
iterator_category;
|
||||
typedef typename std::iterator_traits<Iterator>::pointer pointer;
|
||||
typedef proxy<Iterator> reference;
|
||||
|
||||
copy_iterator_adaptor() : base_() {}
|
||||
explicit copy_iterator_adaptor(Iterator const& it) : base_(it) {}
|
||||
value_type operator*() const { return *base_; }
|
||||
value_type* operator->() const { return &*base_; }
|
||||
value_type operator[](difference_type d) { return base_[d]; }
|
||||
copy_iterator_adaptor& operator++()
|
||||
{
|
||||
return copy_iterator_adaptor<Iterator>(it);
|
||||
++base_;
|
||||
return *this;
|
||||
}
|
||||
copy_iterator_adaptor operator++(int)
|
||||
{
|
||||
copy_iterator_adaptor tmp(*this);
|
||||
++base_;
|
||||
return tmp;
|
||||
}
|
||||
copy_iterator_adaptor& operator--()
|
||||
{
|
||||
--base_;
|
||||
return *this;
|
||||
}
|
||||
copy_iterator_adaptor operator--(int)
|
||||
{
|
||||
copy_iterator_adaptor tmp(*this);
|
||||
--base_;
|
||||
return tmp;
|
||||
}
|
||||
copy_iterator_adaptor operator+=(difference_type x)
|
||||
{
|
||||
base_ += x;
|
||||
return *this;
|
||||
}
|
||||
copy_iterator_adaptor operator-=(difference_type x)
|
||||
{
|
||||
base_ -= x;
|
||||
return *this;
|
||||
}
|
||||
copy_iterator_adaptor operator+(difference_type n)
|
||||
{
|
||||
return copy_iterator_adaptor(base_ + n);
|
||||
}
|
||||
copy_iterator_adaptor operator-(difference_type n)
|
||||
{
|
||||
return copy_iterator_adaptor(base_ - n);
|
||||
}
|
||||
friend copy_iterator_adaptor operator+(
|
||||
difference_type n, copy_iterator_adaptor x)
|
||||
{
|
||||
return x + n;
|
||||
}
|
||||
difference_type operator-(copy_iterator_adaptor const& other)
|
||||
{
|
||||
return base_ - other.base_;
|
||||
}
|
||||
bool operator==(copy_iterator_adaptor const& x) const
|
||||
{
|
||||
return base_ == x.base_;
|
||||
}
|
||||
bool operator!=(copy_iterator_adaptor const& x) const
|
||||
{
|
||||
return base_ != x.base_;
|
||||
}
|
||||
bool operator<(copy_iterator_adaptor const& x) const
|
||||
{
|
||||
return base_ < x.base_;
|
||||
}
|
||||
bool operator>(copy_iterator_adaptor const& x) const
|
||||
{
|
||||
return base_ > x.base_;
|
||||
}
|
||||
bool operator<=(copy_iterator_adaptor const& x) const
|
||||
{
|
||||
return base_ <= x.base_;
|
||||
}
|
||||
bool operator>=(copy_iterator_adaptor const& x) const
|
||||
{
|
||||
return base_ >= x.base_;
|
||||
}
|
||||
|
||||
private:
|
||||
Iterator base_;
|
||||
};
|
||||
|
||||
template <class Iterator>
|
||||
copy_iterator_adaptor<Iterator> copy_iterator(Iterator const& it)
|
||||
{
|
||||
return copy_iterator_adaptor<Iterator>(it);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -9,113 +9,118 @@
|
||||
#if !defined(BOOST_UNORDERED_TEST_HELPERS_INVARIANT_HEADER)
|
||||
#define BOOST_UNORDERED_TEST_HELPERS_INVARIANT_HEADER
|
||||
|
||||
#include <set>
|
||||
#include <cmath>
|
||||
#include "./metafunctions.hpp"
|
||||
#include "./helpers.hpp"
|
||||
#include "./metafunctions.hpp"
|
||||
#include <cmath>
|
||||
#include <set>
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127) // conditional expression is constant
|
||||
#pragma warning(disable:4267) // conversion from 'size_t' to 'unsigned int',
|
||||
#pragma warning(disable : 4127) // conditional expression is constant
|
||||
#pragma warning(disable : 4267) // conversion from 'size_t' to 'unsigned int',
|
||||
// possible loss of data
|
||||
#endif
|
||||
|
||||
namespace test
|
||||
{
|
||||
template <class X>
|
||||
void check_equivalent_keys(X const& x1)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME X::key_equal eq = x1.key_eq();
|
||||
typedef BOOST_DEDUCED_TYPENAME X::key_type key_type;
|
||||
std::set<key_type, std::less<key_type> > found_;
|
||||
namespace test {
|
||||
template <class X> void check_equivalent_keys(X const& x1)
|
||||
{
|
||||
typename X::key_equal eq = x1.key_eq();
|
||||
typedef typename X::key_type key_type;
|
||||
std::set<key_type, std::less<key_type> > found_;
|
||||
|
||||
BOOST_DEDUCED_TYPENAME X::const_iterator
|
||||
it = x1.begin(), end = x1.end();
|
||||
BOOST_DEDUCED_TYPENAME X::size_type size = 0;
|
||||
while(it != end) {
|
||||
// First test that the current key has not occurred before, required
|
||||
// to test either that keys are unique or that equivalent keys are
|
||||
// adjacent. (6.3.1/6)
|
||||
key_type key = get_key<X>(*it);
|
||||
if(!found_.insert(key).second)
|
||||
BOOST_ERROR("Elements with equivalent keys aren't adjacent.");
|
||||
typename X::const_iterator it = x1.begin(), end = x1.end();
|
||||
typename X::size_type size = 0;
|
||||
while (it != end) {
|
||||
// First test that the current key has not occurred before, required
|
||||
// to test either that keys are unique or that equivalent keys are
|
||||
// adjacent. (6.3.1/6)
|
||||
key_type key = get_key<X>(*it);
|
||||
if (!found_.insert(key).second)
|
||||
BOOST_ERROR("Elements with equivalent keys aren't adjacent.");
|
||||
|
||||
// Iterate over equivalent keys, counting them.
|
||||
unsigned int count = 0;
|
||||
do {
|
||||
++it;
|
||||
++count;
|
||||
++size;
|
||||
} while(it != end && eq(get_key<X>(*it), key));
|
||||
// Iterate over equivalent keys, counting them.
|
||||
unsigned int count = 0;
|
||||
do {
|
||||
++it;
|
||||
++count;
|
||||
++size;
|
||||
} while (it != end && eq(get_key<X>(*it), key));
|
||||
|
||||
// If the container has unique keys, test that there's only one.
|
||||
// Since the previous test makes sure that all equivalent keys are
|
||||
// adjacent, this is all the equivalent keys - so the test is
|
||||
// sufficient. (6.3.1/6 again).
|
||||
if(test::has_unique_keys<X>::value && count != 1)
|
||||
BOOST_ERROR("Non-unique key.");
|
||||
// If the container has unique keys, test that there's only one.
|
||||
// Since the previous test makes sure that all equivalent keys are
|
||||
// adjacent, this is all the equivalent keys - so the test is
|
||||
// sufficient. (6.3.1/6 again).
|
||||
if (test::has_unique_keys<X>::value && count != 1)
|
||||
BOOST_ERROR("Non-unique key.");
|
||||
|
||||
if(x1.count(key) != count) {
|
||||
BOOST_ERROR("Incorrect output of count.");
|
||||
std::cerr<<x1.count(key)<<","<<count<<"\n";
|
||||
}
|
||||
if (x1.count(key) != count) {
|
||||
BOOST_ERROR("Incorrect output of count.");
|
||||
std::cerr << x1.count(key) << "," << count << "\n";
|
||||
}
|
||||
|
||||
// Check that the keys are in the correct bucket and are
|
||||
// adjacent in the bucket.
|
||||
BOOST_DEDUCED_TYPENAME X::size_type bucket = x1.bucket(key);
|
||||
BOOST_DEDUCED_TYPENAME X::const_local_iterator
|
||||
lit = x1.begin(bucket), lend = x1.end(bucket);
|
||||
for(; lit != lend && !eq(get_key<X>(*lit), key); ++lit) continue;
|
||||
if(lit == lend)
|
||||
BOOST_ERROR("Unable to find element with a local_iterator");
|
||||
unsigned int count2 = 0;
|
||||
for(; lit != lend && eq(get_key<X>(*lit), key); ++lit) ++count2;
|
||||
if(count != count2)
|
||||
BOOST_ERROR("Element count doesn't match local_iterator.");
|
||||
for(; lit != lend; ++lit) {
|
||||
if(eq(get_key<X>(*lit), key)) {
|
||||
BOOST_ERROR("Non-adjacent element with equivalent key "
|
||||
// Check that the keys are in the correct bucket and are
|
||||
// adjacent in the bucket.
|
||||
typename X::size_type bucket = x1.bucket(key);
|
||||
typename X::const_local_iterator lit = x1.begin(bucket),
|
||||
lend = x1.end(bucket);
|
||||
|
||||
unsigned int count_checked = 0;
|
||||
for (; lit != lend && !eq(get_key<X>(*lit), key); ++lit) {
|
||||
++count_checked;
|
||||
}
|
||||
|
||||
if (lit == lend) {
|
||||
BOOST_ERROR("Unable to find element with a local_iterator");
|
||||
std::cerr << "Checked: " << count_checked << " elements" << std::endl;
|
||||
} else {
|
||||
unsigned int count2 = 0;
|
||||
for (; lit != lend && eq(get_key<X>(*lit), key); ++lit)
|
||||
++count2;
|
||||
if (count != count2)
|
||||
BOOST_ERROR("Element count doesn't match local_iterator.");
|
||||
for (; lit != lend; ++lit) {
|
||||
if (eq(get_key<X>(*lit), key)) {
|
||||
BOOST_ERROR("Non-adjacent element with equivalent key "
|
||||
"in bucket.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Check that size matches up.
|
||||
|
||||
if(x1.size() != size) {
|
||||
BOOST_ERROR("x1.size() doesn't match actual size.");
|
||||
std::cout<<x1.size()<<"/"<<size<<std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Check the load factor.
|
||||
// Check that size matches up.
|
||||
|
||||
float load_factor =
|
||||
static_cast<float>(size) / static_cast<float>(x1.bucket_count());
|
||||
using namespace std;
|
||||
if(fabs(x1.load_factor() - load_factor) > x1.load_factor() / 64)
|
||||
BOOST_ERROR("x1.load_factor() doesn't match actual load_factor.");
|
||||
|
||||
// Check that size in the buckets matches up.
|
||||
|
||||
BOOST_DEDUCED_TYPENAME X::size_type bucket_size = 0;
|
||||
|
||||
for (BOOST_DEDUCED_TYPENAME X::size_type
|
||||
i = 0; i < x1.bucket_count(); ++i)
|
||||
{
|
||||
for (BOOST_DEDUCED_TYPENAME X::const_local_iterator
|
||||
begin = x1.begin(i), end = x1.end(i); begin != end; ++begin)
|
||||
{
|
||||
++bucket_size;
|
||||
}
|
||||
}
|
||||
|
||||
if(x1.size() != bucket_size) {
|
||||
BOOST_ERROR("x1.size() doesn't match bucket size.");
|
||||
std::cout<<x1.size()<<"/"<<bucket_size<<std::endl;
|
||||
}
|
||||
if (x1.size() != size) {
|
||||
BOOST_ERROR("x1.size() doesn't match actual size.");
|
||||
std::cout << x1.size() << "/" << size << std::endl;
|
||||
}
|
||||
|
||||
// Check the load factor.
|
||||
|
||||
float load_factor = size == 0 ? 0
|
||||
: static_cast<float>(size) /
|
||||
static_cast<float>(x1.bucket_count());
|
||||
using namespace std;
|
||||
if (fabs(x1.load_factor() - load_factor) > x1.load_factor() / 64)
|
||||
BOOST_ERROR("x1.load_factor() doesn't match actual load_factor.");
|
||||
|
||||
// Check that size in the buckets matches up.
|
||||
|
||||
typename X::size_type bucket_size = 0;
|
||||
|
||||
for (typename X::size_type i = 0; i < x1.bucket_count(); ++i) {
|
||||
for (typename X::const_local_iterator begin2 = x1.begin(i),
|
||||
end2 = x1.end(i);
|
||||
begin2 != end2; ++begin2) {
|
||||
++bucket_size;
|
||||
}
|
||||
}
|
||||
|
||||
if (x1.size() != bucket_size) {
|
||||
BOOST_ERROR("x1.size() doesn't match bucket size.");
|
||||
std::cout << x1.size() << "/" << bucket_size << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
@ -123,4 +128,3 @@ namespace test
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -11,308 +11,317 @@
|
||||
#if !defined(UNORDERED_TEST_LIST_HEADER)
|
||||
#define UNORDERED_TEST_LIST_HEADER
|
||||
|
||||
#include <boost/iterator.hpp>
|
||||
#include <boost/limits.hpp>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
|
||||
namespace test
|
||||
{
|
||||
template <typename It1, typename It2>
|
||||
bool equal(It1 begin, It1 end, It2 compare)
|
||||
namespace test {
|
||||
template <typename It1, typename It2>
|
||||
bool equal(It1 begin, It1 end, It2 compare)
|
||||
{
|
||||
for (; begin != end; ++begin, ++compare)
|
||||
if (*begin != *compare)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename It1, typename It2, typename Pred>
|
||||
bool equal(It1 begin, It1 end, It2 compare, Pred predicate)
|
||||
{
|
||||
for (; begin != end; ++begin, ++compare)
|
||||
if (!predicate(*begin, *compare))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T> class list;
|
||||
|
||||
namespace test_detail {
|
||||
template <typename T> class list_node;
|
||||
template <typename T> class list_data;
|
||||
template <typename T> class list_iterator;
|
||||
template <typename T> class list_const_iterator;
|
||||
|
||||
template <typename T> class list_node
|
||||
{
|
||||
for(;begin != end; ++begin, ++compare)
|
||||
if(*begin != *compare) return false;
|
||||
return true;
|
||||
}
|
||||
list_node(list_node const&);
|
||||
list_node& operator=(list_node const&);
|
||||
|
||||
template <typename It1, typename It2, typename Pred>
|
||||
bool equal(It1 begin, It1 end, It2 compare, Pred predicate)
|
||||
{
|
||||
for(;begin != end; ++begin, ++compare)
|
||||
if(!predicate(*begin, *compare)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template <typename T> class list;
|
||||
|
||||
namespace test_detail
|
||||
{
|
||||
template <typename T> class list_node;
|
||||
template <typename T> class list_data;
|
||||
template <typename T> class list_iterator;
|
||||
template <typename T> class list_const_iterator;
|
||||
|
||||
template <typename T>
|
||||
class list_node
|
||||
{
|
||||
list_node(list_node const&);
|
||||
list_node& operator=(list_node const&);
|
||||
public:
|
||||
T value_;
|
||||
list_node* next_;
|
||||
|
||||
list_node(T const& v) : value_(v), next_(0) {}
|
||||
list_node(T const& v, list_node* n) : value_(v), next_(n) {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class list_data
|
||||
{
|
||||
public:
|
||||
typedef list_node<T> node;
|
||||
typedef unsigned int size_type;
|
||||
|
||||
node* first_;
|
||||
node** last_ptr_;
|
||||
size_type size_;
|
||||
|
||||
list_data() : first_(0), last_ptr_(&first_), size_(0) {}
|
||||
|
||||
~list_data() {
|
||||
while(first_) {
|
||||
node* tmp = first_;
|
||||
first_ = first_->next_;
|
||||
delete tmp;
|
||||
}
|
||||
}
|
||||
private:
|
||||
list_data(list_data const&);
|
||||
list_data& operator=(list_data const&);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class list_iterator
|
||||
: public boost::iterator<
|
||||
std::forward_iterator_tag, T,
|
||||
int, T*, T&>
|
||||
{
|
||||
friend class list_const_iterator<T>;
|
||||
friend class test::list<T>;
|
||||
typedef list_node<T> node;
|
||||
typedef list_const_iterator<T> const_iterator;
|
||||
|
||||
node* ptr_;
|
||||
public:
|
||||
list_iterator() : ptr_(0) {}
|
||||
explicit list_iterator(node* x) : ptr_(x) {}
|
||||
|
||||
T& operator*() const { return ptr_->value_; }
|
||||
T* operator->() const { return &ptr_->value_; }
|
||||
list_iterator& operator++() {
|
||||
ptr_ = ptr_->next_; return *this; }
|
||||
list_iterator operator++(int) {
|
||||
list_iterator tmp = *this; ptr_ = ptr_->next_; return tmp; }
|
||||
bool operator==(const_iterator y) const { return ptr_ == y.ptr_; }
|
||||
bool operator!=(const_iterator y) const { return ptr_ != y.ptr_; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class list_const_iterator
|
||||
: public boost::iterator<
|
||||
std::forward_iterator_tag, T,
|
||||
int, T const*, T const&>
|
||||
{
|
||||
friend class list_iterator<T>;
|
||||
friend class test::list<T>;
|
||||
typedef list_node<T> node;
|
||||
typedef list_iterator<T> iterator;
|
||||
typedef list_const_iterator<T> const_iterator;
|
||||
|
||||
node* ptr_;
|
||||
public:
|
||||
list_const_iterator() : ptr_(0) {}
|
||||
list_const_iterator(list_iterator<T> const& x) : ptr_(x.ptr_) {}
|
||||
|
||||
T const& operator*() const { return ptr_->value_; }
|
||||
T const* operator->() const { return &ptr_->value_; }
|
||||
|
||||
list_const_iterator& operator++()
|
||||
{
|
||||
ptr_ = ptr_->next_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
list_const_iterator operator++(int)
|
||||
{
|
||||
list_const_iterator tmp = *this;
|
||||
ptr_ = ptr_->next_;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator==(const_iterator y) const
|
||||
{
|
||||
return ptr_ == y.ptr_;
|
||||
}
|
||||
|
||||
bool operator!=(const_iterator y) const
|
||||
{
|
||||
return ptr_ != y.ptr_;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class list
|
||||
{
|
||||
typedef test::test_detail::list_data<T> data;
|
||||
typedef test::test_detail::list_node<T> node;
|
||||
data data_;
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef value_type& reference;
|
||||
typedef value_type const& const_reference;
|
||||
typedef unsigned int size_type;
|
||||
T value_;
|
||||
list_node* next_;
|
||||
|
||||
typedef test::test_detail::list_iterator<T> iterator;
|
||||
typedef test::test_detail::list_const_iterator<T> const_iterator;
|
||||
list_node(T const& v) : value_(v), next_(0) {}
|
||||
list_node(T const& v, list_node* n) : value_(v), next_(n) {}
|
||||
};
|
||||
|
||||
list() : data_() {}
|
||||
template <typename T> class list_data
|
||||
{
|
||||
public:
|
||||
typedef list_node<T> node;
|
||||
typedef unsigned int size_type;
|
||||
|
||||
list(list const& other) : data_() {
|
||||
insert(other.begin(), other.end());
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
list(InputIterator i, InputIterator j) : data_() {
|
||||
insert(i, j);
|
||||
}
|
||||
|
||||
list& operator=(list const& other) {
|
||||
clear();
|
||||
insert(other.begin(), other.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator begin() { return iterator(data_.first_); }
|
||||
iterator end() { return iterator(); }
|
||||
const_iterator begin() const { return iterator(data_.first_); }
|
||||
const_iterator end() const { return iterator(); }
|
||||
const_iterator cbegin() const { return iterator(data_.first_); }
|
||||
const_iterator cend() const { return iterator(); }
|
||||
|
||||
template <class InputIterator>
|
||||
void insert(InputIterator i, InputIterator j) {
|
||||
for(; i != j; ++i)
|
||||
push_back(*i);
|
||||
}
|
||||
|
||||
void push_front(value_type const& v) {
|
||||
data_.first_ = new node(v, data_.first_);
|
||||
if(!data_.size_) data_.last_ptr_ = &(*data_.last_ptr_)->next_;
|
||||
++data_.size_;
|
||||
}
|
||||
|
||||
void push_back(value_type const& v) {
|
||||
*data_.last_ptr_ = new node(v);
|
||||
data_.last_ptr_ = &(*data_.last_ptr_)->next_;
|
||||
++data_.size_;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
while(data_.first_) {
|
||||
node* tmp = data_.first_;
|
||||
data_.first_ = data_.first_->next_;
|
||||
--data_.size_;
|
||||
delete tmp;
|
||||
}
|
||||
data_.last_ptr_ = &data_.first_;
|
||||
}
|
||||
|
||||
void erase(const_iterator i, const_iterator j) {
|
||||
node** ptr = &data_.first_;
|
||||
|
||||
while(*ptr != i.ptr_) {
|
||||
ptr = &(*ptr)->next_;
|
||||
}
|
||||
|
||||
while(*ptr != j.ptr_) {
|
||||
node* to_delete = *ptr;
|
||||
*ptr = (*ptr)->next_;
|
||||
--data_.size_;
|
||||
delete to_delete;
|
||||
}
|
||||
|
||||
if(!*ptr) data_.last_ptr_ = ptr;
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return !data_.size_;
|
||||
}
|
||||
|
||||
size_type size() const {
|
||||
return data_.size_;
|
||||
}
|
||||
|
||||
void sort() {
|
||||
sort(std::less<T>());
|
||||
}
|
||||
|
||||
template <typename Less>
|
||||
void sort(Less less = Less()) {
|
||||
if(!empty()) merge_sort(&data_.first_,
|
||||
(std::numeric_limits<size_type>::max)(), less);
|
||||
}
|
||||
|
||||
bool operator==(list const& y) const {
|
||||
return size() == y.size() &&
|
||||
test::equal(begin(), end(), y.begin());
|
||||
}
|
||||
|
||||
bool operator!=(list const& y) const {
|
||||
return !(*this == y);
|
||||
node* first_;
|
||||
node** last_ptr_;
|
||||
size_type size_;
|
||||
|
||||
list_data() : first_(0), last_ptr_(&first_), size_(0) {}
|
||||
|
||||
~list_data()
|
||||
{
|
||||
while (first_) {
|
||||
node* tmp = first_;
|
||||
first_ = first_->next_;
|
||||
delete tmp;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Less>
|
||||
node** merge_sort(node** l, size_type recurse_limit, Less less)
|
||||
{
|
||||
node** ptr = &(*l)->next_;
|
||||
for(size_type count = 0; count < recurse_limit && *ptr; ++count)
|
||||
{
|
||||
ptr = merge_adjacent_ranges(l, ptr,
|
||||
merge_sort(ptr, count, less), less);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template <typename Less>
|
||||
node** merge_adjacent_ranges(node** first, node** second,
|
||||
node** third, Less less)
|
||||
{
|
||||
for(;;) {
|
||||
for(;;) {
|
||||
if(first == second) return third;
|
||||
if(less((*second)->value_, (*first)->value_)) break;
|
||||
first = &(*first)->next_;
|
||||
}
|
||||
|
||||
swap_adjacent_ranges(first, second, third);
|
||||
first = &(*first)->next_;
|
||||
|
||||
// Since the two ranges we just swapped, the order is now:
|
||||
// first...third...second
|
||||
|
||||
for(;;) {
|
||||
if(first == third) return second;
|
||||
if(!less((*first)->value_, (*third)->value_)) break;
|
||||
first = &(*first)->next_;
|
||||
}
|
||||
|
||||
swap_adjacent_ranges(first, third, second);
|
||||
first = &(*first)->next_;
|
||||
}
|
||||
}
|
||||
|
||||
void swap_adjacent_ranges(node** first, node** second, node** third)
|
||||
{
|
||||
node* tmp = *first;
|
||||
*first = *second;
|
||||
*second = *third;
|
||||
*third = tmp;
|
||||
if(!*second) data_.last_ptr_ = second;
|
||||
}
|
||||
list_data(list_data const&);
|
||||
list_data& operator=(list_data const&);
|
||||
};
|
||||
|
||||
template <typename T> class list_iterator
|
||||
{
|
||||
friend class list_const_iterator<T>;
|
||||
friend class test::list<T>;
|
||||
typedef list_node<T> node;
|
||||
typedef list_const_iterator<T> const_iterator;
|
||||
|
||||
node* ptr_;
|
||||
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef T* pointer;
|
||||
typedef T& reference;
|
||||
typedef int difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
list_iterator() : ptr_(0) {}
|
||||
explicit list_iterator(node* x) : ptr_(x) {}
|
||||
|
||||
T& operator*() const { return ptr_->value_; }
|
||||
T* operator->() const { return &ptr_->value_; }
|
||||
list_iterator& operator++()
|
||||
{
|
||||
ptr_ = ptr_->next_;
|
||||
return *this;
|
||||
}
|
||||
list_iterator operator++(int)
|
||||
{
|
||||
list_iterator tmp = *this;
|
||||
ptr_ = ptr_->next_;
|
||||
return tmp;
|
||||
}
|
||||
bool operator==(const_iterator y) const { return ptr_ == y.ptr_; }
|
||||
bool operator!=(const_iterator y) const { return ptr_ != y.ptr_; }
|
||||
};
|
||||
|
||||
template <typename T> class list_const_iterator
|
||||
{
|
||||
friend class list_iterator<T>;
|
||||
friend class test::list<T>;
|
||||
typedef list_node<T> node;
|
||||
typedef list_iterator<T> iterator;
|
||||
typedef list_const_iterator<T> const_iterator;
|
||||
|
||||
node* ptr_;
|
||||
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef T const* pointer;
|
||||
typedef T const& reference;
|
||||
typedef int difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
list_const_iterator() : ptr_(0) {}
|
||||
list_const_iterator(list_iterator<T> const& x) : ptr_(x.ptr_) {}
|
||||
|
||||
T const& operator*() const { return ptr_->value_; }
|
||||
T const* operator->() const { return &ptr_->value_; }
|
||||
|
||||
list_const_iterator& operator++()
|
||||
{
|
||||
ptr_ = ptr_->next_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
list_const_iterator operator++(int)
|
||||
{
|
||||
list_const_iterator tmp = *this;
|
||||
ptr_ = ptr_->next_;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator==(const_iterator y) const { return ptr_ == y.ptr_; }
|
||||
|
||||
bool operator!=(const_iterator y) const { return ptr_ != y.ptr_; }
|
||||
};
|
||||
}
|
||||
|
||||
template <typename T> class list
|
||||
{
|
||||
typedef test::test_detail::list_data<T> data;
|
||||
typedef test::test_detail::list_node<T> node;
|
||||
data data_;
|
||||
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef value_type& reference;
|
||||
typedef value_type const& const_reference;
|
||||
typedef unsigned int size_type;
|
||||
|
||||
typedef test::test_detail::list_iterator<T> iterator;
|
||||
typedef test::test_detail::list_const_iterator<T> const_iterator;
|
||||
|
||||
list() : data_() {}
|
||||
|
||||
list(list const& other) : data_() { insert(other.begin(), other.end()); }
|
||||
|
||||
template <class InputIterator>
|
||||
list(InputIterator i, InputIterator j) : data_()
|
||||
{
|
||||
insert(i, j);
|
||||
}
|
||||
|
||||
list& operator=(list const& other)
|
||||
{
|
||||
clear();
|
||||
insert(other.begin(), other.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator begin() { return iterator(data_.first_); }
|
||||
iterator end() { return iterator(); }
|
||||
const_iterator begin() const { return iterator(data_.first_); }
|
||||
const_iterator end() const { return iterator(); }
|
||||
const_iterator cbegin() const { return iterator(data_.first_); }
|
||||
const_iterator cend() const { return iterator(); }
|
||||
|
||||
template <class InputIterator> void insert(InputIterator i, InputIterator j)
|
||||
{
|
||||
for (; i != j; ++i)
|
||||
push_back(*i);
|
||||
}
|
||||
|
||||
void push_front(value_type const& v)
|
||||
{
|
||||
data_.first_ = new node(v, data_.first_);
|
||||
if (!data_.size_)
|
||||
data_.last_ptr_ = &(*data_.last_ptr_)->next_;
|
||||
++data_.size_;
|
||||
}
|
||||
|
||||
void push_back(value_type const& v)
|
||||
{
|
||||
*data_.last_ptr_ = new node(v);
|
||||
data_.last_ptr_ = &(*data_.last_ptr_)->next_;
|
||||
++data_.size_;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
while (data_.first_) {
|
||||
node* tmp = data_.first_;
|
||||
data_.first_ = data_.first_->next_;
|
||||
--data_.size_;
|
||||
delete tmp;
|
||||
}
|
||||
data_.last_ptr_ = &data_.first_;
|
||||
}
|
||||
|
||||
void erase(const_iterator i, const_iterator j)
|
||||
{
|
||||
node** ptr = &data_.first_;
|
||||
|
||||
while (*ptr != i.ptr_) {
|
||||
ptr = &(*ptr)->next_;
|
||||
}
|
||||
|
||||
while (*ptr != j.ptr_) {
|
||||
node* to_delete = *ptr;
|
||||
*ptr = (*ptr)->next_;
|
||||
--data_.size_;
|
||||
delete to_delete;
|
||||
}
|
||||
|
||||
if (!*ptr)
|
||||
data_.last_ptr_ = ptr;
|
||||
}
|
||||
|
||||
bool empty() const { return !data_.size_; }
|
||||
|
||||
size_type size() const { return data_.size_; }
|
||||
|
||||
void sort() { sort(std::less<T>()); }
|
||||
|
||||
template <typename Less> void sort(Less less = Less())
|
||||
{
|
||||
if (!empty())
|
||||
merge_sort(
|
||||
&data_.first_, (std::numeric_limits<size_type>::max)(), less);
|
||||
}
|
||||
|
||||
bool operator==(list const& y) const
|
||||
{
|
||||
return size() == y.size() && test::equal(begin(), end(), y.begin());
|
||||
}
|
||||
|
||||
bool operator!=(list const& y) const { return !(*this == y); }
|
||||
|
||||
private:
|
||||
template <typename Less>
|
||||
node** merge_sort(node** l, size_type recurse_limit, Less less)
|
||||
{
|
||||
node** ptr = &(*l)->next_;
|
||||
for (size_type count = 0; count < recurse_limit && *ptr; ++count) {
|
||||
ptr = merge_adjacent_ranges(l, ptr, merge_sort(ptr, count, less), less);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template <typename Less>
|
||||
node** merge_adjacent_ranges(
|
||||
node** first, node** second, node** third, Less less)
|
||||
{
|
||||
for (;;) {
|
||||
for (;;) {
|
||||
if (first == second)
|
||||
return third;
|
||||
if (less((*second)->value_, (*first)->value_))
|
||||
break;
|
||||
first = &(*first)->next_;
|
||||
}
|
||||
|
||||
swap_adjacent_ranges(first, second, third);
|
||||
first = &(*first)->next_;
|
||||
|
||||
// Since the two ranges we just swapped, the order is now:
|
||||
// first...third...second
|
||||
|
||||
for (;;) {
|
||||
if (first == third)
|
||||
return second;
|
||||
if (!less((*first)->value_, (*third)->value_))
|
||||
break;
|
||||
first = &(*first)->next_;
|
||||
}
|
||||
|
||||
swap_adjacent_ranges(first, third, second);
|
||||
first = &(*first)->next_;
|
||||
}
|
||||
}
|
||||
|
||||
void swap_adjacent_ranges(node** first, node** second, node** third)
|
||||
{
|
||||
node* tmp = *first;
|
||||
*first = *second;
|
||||
*second = *third;
|
||||
*third = tmp;
|
||||
if (!*second)
|
||||
data_.last_ptr_ = second;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -6,158 +6,184 @@
|
||||
#if !defined(BOOST_UNORDERED_TEST_MEMORY_HEADER)
|
||||
#define BOOST_UNORDERED_TEST_MEMORY_HEADER
|
||||
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/unordered/detail/allocate.hpp>
|
||||
#include "../helpers/test.hpp"
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/unordered/detail/implementation.hpp>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
namespace test
|
||||
{
|
||||
namespace detail
|
||||
namespace test {
|
||||
namespace detail {
|
||||
struct memory_area
|
||||
{
|
||||
struct memory_area {
|
||||
void const* start;
|
||||
void const* end;
|
||||
void const* start;
|
||||
void const* end;
|
||||
|
||||
memory_area(void const* s, void const* e)
|
||||
: start(s), end(e)
|
||||
{
|
||||
BOOST_ASSERT(start != end);
|
||||
}
|
||||
};
|
||||
memory_area(void const* s, void const* e) : start(s), end(e)
|
||||
{
|
||||
BOOST_ASSERT(start != end);
|
||||
}
|
||||
};
|
||||
|
||||
struct memory_track {
|
||||
explicit memory_track(int tag = -1) :
|
||||
constructed_(0),
|
||||
tag_(tag) {}
|
||||
|
||||
int constructed_;
|
||||
int tag_;
|
||||
};
|
||||
|
||||
// This is a bit dodgy as it defines overlapping
|
||||
// areas as 'equal', so this isn't a total ordering.
|
||||
// But it is for non-overlapping memory regions - which
|
||||
// is what'll be stored.
|
||||
//
|
||||
// All searches will be for areas entirely contained by
|
||||
// a member of the set - so it should find the area that contains
|
||||
// the region that is searched for.
|
||||
|
||||
struct memory_area_compare {
|
||||
bool operator()(memory_area const& x, memory_area const& y) const {
|
||||
return x.end <= y.start;
|
||||
}
|
||||
};
|
||||
|
||||
struct memory_tracker {
|
||||
typedef std::map<memory_area, memory_track, memory_area_compare,
|
||||
std::allocator<std::pair<memory_area const, memory_track> >
|
||||
> allocated_memory_type;
|
||||
|
||||
allocated_memory_type allocated_memory;
|
||||
unsigned int count_allocators;
|
||||
unsigned int count_allocations;
|
||||
unsigned int count_constructions;
|
||||
|
||||
memory_tracker() :
|
||||
count_allocators(0), count_allocations(0),
|
||||
count_constructions(0)
|
||||
{}
|
||||
|
||||
void allocator_ref()
|
||||
{
|
||||
if(count_allocators == 0) {
|
||||
count_allocations = 0;
|
||||
count_constructions = 0;
|
||||
allocated_memory.clear();
|
||||
}
|
||||
++count_allocators;
|
||||
}
|
||||
|
||||
void allocator_unref()
|
||||
{
|
||||
BOOST_TEST(count_allocators > 0);
|
||||
if(count_allocators > 0) {
|
||||
--count_allocators;
|
||||
if(count_allocators == 0) {
|
||||
bool no_allocations_left = (count_allocations == 0);
|
||||
bool no_constructions_left = (count_constructions == 0);
|
||||
bool allocated_memory_empty = allocated_memory.empty();
|
||||
|
||||
// Clearing the data before the checks terminate the
|
||||
// tests.
|
||||
count_allocations = 0;
|
||||
count_constructions = 0;
|
||||
allocated_memory.clear();
|
||||
|
||||
BOOST_TEST(no_allocations_left);
|
||||
BOOST_TEST(no_constructions_left);
|
||||
BOOST_TEST(allocated_memory_empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void track_allocate(void *ptr, std::size_t n, std::size_t size,
|
||||
int tag)
|
||||
{
|
||||
if(n == 0) {
|
||||
BOOST_ERROR("Allocating 0 length array.");
|
||||
}
|
||||
else {
|
||||
++count_allocations;
|
||||
allocated_memory.insert(
|
||||
std::pair<memory_area const, memory_track>(
|
||||
memory_area(ptr, (char*) ptr + n * size),
|
||||
memory_track(tag)));
|
||||
}
|
||||
}
|
||||
|
||||
void track_deallocate(void* ptr, std::size_t n, std::size_t size,
|
||||
int tag, bool check_tag_ = true)
|
||||
{
|
||||
allocated_memory_type::iterator pos =
|
||||
allocated_memory.find(
|
||||
memory_area(ptr, (char*) ptr + n * size));
|
||||
if(pos == allocated_memory.end()) {
|
||||
BOOST_ERROR("Deallocating unknown pointer.");
|
||||
} else {
|
||||
BOOST_TEST(pos->first.start == ptr);
|
||||
BOOST_TEST(pos->first.end == (char*) ptr + n * size);
|
||||
if (check_tag_) BOOST_TEST(pos->second.tag_ == tag);
|
||||
allocated_memory.erase(pos);
|
||||
}
|
||||
BOOST_TEST(count_allocations > 0);
|
||||
if(count_allocations > 0) --count_allocations;
|
||||
}
|
||||
|
||||
void track_construct(void* /*ptr*/, std::size_t /*size*/,
|
||||
int /*tag*/)
|
||||
{
|
||||
++count_constructions;
|
||||
}
|
||||
|
||||
void track_destroy(void* /*ptr*/, std::size_t /*size*/,
|
||||
int /*tag*/)
|
||||
{
|
||||
BOOST_TEST(count_constructions > 0);
|
||||
if(count_constructions > 0) --count_constructions;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace detail
|
||||
struct memory_track
|
||||
{
|
||||
// This won't be a problem as I'm only using a single compile unit
|
||||
// in each test (this is actually required by the minimal test
|
||||
// framework).
|
||||
//
|
||||
// boostinspect:nounnamed
|
||||
namespace {
|
||||
test::detail::memory_tracker tracker;
|
||||
explicit memory_track(int tag = -1) : constructed_(0), tag_(tag) {}
|
||||
|
||||
int constructed_;
|
||||
int tag_;
|
||||
};
|
||||
|
||||
// This is a bit dodgy as it defines overlapping
|
||||
// areas as 'equal', so this isn't a total ordering.
|
||||
// But it is for non-overlapping memory regions - which
|
||||
// is what'll be stored.
|
||||
//
|
||||
// All searches will be for areas entirely contained by
|
||||
// a member of the set - so it should find the area that contains
|
||||
// the region that is searched for.
|
||||
|
||||
struct memory_area_compare
|
||||
{
|
||||
bool operator()(memory_area const& x, memory_area const& y) const
|
||||
{
|
||||
return x.end <= y.start;
|
||||
}
|
||||
};
|
||||
|
||||
struct memory_tracker
|
||||
{
|
||||
typedef std::map<memory_area, memory_track, memory_area_compare,
|
||||
std::allocator<std::pair<memory_area const, memory_track> > >
|
||||
allocated_memory_type;
|
||||
|
||||
allocated_memory_type allocated_memory;
|
||||
unsigned int count_allocators;
|
||||
unsigned int count_allocations;
|
||||
unsigned int count_constructions;
|
||||
bool tracking_constructions;
|
||||
|
||||
memory_tracker()
|
||||
: count_allocators(0), count_allocations(0), count_constructions(0),
|
||||
tracking_constructions(true)
|
||||
{
|
||||
}
|
||||
|
||||
~memory_tracker() { BOOST_TEST(count_allocators == 0); }
|
||||
|
||||
void allocator_ref()
|
||||
{
|
||||
if (count_allocators == 0) {
|
||||
count_allocations = 0;
|
||||
count_constructions = 0;
|
||||
allocated_memory.clear();
|
||||
}
|
||||
++count_allocators;
|
||||
}
|
||||
|
||||
void allocator_unref()
|
||||
{
|
||||
BOOST_TEST(count_allocators > 0);
|
||||
if (count_allocators > 0) {
|
||||
--count_allocators;
|
||||
if (count_allocators == 0) {
|
||||
bool no_allocations_left = (count_allocations == 0);
|
||||
bool no_constructions_left = (count_constructions == 0);
|
||||
bool allocated_memory_empty = allocated_memory.empty();
|
||||
|
||||
// Clearing the data before the checks terminate the
|
||||
// tests.
|
||||
count_allocations = 0;
|
||||
count_constructions = 0;
|
||||
allocated_memory.clear();
|
||||
|
||||
BOOST_TEST(no_allocations_left);
|
||||
BOOST_TEST(no_constructions_left);
|
||||
BOOST_TEST(allocated_memory_empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void track_allocate(void* ptr, std::size_t n, std::size_t size, int tag)
|
||||
{
|
||||
if (n == 0) {
|
||||
BOOST_ERROR("Allocating 0 length array.");
|
||||
} else {
|
||||
++count_allocations;
|
||||
allocated_memory.insert(std::pair<memory_area const, memory_track>(
|
||||
memory_area(ptr, (char*)ptr + n * size), memory_track(tag)));
|
||||
}
|
||||
}
|
||||
|
||||
void track_deallocate(void* ptr, std::size_t n, std::size_t size, int tag,
|
||||
bool check_tag_ = true)
|
||||
{
|
||||
allocated_memory_type::iterator pos =
|
||||
allocated_memory.find(memory_area(ptr, (char*)ptr + n * size));
|
||||
if (pos == allocated_memory.end()) {
|
||||
BOOST_ERROR("Deallocating unknown pointer.");
|
||||
} else {
|
||||
BOOST_TEST(pos->first.start == ptr);
|
||||
BOOST_TEST(pos->first.end == (char*)ptr + n * size);
|
||||
if (check_tag_)
|
||||
BOOST_TEST(pos->second.tag_ == tag);
|
||||
allocated_memory.erase(pos);
|
||||
}
|
||||
BOOST_TEST(count_allocations > 0);
|
||||
if (count_allocations > 0)
|
||||
--count_allocations;
|
||||
}
|
||||
|
||||
void track_construct(void* /*ptr*/, std::size_t /*size*/, int /*tag*/)
|
||||
{
|
||||
if (tracking_constructions) {
|
||||
++count_constructions;
|
||||
}
|
||||
}
|
||||
|
||||
void track_destroy(void* /*ptr*/, std::size_t /*size*/, int /*tag*/)
|
||||
{
|
||||
if (tracking_constructions) {
|
||||
BOOST_TEST(count_constructions > 0);
|
||||
if (count_constructions > 0)
|
||||
--count_constructions;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
// This won't be a problem as I'm only using a single compile unit
|
||||
// in each test (this is actually required by the minimal test
|
||||
// framework).
|
||||
//
|
||||
// boostinspect:nounnamed
|
||||
namespace {
|
||||
test::detail::memory_tracker tracker;
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
struct disable_construction_tracking
|
||||
{
|
||||
bool old_value;
|
||||
|
||||
disable_construction_tracking()
|
||||
: old_value(detail::tracker.tracking_constructions)
|
||||
{
|
||||
test::detail::tracker.tracking_constructions = false;
|
||||
}
|
||||
|
||||
~disable_construction_tracking()
|
||||
{
|
||||
test::detail::tracker.tracking_constructions = old_value;
|
||||
}
|
||||
|
||||
private:
|
||||
disable_construction_tracking(disable_construction_tracking const&);
|
||||
disable_construction_tracking& operator=(
|
||||
disable_construction_tracking const&);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -8,35 +8,23 @@
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
namespace test
|
||||
{
|
||||
template <class Container>
|
||||
struct is_set
|
||||
: public boost::is_same<
|
||||
BOOST_DEDUCED_TYPENAME Container::key_type,
|
||||
BOOST_DEDUCED_TYPENAME Container::value_type> {};
|
||||
namespace test {
|
||||
template <class Container>
|
||||
struct is_set : public boost::is_same<typename Container::key_type,
|
||||
typename Container::value_type>
|
||||
{
|
||||
};
|
||||
|
||||
template <class Container>
|
||||
struct has_unique_keys
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = false);
|
||||
};
|
||||
|
||||
template <class V, class H, class P, class A>
|
||||
struct has_unique_keys<boost::unordered_set<V, H, P, A> >
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
|
||||
template <class K, class M, class H, class P, class A>
|
||||
struct has_unique_keys<boost::unordered_map<K, M, H, P, A> >
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
template <class Container> struct has_unique_keys
|
||||
{
|
||||
static char flip(typename Container::iterator const&);
|
||||
static long flip(std::pair<typename Container::iterator, bool> const&);
|
||||
BOOST_STATIC_CONSTANT(bool,
|
||||
value = sizeof(long) ==
|
||||
sizeof(flip(
|
||||
((Container*)0)->insert(*(typename Container::value_type*)0))));
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -6,6 +6,6 @@
|
||||
#if defined(_WIN32_WCE)
|
||||
// The standard windows mobile headers trigger this warning so I disable it
|
||||
// before doing anything else.
|
||||
#pragma warning(disable:4201) // nonstandard extension used :
|
||||
#pragma warning(disable : 4201) // nonstandard extension used :
|
||||
// nameless struct/union
|
||||
#endif
|
||||
|
@ -6,110 +6,104 @@
|
||||
#if !defined(BOOST_UNORDERED_TEST_HELPERS_RANDOM_VALUES_HEADER)
|
||||
#define BOOST_UNORDERED_TEST_HELPERS_RANDOM_VALUES_HEADER
|
||||
|
||||
#include "./generators.hpp"
|
||||
#include "./list.hpp"
|
||||
#include "./metafunctions.hpp"
|
||||
#include <algorithm>
|
||||
#include <boost/detail/select_type.hpp>
|
||||
#include "./generators.hpp"
|
||||
#include "./metafunctions.hpp"
|
||||
|
||||
namespace test
|
||||
{
|
||||
typedef enum {
|
||||
default_generator,
|
||||
generate_collisions
|
||||
} random_generator;
|
||||
namespace test {
|
||||
template <class X> struct unordered_generator_set
|
||||
{
|
||||
typedef typename X::value_type value_type;
|
||||
|
||||
template <class X>
|
||||
struct unordered_generator_set
|
||||
random_generator type_;
|
||||
|
||||
unordered_generator_set(random_generator type) : type_(type) {}
|
||||
|
||||
template <class T> void fill(T& x, std::size_t len)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME X::value_type value_type;
|
||||
value_type* value_ptr = 0;
|
||||
len += x.size();
|
||||
|
||||
random_generator type_;
|
||||
for (std::size_t i = 0; i < len; ++i) {
|
||||
value_type value = generate(value_ptr, type_);
|
||||
|
||||
unordered_generator_set(random_generator type)
|
||||
: type_(type) {}
|
||||
std::size_t count =
|
||||
type_ == generate_collisions ? random_value(5) + 1 : 1;
|
||||
|
||||
template <class T>
|
||||
void fill(T& x, std::size_t len) {
|
||||
value_type* value_ptr = 0;
|
||||
int* int_ptr = 0;
|
||||
len += x.size();
|
||||
|
||||
for (std::size_t i = 0; i < len; ++i) {
|
||||
value_type value = generate(value_ptr);
|
||||
|
||||
int count = type_ == generate_collisions ?
|
||||
1 + (generate(int_ptr) % 5) : 1;
|
||||
|
||||
for(int i = 0; i < count; ++i) {
|
||||
x.push_back(value);
|
||||
}
|
||||
}
|
||||
for (std::size_t j = 0; j < count; ++j) {
|
||||
x.push_back(value);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class X>
|
||||
struct unordered_generator_map
|
||||
template <class X> struct unordered_generator_map
|
||||
{
|
||||
typedef typename X::key_type key_type;
|
||||
typedef typename X::mapped_type mapped_type;
|
||||
|
||||
random_generator type_;
|
||||
|
||||
unordered_generator_map(random_generator type) : type_(type) {}
|
||||
|
||||
template <class T> void fill(T& x, std::size_t len)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME X::key_type key_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME X::mapped_type mapped_type;
|
||||
key_type* key_ptr = 0;
|
||||
mapped_type* mapped_ptr = 0;
|
||||
|
||||
random_generator type_;
|
||||
for (std::size_t i = 0; i < len; ++i) {
|
||||
key_type key = generate(key_ptr, type_);
|
||||
|
||||
unordered_generator_map(random_generator type)
|
||||
: type_(type) {}
|
||||
std::size_t count =
|
||||
type_ == generate_collisions ? random_value(5) + 1 : 1;
|
||||
|
||||
template <class T>
|
||||
void fill(T& x, std::size_t len) {
|
||||
key_type* key_ptr = 0;
|
||||
mapped_type* mapped_ptr = 0;
|
||||
int* int_ptr = 0;
|
||||
|
||||
for (std::size_t i = 0; i < len; ++i) {
|
||||
key_type key = generate(key_ptr);
|
||||
|
||||
int count = type_ == generate_collisions ?
|
||||
1 + (generate(int_ptr) % 5) : 1;
|
||||
|
||||
for(int i = 0; i < count; ++i) {
|
||||
x.push_back(std::pair<key_type const, mapped_type>(
|
||||
key, generate(mapped_ptr)));
|
||||
}
|
||||
}
|
||||
for (std::size_t j = 0; j < count; ++j) {
|
||||
x.push_back(std::pair<key_type const, mapped_type>(
|
||||
key, generate(mapped_ptr, type_)));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class X>
|
||||
struct unordered_generator_base
|
||||
: public boost::detail::if_true<
|
||||
test::is_set<X>::value
|
||||
>::BOOST_NESTED_TEMPLATE then<
|
||||
test::unordered_generator_set<X>,
|
||||
test::unordered_generator_map<X>
|
||||
>
|
||||
template <class X>
|
||||
struct unordered_generator_base
|
||||
: public boost::detail::if_true<test::is_set<X>::value>::
|
||||
BOOST_NESTED_TEMPLATE then<test::unordered_generator_set<X>,
|
||||
test::unordered_generator_map<X> >
|
||||
{
|
||||
};
|
||||
|
||||
template <class X>
|
||||
struct unordered_generator : public unordered_generator_base<X>::type
|
||||
{
|
||||
typedef typename unordered_generator_base<X>::type base;
|
||||
|
||||
unordered_generator(random_generator const& type = default_generator)
|
||||
: base(type)
|
||||
{
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
template <class X>
|
||||
struct unordered_generator : public unordered_generator_base<X>::type
|
||||
template <class X>
|
||||
struct random_values : public test::list<typename X::value_type>
|
||||
{
|
||||
random_values() {}
|
||||
|
||||
explicit random_values(std::size_t count,
|
||||
test::random_generator const& generator = test::default_generator)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME unordered_generator_base<X>::type base;
|
||||
fill(count, generator);
|
||||
}
|
||||
|
||||
unordered_generator(random_generator const& type = default_generator)
|
||||
: base(type) {}
|
||||
};
|
||||
|
||||
template <class X>
|
||||
struct random_values
|
||||
: public test::list<BOOST_DEDUCED_TYPENAME X::value_type>
|
||||
void fill(std::size_t count,
|
||||
test::random_generator const& generator = test::default_generator)
|
||||
{
|
||||
random_values(int count, test::random_generator const& generator =
|
||||
test::default_generator)
|
||||
{
|
||||
test::unordered_generator<X> gen(generator);
|
||||
gen.fill(*this, count);
|
||||
}
|
||||
};
|
||||
test::unordered_generator<X> gen(generator);
|
||||
gen.fill(*this, count);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -6,37 +6,37 @@
|
||||
#if !defined(BOOST_UNORDERED_TEST_HELPERS_STRONG_HEADER)
|
||||
#define BOOST_UNORDERED_TEST_HELPERS_STRONG_HEADER
|
||||
|
||||
#include "./equivalent.hpp"
|
||||
#include "./exception_test.hpp"
|
||||
#include "./list.hpp"
|
||||
#include <boost/config.hpp>
|
||||
#include <iterator>
|
||||
#include "./equivalent.hpp"
|
||||
#include "./list.hpp"
|
||||
#include "./exception_test.hpp"
|
||||
|
||||
namespace test
|
||||
{
|
||||
template <class X>
|
||||
class strong
|
||||
namespace test {
|
||||
template <class X> class strong
|
||||
{
|
||||
typedef test::list<typename X::value_type> values_type;
|
||||
values_type values_;
|
||||
unsigned int allocations_;
|
||||
|
||||
public:
|
||||
void store(X const& x, unsigned int allocations = 0)
|
||||
{
|
||||
typedef test::list<BOOST_DEDUCED_TYPENAME X::value_type> values_type;
|
||||
values_type values_;
|
||||
unsigned int allocations_;
|
||||
public:
|
||||
void store(X const& x, unsigned int allocations = 0) {
|
||||
DISABLE_EXCEPTIONS;
|
||||
values_.clear();
|
||||
values_.insert(x.cbegin(), x.cend());
|
||||
allocations_ = allocations;
|
||||
}
|
||||
DISABLE_EXCEPTIONS;
|
||||
values_.clear();
|
||||
values_.insert(x.cbegin(), x.cend());
|
||||
allocations_ = allocations;
|
||||
}
|
||||
|
||||
void test(X const& x, unsigned int allocations = 0) const {
|
||||
if(!(x.size() == values_.size() &&
|
||||
test::equal(x.cbegin(), x.cend(), values_.begin(),
|
||||
test::equivalent)))
|
||||
BOOST_ERROR("Strong exception safety failure.");
|
||||
if(allocations != allocations_)
|
||||
BOOST_ERROR("Strong exception failure: extra allocations.");
|
||||
}
|
||||
};
|
||||
void test(X const& x, unsigned int allocations = 0) const
|
||||
{
|
||||
if (!(x.size() == values_.size() && test::equal(x.cbegin(), x.cend(),
|
||||
values_.begin(), test::equivalent)))
|
||||
BOOST_ERROR("Strong exception safety failure.");
|
||||
if (allocations != allocations_)
|
||||
BOOST_ERROR("Strong exception failure: extra allocations.");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -6,99 +6,196 @@
|
||||
#if !defined(BOOST_UNORDERED_TEST_TEST_HEADER)
|
||||
#define BOOST_UNORDERED_TEST_TEST_HEADER
|
||||
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/preprocessor/cat.hpp>
|
||||
#include <boost/preprocessor/stringize.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#define UNORDERED_AUTO_TEST(x) \
|
||||
struct BOOST_PP_CAT(x, _type) : public ::test::registered_test_base { \
|
||||
BOOST_PP_CAT(x, _type)() \
|
||||
: ::test::registered_test_base(BOOST_PP_STRINGIZE(x)) \
|
||||
{ \
|
||||
::test::test_list::add_test(this); \
|
||||
} \
|
||||
void run(); \
|
||||
}; \
|
||||
BOOST_PP_CAT(x, _type) x; \
|
||||
void BOOST_PP_CAT(x, _type)::run() \
|
||||
#define UNORDERED_AUTO_TEST(x) \
|
||||
struct BOOST_PP_CAT(x, _type) : public ::test::registered_test_base \
|
||||
{ \
|
||||
BOOST_PP_CAT(x, _type) \
|
||||
() : ::test::registered_test_base(BOOST_PP_STRINGIZE(x)) \
|
||||
{ \
|
||||
::test::get_state().add_test(this); \
|
||||
} \
|
||||
void run(); \
|
||||
}; \
|
||||
BOOST_PP_CAT(x, _type) x; \
|
||||
void BOOST_PP_CAT(x, _type)::run()
|
||||
|
||||
#define RUN_TESTS() int main(int, char**) \
|
||||
{ ::test::test_list::run_tests(); return boost::report_errors(); } \
|
||||
#define RUN_TESTS() \
|
||||
int main(int, char**) \
|
||||
{ \
|
||||
BOOST_UNORDERED_TEST_COMPILER_INFO() \
|
||||
::test::get_state().run_tests(); \
|
||||
return boost::report_errors(); \
|
||||
}
|
||||
|
||||
#define RUN_TESTS_QUIET() \
|
||||
int main(int, char**) \
|
||||
{ \
|
||||
BOOST_UNORDERED_TEST_COMPILER_INFO() \
|
||||
::test::get_state().run_tests(true); \
|
||||
return boost::report_errors(); \
|
||||
}
|
||||
|
||||
#define UNORDERED_SUB_TEST(x) \
|
||||
for (int UNORDERED_SUB_TEST_VALUE = ::test::get_state().start_sub_test(x); \
|
||||
UNORDERED_SUB_TEST_VALUE; \
|
||||
UNORDERED_SUB_TEST_VALUE = \
|
||||
::test::get_state().end_sub_test(x, UNORDERED_SUB_TEST_VALUE))
|
||||
|
||||
namespace test {
|
||||
struct registered_test_base {
|
||||
registered_test_base* next;
|
||||
char const* name;
|
||||
explicit registered_test_base(char const* n) : name(n) {}
|
||||
virtual void run() = 0;
|
||||
virtual ~registered_test_base() {}
|
||||
};
|
||||
|
||||
namespace test_list {
|
||||
static inline registered_test_base*& first() {
|
||||
static registered_test_base* ptr = 0;
|
||||
return ptr;
|
||||
}
|
||||
struct registered_test_base
|
||||
{
|
||||
registered_test_base* next;
|
||||
char const* name;
|
||||
explicit registered_test_base(char const* n) : name(n) {}
|
||||
virtual void run() = 0;
|
||||
virtual ~registered_test_base() {}
|
||||
};
|
||||
|
||||
static inline registered_test_base*& last() {
|
||||
static registered_test_base* ptr = 0;
|
||||
return ptr;
|
||||
}
|
||||
struct state
|
||||
{
|
||||
bool is_quiet;
|
||||
registered_test_base* first_test;
|
||||
registered_test_base* last_test;
|
||||
|
||||
static inline void add_test(registered_test_base* test) {
|
||||
if(last()) {
|
||||
last()->next = test;
|
||||
}
|
||||
else {
|
||||
first() = test;
|
||||
}
|
||||
state() : is_quiet(false), first_test(0), last_test(0) {}
|
||||
|
||||
last() = test;
|
||||
}
|
||||
|
||||
static inline void run_tests() {
|
||||
for(registered_test_base* i = first(); i; i = i->next) {
|
||||
std::cout<<"Running "<<i->name<<"\n"<<std::flush;
|
||||
i->run();
|
||||
std::cerr<<std::flush;
|
||||
std::cout<<std::flush;
|
||||
}
|
||||
}
|
||||
void add_test(registered_test_base* test)
|
||||
{
|
||||
if (last_test) {
|
||||
last_test->next = test;
|
||||
} else {
|
||||
first_test = test;
|
||||
}
|
||||
last_test = test;
|
||||
}
|
||||
|
||||
void run_tests(bool quiet = false)
|
||||
{
|
||||
is_quiet = quiet;
|
||||
|
||||
for (registered_test_base* i = first_test; i; i = i->next) {
|
||||
int error_count = boost::detail::test_errors();
|
||||
if (!quiet) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Running " << i->name << "\n"
|
||||
<< std::flush;
|
||||
}
|
||||
i->run();
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << std::flush;
|
||||
if (quiet && error_count != boost::detail::test_errors()) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Error in: " << i->name << "\n"
|
||||
<< std::flush;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int start_sub_test(char const* name)
|
||||
{
|
||||
if (!is_quiet) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Sub-test: " << name << "\n"
|
||||
<< std::flush;
|
||||
}
|
||||
// Add one because it's used as a loop condition.
|
||||
return boost::detail::test_errors() + 1;
|
||||
}
|
||||
|
||||
int end_sub_test(char const* name, int value)
|
||||
{
|
||||
if (is_quiet && value != boost::detail::test_errors() + 1) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Error in sub-test: " << name << "\n"
|
||||
<< std::flush;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
// Get the currnet translation unit's test state.
|
||||
static inline state& get_state()
|
||||
{
|
||||
static state instance;
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
#include <boost/preprocessor/seq/for_each_product.hpp>
|
||||
#include <boost/preprocessor/seq/fold_left.hpp>
|
||||
#include <boost/preprocessor/seq/to_tuple.hpp>
|
||||
#include <boost/preprocessor/seq/seq.hpp>
|
||||
#if defined(__cplusplus)
|
||||
#define BOOST_UNORDERED_CPLUSPLUS __cplusplus
|
||||
#else
|
||||
#define BOOST_UNORDERED_CPLUSPLUS "(not defined)"
|
||||
#endif
|
||||
|
||||
#define BOOST_UNORDERED_TEST_COMPILER_INFO() \
|
||||
{ \
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM \
|
||||
<< "Compiler: " << BOOST_COMPILER << "\n" \
|
||||
<< "Library: " << BOOST_STDLIB << "\n" \
|
||||
<< "__cplusplus: " << BOOST_UNORDERED_CPLUSPLUS << "\n\n" \
|
||||
<< "BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT: " \
|
||||
<< BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT << "\n" \
|
||||
<< "BOOST_UNORDERED_EMPLACE_LIMIT: " << BOOST_UNORDERED_EMPLACE_LIMIT \
|
||||
<< "\n" \
|
||||
<< "BOOST_UNORDERED_USE_ALLOCATOR_TRAITS: " \
|
||||
<< BOOST_UNORDERED_USE_ALLOCATOR_TRAITS << "\n" \
|
||||
<< "BOOST_UNORDERED_CXX11_CONSTRUCTION: " \
|
||||
<< BOOST_UNORDERED_CXX11_CONSTRUCTION << "\n\n" \
|
||||
<< std::flush; \
|
||||
}
|
||||
|
||||
#include <boost/preprocessor/cat.hpp>
|
||||
#include <boost/preprocessor/seq/fold_left.hpp>
|
||||
#include <boost/preprocessor/seq/for_each_product.hpp>
|
||||
#include <boost/preprocessor/seq/seq.hpp>
|
||||
#include <boost/preprocessor/seq/to_tuple.hpp>
|
||||
|
||||
// Run test with every combination of the parameters (a sequence of sequences)
|
||||
#define UNORDERED_TEST(name, parameters) \
|
||||
BOOST_PP_SEQ_FOR_EACH_PRODUCT(UNORDERED_TEST_OP, \
|
||||
((name))((1)) parameters) \
|
||||
#define UNORDERED_TEST(name, parameters) \
|
||||
BOOST_PP_SEQ_FOR_EACH_PRODUCT(UNORDERED_TEST_OP, ((name))((1))parameters)
|
||||
|
||||
#define UNORDERED_TEST_REPEAT(name, n, parameters) \
|
||||
BOOST_PP_SEQ_FOR_EACH_PRODUCT(UNORDERED_TEST_OP, \
|
||||
((name))((n)) parameters) \
|
||||
#define UNORDERED_TEST_REPEAT(name, n, parameters) \
|
||||
BOOST_PP_SEQ_FOR_EACH_PRODUCT(UNORDERED_TEST_OP, ((name))((n))parameters)
|
||||
|
||||
#define UNORDERED_TEST_OP(r, product) \
|
||||
UNORDERED_TEST_OP2( \
|
||||
BOOST_PP_SEQ_ELEM(0, product), \
|
||||
BOOST_PP_SEQ_ELEM(1, product), \
|
||||
BOOST_PP_SEQ_TAIL(BOOST_PP_SEQ_TAIL(product))) \
|
||||
#define UNORDERED_TEST_OP(r, product) \
|
||||
UNORDERED_TEST_OP2(BOOST_PP_SEQ_ELEM(0, product), \
|
||||
BOOST_PP_SEQ_ELEM(1, product), \
|
||||
BOOST_PP_SEQ_TAIL(BOOST_PP_SEQ_TAIL(product)))
|
||||
|
||||
#define UNORDERED_TEST_OP2(name, n, params) \
|
||||
UNORDERED_AUTO_TEST( \
|
||||
BOOST_PP_SEQ_FOLD_LEFT(UNORDERED_TEST_OP_JOIN, name, params)) \
|
||||
{ \
|
||||
for (int i = 0; i < n; ++i) \
|
||||
name BOOST_PP_SEQ_TO_TUPLE(params); \
|
||||
} \
|
||||
#define UNORDERED_TEST_OP2(name, n, params) \
|
||||
UNORDERED_AUTO_TEST ( \
|
||||
BOOST_PP_SEQ_FOLD_LEFT(UNORDERED_TEST_OP_JOIN, name, params)) { \
|
||||
for (int i = 0; i < n; ++i) \
|
||||
name BOOST_PP_SEQ_TO_TUPLE(params); \
|
||||
}
|
||||
|
||||
#define UNORDERED_TEST_OP_JOIN(s, state, elem) \
|
||||
BOOST_PP_CAT(state, BOOST_PP_CAT(_, elem)) \
|
||||
#define UNORDERED_TEST_OP_JOIN(s, state, elem) \
|
||||
BOOST_PP_CAT(state, BOOST_PP_CAT(_, elem))
|
||||
|
||||
#define UNORDERED_MULTI_TEST(name, impl, parameters) \
|
||||
UNORDERED_MULTI_TEST_REPEAT(name, impl, 1, parameters)
|
||||
|
||||
#define UNORDERED_MULTI_TEST_REPEAT(name, impl, n, parameters) \
|
||||
UNORDERED_AUTO_TEST (name) { \
|
||||
BOOST_PP_SEQ_FOR_EACH_PRODUCT( \
|
||||
UNORDERED_MULTI_TEST_OP, ((impl))((n))parameters) \
|
||||
}
|
||||
|
||||
#define UNORDERED_MULTI_TEST_OP(r, product) \
|
||||
UNORDERED_MULTI_TEST_OP2(BOOST_PP_SEQ_ELEM(0, product), \
|
||||
BOOST_PP_SEQ_ELEM(1, product), \
|
||||
BOOST_PP_SEQ_TAIL(BOOST_PP_SEQ_TAIL(product)))
|
||||
|
||||
// Need to wrap UNORDERED_SUB_TEST in a block to avoid an msvc bug.
|
||||
// https://support.microsoft.com/en-gb/help/315481/bug-too-many-unnested-loops-incorrectly-causes-a-c1061-compiler-error-in-visual-c
|
||||
#define UNORDERED_MULTI_TEST_OP2(name, n, params) \
|
||||
{ \
|
||||
UNORDERED_SUB_TEST(BOOST_PP_STRINGIZE( \
|
||||
BOOST_PP_SEQ_FOLD_LEFT(UNORDERED_TEST_OP_JOIN, name, params))) \
|
||||
{ \
|
||||
for (int i = 0; i < n; ++i) \
|
||||
name BOOST_PP_SEQ_TO_TUPLE(params); \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -9,152 +9,130 @@
|
||||
#if !defined(BOOST_UNORDERED_TEST_HELPERS_TRACKER_HEADER)
|
||||
#define BOOST_UNORDERED_TEST_HELPERS_TRACKER_HEADER
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include "../objects/fwd.hpp"
|
||||
#include "./metafunctions.hpp"
|
||||
#include "./helpers.hpp"
|
||||
#include "./equivalent.hpp"
|
||||
#include "./helpers.hpp"
|
||||
#include "./list.hpp"
|
||||
#include "./metafunctions.hpp"
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace test
|
||||
{
|
||||
template <typename X>
|
||||
struct equals_to_compare
|
||||
{
|
||||
typedef std::less<BOOST_DEDUCED_TYPENAME X::first_argument_type>
|
||||
type;
|
||||
};
|
||||
namespace test {
|
||||
template <typename X> struct equals_to_compare
|
||||
{
|
||||
typedef std::less<typename X::first_argument_type> type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct equals_to_compare<test::equal_to>
|
||||
{
|
||||
typedef test::less type;
|
||||
};
|
||||
template <> struct equals_to_compare<test::equal_to>
|
||||
{
|
||||
typedef test::less type;
|
||||
};
|
||||
|
||||
template <class X1, class X2>
|
||||
void compare_range(X1 const& x1, X2 const& x2)
|
||||
template <class X1, class X2> void compare_range(X1 const& x1, X2 const& x2)
|
||||
{
|
||||
typedef test::list<typename X1::value_type> value_list;
|
||||
value_list values1(x1.begin(), x1.end());
|
||||
value_list values2(x2.begin(), x2.end());
|
||||
values1.sort();
|
||||
values2.sort();
|
||||
BOOST_TEST(values1.size() == values2.size() &&
|
||||
test::equal(values1.begin(), values1.end(), values2.begin(),
|
||||
test::equivalent));
|
||||
}
|
||||
|
||||
template <class X1, class X2, class T>
|
||||
void compare_pairs(X1 const& x1, X2 const& x2, T*)
|
||||
{
|
||||
test::list<T> values1(x1.first, x1.second);
|
||||
test::list<T> values2(x2.first, x2.second);
|
||||
values1.sort();
|
||||
values2.sort();
|
||||
BOOST_TEST(values1.size() == values2.size() &&
|
||||
test::equal(values1.begin(), values1.end(), values2.begin(),
|
||||
test::equivalent));
|
||||
}
|
||||
|
||||
template <typename X, bool is_set = test::is_set<X>::value,
|
||||
bool has_unique_keys = test::has_unique_keys<X>::value>
|
||||
struct ordered_base;
|
||||
|
||||
template <typename X> struct ordered_base<X, true, true>
|
||||
{
|
||||
typedef std::set<typename X::value_type,
|
||||
typename equals_to_compare<typename X::key_equal>::type>
|
||||
type;
|
||||
};
|
||||
|
||||
template <typename X> struct ordered_base<X, true, false>
|
||||
{
|
||||
typedef std::multiset<typename X::value_type,
|
||||
typename equals_to_compare<typename X::key_equal>::type>
|
||||
type;
|
||||
};
|
||||
|
||||
template <typename X> struct ordered_base<X, false, true>
|
||||
{
|
||||
typedef std::map<typename X::key_type, typename X::mapped_type,
|
||||
typename equals_to_compare<typename X::key_equal>::type>
|
||||
type;
|
||||
};
|
||||
|
||||
template <typename X> struct ordered_base<X, false, false>
|
||||
{
|
||||
typedef std::multimap<typename X::key_type, typename X::mapped_type,
|
||||
typename equals_to_compare<typename X::key_equal>::type>
|
||||
type;
|
||||
};
|
||||
|
||||
template <class X> class ordered : public ordered_base<X>::type
|
||||
{
|
||||
typedef typename ordered_base<X>::type base;
|
||||
|
||||
public:
|
||||
typedef typename base::key_compare key_compare;
|
||||
|
||||
ordered() : base() {}
|
||||
|
||||
explicit ordered(key_compare const& kc) : base(kc) {}
|
||||
|
||||
void compare(X const& x) { compare_range(x, *this); }
|
||||
|
||||
void compare_key(X const& x, typename X::value_type const& val)
|
||||
{
|
||||
typedef test::list<BOOST_DEDUCED_TYPENAME X1::value_type> value_list;
|
||||
value_list values1(x1.begin(), x1.end());
|
||||
value_list values2(x2.begin(), x2.end());
|
||||
values1.sort();
|
||||
values2.sort();
|
||||
BOOST_TEST(values1.size() == values2.size() &&
|
||||
test::equal(values1.begin(), values1.end(), values2.begin(),
|
||||
test::equivalent));
|
||||
compare_pairs(x.equal_range(get_key<X>(val)),
|
||||
this->equal_range(get_key<X>(val)), (typename X::value_type*)0);
|
||||
}
|
||||
|
||||
template <class X1, class X2, class T>
|
||||
void compare_pairs(X1 const& x1, X2 const& x2, T*)
|
||||
template <class It> void insert_range(It b, It e)
|
||||
{
|
||||
test::list<T> values1(x1.first, x1.second);
|
||||
test::list<T> values2(x2.first, x2.second);
|
||||
values1.sort();
|
||||
values2.sort();
|
||||
BOOST_TEST(values1.size() == values2.size() &&
|
||||
test::equal(values1.begin(), values1.end(),
|
||||
values2.begin(), test::equivalent));
|
||||
while (b != e) {
|
||||
this->insert(*b);
|
||||
++b;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename X>
|
||||
struct ordered_base;
|
||||
template <class Equals>
|
||||
typename equals_to_compare<Equals>::type create_compare(Equals const&)
|
||||
{
|
||||
typename equals_to_compare<Equals>::type x;
|
||||
return x;
|
||||
}
|
||||
|
||||
template <class V, class H, class P, class A>
|
||||
struct ordered_base<boost::unordered_set<V, H, P, A> >
|
||||
{
|
||||
typedef std::set<V,
|
||||
BOOST_DEDUCED_TYPENAME equals_to_compare<P>::type>
|
||||
type;
|
||||
};
|
||||
template <class X> ordered<X> create_ordered(X const& container)
|
||||
{
|
||||
return ordered<X>(create_compare(container.key_eq()));
|
||||
}
|
||||
|
||||
template <class V, class H, class P, class A>
|
||||
struct ordered_base<boost::unordered_multiset<V, H, P, A> >
|
||||
{
|
||||
typedef std::multiset<V,
|
||||
BOOST_DEDUCED_TYPENAME equals_to_compare<P>::type>
|
||||
type;
|
||||
};
|
||||
|
||||
template <class K, class M, class H, class P, class A>
|
||||
struct ordered_base<boost::unordered_map<K, M, H, P, A> >
|
||||
{
|
||||
typedef std::map<K, M,
|
||||
BOOST_DEDUCED_TYPENAME equals_to_compare<P>::type>
|
||||
type;
|
||||
};
|
||||
|
||||
template <class K, class M, class H, class P, class A>
|
||||
struct ordered_base<boost::unordered_multimap<K, M, H, P, A> >
|
||||
{
|
||||
typedef std::multimap<K, M,
|
||||
BOOST_DEDUCED_TYPENAME equals_to_compare<P>::type>
|
||||
type;
|
||||
};
|
||||
|
||||
template <class X>
|
||||
class ordered : public ordered_base<X>::type
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME ordered_base<X>::type base;
|
||||
public:
|
||||
typedef BOOST_DEDUCED_TYPENAME base::key_compare key_compare;
|
||||
|
||||
ordered()
|
||||
: base()
|
||||
{}
|
||||
|
||||
explicit ordered(key_compare const& kc)
|
||||
: base(kc)
|
||||
{}
|
||||
|
||||
void compare(X const& x)
|
||||
{
|
||||
compare_range(x, *this);
|
||||
}
|
||||
|
||||
void compare_key(X const& x,
|
||||
BOOST_DEDUCED_TYPENAME X::value_type const& val)
|
||||
{
|
||||
compare_pairs(
|
||||
x.equal_range(get_key<X>(val)),
|
||||
this->equal_range(get_key<X>(val)),
|
||||
(BOOST_DEDUCED_TYPENAME X::value_type*) 0);
|
||||
}
|
||||
|
||||
template <class It>
|
||||
void insert_range(It b, It e) {
|
||||
while(b != e) {
|
||||
this->insert(*b);
|
||||
++b;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class Equals>
|
||||
BOOST_DEDUCED_TYPENAME
|
||||
equals_to_compare<Equals>::type create_compare(Equals const&)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME equals_to_compare<Equals>::type x;
|
||||
return x;
|
||||
}
|
||||
|
||||
template <class X>
|
||||
ordered<X> create_ordered(X const& container)
|
||||
{
|
||||
return ordered<X>(create_compare(container.key_eq()));
|
||||
}
|
||||
|
||||
template <class X1, class X2>
|
||||
void check_container(X1 const& container, X2 const& values)
|
||||
{
|
||||
ordered<X1> tracker = create_ordered(container);
|
||||
tracker.insert_range(values.begin(), values.end());
|
||||
tracker.compare(container);
|
||||
}
|
||||
template <class X1, class X2>
|
||||
void check_container(X1 const& container, X2 const& values)
|
||||
{
|
||||
ordered<X1> tracker = create_ordered(container);
|
||||
tracker.insert_range(values.begin(), values.end());
|
||||
tracker.compare(container);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -13,305 +13,332 @@
|
||||
#include "../helpers/fwd.hpp"
|
||||
#include "../helpers/memory.hpp"
|
||||
|
||||
namespace test
|
||||
{
|
||||
struct allocator_false
|
||||
namespace test {
|
||||
struct allocator_false
|
||||
{
|
||||
enum
|
||||
{
|
||||
enum {
|
||||
is_select_on_copy = 0,
|
||||
is_propagate_on_swap = 0,
|
||||
is_propagate_on_assign = 0,
|
||||
is_propagate_on_move = 0,
|
||||
cxx11_construct = 0
|
||||
};
|
||||
is_select_on_copy = 0,
|
||||
is_propagate_on_swap = 0,
|
||||
is_propagate_on_assign = 0,
|
||||
is_propagate_on_move = 0,
|
||||
cxx11_construct = 0
|
||||
};
|
||||
};
|
||||
|
||||
struct allocator_flags_all
|
||||
struct allocator_flags_all
|
||||
{
|
||||
enum
|
||||
{
|
||||
enum {
|
||||
is_select_on_copy = 1,
|
||||
is_propagate_on_swap = 1,
|
||||
is_propagate_on_assign = 1,
|
||||
is_propagate_on_move = 1,
|
||||
cxx11_construct = 1
|
||||
};
|
||||
is_select_on_copy = 1,
|
||||
is_propagate_on_swap = 1,
|
||||
is_propagate_on_assign = 1,
|
||||
is_propagate_on_move = 1,
|
||||
cxx11_construct = 1
|
||||
};
|
||||
|
||||
struct select_copy : allocator_false
|
||||
{ enum { is_select_on_copy = 1 }; };
|
||||
struct propagate_swap : allocator_false
|
||||
{ enum { is_propagate_on_swap = 1 }; };
|
||||
struct propagate_assign : allocator_false
|
||||
{ enum { is_propagate_on_assign = 1 }; };
|
||||
struct propagate_move : allocator_false
|
||||
{ enum { is_propagate_on_move = 1 }; };
|
||||
};
|
||||
|
||||
struct no_select_copy : allocator_flags_all
|
||||
{ enum { is_select_on_copy = 0 }; };
|
||||
struct no_propagate_swap : allocator_flags_all
|
||||
{ enum { is_propagate_on_swap = 0 }; };
|
||||
struct no_propagate_assign : allocator_flags_all
|
||||
{ enum { is_propagate_on_assign = 0 }; };
|
||||
struct no_propagate_move : allocator_flags_all
|
||||
{ enum { is_propagate_on_move = 0 }; };
|
||||
|
||||
template <typename Flag>
|
||||
struct swap_allocator_base
|
||||
struct select_copy : allocator_false
|
||||
{
|
||||
enum
|
||||
{
|
||||
struct propagate_on_container_swap {
|
||||
enum { value = Flag::is_propagate_on_swap }; };
|
||||
is_select_on_copy = 1
|
||||
};
|
||||
|
||||
template <typename Flag>
|
||||
struct assign_allocator_base
|
||||
};
|
||||
struct propagate_swap : allocator_false
|
||||
{
|
||||
enum
|
||||
{
|
||||
struct propagate_on_container_copy_assignment {
|
||||
enum { value = Flag::is_propagate_on_assign }; };
|
||||
is_propagate_on_swap = 1
|
||||
};
|
||||
|
||||
template <typename Flag>
|
||||
struct move_allocator_base
|
||||
};
|
||||
struct propagate_assign : allocator_false
|
||||
{
|
||||
enum
|
||||
{
|
||||
struct propagate_on_container_move_assignment {
|
||||
enum { value = Flag::is_propagate_on_move }; };
|
||||
is_propagate_on_assign = 1
|
||||
};
|
||||
|
||||
namespace
|
||||
};
|
||||
struct propagate_move : allocator_false
|
||||
{
|
||||
enum
|
||||
{
|
||||
// boostinspect:nounnamed
|
||||
bool force_equal_allocator_value = false;
|
||||
is_propagate_on_move = 1
|
||||
};
|
||||
};
|
||||
|
||||
struct no_select_copy : allocator_flags_all
|
||||
{
|
||||
enum
|
||||
{
|
||||
is_select_on_copy = 0
|
||||
};
|
||||
};
|
||||
struct no_propagate_swap : allocator_flags_all
|
||||
{
|
||||
enum
|
||||
{
|
||||
is_propagate_on_swap = 0
|
||||
};
|
||||
};
|
||||
struct no_propagate_assign : allocator_flags_all
|
||||
{
|
||||
enum
|
||||
{
|
||||
is_propagate_on_assign = 0
|
||||
};
|
||||
};
|
||||
struct no_propagate_move : allocator_flags_all
|
||||
{
|
||||
enum
|
||||
{
|
||||
is_propagate_on_move = 0
|
||||
};
|
||||
};
|
||||
|
||||
template <typename Flag> struct swap_allocator_base
|
||||
{
|
||||
struct propagate_on_container_swap
|
||||
{
|
||||
enum
|
||||
{
|
||||
value = Flag::is_propagate_on_swap
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
template <typename Flag> struct assign_allocator_base
|
||||
{
|
||||
struct propagate_on_container_copy_assignment
|
||||
{
|
||||
enum
|
||||
{
|
||||
value = Flag::is_propagate_on_assign
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
template <typename Flag> struct move_allocator_base
|
||||
{
|
||||
struct propagate_on_container_move_assignment
|
||||
{
|
||||
enum
|
||||
{
|
||||
value = Flag::is_propagate_on_move
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
namespace {
|
||||
// boostinspect:nounnamed
|
||||
bool force_equal_allocator_value = false;
|
||||
}
|
||||
|
||||
struct force_equal_allocator
|
||||
{
|
||||
bool old_value_;
|
||||
|
||||
explicit force_equal_allocator(bool value)
|
||||
: old_value_(force_equal_allocator_value)
|
||||
{
|
||||
force_equal_allocator_value = value;
|
||||
}
|
||||
|
||||
struct force_equal_allocator
|
||||
~force_equal_allocator() { force_equal_allocator_value = old_value_; }
|
||||
};
|
||||
|
||||
template <typename T> struct cxx11_allocator_base
|
||||
{
|
||||
int tag_;
|
||||
int selected_;
|
||||
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef T* pointer;
|
||||
typedef T const* const_pointer;
|
||||
typedef T& reference;
|
||||
typedef T const& const_reference;
|
||||
typedef T value_type;
|
||||
|
||||
explicit cxx11_allocator_base(int t) : tag_(t), selected_(0)
|
||||
{
|
||||
bool old_value_;
|
||||
|
||||
explicit force_equal_allocator(bool value)
|
||||
: old_value_(force_equal_allocator_value)
|
||||
{ force_equal_allocator_value = value; }
|
||||
|
||||
~force_equal_allocator()
|
||||
{ force_equal_allocator_value = old_value_; }
|
||||
};
|
||||
detail::tracker.allocator_ref();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct cxx11_allocator_base
|
||||
template <typename Y>
|
||||
cxx11_allocator_base(cxx11_allocator_base<Y> const& x)
|
||||
: tag_(x.tag_), selected_(x.selected_)
|
||||
{
|
||||
int tag_;
|
||||
int selected_;
|
||||
detail::tracker.allocator_ref();
|
||||
}
|
||||
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef T* pointer;
|
||||
typedef T const* const_pointer;
|
||||
typedef T& reference;
|
||||
typedef T const& const_reference;
|
||||
typedef T value_type;
|
||||
cxx11_allocator_base(cxx11_allocator_base const& x)
|
||||
: tag_(x.tag_), selected_(x.selected_)
|
||||
{
|
||||
detail::tracker.allocator_ref();
|
||||
}
|
||||
|
||||
explicit cxx11_allocator_base(int t)
|
||||
: tag_(t), selected_(0)
|
||||
{
|
||||
detail::tracker.allocator_ref();
|
||||
}
|
||||
|
||||
template <typename Y> cxx11_allocator_base(
|
||||
cxx11_allocator_base<Y> const& x)
|
||||
: tag_(x.tag_), selected_(x.selected_)
|
||||
{
|
||||
detail::tracker.allocator_ref();
|
||||
}
|
||||
~cxx11_allocator_base() { detail::tracker.allocator_unref(); }
|
||||
|
||||
cxx11_allocator_base(cxx11_allocator_base const& x)
|
||||
: tag_(x.tag_), selected_(x.selected_)
|
||||
{
|
||||
detail::tracker.allocator_ref();
|
||||
}
|
||||
pointer address(reference r) { return pointer(&r); }
|
||||
|
||||
~cxx11_allocator_base()
|
||||
{
|
||||
detail::tracker.allocator_unref();
|
||||
}
|
||||
const_pointer address(const_reference r) { return const_pointer(&r); }
|
||||
|
||||
pointer address(reference r)
|
||||
{
|
||||
return pointer(&r);
|
||||
}
|
||||
pointer allocate(size_type n)
|
||||
{
|
||||
pointer ptr(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||
detail::tracker.track_allocate((void*)ptr, n, sizeof(T), tag_);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
const_pointer address(const_reference r)
|
||||
{
|
||||
return const_pointer(&r);
|
||||
}
|
||||
pointer allocate(size_type n, void const*)
|
||||
{
|
||||
pointer ptr(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||
detail::tracker.track_allocate((void*)ptr, n, sizeof(T), tag_);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
pointer allocate(size_type n) {
|
||||
pointer ptr(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||
detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
|
||||
return ptr;
|
||||
}
|
||||
void deallocate(pointer p, size_type n)
|
||||
{
|
||||
// Only checking tags when propagating swap.
|
||||
// Note that tags will be tested
|
||||
// properly in the normal allocator.
|
||||
detail::tracker.track_deallocate(
|
||||
(void*)p, n, sizeof(T), tag_, !force_equal_allocator_value);
|
||||
::operator delete((void*)p);
|
||||
}
|
||||
|
||||
pointer allocate(size_type n, void const* u)
|
||||
{
|
||||
pointer ptr(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||
detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void deallocate(pointer p, size_type n)
|
||||
{
|
||||
// Only checking tags when propagating swap.
|
||||
// Note that tags will be tested
|
||||
// properly in the normal allocator.
|
||||
detail::tracker.track_deallocate((void*) p, n, sizeof(T), tag_,
|
||||
!force_equal_allocator_value);
|
||||
::operator delete((void*) p);
|
||||
}
|
||||
|
||||
void construct(T* p, T const& t) {
|
||||
detail::tracker.track_construct((void*) p, sizeof(T), tag_);
|
||||
new(p) T(t);
|
||||
}
|
||||
void construct(T* p, T const& t)
|
||||
{
|
||||
detail::tracker.track_construct((void*)p, sizeof(T), tag_);
|
||||
new (p) T(t);
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
template<typename... Args> void construct(T* p, BOOST_FWD_REF(Args)... args) {
|
||||
detail::tracker.track_construct((void*) p, sizeof(T), tag_);
|
||||
new(p) T(boost::forward<Args>(args)...);
|
||||
}
|
||||
template <typename... Args>
|
||||
void construct(T* p, BOOST_FWD_REF(Args)... args)
|
||||
{
|
||||
detail::tracker.track_construct((void*)p, sizeof(T), tag_);
|
||||
new (p) T(boost::forward<Args>(args)...);
|
||||
}
|
||||
#endif
|
||||
|
||||
void destroy(T* p) {
|
||||
detail::tracker.track_destroy((void*) p, sizeof(T), tag_);
|
||||
p->~T();
|
||||
}
|
||||
|
||||
size_type max_size() const {
|
||||
return (std::numeric_limits<size_type>::max)();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Flags = propagate_swap,
|
||||
typename Enable = void>
|
||||
struct cxx11_allocator;
|
||||
|
||||
template <typename T, typename Flags>
|
||||
struct cxx11_allocator<
|
||||
T, Flags,
|
||||
typename boost::disable_if_c<Flags::is_select_on_copy>::type
|
||||
> : public cxx11_allocator_base<T>,
|
||||
public swap_allocator_base<Flags>,
|
||||
public assign_allocator_base<Flags>,
|
||||
public move_allocator_base<Flags>,
|
||||
Flags
|
||||
void destroy(T* p)
|
||||
{
|
||||
template <typename U> struct rebind {
|
||||
typedef cxx11_allocator<U, Flags> other;
|
||||
};
|
||||
|
||||
explicit cxx11_allocator(int t = 0)
|
||||
: cxx11_allocator_base<T>(t)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Y> cxx11_allocator(
|
||||
cxx11_allocator<Y, Flags> const& x)
|
||||
: cxx11_allocator_base<T>(x)
|
||||
{
|
||||
}
|
||||
|
||||
cxx11_allocator(cxx11_allocator const& x)
|
||||
: cxx11_allocator_base<T>(x)
|
||||
{
|
||||
}
|
||||
|
||||
// When not propagating swap, allocators are always equal
|
||||
// to avoid undefined behaviour.
|
||||
bool operator==(cxx11_allocator const& x) const
|
||||
{
|
||||
return force_equal_allocator_value || (this->tag_ == x.tag_);
|
||||
}
|
||||
|
||||
bool operator!=(cxx11_allocator const& x) const
|
||||
{
|
||||
return !(*this == x);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Flags>
|
||||
struct cxx11_allocator<
|
||||
T, Flags,
|
||||
typename boost::enable_if_c<Flags::is_select_on_copy>::type
|
||||
> : public cxx11_allocator_base<T>,
|
||||
public swap_allocator_base<Flags>,
|
||||
public assign_allocator_base<Flags>,
|
||||
public move_allocator_base<Flags>,
|
||||
Flags
|
||||
{
|
||||
cxx11_allocator select_on_container_copy_construction() const
|
||||
{
|
||||
cxx11_allocator tmp(*this);
|
||||
++tmp.selected_;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
template <typename U> struct rebind {
|
||||
typedef cxx11_allocator<U, Flags> other;
|
||||
};
|
||||
|
||||
explicit cxx11_allocator(int t = 0)
|
||||
: cxx11_allocator_base<T>(t)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Y> cxx11_allocator(
|
||||
cxx11_allocator<Y, Flags> const& x)
|
||||
: cxx11_allocator_base<T>(x)
|
||||
{
|
||||
}
|
||||
|
||||
cxx11_allocator(cxx11_allocator const& x)
|
||||
: cxx11_allocator_base<T>(x)
|
||||
{
|
||||
}
|
||||
|
||||
// When not propagating swap, allocators are always equal
|
||||
// to avoid undefined behaviour.
|
||||
bool operator==(cxx11_allocator const& x) const
|
||||
{
|
||||
return force_equal_allocator_value || (this->tag_ == x.tag_);
|
||||
}
|
||||
|
||||
bool operator!=(cxx11_allocator const& x) const
|
||||
{
|
||||
return !(*this == x);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Flags>
|
||||
bool equivalent_impl(
|
||||
cxx11_allocator<T, Flags> const& x,
|
||||
cxx11_allocator<T, Flags> const& y,
|
||||
test::derived_type)
|
||||
{
|
||||
return x.tag_ == y.tag_;
|
||||
detail::tracker.track_destroy((void*)p, sizeof(T), tag_);
|
||||
p->~T();
|
||||
}
|
||||
|
||||
// Function to check how many times an allocator has been selected,
|
||||
// return 0 for other allocators.
|
||||
|
||||
struct convert_from_anything
|
||||
size_type max_size() const
|
||||
{
|
||||
template <typename T>
|
||||
convert_from_anything(T const&) {}
|
||||
return (std::numeric_limits<size_type>::max)();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Flags = propagate_swap, typename Enable = void>
|
||||
struct cxx11_allocator;
|
||||
|
||||
template <typename T, typename Flags>
|
||||
struct cxx11_allocator<T, Flags,
|
||||
typename boost::disable_if_c<Flags::is_select_on_copy>::type>
|
||||
: public cxx11_allocator_base<T>,
|
||||
public swap_allocator_base<Flags>,
|
||||
public assign_allocator_base<Flags>,
|
||||
public move_allocator_base<Flags>,
|
||||
Flags
|
||||
{
|
||||
#if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 402000)
|
||||
template <typename U> struct rebind
|
||||
{
|
||||
typedef cxx11_allocator<U, Flags> other;
|
||||
};
|
||||
#endif
|
||||
|
||||
inline int selected_count(convert_from_anything)
|
||||
explicit cxx11_allocator(int t = 0) : cxx11_allocator_base<T>(t) {}
|
||||
|
||||
template <typename Y>
|
||||
cxx11_allocator(cxx11_allocator<Y, Flags> const& x)
|
||||
: cxx11_allocator_base<T>(x)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename T, typename Flags>
|
||||
int selected_count(cxx11_allocator<T, Flags> const& x)
|
||||
cxx11_allocator(cxx11_allocator const& x) : cxx11_allocator_base<T>(x) {}
|
||||
|
||||
// When not propagating swap, allocators are always equal
|
||||
// to avoid undefined behaviour.
|
||||
bool operator==(cxx11_allocator const& x) const
|
||||
{
|
||||
return x.selected_;
|
||||
return force_equal_allocator_value || (this->tag_ == x.tag_);
|
||||
}
|
||||
|
||||
bool operator!=(cxx11_allocator const& x) const { return !(*this == x); }
|
||||
};
|
||||
|
||||
template <typename T, typename Flags>
|
||||
struct cxx11_allocator<T, Flags,
|
||||
typename boost::enable_if_c<Flags::is_select_on_copy>::type>
|
||||
: public cxx11_allocator_base<T>,
|
||||
public swap_allocator_base<Flags>,
|
||||
public assign_allocator_base<Flags>,
|
||||
public move_allocator_base<Flags>,
|
||||
Flags
|
||||
{
|
||||
cxx11_allocator select_on_container_copy_construction() const
|
||||
{
|
||||
cxx11_allocator tmp(*this);
|
||||
++tmp.selected_;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 402000)
|
||||
template <typename U> struct rebind
|
||||
{
|
||||
typedef cxx11_allocator<U, Flags> other;
|
||||
};
|
||||
#endif
|
||||
|
||||
explicit cxx11_allocator(int t = 0) : cxx11_allocator_base<T>(t) {}
|
||||
|
||||
template <typename Y>
|
||||
cxx11_allocator(cxx11_allocator<Y, Flags> const& x)
|
||||
: cxx11_allocator_base<T>(x)
|
||||
{
|
||||
}
|
||||
|
||||
cxx11_allocator(cxx11_allocator const& x) : cxx11_allocator_base<T>(x) {}
|
||||
|
||||
// When not propagating swap, allocators are always equal
|
||||
// to avoid undefined behaviour.
|
||||
bool operator==(cxx11_allocator const& x) const
|
||||
{
|
||||
return force_equal_allocator_value || (this->tag_ == x.tag_);
|
||||
}
|
||||
|
||||
bool operator!=(cxx11_allocator const& x) const { return !(*this == x); }
|
||||
};
|
||||
|
||||
template <typename T, typename Flags>
|
||||
bool equivalent_impl(cxx11_allocator<T, Flags> const& x,
|
||||
cxx11_allocator<T, Flags> const& y, test::derived_type)
|
||||
{
|
||||
return x.tag_ == y.tag_;
|
||||
}
|
||||
|
||||
// Function to check how many times an allocator has been selected,
|
||||
// return 0 for other allocators.
|
||||
|
||||
struct convert_from_anything
|
||||
{
|
||||
template <typename T> convert_from_anything(T const&) {}
|
||||
};
|
||||
|
||||
inline int selected_count(convert_from_anything) { return 0; }
|
||||
|
||||
template <typename T, typename Flags>
|
||||
int selected_count(cxx11_allocator<T, Flags> const& x)
|
||||
{
|
||||
return x.selected_;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -6,13 +6,12 @@
|
||||
#if !defined(BOOST_UNORDERED_TEST_OBJECTS_FWD_HEADER)
|
||||
#define BOOST_UNORDERED_TEST_OBJECTS_FWD_HEADER
|
||||
|
||||
namespace test
|
||||
{
|
||||
class object;
|
||||
class hash;
|
||||
class less;
|
||||
class equal_to;
|
||||
template <class T> class allocator;
|
||||
namespace test {
|
||||
class object;
|
||||
class hash;
|
||||
class less;
|
||||
class equal_to;
|
||||
template <class T> class allocator;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -10,26 +10,33 @@
|
||||
#if !defined(BOOST_UNORDERED_OBJECTS_MINIMAL_HEADER)
|
||||
#define BOOST_UNORDERED_OBJECTS_MINIMAL_HEADER
|
||||
|
||||
#include <cstddef>
|
||||
#include <boost/move/move.hpp>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4100) // unreferenced formal parameter
|
||||
#pragma warning(disable : 4100) // unreferenced formal parameter
|
||||
#endif
|
||||
|
||||
namespace test
|
||||
{
|
||||
namespace minimal
|
||||
{
|
||||
#if !BOOST_WORKAROUND(BOOST_MSVC, == 1500)
|
||||
#define BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED 1
|
||||
#else
|
||||
#define BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED 0
|
||||
#endif
|
||||
|
||||
namespace test {
|
||||
namespace minimal {
|
||||
class destructible;
|
||||
class copy_constructible;
|
||||
class copy_constructible_equality_comparable;
|
||||
class default_assignable;
|
||||
class assignable;
|
||||
|
||||
struct ampersand_operator_used {};
|
||||
struct ampersand_operator_used
|
||||
{
|
||||
ampersand_operator_used() { BOOST_TEST(false); }
|
||||
};
|
||||
|
||||
template <class T> class hash;
|
||||
template <class T> class equal_to;
|
||||
@ -40,167 +47,186 @@ namespace minimal
|
||||
|
||||
struct constructor_param
|
||||
{
|
||||
operator int() const { return 0; }
|
||||
operator int() const { return 0; }
|
||||
};
|
||||
|
||||
class destructible
|
||||
{
|
||||
public:
|
||||
destructible(constructor_param const&) {}
|
||||
~destructible() {}
|
||||
destructible(constructor_param const&) {}
|
||||
~destructible() {}
|
||||
void dummy_member() const {}
|
||||
|
||||
private:
|
||||
destructible(destructible const&);
|
||||
destructible& operator=(destructible const&);
|
||||
destructible(destructible const&);
|
||||
destructible& operator=(destructible const&);
|
||||
};
|
||||
|
||||
class copy_constructible
|
||||
{
|
||||
public:
|
||||
copy_constructible(constructor_param const&) {}
|
||||
copy_constructible(copy_constructible const&) {}
|
||||
~copy_constructible() {}
|
||||
copy_constructible(constructor_param const&) {}
|
||||
copy_constructible(copy_constructible const&) {}
|
||||
~copy_constructible() {}
|
||||
void dummy_member() const {}
|
||||
|
||||
private:
|
||||
copy_constructible& operator=(copy_constructible const&);
|
||||
copy_constructible() {}
|
||||
copy_constructible& operator=(copy_constructible const&);
|
||||
copy_constructible() {}
|
||||
};
|
||||
|
||||
class copy_constructible_equality_comparable
|
||||
{
|
||||
public:
|
||||
copy_constructible_equality_comparable(constructor_param const&) {}
|
||||
copy_constructible_equality_comparable(constructor_param const&) {}
|
||||
|
||||
copy_constructible_equality_comparable(
|
||||
copy_constructible_equality_comparable const&)
|
||||
{
|
||||
}
|
||||
copy_constructible_equality_comparable(
|
||||
copy_constructible_equality_comparable const&)
|
||||
{
|
||||
}
|
||||
|
||||
~copy_constructible_equality_comparable()
|
||||
{
|
||||
}
|
||||
~copy_constructible_equality_comparable() {}
|
||||
|
||||
void dummy_member() const {}
|
||||
|
||||
private:
|
||||
copy_constructible_equality_comparable& operator=(
|
||||
copy_constructible_equality_comparable const&);
|
||||
copy_constructible_equality_comparable() {}
|
||||
ampersand_operator_used operator&() const { return ampersand_operator_used(); }
|
||||
copy_constructible_equality_comparable& operator=(
|
||||
copy_constructible_equality_comparable const&);
|
||||
copy_constructible_equality_comparable() {}
|
||||
#if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED
|
||||
ampersand_operator_used operator&() const
|
||||
{
|
||||
return ampersand_operator_used();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
bool operator==(
|
||||
copy_constructible_equality_comparable,
|
||||
copy_constructible_equality_comparable)
|
||||
bool operator==(copy_constructible_equality_comparable,
|
||||
copy_constructible_equality_comparable)
|
||||
{
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(
|
||||
copy_constructible_equality_comparable,
|
||||
copy_constructible_equality_comparable)
|
||||
bool operator!=(copy_constructible_equality_comparable,
|
||||
copy_constructible_equality_comparable)
|
||||
{
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
class default_assignable
|
||||
{
|
||||
public:
|
||||
default_assignable(constructor_param const&) {}
|
||||
default_assignable(constructor_param const&) {}
|
||||
|
||||
default_assignable()
|
||||
{
|
||||
}
|
||||
default_assignable() {}
|
||||
|
||||
default_assignable(default_assignable const&)
|
||||
{
|
||||
}
|
||||
default_assignable(default_assignable const&) {}
|
||||
|
||||
default_assignable& operator=(default_assignable const&)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
default_assignable& operator=(default_assignable const&) { return *this; }
|
||||
|
||||
~default_assignable()
|
||||
{
|
||||
}
|
||||
~default_assignable() {}
|
||||
|
||||
private:
|
||||
ampersand_operator_used operator&() const {
|
||||
return ampersand_operator_used(); }
|
||||
void dummy_member() const {}
|
||||
|
||||
#if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED
|
||||
ampersand_operator_used operator&() const
|
||||
{
|
||||
return ampersand_operator_used();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
class assignable
|
||||
{
|
||||
public:
|
||||
assignable(constructor_param const&) {}
|
||||
assignable(assignable const&) {}
|
||||
assignable& operator=(assignable const&) { return *this; }
|
||||
~assignable() {}
|
||||
assignable(constructor_param const&) {}
|
||||
assignable(assignable const&) {}
|
||||
assignable& operator=(assignable const&) { return *this; }
|
||||
~assignable() {}
|
||||
void dummy_member() const {}
|
||||
|
||||
private:
|
||||
assignable() {}
|
||||
// TODO: This messes up a concept check in the tests.
|
||||
//ampersand_operator_used operator&() const { return ampersand_operator_used(); }
|
||||
assignable() {}
|
||||
#if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED
|
||||
ampersand_operator_used operator&() const
|
||||
{
|
||||
return ampersand_operator_used();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
struct movable_init {};
|
||||
struct movable_init
|
||||
{
|
||||
};
|
||||
|
||||
class movable1
|
||||
{
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE(movable1)
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE(movable1)
|
||||
|
||||
public:
|
||||
movable1(constructor_param const&) {}
|
||||
movable1() {}
|
||||
explicit movable1(movable_init) {}
|
||||
movable1(BOOST_RV_REF(movable1)) {}
|
||||
movable1& operator=(BOOST_RV_REF(movable1)) { return *this; }
|
||||
~movable1() {}
|
||||
movable1(constructor_param const&) {}
|
||||
movable1() {}
|
||||
explicit movable1(movable_init) {}
|
||||
movable1(BOOST_RV_REF(movable1)) {}
|
||||
movable1& operator=(BOOST_RV_REF(movable1)) { return *this; }
|
||||
~movable1() {}
|
||||
void dummy_member() const {}
|
||||
};
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
class movable2
|
||||
{
|
||||
public:
|
||||
movable2(constructor_param const&) {}
|
||||
explicit movable2(movable_init) {}
|
||||
movable2(movable2&&) {}
|
||||
~movable2() {}
|
||||
movable2& operator=(movable2&&) { return *this; }
|
||||
movable2(constructor_param const&) {}
|
||||
explicit movable2(movable_init) {}
|
||||
movable2(movable2&&) {}
|
||||
~movable2() {}
|
||||
movable2& operator=(movable2&&) { return *this; }
|
||||
void dummy_member() const {}
|
||||
|
||||
private:
|
||||
movable2() {}
|
||||
movable2(movable2 const&);
|
||||
movable2& operator=(movable2 const&);
|
||||
movable2() {}
|
||||
movable2(movable2 const&);
|
||||
movable2& operator=(movable2 const&);
|
||||
};
|
||||
#else
|
||||
typedef movable1 movable2;
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
class hash
|
||||
template <class T> class hash
|
||||
{
|
||||
public:
|
||||
hash(constructor_param const&) {}
|
||||
hash() {}
|
||||
hash(hash const&) {}
|
||||
hash& operator=(hash const&) { return *this; }
|
||||
~hash() {}
|
||||
hash(constructor_param const&) {}
|
||||
hash() {}
|
||||
hash(hash const&) {}
|
||||
hash& operator=(hash const&) { return *this; }
|
||||
~hash() {}
|
||||
|
||||
std::size_t operator()(T const&) const { return 0; }
|
||||
private:
|
||||
ampersand_operator_used operator&() const { return ampersand_operator_used(); }
|
||||
std::size_t operator()(T const&) const { return 0; }
|
||||
#if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED
|
||||
ampersand_operator_used operator&() const
|
||||
{
|
||||
return ampersand_operator_used();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class equal_to
|
||||
template <class T> class equal_to
|
||||
{
|
||||
public:
|
||||
equal_to(constructor_param const&) {}
|
||||
equal_to() {}
|
||||
equal_to(equal_to const&) {}
|
||||
equal_to& operator=(equal_to const&) { return *this; }
|
||||
~equal_to() {}
|
||||
equal_to(constructor_param const&) {}
|
||||
equal_to() {}
|
||||
equal_to(equal_to const&) {}
|
||||
equal_to& operator=(equal_to const&) { return *this; }
|
||||
~equal_to() {}
|
||||
|
||||
bool operator()(T const&, T const&) const { return true; }
|
||||
private:
|
||||
ampersand_operator_used operator&() const { return ampersand_operator_used(); }
|
||||
bool operator()(T const&, T const&) const { return true; }
|
||||
#if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED
|
||||
ampersand_operator_used operator&() const
|
||||
{
|
||||
return ampersand_operator_used();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <class T> class ptr;
|
||||
@ -209,288 +235,391 @@ namespace minimal
|
||||
struct void_ptr
|
||||
{
|
||||
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
|
||||
template <typename T>
|
||||
friend class ptr;
|
||||
template <typename T> friend class ptr;
|
||||
|
||||
private:
|
||||
#endif
|
||||
|
||||
void* ptr_;
|
||||
void* ptr_;
|
||||
|
||||
public:
|
||||
void_ptr() : ptr_(0) {}
|
||||
void_ptr() : ptr_(0) {}
|
||||
|
||||
template <typename T>
|
||||
explicit void_ptr(ptr<T> const& x) : ptr_(x.ptr_) {}
|
||||
template <typename T> explicit void_ptr(ptr<T> const& x) : ptr_(x.ptr_) {}
|
||||
|
||||
// I'm not using the safe bool idiom because the containers should be
|
||||
// able to cope with bool conversions.
|
||||
operator bool() const { return !!ptr_; }
|
||||
// I'm not using the safe bool idiom because the containers should be
|
||||
// able to cope with bool conversions.
|
||||
operator bool() const { return !!ptr_; }
|
||||
|
||||
bool operator==(void_ptr const& x) const { return ptr_ == x.ptr_; }
|
||||
bool operator!=(void_ptr const& x) const { return ptr_ != x.ptr_; }
|
||||
bool operator==(void_ptr const& x) const { return ptr_ == x.ptr_; }
|
||||
bool operator!=(void_ptr const& x) const { return ptr_ != x.ptr_; }
|
||||
};
|
||||
|
||||
class void_const_ptr
|
||||
{
|
||||
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
|
||||
template <typename T>
|
||||
friend class const_ptr;
|
||||
template <typename T> friend class const_ptr;
|
||||
|
||||
private:
|
||||
#endif
|
||||
|
||||
void* ptr_;
|
||||
void* ptr_;
|
||||
|
||||
public:
|
||||
void_const_ptr() : ptr_(0) {}
|
||||
void_const_ptr() : ptr_(0) {}
|
||||
|
||||
template <typename T>
|
||||
explicit void_const_ptr(const_ptr<T> const& x) : ptr_(x.ptr_) {}
|
||||
template <typename T>
|
||||
explicit void_const_ptr(const_ptr<T> const& x) : ptr_(x.ptr_)
|
||||
{
|
||||
}
|
||||
|
||||
// I'm not using the safe bool idiom because the containers should be
|
||||
// able to cope with bool conversions.
|
||||
operator bool() const { return !!ptr_; }
|
||||
// I'm not using the safe bool idiom because the containers should be
|
||||
// able to cope with bool conversions.
|
||||
operator bool() const { return !!ptr_; }
|
||||
|
||||
bool operator==(void_const_ptr const& x) const { return ptr_ == x.ptr_; }
|
||||
bool operator!=(void_const_ptr const& x) const { return ptr_ != x.ptr_; }
|
||||
bool operator==(void_const_ptr const& x) const { return ptr_ == x.ptr_; }
|
||||
bool operator!=(void_const_ptr const& x) const { return ptr_ != x.ptr_; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class ptr
|
||||
template <class T> class ptr
|
||||
{
|
||||
friend class allocator<T>;
|
||||
friend class const_ptr<T>;
|
||||
friend struct void_ptr;
|
||||
friend class allocator<T>;
|
||||
friend class const_ptr<T>;
|
||||
friend struct void_ptr;
|
||||
|
||||
T* ptr_;
|
||||
T* ptr_;
|
||||
|
||||
ptr(T* x) : ptr_(x) {}
|
||||
|
||||
ptr(T* x) : ptr_(x) {}
|
||||
public:
|
||||
ptr() : ptr_(0) {}
|
||||
explicit ptr(void_ptr const& x) : ptr_((T*) x.ptr_) {}
|
||||
ptr() : ptr_(0) {}
|
||||
explicit ptr(void_ptr const& x) : ptr_((T*)x.ptr_) {}
|
||||
|
||||
T& operator*() const { return *ptr_; }
|
||||
T* operator->() const { return ptr_; }
|
||||
ptr& operator++() { ++ptr_; return *this; }
|
||||
ptr operator++(int) { ptr tmp(*this); ++ptr_; return tmp; }
|
||||
ptr operator+(std::ptrdiff_t s) const { return ptr<T>(ptr_ + s); }
|
||||
friend ptr operator+(std::ptrdiff_t s, ptr p)
|
||||
{ return ptr<T>(s + p.ptr_); }
|
||||
T& operator[](std::ptrdiff_t s) const { return ptr_[s]; }
|
||||
bool operator!() const { return !ptr_; }
|
||||
|
||||
// I'm not using the safe bool idiom because the containers should be
|
||||
// able to cope with bool conversions.
|
||||
operator bool() const { return !!ptr_; }
|
||||
T& operator*() const { return *ptr_; }
|
||||
T* operator->() const { return ptr_; }
|
||||
ptr& operator++()
|
||||
{
|
||||
++ptr_;
|
||||
return *this;
|
||||
}
|
||||
ptr operator++(int)
|
||||
{
|
||||
ptr tmp(*this);
|
||||
++ptr_;
|
||||
return tmp;
|
||||
}
|
||||
ptr operator+(std::ptrdiff_t s) const { return ptr<T>(ptr_ + s); }
|
||||
friend ptr operator+(std::ptrdiff_t s, ptr p)
|
||||
{
|
||||
return ptr<T>(s + p.ptr_);
|
||||
}
|
||||
T& operator[](std::ptrdiff_t s) const { return ptr_[s]; }
|
||||
bool operator!() const { return !ptr_; }
|
||||
|
||||
bool operator==(ptr const& x) const { return ptr_ == x.ptr_; }
|
||||
bool operator!=(ptr const& x) const { return ptr_ != x.ptr_; }
|
||||
bool operator<(ptr const& x) const { return ptr_ < x.ptr_; }
|
||||
bool operator>(ptr const& x) const { return ptr_ > x.ptr_; }
|
||||
bool operator<=(ptr const& x) const { return ptr_ <= x.ptr_; }
|
||||
bool operator>=(ptr const& x) const { return ptr_ >= x.ptr_; }
|
||||
private:
|
||||
// TODO:
|
||||
//ampersand_operator_used operator&() const { return ampersand_operator_used(); }
|
||||
// I'm not using the safe bool idiom because the containers should be
|
||||
// able to cope with bool conversions.
|
||||
operator bool() const { return !!ptr_; }
|
||||
|
||||
bool operator==(ptr const& x) const { return ptr_ == x.ptr_; }
|
||||
bool operator!=(ptr const& x) const { return ptr_ != x.ptr_; }
|
||||
bool operator<(ptr const& x) const { return ptr_ < x.ptr_; }
|
||||
bool operator>(ptr const& x) const { return ptr_ > x.ptr_; }
|
||||
bool operator<=(ptr const& x) const { return ptr_ <= x.ptr_; }
|
||||
bool operator>=(ptr const& x) const { return ptr_ >= x.ptr_; }
|
||||
#if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED
|
||||
ampersand_operator_used operator&() const
|
||||
{
|
||||
return ampersand_operator_used();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class const_ptr
|
||||
template <class T> class const_ptr
|
||||
{
|
||||
friend class allocator<T>;
|
||||
friend struct const_void_ptr;
|
||||
friend class allocator<T>;
|
||||
friend struct const_void_ptr;
|
||||
|
||||
T const* ptr_;
|
||||
T const* ptr_;
|
||||
|
||||
const_ptr(T const* ptr) : ptr_(ptr) {}
|
||||
|
||||
const_ptr(T const* ptr) : ptr_(ptr) {}
|
||||
public:
|
||||
const_ptr() : ptr_(0) {}
|
||||
const_ptr(ptr<T> const& x) : ptr_(x.ptr_) {}
|
||||
explicit const_ptr(void_const_ptr const& x) : ptr_((T const*) x.ptr_) {}
|
||||
const_ptr() : ptr_(0) {}
|
||||
const_ptr(ptr<T> const& x) : ptr_(x.ptr_) {}
|
||||
explicit const_ptr(void_const_ptr const& x) : ptr_((T const*)x.ptr_) {}
|
||||
|
||||
T const& operator*() const { return *ptr_; }
|
||||
T const* operator->() const { return ptr_; }
|
||||
const_ptr& operator++() { ++ptr_; return *this; }
|
||||
const_ptr operator++(int) { const_ptr tmp(*this); ++ptr_; return tmp; }
|
||||
const_ptr operator+(std::ptrdiff_t s) const
|
||||
{ return const_ptr(ptr_ + s); }
|
||||
friend const_ptr operator+(std::ptrdiff_t s, const_ptr p)
|
||||
{ return ptr<T>(s + p.ptr_); }
|
||||
T const& operator[](int s) const { return ptr_[s]; }
|
||||
bool operator!() const { return !ptr_; }
|
||||
operator bool() const { return !!ptr_; }
|
||||
T const& operator*() const { return *ptr_; }
|
||||
T const* operator->() const { return ptr_; }
|
||||
const_ptr& operator++()
|
||||
{
|
||||
++ptr_;
|
||||
return *this;
|
||||
}
|
||||
const_ptr operator++(int)
|
||||
{
|
||||
const_ptr tmp(*this);
|
||||
++ptr_;
|
||||
return tmp;
|
||||
}
|
||||
const_ptr operator+(std::ptrdiff_t s) const
|
||||
{
|
||||
return const_ptr(ptr_ + s);
|
||||
}
|
||||
friend const_ptr operator+(std::ptrdiff_t s, const_ptr p)
|
||||
{
|
||||
return ptr<T>(s + p.ptr_);
|
||||
}
|
||||
T const& operator[](int s) const { return ptr_[s]; }
|
||||
bool operator!() const { return !ptr_; }
|
||||
operator bool() const { return !!ptr_; }
|
||||
|
||||
bool operator==(const_ptr const& x) const { return ptr_ == x.ptr_; }
|
||||
bool operator!=(const_ptr const& x) const { return ptr_ != x.ptr_; }
|
||||
bool operator<(const_ptr const& x) const { return ptr_ < x.ptr_; }
|
||||
bool operator>(const_ptr const& x) const { return ptr_ > x.ptr_; }
|
||||
bool operator<=(const_ptr const& x) const { return ptr_ <= x.ptr_; }
|
||||
bool operator>=(const_ptr const& x) const { return ptr_ >= x.ptr_; }
|
||||
private:
|
||||
// TODO:
|
||||
//ampersand_operator_used operator&() const { return ampersand_operator_used(); }
|
||||
bool operator==(const_ptr const& x) const { return ptr_ == x.ptr_; }
|
||||
bool operator!=(const_ptr const& x) const { return ptr_ != x.ptr_; }
|
||||
bool operator<(const_ptr const& x) const { return ptr_ < x.ptr_; }
|
||||
bool operator>(const_ptr const& x) const { return ptr_ > x.ptr_; }
|
||||
bool operator<=(const_ptr const& x) const { return ptr_ <= x.ptr_; }
|
||||
bool operator>=(const_ptr const& x) const { return ptr_ >= x.ptr_; }
|
||||
#if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED
|
||||
ampersand_operator_used operator&() const
|
||||
{
|
||||
return ampersand_operator_used();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class allocator
|
||||
template <class T> class allocator
|
||||
{
|
||||
public:
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef void_ptr void_pointer;
|
||||
typedef void_const_ptr const_void_pointer;
|
||||
typedef ptr<T> pointer;
|
||||
typedef const_ptr<T> const_pointer;
|
||||
typedef T& reference;
|
||||
typedef T const& const_reference;
|
||||
typedef T value_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef void_ptr void_pointer;
|
||||
typedef void_const_ptr const_void_pointer;
|
||||
typedef ptr<T> pointer;
|
||||
typedef const_ptr<T> const_pointer;
|
||||
typedef T& reference;
|
||||
typedef T const& const_reference;
|
||||
typedef T value_type;
|
||||
|
||||
template <class U> struct rebind { typedef allocator<U> other; };
|
||||
template <class U> struct rebind
|
||||
{
|
||||
typedef allocator<U> other;
|
||||
};
|
||||
|
||||
allocator() {}
|
||||
template <class Y> allocator(allocator<Y> const&) {}
|
||||
allocator(allocator const&) {}
|
||||
~allocator() {}
|
||||
allocator() {}
|
||||
template <class Y> allocator(allocator<Y> const&) {}
|
||||
allocator(allocator const&) {}
|
||||
~allocator() {}
|
||||
|
||||
pointer address(reference r) { return pointer(&r); }
|
||||
const_pointer address(const_reference r) { return const_pointer(&r); }
|
||||
pointer address(reference r) { return pointer(&r); }
|
||||
const_pointer address(const_reference r) { return const_pointer(&r); }
|
||||
|
||||
pointer allocate(size_type n) {
|
||||
return pointer(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||
}
|
||||
pointer allocate(size_type n)
|
||||
{
|
||||
return pointer(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||
}
|
||||
|
||||
template <class Y>
|
||||
pointer allocate(size_type n, const_ptr<Y> u)
|
||||
{
|
||||
return pointer(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||
}
|
||||
template <class Y> pointer allocate(size_type n, const_ptr<Y>)
|
||||
{
|
||||
return pointer(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||
}
|
||||
|
||||
void deallocate(pointer p, size_type)
|
||||
{
|
||||
::operator delete((void*) p.ptr_);
|
||||
}
|
||||
void deallocate(pointer p, size_type)
|
||||
{
|
||||
::operator delete((void*)p.ptr_);
|
||||
}
|
||||
|
||||
void construct(T* p, T const& t) { new((void*)p) T(t); }
|
||||
void construct(T* p, T const& t) { new ((void*)p) T(t); }
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
template<class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args) {
|
||||
new((void*)p) T(boost::forward<Args>(args)...);
|
||||
}
|
||||
template <class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args)
|
||||
{
|
||||
new ((void*)p) T(boost::forward<Args>(args)...);
|
||||
}
|
||||
#endif
|
||||
|
||||
void destroy(T* p) { p->~T(); }
|
||||
void destroy(T* p) { p->~T(); }
|
||||
|
||||
size_type max_size() const { return 1000; }
|
||||
size_type max_size() const { return 1000; }
|
||||
|
||||
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) || \
|
||||
BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
|
||||
public: allocator& operator=(allocator const&) { return *this;}
|
||||
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) || \
|
||||
BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
|
||||
public:
|
||||
allocator& operator=(allocator const&) { return *this; }
|
||||
#else
|
||||
private: allocator& operator=(allocator const&);
|
||||
#endif
|
||||
private:
|
||||
ampersand_operator_used operator&() const { return ampersand_operator_used(); }
|
||||
allocator& operator=(allocator const&);
|
||||
#endif
|
||||
#if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED
|
||||
ampersand_operator_used operator&() const
|
||||
{
|
||||
return ampersand_operator_used();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <class T> class allocator<T const>
|
||||
{
|
||||
public:
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef void_ptr void_pointer;
|
||||
typedef void_const_ptr const_void_pointer;
|
||||
// Maybe these two should be const_ptr<T>
|
||||
typedef ptr<T const> pointer;
|
||||
typedef const_ptr<T const> const_pointer;
|
||||
typedef T const& reference;
|
||||
typedef T const& const_reference;
|
||||
typedef T const value_type;
|
||||
|
||||
template <class U> struct rebind
|
||||
{
|
||||
typedef allocator<U> other;
|
||||
};
|
||||
|
||||
allocator() {}
|
||||
template <class Y> allocator(allocator<Y> const&) {}
|
||||
allocator(allocator const&) {}
|
||||
~allocator() {}
|
||||
|
||||
const_pointer address(const_reference r) { return const_pointer(&r); }
|
||||
|
||||
pointer allocate(size_type n)
|
||||
{
|
||||
return pointer(static_cast<T const*>(::operator new(n * sizeof(T))));
|
||||
}
|
||||
|
||||
template <class Y> pointer allocate(size_type n, const_ptr<Y>)
|
||||
{
|
||||
return pointer(static_cast<T const*>(::operator new(n * sizeof(T))));
|
||||
}
|
||||
|
||||
void deallocate(pointer p, size_type)
|
||||
{
|
||||
::operator delete((void*)p.ptr_);
|
||||
}
|
||||
|
||||
void construct(T const* p, T const& t) { new ((void*)p) T(t); }
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
template <class... Args>
|
||||
void construct(T const* p, BOOST_FWD_REF(Args)... args)
|
||||
{
|
||||
new ((void*)p) T(boost::forward<Args>(args)...);
|
||||
}
|
||||
#endif
|
||||
|
||||
void destroy(T const* p) { p->~T(); }
|
||||
|
||||
size_type max_size() const { return 1000; }
|
||||
|
||||
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) || \
|
||||
BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
|
||||
public:
|
||||
allocator& operator=(allocator const&) { return *this; }
|
||||
#else
|
||||
private:
|
||||
allocator& operator=(allocator const&);
|
||||
#endif
|
||||
#if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED
|
||||
ampersand_operator_used operator&() const
|
||||
{
|
||||
return ampersand_operator_used();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline bool operator==(allocator<T> const&, allocator<T> const&)
|
||||
{
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline bool operator!=(allocator<T> const&, allocator<T> const&)
|
||||
{
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void swap(allocator<T>&, allocator<T>&)
|
||||
{
|
||||
}
|
||||
template <class T> void swap(allocator<T>&, allocator<T>&) {}
|
||||
|
||||
// C++11 allocator
|
||||
//
|
||||
// Not a fully minimal C++11 allocator, just what I support. Hopefully will
|
||||
// cut down further in the future.
|
||||
|
||||
template <class T>
|
||||
class cxx11_allocator
|
||||
template <class T> class cxx11_allocator
|
||||
{
|
||||
public:
|
||||
typedef T value_type;
|
||||
template <class U> struct rebind { typedef cxx11_allocator<U> other; };
|
||||
typedef T value_type;
|
||||
// template <class U> struct rebind { typedef cxx11_allocator<U> other; };
|
||||
|
||||
cxx11_allocator() {}
|
||||
template <class Y> cxx11_allocator(cxx11_allocator<Y> const&) {}
|
||||
cxx11_allocator(cxx11_allocator const&) {}
|
||||
~cxx11_allocator() {}
|
||||
cxx11_allocator() {}
|
||||
template <class Y> cxx11_allocator(cxx11_allocator<Y> const&) {}
|
||||
cxx11_allocator(cxx11_allocator const&) {}
|
||||
~cxx11_allocator() {}
|
||||
|
||||
T* address(T& r) { return &r; }
|
||||
T const* address(T const& r) { return &r; }
|
||||
T* address(T& r) { return &r; }
|
||||
T const* address(T const& r) { return &r; }
|
||||
|
||||
T* allocate(std::size_t n) {
|
||||
return static_cast<T*>(::operator new(n * sizeof(T)));
|
||||
}
|
||||
T* allocate(std::size_t n)
|
||||
{
|
||||
return static_cast<T*>(::operator new(n * sizeof(T)));
|
||||
}
|
||||
|
||||
template <class Y>
|
||||
T* allocate(std::size_t n, const_ptr<Y> u) {
|
||||
return static_cast<T*>(::operator new(n * sizeof(T)));
|
||||
}
|
||||
template <class Y> T* allocate(std::size_t n, const_ptr<Y>)
|
||||
{
|
||||
return static_cast<T*>(::operator new(n * sizeof(T)));
|
||||
}
|
||||
|
||||
void deallocate(T* p, std::size_t) {
|
||||
::operator delete((void*) p);
|
||||
}
|
||||
void deallocate(T* p, std::size_t) { ::operator delete((void*)p); }
|
||||
|
||||
void construct(T* p, T const& t) { new((void*)p) T(t); }
|
||||
void construct(T* p, T const& t) { new ((void*)p) T(t); }
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
template<class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args) {
|
||||
new((void*)p) T(boost::forward<Args>(args)...);
|
||||
}
|
||||
template <class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args)
|
||||
{
|
||||
new ((void*)p) T(boost::forward<Args>(args)...);
|
||||
}
|
||||
#endif
|
||||
|
||||
void destroy(T* p) { p->~T(); }
|
||||
void destroy(T* p) { p->~T(); }
|
||||
|
||||
std::size_t max_size() const { return 1000u; }
|
||||
std::size_t max_size() const { return 1000u; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline bool operator==(cxx11_allocator<T> const&, cxx11_allocator<T> const&)
|
||||
{
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline bool operator!=(cxx11_allocator<T> const&, cxx11_allocator<T> const&)
|
||||
{
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void swap(cxx11_allocator<T>&, cxx11_allocator<T>&)
|
||||
{
|
||||
}
|
||||
}
|
||||
template <class T> void swap(cxx11_allocator<T>&, cxx11_allocator<T>&) {}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
|
||||
namespace boost {
|
||||
#else
|
||||
namespace test {
|
||||
namespace minimal {
|
||||
namespace minimal {
|
||||
#endif
|
||||
std::size_t hash_value(
|
||||
test::minimal::copy_constructible_equality_comparable)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
std::size_t hash_value(test::minimal::copy_constructible_equality_comparable)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
|
||||
}}
|
||||
#else
|
||||
}
|
||||
}
|
||||
#else
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,65 +0,0 @@
|
||||
|
||||
# Copyright 2006-2008 Daniel James.
|
||||
# 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 testing ;
|
||||
|
||||
project unordered-test/unordered
|
||||
: requirements
|
||||
<warnings>all
|
||||
<toolset>intel:<warnings>on
|
||||
# Would be nice to define -Wundef, but I'm getting warnings from
|
||||
# Boost.Preprocessor on trunk.
|
||||
<toolset>gcc:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wno-long-long -Wfloat-equal"
|
||||
<toolset>darwin:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal"
|
||||
#<toolset>gcc:<define>_GLIBCXX_DEBUG
|
||||
#<toolset>darwin:<define>_GLIBCXX_DEBUG
|
||||
;
|
||||
|
||||
test-suite unordered
|
||||
:
|
||||
[ run fwd_set_test.cpp ]
|
||||
[ run fwd_map_test.cpp ]
|
||||
[ run allocator_traits.cpp ]
|
||||
[ run minimal_allocator.cpp ]
|
||||
[ run compile_set.cpp ]
|
||||
[ run compile_map.cpp ]
|
||||
[ run noexcept_tests.cpp ]
|
||||
[ run link_test_1.cpp link_test_2.cpp ]
|
||||
[ run incomplete_test.cpp ]
|
||||
[ run simple_tests.cpp ]
|
||||
[ run equivalent_keys_tests.cpp ]
|
||||
[ run constructor_tests.cpp ]
|
||||
[ run copy_tests.cpp ]
|
||||
[ run move_tests.cpp ]
|
||||
[ run assign_tests.cpp ]
|
||||
[ run insert_tests.cpp ]
|
||||
[ run insert_stable_tests.cpp ]
|
||||
[ run unnecessary_copy_tests.cpp ]
|
||||
[ run erase_tests.cpp ]
|
||||
[ run erase_equiv_tests.cpp ]
|
||||
[ run find_tests.cpp ]
|
||||
[ run at_tests.cpp ]
|
||||
[ run bucket_tests.cpp ]
|
||||
[ run load_factor_tests.cpp ]
|
||||
[ run rehash_tests.cpp ]
|
||||
[ run equality_tests.cpp ]
|
||||
[ run swap_tests.cpp ]
|
||||
|
||||
[ run compile_set.cpp : :
|
||||
: <define>BOOST_UNORDERED_USE_MOVE
|
||||
: bmove_compile_set ]
|
||||
[ run compile_map.cpp : :
|
||||
: <define>BOOST_UNORDERED_USE_MOVE
|
||||
: bmove_compile_map ]
|
||||
[ run copy_tests.cpp : :
|
||||
: <define>BOOST_UNORDERED_USE_MOVE
|
||||
: bmove_copy ]
|
||||
[ run move_tests.cpp : :
|
||||
: <define>BOOST_UNORDERED_USE_MOVE
|
||||
: bmove_move ]
|
||||
[ run assign_tests.cpp : :
|
||||
: <define>BOOST_UNORDERED_USE_MOVE
|
||||
: bmove_assign ]
|
||||
;
|
@ -3,252 +3,286 @@
|
||||
// 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 <boost/unordered/detail/allocate.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/limits.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/unordered/detail/implementation.hpp>
|
||||
|
||||
// Boilerplate
|
||||
|
||||
#define ALLOCATOR_METHODS(name) \
|
||||
template <typename U> struct rebind { \
|
||||
typedef name<U> other; \
|
||||
}; \
|
||||
\
|
||||
name() {} \
|
||||
template <typename Y> name(name<Y> const&) {} \
|
||||
T* address(T& r) { return &r;} \
|
||||
T const* address(T const& r) { return &r; } \
|
||||
T* allocate(std::size_t n) \
|
||||
{ return static_cast<T*>(::operator new(n * sizeof(T))); } \
|
||||
T* allocate(std::size_t n, void const* u) \
|
||||
{ return static_cast<T*>(::operator new(n * sizeof(T))); } \
|
||||
void deallocate(T* p, std::size_t n) { ::operator delete((void*) p); } \
|
||||
void construct(T* p, T const& t) { new(p) T(t); } \
|
||||
void destroy(T* p) { p->~T(); } \
|
||||
std::size_t max_size() const \
|
||||
{ return (std::numeric_limits<std::size_t>::max)(); } \
|
||||
bool operator==(name<T> const&) { return true; } \
|
||||
bool operator!=(name<T> const&) { return false; } \
|
||||
#define ALLOCATOR_METHODS(name) \
|
||||
template <typename U> struct rebind \
|
||||
{ \
|
||||
typedef name<U> other; \
|
||||
}; \
|
||||
\
|
||||
name() {} \
|
||||
template <typename Y> name(name<Y> const&) {} \
|
||||
T* address(T& r) { return &r; } \
|
||||
T const* address(T const& r) { return &r; } \
|
||||
T* allocate(std::size_t n) \
|
||||
{ \
|
||||
return static_cast<T*>(::operator new(n * sizeof(T))); \
|
||||
} \
|
||||
T* allocate(std::size_t n, void const*) \
|
||||
{ \
|
||||
return static_cast<T*>(::operator new(n * sizeof(T))); \
|
||||
} \
|
||||
void deallocate(T* p, std::size_t) { ::operator delete((void*)p); } \
|
||||
void construct(T* p, T const& t) { new (p) T(t); } \
|
||||
void destroy(T* p) { p->~T(); } \
|
||||
std::size_t max_size() const \
|
||||
{ \
|
||||
return (std::numeric_limits<std::size_t>::max)(); \
|
||||
} \
|
||||
bool operator==(name<T> const&) const { return true; } \
|
||||
bool operator!=(name<T> const&) const { return false; } \
|
||||
/**/
|
||||
|
||||
#define ALLOCATOR_METHODS_TYPEDEFS(name) \
|
||||
template <typename U> struct rebind { \
|
||||
typedef name<U> other; \
|
||||
}; \
|
||||
\
|
||||
name() {} \
|
||||
template <typename Y> name(name<Y> const&) {} \
|
||||
pointer address(T& r) { return &r;} \
|
||||
const_pointer address(T const& r) { return &r; } \
|
||||
pointer allocate(std::size_t n) \
|
||||
{ return pointer(::operator new(n * sizeof(T))); } \
|
||||
pointer allocate(std::size_t n, void const* u) \
|
||||
{ return pointer(::operator new(n * sizeof(T))); } \
|
||||
void deallocate(pointer p, std::size_t n) \
|
||||
{ ::operator delete((void*) p); } \
|
||||
void construct(T* p, T const& t) { new(p) T(t); } \
|
||||
void destroy(T* p) { p->~T(); } \
|
||||
size_type max_size() const \
|
||||
{ return (std::numeric_limits<size_type>::max)(); } \
|
||||
bool operator==(name<T> const&) { return true; } \
|
||||
bool operator!=(name<T> const&) { return false; } \
|
||||
#define ALLOCATOR_METHODS_TYPEDEFS(name) \
|
||||
template <typename U> struct rebind \
|
||||
{ \
|
||||
typedef name<U> other; \
|
||||
}; \
|
||||
\
|
||||
name() {} \
|
||||
template <typename Y> name(name<Y> const&) {} \
|
||||
pointer address(T& r) { return &r; } \
|
||||
const_pointer address(T const& r) { return &r; } \
|
||||
pointer allocate(std::size_t n) \
|
||||
{ \
|
||||
return pointer(::operator new(n * sizeof(T))); \
|
||||
} \
|
||||
pointer allocate(std::size_t n, void const*) \
|
||||
{ \
|
||||
return pointer(::operator new(n * sizeof(T))); \
|
||||
} \
|
||||
void deallocate(pointer p, std::size_t) { ::operator delete((void*)p); } \
|
||||
void construct(T* p, T const& t) { new (p) T(t); } \
|
||||
void destroy(T* p) { p->~T(); } \
|
||||
size_type max_size() const \
|
||||
{ \
|
||||
return (std::numeric_limits<size_type>::max)(); \
|
||||
} \
|
||||
bool operator==(name<T> const&) { return true; } \
|
||||
bool operator!=(name<T> const&) { return false; } \
|
||||
/**/
|
||||
|
||||
struct yes_type { enum { value = true }; };
|
||||
struct no_type { enum { value = false }; };
|
||||
struct yes_type
|
||||
{
|
||||
enum
|
||||
{
|
||||
value = true
|
||||
};
|
||||
};
|
||||
struct no_type
|
||||
{
|
||||
enum
|
||||
{
|
||||
value = false
|
||||
};
|
||||
};
|
||||
|
||||
// For tracking calls...
|
||||
|
||||
static int selected;
|
||||
void reset() {
|
||||
selected = 0;
|
||||
}
|
||||
void reset() { selected = 0; }
|
||||
|
||||
template <typename Allocator>
|
||||
int call_select()
|
||||
template <typename Allocator> int call_select()
|
||||
{
|
||||
typedef boost::unordered::detail::allocator_traits<Allocator> traits;
|
||||
Allocator a;
|
||||
typedef boost::unordered::detail::allocator_traits<Allocator> traits;
|
||||
Allocator a;
|
||||
|
||||
reset();
|
||||
BOOST_TEST(traits::select_on_container_copy_construction(a) == a);
|
||||
return selected;
|
||||
reset();
|
||||
BOOST_TEST(traits::select_on_container_copy_construction(a) == a);
|
||||
return selected;
|
||||
}
|
||||
|
||||
// Empty allocator test
|
||||
|
||||
template <typename T>
|
||||
struct empty_allocator
|
||||
template <typename T> struct empty_allocator
|
||||
{
|
||||
typedef T value_type;
|
||||
ALLOCATOR_METHODS(empty_allocator)
|
||||
typedef T value_type;
|
||||
ALLOCATOR_METHODS(empty_allocator)
|
||||
};
|
||||
|
||||
void test_empty_allocator()
|
||||
{
|
||||
typedef empty_allocator<int> allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<allocator> traits;
|
||||
typedef empty_allocator<int> allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<allocator> traits;
|
||||
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::size_type,
|
||||
std::make_unsigned<std::ptrdiff_t>::type>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::size_type,
|
||||
std::make_unsigned<std::ptrdiff_t>::type>::value));
|
||||
#else
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::size_type, std::size_t>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::size_type, std::size_t>::value));
|
||||
#endif
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::difference_type, std::ptrdiff_t>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::pointer, int*>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::const_pointer, int const*>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::value_type, int>::value));
|
||||
BOOST_TEST(!traits::propagate_on_container_copy_assignment::value);
|
||||
BOOST_TEST(!traits::propagate_on_container_move_assignment::value);
|
||||
BOOST_TEST(!traits::propagate_on_container_swap::value);
|
||||
BOOST_TEST(call_select<allocator>() == 0);
|
||||
BOOST_STATIC_ASSERT(
|
||||
(boost::is_same<traits::difference_type, std::ptrdiff_t>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::pointer, int*>::value));
|
||||
BOOST_STATIC_ASSERT(
|
||||
(boost::is_same<traits::const_pointer, int const*>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::value_type, int>::value));
|
||||
BOOST_TEST(!traits::propagate_on_container_copy_assignment::value);
|
||||
BOOST_TEST(!traits::propagate_on_container_move_assignment::value);
|
||||
BOOST_TEST(!traits::propagate_on_container_swap::value);
|
||||
BOOST_TEST(traits::is_always_equal::value);
|
||||
BOOST_TEST(call_select<allocator>() == 0);
|
||||
}
|
||||
|
||||
// allocator 1
|
||||
|
||||
template <typename T>
|
||||
struct allocator1
|
||||
template <typename T> struct allocator1
|
||||
{
|
||||
typedef T value_type;
|
||||
ALLOCATOR_METHODS(allocator1)
|
||||
|
||||
typedef yes_type propagate_on_container_copy_assignment;
|
||||
typedef yes_type propagate_on_container_move_assignment;
|
||||
typedef yes_type propagate_on_container_swap;
|
||||
|
||||
allocator1<T> select_on_container_copy_construction() const {
|
||||
++selected;
|
||||
return allocator1<T>();
|
||||
}
|
||||
typedef T value_type;
|
||||
ALLOCATOR_METHODS(allocator1)
|
||||
|
||||
typedef yes_type propagate_on_container_copy_assignment;
|
||||
typedef yes_type propagate_on_container_move_assignment;
|
||||
typedef yes_type propagate_on_container_swap;
|
||||
typedef yes_type is_always_equal;
|
||||
|
||||
allocator1<T> select_on_container_copy_construction() const
|
||||
{
|
||||
++selected;
|
||||
return allocator1<T>();
|
||||
}
|
||||
};
|
||||
|
||||
void test_allocator1()
|
||||
{
|
||||
typedef allocator1<int> allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<allocator> traits;
|
||||
typedef allocator1<int> allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<allocator> traits;
|
||||
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::size_type,
|
||||
std::make_unsigned<std::ptrdiff_t>::type>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::size_type,
|
||||
std::make_unsigned<std::ptrdiff_t>::type>::value));
|
||||
#else
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::size_type, std::size_t>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::size_type, std::size_t>::value));
|
||||
#endif
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::difference_type, std::ptrdiff_t>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::pointer, int*>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::const_pointer, int const*>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::value_type, int>::value));
|
||||
BOOST_TEST(traits::propagate_on_container_copy_assignment::value);
|
||||
BOOST_TEST(traits::propagate_on_container_move_assignment::value);
|
||||
BOOST_TEST(traits::propagate_on_container_swap::value);
|
||||
BOOST_TEST(call_select<allocator>() == 1);
|
||||
BOOST_STATIC_ASSERT(
|
||||
(boost::is_same<traits::difference_type, std::ptrdiff_t>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::pointer, int*>::value));
|
||||
BOOST_STATIC_ASSERT(
|
||||
(boost::is_same<traits::const_pointer, int const*>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::value_type, int>::value));
|
||||
BOOST_TEST(traits::propagate_on_container_copy_assignment::value);
|
||||
BOOST_TEST(traits::propagate_on_container_move_assignment::value);
|
||||
BOOST_TEST(traits::propagate_on_container_swap::value);
|
||||
BOOST_TEST(traits::is_always_equal::value);
|
||||
BOOST_TEST(call_select<allocator>() == 1);
|
||||
}
|
||||
|
||||
// allocator 2
|
||||
|
||||
template <typename Alloc>
|
||||
struct allocator2_base
|
||||
template <typename Alloc> struct allocator2_base
|
||||
{
|
||||
Alloc select_on_container_copy_construction() const {
|
||||
++selected;
|
||||
return Alloc();
|
||||
}
|
||||
Alloc select_on_container_copy_construction() const
|
||||
{
|
||||
++selected;
|
||||
return Alloc();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct allocator2 : allocator2_base<allocator2<T> >
|
||||
template <typename T> struct allocator2 : allocator2_base<allocator2<T> >
|
||||
{
|
||||
typedef T value_type;
|
||||
typedef T* pointer;
|
||||
typedef T const* const_pointer;
|
||||
typedef std::size_t size_type;
|
||||
|
||||
ALLOCATOR_METHODS(allocator2)
|
||||
|
||||
typedef no_type propagate_on_container_copy_assignment;
|
||||
typedef no_type propagate_on_container_move_assignment;
|
||||
typedef no_type propagate_on_container_swap;
|
||||
typedef T value_type;
|
||||
typedef T* pointer;
|
||||
typedef T const* const_pointer;
|
||||
typedef std::size_t size_type;
|
||||
|
||||
ALLOCATOR_METHODS(allocator2)
|
||||
|
||||
typedef no_type propagate_on_container_copy_assignment;
|
||||
typedef no_type propagate_on_container_move_assignment;
|
||||
typedef no_type propagate_on_container_swap;
|
||||
typedef no_type is_always_equal;
|
||||
};
|
||||
|
||||
void test_allocator2()
|
||||
{
|
||||
typedef allocator2<int> allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<allocator> traits;
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::size_type, std::size_t>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::difference_type, std::ptrdiff_t>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::pointer, int*>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::const_pointer, int const*>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::value_type, int>::value));
|
||||
BOOST_TEST(!traits::propagate_on_container_copy_assignment::value);
|
||||
BOOST_TEST(!traits::propagate_on_container_move_assignment::value);
|
||||
BOOST_TEST(!traits::propagate_on_container_swap::value);
|
||||
BOOST_TEST(call_select<allocator>() == 1);
|
||||
typedef allocator2<int> allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<allocator> traits;
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::size_type, std::size_t>::value));
|
||||
BOOST_STATIC_ASSERT(
|
||||
(boost::is_same<traits::difference_type, std::ptrdiff_t>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::pointer, int*>::value));
|
||||
BOOST_STATIC_ASSERT(
|
||||
(boost::is_same<traits::const_pointer, int const*>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::value_type, int>::value));
|
||||
BOOST_TEST(!traits::propagate_on_container_copy_assignment::value);
|
||||
BOOST_TEST(!traits::propagate_on_container_move_assignment::value);
|
||||
BOOST_TEST(!traits::propagate_on_container_swap::value);
|
||||
BOOST_TEST(!traits::is_always_equal::value);
|
||||
BOOST_TEST(call_select<allocator>() == 1);
|
||||
}
|
||||
|
||||
// allocator 3
|
||||
|
||||
template <typename T>
|
||||
struct ptr
|
||||
template <typename T> struct ptr
|
||||
{
|
||||
T* value_;
|
||||
|
||||
ptr(void* v) : value_((T*) v) {}
|
||||
T& operator*() const { return *value_; }
|
||||
T* value_;
|
||||
|
||||
ptr(void* v) : value_((T*)v) {}
|
||||
T& operator*() const { return *value_; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ptr<void>
|
||||
template <> struct ptr<void>
|
||||
{
|
||||
void* value_;
|
||||
ptr(void* v) : value_(v) {}
|
||||
void* value_;
|
||||
ptr(void* v) : value_(v) {}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ptr<const void>
|
||||
template <> struct ptr<const void>
|
||||
{
|
||||
void const* value_;
|
||||
ptr(void const* v) : value_(v) {}
|
||||
void const* value_;
|
||||
ptr(void const* v) : value_(v) {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct allocator3
|
||||
template <typename T> struct allocator3
|
||||
{
|
||||
typedef T value_type;
|
||||
typedef ptr<T> pointer;
|
||||
typedef ptr<T const> const_pointer;
|
||||
typedef unsigned short size_type;
|
||||
typedef T value_type;
|
||||
typedef ptr<T> pointer;
|
||||
typedef ptr<T const> const_pointer;
|
||||
typedef unsigned short size_type;
|
||||
|
||||
ALLOCATOR_METHODS_TYPEDEFS(allocator3)
|
||||
|
||||
typedef yes_type propagate_on_container_copy_assignment;
|
||||
typedef no_type propagate_on_container_move_assignment;
|
||||
int x; // Just to make it non-empty, so that is_always_equal is false.
|
||||
|
||||
allocator3<T> select_on_container_copy_construction() const {
|
||||
++selected;
|
||||
return allocator3<T>();
|
||||
}
|
||||
ALLOCATOR_METHODS_TYPEDEFS(allocator3)
|
||||
|
||||
typedef yes_type propagate_on_container_copy_assignment;
|
||||
typedef no_type propagate_on_container_move_assignment;
|
||||
|
||||
allocator3<T> select_on_container_copy_construction() const
|
||||
{
|
||||
++selected;
|
||||
return allocator3<T>();
|
||||
}
|
||||
};
|
||||
|
||||
void test_allocator3()
|
||||
{
|
||||
typedef allocator3<int> allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<allocator> traits;
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::size_type, unsigned short>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::difference_type, std::ptrdiff_t>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::pointer, ptr<int> >::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::const_pointer, ptr<int const> >::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::value_type, int>::value));
|
||||
BOOST_TEST(traits::propagate_on_container_copy_assignment::value);
|
||||
BOOST_TEST(!traits::propagate_on_container_move_assignment::value);
|
||||
BOOST_TEST(!traits::propagate_on_container_swap::value);
|
||||
BOOST_TEST(call_select<allocator>() == 1);
|
||||
typedef allocator3<int> allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<allocator> traits;
|
||||
BOOST_STATIC_ASSERT(
|
||||
(boost::is_same<traits::size_type, unsigned short>::value));
|
||||
BOOST_STATIC_ASSERT(
|
||||
(boost::is_same<traits::difference_type, std::ptrdiff_t>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::pointer, ptr<int> >::value));
|
||||
BOOST_STATIC_ASSERT(
|
||||
(boost::is_same<traits::const_pointer, ptr<int const> >::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::value_type, int>::value));
|
||||
BOOST_TEST(traits::propagate_on_container_copy_assignment::value);
|
||||
BOOST_TEST(!traits::propagate_on_container_move_assignment::value);
|
||||
BOOST_TEST(!traits::propagate_on_container_swap::value);
|
||||
BOOST_TEST(!traits::is_always_equal::value);
|
||||
BOOST_TEST(call_select<allocator>() == 1);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_empty_allocator();
|
||||
test_allocator1();
|
||||
test_allocator2();
|
||||
test_allocator3();
|
||||
return boost::report_errors();
|
||||
test_empty_allocator();
|
||||
test_allocator1();
|
||||
test_allocator2();
|
||||
test_allocator3();
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
@ -3,10 +3,13 @@
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../objects/test.hpp"
|
||||
#include "../objects/cxx11_allocator.hpp"
|
||||
@ -14,263 +17,257 @@
|
||||
#include "../helpers/tracker.hpp"
|
||||
#include "../helpers/equivalent.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(disable:4127) // conditional expression is constant
|
||||
#pragma warning(disable : 4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
namespace assign_tests {
|
||||
|
||||
test::seed_t initialize_seed(96785);
|
||||
test::seed_t initialize_seed(96785);
|
||||
|
||||
template <class T>
|
||||
void assign_tests1(T*, test::random_generator generator)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf;
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq;
|
||||
template <class T> void assign_tests1(T*, test::random_generator generator)
|
||||
{
|
||||
typename T::hasher hf;
|
||||
typename T::key_equal eq;
|
||||
|
||||
std::cerr<<"assign_tests1.1\n";
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests1.1\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
T x;
|
||||
x = x;
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
T x;
|
||||
x = x;
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
}
|
||||
|
||||
std::cerr<<"assign_tests1.2\n";
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests1.2\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v(1000, generator);
|
||||
T x(v.begin(), v.end());
|
||||
test::random_values<T> v(1000, generator);
|
||||
T x(v.begin(), v.end());
|
||||
|
||||
test::ordered<T> tracker = test::create_ordered(x);
|
||||
tracker.insert_range(v.begin(), v.end());
|
||||
test::ordered<T> tracker = test::create_ordered(x);
|
||||
tracker.insert_range(v.begin(), v.end());
|
||||
|
||||
x = x;
|
||||
tracker.compare(x);
|
||||
x = x;
|
||||
tracker.compare(x);
|
||||
|
||||
T y;
|
||||
y.max_load_factor(x.max_load_factor() / 20);
|
||||
float mlf = x.max_load_factor();
|
||||
y = x;
|
||||
tracker.compare(x);
|
||||
tracker.compare(y);
|
||||
BOOST_TEST(x.max_load_factor() == mlf);
|
||||
BOOST_TEST(y.max_load_factor() == mlf);
|
||||
BOOST_TEST(y.load_factor() <= y.max_load_factor());
|
||||
T y;
|
||||
y.max_load_factor(x.max_load_factor() / 20);
|
||||
float mlf = x.max_load_factor();
|
||||
y = x;
|
||||
tracker.compare(x);
|
||||
tracker.compare(y);
|
||||
BOOST_TEST(x.max_load_factor() == mlf);
|
||||
BOOST_TEST(y.max_load_factor() == mlf);
|
||||
BOOST_TEST(y.load_factor() <= y.max_load_factor());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void assign_tests2(T*, test::random_generator generator)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf1(1);
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf2(2);
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq1(1);
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq2(2);
|
||||
BOOST_DEDUCED_TYPENAME T::allocator_type al1(1);
|
||||
BOOST_DEDUCED_TYPENAME T::allocator_type al2(2);
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
|
||||
|
||||
std::cerr<<"assign_tests2.1\n";
|
||||
template <class T> void assign_tests2(T*, test::random_generator generator)
|
||||
{
|
||||
typename T::hasher hf1(1);
|
||||
typename T::hasher hf2(2);
|
||||
typename T::key_equal eq1(1);
|
||||
typename T::key_equal eq2(2);
|
||||
typename T::allocator_type al1(1);
|
||||
typename T::allocator_type al2(2);
|
||||
|
||||
typedef typename T::allocator_type allocator_type;
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.0 - empty container\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v(1000, generator);
|
||||
T x1(v.begin(), v.end(), 0, hf1, eq1);
|
||||
T x2(0, hf2, eq2);
|
||||
x2 = x1;
|
||||
BOOST_TEST(test::equivalent(x1.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x1.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
|
||||
test::check_container(x1, v);
|
||||
test::check_container(x2, v);
|
||||
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
|
||||
T x1(0, hf1, eq1);
|
||||
T x2(0, hf2, eq2);
|
||||
x2 = x1;
|
||||
BOOST_TEST(test::equivalent(x1.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x1.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
|
||||
test::check_container(x1, x2);
|
||||
}
|
||||
|
||||
std::cerr<<"assign_tests2.1a\n";
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.1\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v1(0, generator);
|
||||
test::random_values<T> v2(1000, generator);
|
||||
T x1(0, hf2, eq2);
|
||||
T x2(v2.begin(), v2.end(), 0, hf1, eq1);
|
||||
x2 = x1;
|
||||
BOOST_TEST(test::equivalent(x1.hash_function(), hf2));
|
||||
BOOST_TEST(test::equivalent(x1.key_eq(), eq2));
|
||||
BOOST_TEST(test::equivalent(x2.hash_function(), hf2));
|
||||
BOOST_TEST(test::equivalent(x2.key_eq(), eq2));
|
||||
test::check_container(x1, v1);
|
||||
test::check_container(x2, v1);
|
||||
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
|
||||
test::random_values<T> v(1000, generator);
|
||||
T x1(v.begin(), v.end(), 0, hf1, eq1);
|
||||
T x2(0, hf2, eq2);
|
||||
x2 = x1;
|
||||
BOOST_TEST(test::equivalent(x1.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x1.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
|
||||
test::check_container(x1, v);
|
||||
test::check_container(x2, v);
|
||||
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
|
||||
}
|
||||
|
||||
std::cerr<<"assign_tests2.2\n";
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.1a\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v1(100, generator), v2(100, generator);
|
||||
T x1(v1.begin(), v1.end(), 0, hf1, eq1, al1);
|
||||
T x2(v2.begin(), v2.end(), 0, hf2, eq2, al2);
|
||||
x2 = x1;
|
||||
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
|
||||
if (allocator_type::is_propagate_on_assign) {
|
||||
BOOST_TEST(test::equivalent(x2.get_allocator(), al1));
|
||||
BOOST_TEST(!test::equivalent(x2.get_allocator(), al2));
|
||||
}
|
||||
else {
|
||||
BOOST_TEST(test::equivalent(x2.get_allocator(), al2));
|
||||
BOOST_TEST(!test::equivalent(x2.get_allocator(), al1));
|
||||
}
|
||||
test::check_container(x1, v1);
|
||||
test::check_container(x2, v1);
|
||||
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
|
||||
test::random_values<T> v1(0, generator);
|
||||
test::random_values<T> v2(1000, generator);
|
||||
T x1(0, hf2, eq2);
|
||||
T x2(v2.begin(), v2.end(), 0, hf1, eq1);
|
||||
x2 = x1;
|
||||
BOOST_TEST(test::equivalent(x1.hash_function(), hf2));
|
||||
BOOST_TEST(test::equivalent(x1.key_eq(), eq2));
|
||||
BOOST_TEST(test::equivalent(x2.hash_function(), hf2));
|
||||
BOOST_TEST(test::equivalent(x2.key_eq(), eq2));
|
||||
test::check_container(x1, v1);
|
||||
test::check_container(x2, v1);
|
||||
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
|
||||
}
|
||||
|
||||
std::cerr<<"assign_tests2.3\n";
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.2\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v1(100, generator), v2(1000, generator);
|
||||
T x1(v1.begin(), v1.end(), 0, hf1, eq1, al1);
|
||||
T x2(v2.begin(), v2.end(), 0, hf2, eq2, al2);
|
||||
x2 = x1;
|
||||
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
|
||||
if (allocator_type::is_propagate_on_assign) {
|
||||
BOOST_TEST(test::equivalent(x2.get_allocator(), al1));
|
||||
BOOST_TEST(!test::equivalent(x2.get_allocator(), al2));
|
||||
}
|
||||
else {
|
||||
BOOST_TEST(test::equivalent(x2.get_allocator(), al2));
|
||||
BOOST_TEST(!test::equivalent(x2.get_allocator(), al1));
|
||||
}
|
||||
test::check_container(x1, v1);
|
||||
test::check_container(x2, v1);
|
||||
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
|
||||
test::random_values<T> v1(100, generator), v2(100, generator);
|
||||
T x1(v1.begin(), v1.end(), 0, hf1, eq1, al1);
|
||||
T x2(v2.begin(), v2.end(), 0, hf2, eq2, al2);
|
||||
x2 = x1;
|
||||
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
|
||||
if (allocator_type::is_propagate_on_assign) {
|
||||
BOOST_TEST(test::equivalent(x2.get_allocator(), al1));
|
||||
BOOST_TEST(!test::equivalent(x2.get_allocator(), al2));
|
||||
} else {
|
||||
BOOST_TEST(test::equivalent(x2.get_allocator(), al2));
|
||||
BOOST_TEST(!test::equivalent(x2.get_allocator(), al1));
|
||||
}
|
||||
test::check_container(x1, v1);
|
||||
test::check_container(x2, v1);
|
||||
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
|
||||
}
|
||||
|
||||
std::cerr<<"assign_tests2.4\n";
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.3\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v1(1000, generator), v2(100, generator);
|
||||
T x1(v1.begin(), v1.end(), 0, hf1, eq1, al1);
|
||||
T x2(v2.begin(), v2.end(), 0, hf2, eq2, al2);
|
||||
x2 = x1;
|
||||
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
|
||||
if (allocator_type::is_propagate_on_assign) {
|
||||
BOOST_TEST(test::equivalent(x2.get_allocator(), al1));
|
||||
BOOST_TEST(!test::equivalent(x2.get_allocator(), al2));
|
||||
}
|
||||
else {
|
||||
BOOST_TEST(test::equivalent(x2.get_allocator(), al2));
|
||||
BOOST_TEST(!test::equivalent(x2.get_allocator(), al1));
|
||||
}
|
||||
test::check_container(x1, v1);
|
||||
test::check_container(x2, v1);
|
||||
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
|
||||
test::random_values<T> v1(100, generator), v2(1000, generator);
|
||||
T x1(v1.begin(), v1.end(), 0, hf1, eq1, al1);
|
||||
T x2(v2.begin(), v2.end(), 0, hf2, eq2, al2);
|
||||
x2 = x1;
|
||||
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
|
||||
if (allocator_type::is_propagate_on_assign) {
|
||||
BOOST_TEST(test::equivalent(x2.get_allocator(), al1));
|
||||
BOOST_TEST(!test::equivalent(x2.get_allocator(), al2));
|
||||
} else {
|
||||
BOOST_TEST(test::equivalent(x2.get_allocator(), al2));
|
||||
BOOST_TEST(!test::equivalent(x2.get_allocator(), al1));
|
||||
}
|
||||
test::check_container(x1, v1);
|
||||
test::check_container(x2, v1);
|
||||
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
|
||||
}
|
||||
}
|
||||
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.4\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v1(1000, generator), v2(100, generator);
|
||||
T x1(v1.begin(), v1.end(), 0, hf1, eq1, al1);
|
||||
T x2(v2.begin(), v2.end(), 0, hf2, eq2, al2);
|
||||
x2 = x1;
|
||||
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
|
||||
if (allocator_type::is_propagate_on_assign) {
|
||||
BOOST_TEST(test::equivalent(x2.get_allocator(), al1));
|
||||
BOOST_TEST(!test::equivalent(x2.get_allocator(), al2));
|
||||
} else {
|
||||
BOOST_TEST(test::equivalent(x2.get_allocator(), al2));
|
||||
BOOST_TEST(!test::equivalent(x2.get_allocator(), al1));
|
||||
}
|
||||
test::check_container(x1, v1);
|
||||
test::check_container(x2, v1);
|
||||
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
|
||||
}
|
||||
}
|
||||
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
std::allocator<test::object> >* test_map_std_alloc;
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_multimap;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator1<test::object> >* test_multimap;
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::propagate_assign> >*
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::propagate_assign> >*
|
||||
test_set_prop_assign;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::propagate_assign> >*
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::propagate_assign> >*
|
||||
test_multiset_prop_assign;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::propagate_assign> >*
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::propagate_assign> >*
|
||||
test_map_prop_assign;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::propagate_assign> >*
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::propagate_assign> >*
|
||||
test_multimap_prop_assign;
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_propagate_assign> >*
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_propagate_assign> >*
|
||||
test_set_no_prop_assign;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_propagate_assign> >*
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_propagate_assign> >*
|
||||
test_multiset_no_prop_assign;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_propagate_assign> >*
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_propagate_assign> >*
|
||||
test_map_no_prop_assign;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_propagate_assign> >*
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_propagate_assign> >*
|
||||
test_multimap_no_prop_assign;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
using test::limited_range;
|
||||
|
||||
template <typename T>
|
||||
bool is_propagate(T*)
|
||||
{
|
||||
template <typename T> bool is_propagate(T*)
|
||||
{
|
||||
return T::allocator_type::is_propagate_on_assign;
|
||||
}
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(check_traits)
|
||||
{
|
||||
UNORDERED_AUTO_TEST (check_traits) {
|
||||
BOOST_TEST(!is_propagate(test_set));
|
||||
BOOST_TEST(is_propagate(test_set_prop_assign));
|
||||
BOOST_TEST(!is_propagate(test_set_no_prop_assign));
|
||||
}
|
||||
}
|
||||
|
||||
UNORDERED_TEST(assign_tests1, (
|
||||
(test_map_std_alloc)
|
||||
(test_set)(test_multiset)(test_map)(test_multimap)
|
||||
(test_set_prop_assign)(test_multiset_prop_assign)(test_map_prop_assign)(test_multimap_prop_assign)
|
||||
(test_set_no_prop_assign)(test_multiset_no_prop_assign)(test_map_no_prop_assign)(test_multimap_no_prop_assign)
|
||||
)
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
UNORDERED_TEST(assign_tests1,
|
||||
((test_map_std_alloc)(test_set)(test_multiset)(test_map)(test_multimap)(
|
||||
test_set_prop_assign)(test_multiset_prop_assign)(test_map_prop_assign)(
|
||||
test_multimap_prop_assign)(test_set_no_prop_assign)(
|
||||
test_multiset_no_prop_assign)(test_map_no_prop_assign)(
|
||||
test_multimap_no_prop_assign))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(assign_tests2, (
|
||||
(test_set)(test_multiset)(test_map)(test_multimap)
|
||||
(test_set_prop_assign)(test_multiset_prop_assign)(test_map_prop_assign)(test_multimap_prop_assign)
|
||||
(test_set_no_prop_assign)(test_multiset_no_prop_assign)(test_map_no_prop_assign)(test_multimap_no_prop_assign)
|
||||
)
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
UNORDERED_TEST(
|
||||
assign_tests2, ((test_set)(test_multiset)(test_map)(test_multimap)(
|
||||
test_set_prop_assign)(test_multiset_prop_assign)(
|
||||
test_map_prop_assign)(test_multimap_prop_assign)(
|
||||
test_set_no_prop_assign)(test_multiset_no_prop_assign)(
|
||||
test_map_no_prop_assign)(test_multimap_no_prop_assign))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
|
||||
UNORDERED_AUTO_TEST(assign_default_initializer_list) {
|
||||
std::cerr<<"Initializer List Tests\n";
|
||||
UNORDERED_AUTO_TEST (assign_default_initializer_list) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Initializer List Tests\n";
|
||||
std::initializer_list<std::pair<int const, int> > init;
|
||||
boost::unordered_map<int, int> x1;
|
||||
x1[25] = 3;
|
||||
@ -278,25 +275,23 @@ UNORDERED_AUTO_TEST(assign_default_initializer_list) {
|
||||
BOOST_TEST(!x1.empty());
|
||||
x1 = init;
|
||||
BOOST_TEST(x1.empty());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
UNORDERED_AUTO_TEST(assign_initializer_list)
|
||||
{
|
||||
std::cerr<<"Initializer List Tests\n";
|
||||
UNORDERED_AUTO_TEST (assign_initializer_list) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Initializer List Tests\n";
|
||||
|
||||
boost::unordered_set<int> x;
|
||||
x.insert(10);
|
||||
x.insert(20);
|
||||
x = { 1, 2, -10 };
|
||||
x = {1, 2, -10};
|
||||
BOOST_TEST(x.find(10) == x.end());
|
||||
BOOST_TEST(x.find(-10) != x.end());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -3,20 +3,36 @@
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include <string>
|
||||
|
||||
namespace at_tests {
|
||||
|
||||
UNORDERED_AUTO_TEST(at_tests) {
|
||||
UNORDERED_AUTO_TEST (at_tests) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Create Map" << std::endl;
|
||||
|
||||
boost::unordered_map<std::string, int> x;
|
||||
typedef boost::unordered_map<std::string, int>::iterator iterator;
|
||||
boost::unordered_map<std::string, int> const& x_const(x);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Check empty container" << std::endl;
|
||||
|
||||
try {
|
||||
x.at("one");
|
||||
BOOST_ERROR("Should have thrown.");
|
||||
} catch (std::out_of_range&) {
|
||||
}
|
||||
|
||||
try {
|
||||
x_const.at("one");
|
||||
BOOST_ERROR("Should have thrown.");
|
||||
} catch (std::out_of_range&) {
|
||||
}
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Add elements" << std::endl;
|
||||
|
||||
@ -27,19 +43,25 @@ UNORDERED_AUTO_TEST(at_tests) {
|
||||
|
||||
BOOST_TEST(x.at("one") == 1);
|
||||
BOOST_TEST(x.at("two") == 2);
|
||||
BOOST_TEST(x_const.at("one") == 1);
|
||||
BOOST_TEST(x_const.at("two") == 2);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Check missing element" << std::endl;
|
||||
|
||||
try {
|
||||
x.at("three");
|
||||
BOOST_ERROR("Should have thrown.");
|
||||
x.at("three");
|
||||
BOOST_ERROR("Should have thrown.");
|
||||
} catch (std::out_of_range&) {
|
||||
}
|
||||
catch(std::out_of_range) {
|
||||
|
||||
try {
|
||||
x_const.at("three");
|
||||
BOOST_ERROR("Should have thrown.");
|
||||
} catch (std::out_of_range&) {
|
||||
}
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Finished" << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -3,10 +3,12 @@
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include <algorithm>
|
||||
@ -15,84 +17,78 @@
|
||||
#include "../helpers/helpers.hpp"
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, < 1400)
|
||||
#pragma warning(disable:4267) // conversion from 'size_t' to 'unsigned int',
|
||||
// possible loss of data.
|
||||
#pragma warning(disable : 4267) // conversion from 'size_t' to 'unsigned int',
|
||||
// possible loss of data.
|
||||
#endif
|
||||
|
||||
namespace bucket_tests {
|
||||
|
||||
test::seed_t initialize_seed(54635);
|
||||
test::seed_t initialize_seed(54635);
|
||||
|
||||
template <class X>
|
||||
void tests(X*, test::random_generator generator)
|
||||
{
|
||||
template <class X> void tests(X*, test::random_generator generator)
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME X::size_type size_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME X::const_local_iterator const_local_iterator;
|
||||
typedef typename X::size_type size_type;
|
||||
typedef typename X::const_local_iterator const_local_iterator;
|
||||
test::random_values<X> v(1000, generator);
|
||||
|
||||
X x(v.begin(), v.end());
|
||||
|
||||
BOOST_TEST(x.bucket_count() < x.max_bucket_count());
|
||||
std::cerr<<x.bucket_count()<<"<"<<x.max_bucket_count()<<"\n";
|
||||
BOOST_TEST(x.bucket_count() <= x.max_bucket_count());
|
||||
if (!(x.bucket_count() <= x.max_bucket_count())) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << x.bucket_count()
|
||||
<< "<=" << x.max_bucket_count() << "\n";
|
||||
}
|
||||
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<X>::const_iterator
|
||||
it = v.begin(), end = v.end(); it != end; ++it)
|
||||
{
|
||||
size_type bucket = x.bucket(test::get_key<X>(*it));
|
||||
for (typename test::random_values<X>::const_iterator it = v.begin(),
|
||||
end = v.end();
|
||||
it != end; ++it) {
|
||||
size_type bucket = x.bucket(test::get_key<X>(*it));
|
||||
|
||||
BOOST_TEST(bucket < x.bucket_count());
|
||||
if(bucket < x.max_bucket_count()) {
|
||||
// lit? lend?? I need a new naming scheme.
|
||||
const_local_iterator lit = x.begin(bucket), lend = x.end(bucket);
|
||||
while(lit != lend
|
||||
&& test::get_key<X>(*it) != test::get_key<X>(*lit))
|
||||
{
|
||||
++lit;
|
||||
}
|
||||
BOOST_TEST(lit != lend);
|
||||
BOOST_TEST(bucket < x.bucket_count());
|
||||
if (bucket < x.bucket_count()) {
|
||||
// lit? lend?? I need a new naming scheme.
|
||||
const_local_iterator lit = x.begin(bucket), lend = x.end(bucket);
|
||||
while (lit != lend && test::get_key<X>(*it) != test::get_key<X>(*lit)) {
|
||||
++lit;
|
||||
}
|
||||
BOOST_TEST(lit != lend);
|
||||
}
|
||||
}
|
||||
|
||||
for(size_type i = 0; i < x.bucket_count(); ++i) {
|
||||
BOOST_TEST(x.bucket_size(i) == static_cast<size_type>(
|
||||
std::distance(x.begin(i), x.end(i))));
|
||||
BOOST_TEST(x.bucket_size(i) == static_cast<size_type>(
|
||||
std::distance(x.cbegin(i), x.cend(i))));
|
||||
X const& x_ref = x;
|
||||
BOOST_TEST(x.bucket_size(i) == static_cast<size_type>(
|
||||
std::distance(x_ref.begin(i), x_ref.end(i))));
|
||||
BOOST_TEST(x.bucket_size(i) == static_cast<size_type>(
|
||||
std::distance(x_ref.cbegin(i), x_ref.cend(i))));
|
||||
for (size_type i = 0; i < x.bucket_count(); ++i) {
|
||||
BOOST_TEST(x.bucket_size(i) ==
|
||||
static_cast<size_type>(std::distance(x.begin(i), x.end(i))));
|
||||
BOOST_TEST(x.bucket_size(i) ==
|
||||
static_cast<size_type>(std::distance(x.cbegin(i), x.cend(i))));
|
||||
X const& x_ref = x;
|
||||
BOOST_TEST(x.bucket_size(i) == static_cast<size_type>(std::distance(
|
||||
x_ref.begin(i), x_ref.end(i))));
|
||||
BOOST_TEST(x.bucket_size(i) == static_cast<size_type>(std::distance(
|
||||
x_ref.cbegin(i), x_ref.cend(i))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
std::allocator<test::object> >* test_multimap_std_alloc;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to, std::allocator<test::object> >* test_multimap_std_alloc;
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_multimap;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator2<test::object> >* test_multimap;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
|
||||
UNORDERED_TEST(tests,
|
||||
((test_multimap_std_alloc)(test_set)(test_multiset)(test_map)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
using test::limited_range;
|
||||
|
||||
UNORDERED_TEST(tests,
|
||||
((test_multimap_std_alloc)(test_set)(test_multiset)(test_map)(
|
||||
test_multimap))((default_generator)(generate_collisions)(limited_range)))
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -6,226 +6,243 @@
|
||||
// This test creates the containers with members that meet their minimum
|
||||
// requirements. Makes sure everything compiles and is defined correctly.
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include <iostream>
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../objects/minimal.hpp"
|
||||
#include "./compile_tests.hpp"
|
||||
|
||||
// Explicit instantiation to catch compile-time errors
|
||||
|
||||
template class boost::unordered_map<
|
||||
int,
|
||||
int,
|
||||
boost::hash<int>,
|
||||
std::equal_to<int>,
|
||||
test::minimal::allocator<std::pair<int const, int> > >;
|
||||
template class boost::unordered_multimap<
|
||||
int,
|
||||
int,
|
||||
boost::hash<int>,
|
||||
std::equal_to<int>,
|
||||
test::minimal::allocator<std::pair<int const, int> > >;
|
||||
#define INSTANTIATE(type) \
|
||||
template class boost::unordered::detail::instantiate_##type
|
||||
|
||||
template class boost::unordered_map<
|
||||
test::minimal::assignable,
|
||||
INSTANTIATE(map)<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::allocator<int> >;
|
||||
INSTANTIATE(multimap)<int const, int const, boost::hash<int>,
|
||||
std::equal_to<int>, test::minimal::allocator<int> >;
|
||||
|
||||
INSTANTIATE(
|
||||
map)<test::minimal::assignable const, test::minimal::default_assignable const,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<int> >;
|
||||
INSTANTIATE(multimap)<test::minimal::assignable, test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<int> >;
|
||||
|
||||
UNORDERED_AUTO_TEST (test0) {
|
||||
test::minimal::constructor_param x;
|
||||
|
||||
typedef std::pair<test::minimal::assignable const, test::minimal::assignable>
|
||||
value_type;
|
||||
value_type value(x, x);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_map.\n";
|
||||
|
||||
boost::unordered_map<int, int> int_map;
|
||||
|
||||
boost::unordered_map<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<std::pair<int const, int> > >
|
||||
int_map2;
|
||||
|
||||
boost::unordered_map<test::minimal::assignable, test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<value_type> >
|
||||
map;
|
||||
|
||||
container_test(int_map, std::pair<int const, int>(0, 0));
|
||||
container_test(int_map2, std::pair<int const, int>(0, 0));
|
||||
container_test(map, value);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multimap.\n";
|
||||
|
||||
boost::unordered_multimap<int, int> int_multimap;
|
||||
|
||||
boost::unordered_multimap<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<std::pair<int const, int> > >
|
||||
int_multimap2;
|
||||
|
||||
boost::unordered_multimap<test::minimal::assignable,
|
||||
test::minimal::assignable, test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<value_type> >
|
||||
multimap;
|
||||
|
||||
container_test(int_multimap, std::pair<int const, int>(0, 0));
|
||||
container_test(int_multimap2, std::pair<int const, int>(0, 0));
|
||||
container_test(multimap, value);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (equality_tests) {
|
||||
typedef std::pair<test::minimal::copy_constructible_equality_comparable const,
|
||||
test::minimal::copy_constructible_equality_comparable>
|
||||
value_type;
|
||||
|
||||
boost::unordered_map<int, int> int_map;
|
||||
|
||||
boost::unordered_map<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<std::pair<int const, int> > >
|
||||
int_map2;
|
||||
|
||||
boost::unordered_map<test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::equal_to<
|
||||
test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::allocator<value_type> >
|
||||
map;
|
||||
|
||||
equality_test(int_map);
|
||||
equality_test(int_map2);
|
||||
equality_test(map);
|
||||
|
||||
boost::unordered_multimap<int, int> int_multimap;
|
||||
|
||||
boost::unordered_multimap<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<std::pair<int const, int> > >
|
||||
int_multimap2;
|
||||
|
||||
boost::unordered_multimap<
|
||||
test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::equal_to<
|
||||
test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::allocator<value_type> >
|
||||
multimap;
|
||||
|
||||
equality_test(int_multimap);
|
||||
equality_test(int_multimap2);
|
||||
equality_test(multimap);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (test1) {
|
||||
boost::hash<int> hash;
|
||||
std::equal_to<int> equal_to;
|
||||
int value = 0;
|
||||
std::pair<int const, int> map_value(0, 0);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_map.\n";
|
||||
|
||||
boost::unordered_map<int, int> map;
|
||||
|
||||
boost::unordered_map<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<std::pair<int const, int> > >
|
||||
map2;
|
||||
|
||||
unordered_unique_test(map, map_value);
|
||||
unordered_map_test(map, value, value);
|
||||
unordered_copyable_test(map, value, map_value, hash, equal_to);
|
||||
unordered_map_functions(map, value, value);
|
||||
|
||||
unordered_unique_test(map2, map_value);
|
||||
unordered_map_test(map2, value, value);
|
||||
unordered_copyable_test(map2, value, map_value, hash, equal_to);
|
||||
unordered_map_functions(map2, value, value);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multimap.\n";
|
||||
|
||||
boost::unordered_multimap<int, int> multimap;
|
||||
|
||||
boost::unordered_multimap<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<std::pair<int const, int> > >
|
||||
multimap2;
|
||||
|
||||
unordered_equivalent_test(multimap, map_value);
|
||||
unordered_map_test(multimap, value, value);
|
||||
unordered_copyable_test(multimap, value, map_value, hash, equal_to);
|
||||
|
||||
unordered_equivalent_test(multimap2, map_value);
|
||||
unordered_map_test(multimap2, value, value);
|
||||
unordered_copyable_test(multimap2, value, map_value, hash, equal_to);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (test2) {
|
||||
test::minimal::constructor_param x;
|
||||
|
||||
test::minimal::assignable assignable(x);
|
||||
test::minimal::copy_constructible copy_constructible(x);
|
||||
test::minimal::hash<test::minimal::assignable> hash(x);
|
||||
test::minimal::equal_to<test::minimal::assignable> equal_to(x);
|
||||
|
||||
typedef std::pair<test::minimal::assignable const, test::minimal::assignable>
|
||||
map_value_type;
|
||||
map_value_type map_value(assignable, assignable);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_map.\n";
|
||||
|
||||
boost::unordered_map<test::minimal::assignable, test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<map_value_type> >
|
||||
map;
|
||||
|
||||
unordered_unique_test(map, map_value);
|
||||
unordered_map_test(map, assignable, assignable);
|
||||
unordered_copyable_test(map, assignable, map_value, hash, equal_to);
|
||||
unordered_map_member_test(map, map_value);
|
||||
|
||||
boost::unordered_map<test::minimal::assignable,
|
||||
test::minimal::default_assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<test::minimal::assignable> >;
|
||||
template class boost::unordered_multimap<
|
||||
test::minimal::assignable,
|
||||
test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::allocator<map_value_type> >
|
||||
map2;
|
||||
|
||||
test::minimal::default_assignable default_assignable;
|
||||
|
||||
unordered_map_functions(map2, assignable, default_assignable);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multimap.\n";
|
||||
|
||||
boost::unordered_multimap<test::minimal::assignable,
|
||||
test::minimal::assignable, test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<test::minimal::assignable> >;
|
||||
test::minimal::allocator<map_value_type> >
|
||||
multimap;
|
||||
|
||||
UNORDERED_AUTO_TEST(test0)
|
||||
unordered_equivalent_test(multimap, map_value);
|
||||
unordered_map_test(multimap, assignable, assignable);
|
||||
unordered_copyable_test(multimap, assignable, map_value, hash, equal_to);
|
||||
unordered_map_member_test(multimap, map_value);
|
||||
}
|
||||
|
||||
// Test for ambiguity when using key convertible from iterator
|
||||
// See LWG2059
|
||||
|
||||
struct lwg2059_key
|
||||
{
|
||||
test::minimal::constructor_param x;
|
||||
int value;
|
||||
|
||||
typedef std::pair<test::minimal::assignable const,
|
||||
test::minimal::assignable> value_type;
|
||||
value_type value(x, x);
|
||||
template <typename T> lwg2059_key(T v) : value(v) {}
|
||||
};
|
||||
|
||||
std::cout<<"Test unordered_map.\n";
|
||||
|
||||
boost::unordered_map<int, int> int_map;
|
||||
|
||||
boost::unordered_map<int, int,
|
||||
boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<std::pair<int const, int> >
|
||||
> int_map2;
|
||||
|
||||
boost::unordered_map<
|
||||
test::minimal::assignable,
|
||||
test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<value_type> > map;
|
||||
|
||||
container_test(int_map, std::pair<int const, int>(0, 0));
|
||||
container_test(int_map2, std::pair<int const, int>(0, 0));
|
||||
container_test(map, value);
|
||||
|
||||
std::cout<<"Test unordered_multimap.\n";
|
||||
|
||||
boost::unordered_multimap<int, int> int_multimap;
|
||||
|
||||
boost::unordered_multimap<int, int,
|
||||
boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<std::pair<int const, int> >
|
||||
> int_multimap2;
|
||||
|
||||
boost::unordered_multimap<
|
||||
test::minimal::assignable,
|
||||
test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<value_type> > multimap;
|
||||
|
||||
container_test(int_multimap, std::pair<int const, int>(0, 0));
|
||||
container_test(int_multimap2, std::pair<int const, int>(0, 0));
|
||||
container_test(multimap, value);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(equality_tests) {
|
||||
typedef std::pair<
|
||||
test::minimal::copy_constructible_equality_comparable const,
|
||||
test::minimal::copy_constructible_equality_comparable> value_type;
|
||||
|
||||
boost::unordered_map<int, int> int_map;
|
||||
|
||||
boost::unordered_map<int, int,
|
||||
boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<std::pair<int const, int> >
|
||||
> int_map2;
|
||||
|
||||
boost::unordered_map<
|
||||
test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::equal_to<test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::allocator<value_type> > map;
|
||||
|
||||
equality_test(int_map);
|
||||
equality_test(int_map2);
|
||||
equality_test(map);
|
||||
|
||||
boost::unordered_multimap<int, int> int_multimap;
|
||||
|
||||
boost::unordered_multimap<int, int,
|
||||
boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<std::pair<int const, int> >
|
||||
> int_multimap2;
|
||||
|
||||
boost::unordered_multimap<
|
||||
test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::equal_to<test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::allocator<value_type> > multimap;
|
||||
|
||||
equality_test(int_multimap);
|
||||
equality_test(int_multimap2);
|
||||
equality_test(multimap);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(test1) {
|
||||
boost::hash<int> hash;
|
||||
std::equal_to<int> equal_to;
|
||||
int value = 0;
|
||||
std::pair<int const, int> map_value(0, 0);
|
||||
|
||||
std::cout<<"Test unordered_map.\n";
|
||||
|
||||
boost::unordered_map<int, int> map;
|
||||
|
||||
boost::unordered_map<int, int,
|
||||
boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<std::pair<int const, int> >
|
||||
> map2;
|
||||
|
||||
unordered_unique_test(map, map_value);
|
||||
unordered_map_test(map, value, value);
|
||||
unordered_copyable_test(map, value, map_value, hash, equal_to);
|
||||
unordered_map_functions(map, value, value);
|
||||
|
||||
unordered_unique_test(map2, map_value);
|
||||
unordered_map_test(map2, value, value);
|
||||
unordered_copyable_test(map2, value, map_value, hash, equal_to);
|
||||
unordered_map_functions(map2, value, value);
|
||||
|
||||
std::cout<<"Test unordered_multimap.\n";
|
||||
|
||||
boost::unordered_multimap<int, int> multimap;
|
||||
|
||||
boost::unordered_multimap<int, int,
|
||||
boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<std::pair<int const, int> >
|
||||
> multimap2;
|
||||
|
||||
unordered_equivalent_test(multimap, map_value);
|
||||
unordered_map_test(multimap, value, value);
|
||||
unordered_copyable_test(multimap, value, map_value, hash, equal_to);
|
||||
|
||||
unordered_equivalent_test(multimap2, map_value);
|
||||
unordered_map_test(multimap2, value, value);
|
||||
unordered_copyable_test(multimap2, value, map_value, hash, equal_to);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(test2)
|
||||
std::size_t hash_value(lwg2059_key x)
|
||||
{
|
||||
test::minimal::constructor_param x;
|
||||
return static_cast<std::size_t>(x.value);
|
||||
}
|
||||
|
||||
test::minimal::assignable assignable(x);
|
||||
test::minimal::copy_constructible copy_constructible(x);
|
||||
test::minimal::hash<test::minimal::assignable> hash(x);
|
||||
test::minimal::equal_to<test::minimal::assignable> equal_to(x);
|
||||
bool operator==(lwg2059_key x, lwg2059_key y) { return x.value == y.value; }
|
||||
|
||||
typedef std::pair<test::minimal::assignable const,
|
||||
test::minimal::assignable> map_value_type;
|
||||
map_value_type map_value(assignable, assignable);
|
||||
UNORDERED_AUTO_TEST (lwg2059) {
|
||||
{
|
||||
boost::unordered_map<lwg2059_key, int> x;
|
||||
x.emplace(lwg2059_key(10), 5);
|
||||
x.erase(x.begin());
|
||||
}
|
||||
|
||||
std::cout<<"Test unordered_map.\n";
|
||||
|
||||
boost::unordered_map<
|
||||
test::minimal::assignable,
|
||||
test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<map_value_type> > map;
|
||||
|
||||
unordered_unique_test(map, map_value);
|
||||
unordered_map_test(map, assignable, assignable);
|
||||
unordered_copyable_test(map, assignable, map_value, hash, equal_to);
|
||||
|
||||
boost::unordered_map<
|
||||
test::minimal::assignable,
|
||||
test::minimal::default_assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<map_value_type> > map2;
|
||||
|
||||
test::minimal::default_assignable default_assignable;
|
||||
|
||||
unordered_map_functions(map2, assignable, default_assignable);
|
||||
|
||||
std::cout<<"Test unordered_multimap.\n";
|
||||
|
||||
boost::unordered_multimap<
|
||||
test::minimal::assignable,
|
||||
test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<map_value_type> > multimap;
|
||||
|
||||
unordered_equivalent_test(multimap, map_value);
|
||||
unordered_map_test(multimap, assignable, assignable);
|
||||
unordered_copyable_test(multimap, assignable, map_value, hash, equal_to);
|
||||
{
|
||||
boost::unordered_multimap<lwg2059_key, int> x;
|
||||
x.emplace(lwg2059_key(10), 5);
|
||||
x.erase(x.begin());
|
||||
}
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -6,288 +6,308 @@
|
||||
// This test creates the containers with members that meet their minimum
|
||||
// requirements. Makes sure everything compiles and is defined correctly.
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include <iostream>
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../objects/minimal.hpp"
|
||||
#include "./compile_tests.hpp"
|
||||
|
||||
// Explicit instantiation to catch compile-time errors
|
||||
|
||||
template class boost::unordered_set<
|
||||
int,
|
||||
boost::hash<int>,
|
||||
std::equal_to<int>,
|
||||
test::minimal::allocator<int> >;
|
||||
template class boost::unordered_multiset<
|
||||
int,
|
||||
boost::hash<int>,
|
||||
std::equal_to<int>,
|
||||
test::minimal::allocator<int> >;
|
||||
#define INSTANTIATE(type) \
|
||||
template class boost::unordered::detail::instantiate_##type
|
||||
|
||||
template class boost::unordered_set<
|
||||
test::minimal::assignable,
|
||||
INSTANTIATE(set)<int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::allocator<int> >;
|
||||
INSTANTIATE(multiset)<int const, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::allocator<int> >;
|
||||
|
||||
INSTANTIATE(set)<test::minimal::assignable const,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<int> >;
|
||||
INSTANTIATE(multiset)<test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<int> >;
|
||||
|
||||
UNORDERED_AUTO_TEST (test0) {
|
||||
test::minimal::constructor_param x;
|
||||
|
||||
test::minimal::assignable assignable(x);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n";
|
||||
|
||||
boost::unordered_set<int> int_set;
|
||||
|
||||
boost::unordered_set<int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<int> >
|
||||
int_set2;
|
||||
|
||||
boost::unordered_set<test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<test::minimal::assignable> >;
|
||||
template class boost::unordered_multiset<
|
||||
test::minimal::assignable,
|
||||
test::minimal::allocator<test::minimal::assignable> >
|
||||
set;
|
||||
|
||||
container_test(int_set, 0);
|
||||
container_test(int_set2, 0);
|
||||
container_test(set, assignable);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n";
|
||||
|
||||
boost::unordered_multiset<int> int_multiset;
|
||||
|
||||
boost::unordered_multiset<int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<int> >
|
||||
int_multiset2;
|
||||
|
||||
boost::unordered_multiset<test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<test::minimal::assignable> >;
|
||||
test::minimal::allocator<test::minimal::assignable> >
|
||||
multiset;
|
||||
|
||||
UNORDERED_AUTO_TEST(test0)
|
||||
{
|
||||
test::minimal::constructor_param x;
|
||||
|
||||
test::minimal::assignable assignable(x);
|
||||
|
||||
std::cout<<"Test unordered_set.\n";
|
||||
|
||||
boost::unordered_set<int> int_set;
|
||||
|
||||
boost::unordered_set<int,
|
||||
boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<int>
|
||||
> int_set2;
|
||||
|
||||
boost::unordered_set<
|
||||
test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<test::minimal::assignable> > set;
|
||||
|
||||
container_test(int_set, 0);
|
||||
container_test(int_set2, 0);
|
||||
container_test(set, assignable);
|
||||
|
||||
std::cout<<"Test unordered_multiset.\n";
|
||||
|
||||
boost::unordered_multiset<int> int_multiset;
|
||||
|
||||
boost::unordered_multiset<int,
|
||||
boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<int>
|
||||
> int_multiset2;
|
||||
|
||||
boost::unordered_multiset<
|
||||
test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<test::minimal::assignable> > multiset;
|
||||
|
||||
container_test(int_multiset, 0);
|
||||
container_test(int_multiset2, 0);
|
||||
container_test(multiset, assignable);
|
||||
container_test(int_multiset, 0);
|
||||
container_test(int_multiset2, 0);
|
||||
container_test(multiset, assignable);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(equality_tests) {
|
||||
typedef test::minimal::copy_constructible_equality_comparable value_type;
|
||||
UNORDERED_AUTO_TEST (equality_tests) {
|
||||
typedef test::minimal::copy_constructible_equality_comparable value_type;
|
||||
|
||||
boost::unordered_set<int> int_set;
|
||||
boost::unordered_set<int> int_set;
|
||||
|
||||
boost::unordered_set<int,
|
||||
boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<int>
|
||||
> int_set2;
|
||||
boost::unordered_set<int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<int> >
|
||||
int_set2;
|
||||
|
||||
boost::unordered_set<
|
||||
test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::equal_to<test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::allocator<value_type> > set;
|
||||
boost::unordered_set<test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::equal_to<
|
||||
test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::allocator<value_type> >
|
||||
set;
|
||||
|
||||
equality_test(int_set);
|
||||
equality_test(int_set2);
|
||||
equality_test(set);
|
||||
equality_test(int_set);
|
||||
equality_test(int_set2);
|
||||
equality_test(set);
|
||||
|
||||
boost::unordered_multiset<int> int_multiset;
|
||||
boost::unordered_multiset<int> int_multiset;
|
||||
|
||||
boost::unordered_multiset<int,
|
||||
boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<int>
|
||||
> int_multiset2;
|
||||
boost::unordered_multiset<int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<int> >
|
||||
int_multiset2;
|
||||
|
||||
boost::unordered_multiset<
|
||||
test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::equal_to<test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::allocator<value_type> > multiset;
|
||||
boost::unordered_multiset<
|
||||
test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::equal_to<
|
||||
test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::allocator<value_type> >
|
||||
multiset;
|
||||
|
||||
equality_test(int_multiset);
|
||||
equality_test(int_multiset2);
|
||||
equality_test(multiset);
|
||||
equality_test(int_multiset);
|
||||
equality_test(int_multiset2);
|
||||
equality_test(multiset);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(test1)
|
||||
{
|
||||
boost::hash<int> hash;
|
||||
std::equal_to<int> equal_to;
|
||||
int value = 0;
|
||||
UNORDERED_AUTO_TEST (test1) {
|
||||
boost::hash<int> hash;
|
||||
std::equal_to<int> equal_to;
|
||||
int value = 0;
|
||||
|
||||
std::cout<<"Test unordered_set." << std::endl;
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set." << std::endl;
|
||||
|
||||
boost::unordered_set<int> set;
|
||||
|
||||
boost::unordered_set<int,
|
||||
boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<int>
|
||||
> set2;
|
||||
boost::unordered_set<int> set;
|
||||
|
||||
unordered_unique_test(set, value);
|
||||
unordered_set_test(set, value);
|
||||
unordered_copyable_test(set, value, value, hash, equal_to);
|
||||
boost::unordered_set<int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<int> >
|
||||
set2;
|
||||
|
||||
unordered_unique_test(set2, value);
|
||||
unordered_set_test(set2, value);
|
||||
unordered_copyable_test(set2, value, value, hash, equal_to);
|
||||
unordered_unique_test(set, value);
|
||||
unordered_set_test(set, value);
|
||||
unordered_copyable_test(set, value, value, hash, equal_to);
|
||||
|
||||
std::cout<<"Test unordered_multiset." << std::endl;
|
||||
unordered_unique_test(set2, value);
|
||||
unordered_set_test(set2, value);
|
||||
unordered_copyable_test(set2, value, value, hash, equal_to);
|
||||
|
||||
boost::unordered_multiset<int> multiset;
|
||||
|
||||
boost::unordered_multiset<int,
|
||||
boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<int>
|
||||
> multiset2;
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset." << std::endl;
|
||||
|
||||
unordered_equivalent_test(multiset, value);
|
||||
unordered_set_test(multiset, value);
|
||||
unordered_copyable_test(multiset, value, value, hash, equal_to);
|
||||
boost::unordered_multiset<int> multiset;
|
||||
|
||||
unordered_equivalent_test(multiset2, value);
|
||||
unordered_set_test(multiset2, value);
|
||||
unordered_copyable_test(multiset2, value, value, hash, equal_to);
|
||||
boost::unordered_multiset<int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<int> >
|
||||
multiset2;
|
||||
|
||||
unordered_equivalent_test(multiset, value);
|
||||
unordered_set_test(multiset, value);
|
||||
unordered_copyable_test(multiset, value, value, hash, equal_to);
|
||||
|
||||
unordered_equivalent_test(multiset2, value);
|
||||
unordered_set_test(multiset2, value);
|
||||
unordered_copyable_test(multiset2, value, value, hash, equal_to);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(test2)
|
||||
{
|
||||
test::minimal::constructor_param x;
|
||||
|
||||
test::minimal::assignable assignable(x);
|
||||
test::minimal::copy_constructible copy_constructible(x);
|
||||
test::minimal::hash<test::minimal::assignable> hash(x);
|
||||
test::minimal::equal_to<test::minimal::assignable> equal_to(x);
|
||||
UNORDERED_AUTO_TEST (test2) {
|
||||
test::minimal::constructor_param x;
|
||||
|
||||
std::cout<<"Test unordered_set.\n";
|
||||
test::minimal::assignable assignable(x);
|
||||
test::minimal::copy_constructible copy_constructible(x);
|
||||
test::minimal::hash<test::minimal::assignable> hash(x);
|
||||
test::minimal::equal_to<test::minimal::assignable> equal_to(x);
|
||||
|
||||
boost::unordered_set<
|
||||
test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<test::minimal::assignable> > set;
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n";
|
||||
|
||||
unordered_unique_test(set, assignable);
|
||||
unordered_set_test(set, assignable);
|
||||
unordered_copyable_test(set, assignable, assignable, hash, equal_to);
|
||||
boost::unordered_set<test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<test::minimal::assignable> >
|
||||
set;
|
||||
|
||||
std::cout<<"Test unordered_multiset.\n";
|
||||
unordered_unique_test(set, assignable);
|
||||
unordered_set_test(set, assignable);
|
||||
unordered_copyable_test(set, assignable, assignable, hash, equal_to);
|
||||
unordered_set_member_test(set, assignable);
|
||||
|
||||
boost::unordered_multiset<
|
||||
test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<test::minimal::assignable> > multiset;
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n";
|
||||
|
||||
unordered_equivalent_test(multiset, assignable);
|
||||
unordered_set_test(multiset, assignable);
|
||||
unordered_copyable_test(multiset, assignable, assignable, hash, equal_to);
|
||||
boost::unordered_multiset<test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<test::minimal::assignable> >
|
||||
multiset;
|
||||
|
||||
unordered_equivalent_test(multiset, assignable);
|
||||
unordered_set_test(multiset, assignable);
|
||||
unordered_copyable_test(multiset, assignable, assignable, hash, equal_to);
|
||||
unordered_set_member_test(multiset, assignable);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(movable1_tests)
|
||||
{
|
||||
test::minimal::constructor_param x;
|
||||
UNORDERED_AUTO_TEST (movable1_tests) {
|
||||
test::minimal::constructor_param x;
|
||||
|
||||
test::minimal::movable1 movable1(x);
|
||||
test::minimal::hash<test::minimal::movable1> hash(x);
|
||||
test::minimal::equal_to<test::minimal::movable1> equal_to(x);
|
||||
test::minimal::movable1 movable1(x);
|
||||
test::minimal::hash<test::minimal::movable1> hash(x);
|
||||
test::minimal::equal_to<test::minimal::movable1> equal_to(x);
|
||||
|
||||
std::cout<<"Test unordered_set.\n";
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n";
|
||||
|
||||
boost::unordered_set<
|
||||
test::minimal::movable1,
|
||||
test::minimal::hash<test::minimal::movable1>,
|
||||
test::minimal::equal_to<test::minimal::movable1>,
|
||||
test::minimal::allocator<test::minimal::movable1> > set;
|
||||
boost::unordered_set<test::minimal::movable1,
|
||||
test::minimal::hash<test::minimal::movable1>,
|
||||
test::minimal::equal_to<test::minimal::movable1>,
|
||||
test::minimal::allocator<test::minimal::movable1> >
|
||||
set;
|
||||
|
||||
//unordered_unique_test(set, movable1);
|
||||
unordered_set_test(set, movable1);
|
||||
unordered_movable_test(set, movable1, movable1, hash, equal_to);
|
||||
// unordered_unique_test(set, movable1);
|
||||
unordered_set_test(set, movable1);
|
||||
unordered_movable_test(set, movable1, movable1, hash, equal_to);
|
||||
|
||||
std::cout<<"Test unordered_multiset.\n";
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n";
|
||||
|
||||
boost::unordered_multiset<
|
||||
test::minimal::movable1,
|
||||
test::minimal::hash<test::minimal::movable1>,
|
||||
test::minimal::equal_to<test::minimal::movable1>,
|
||||
test::minimal::allocator<test::minimal::movable1> > multiset;
|
||||
boost::unordered_multiset<test::minimal::movable1,
|
||||
test::minimal::hash<test::minimal::movable1>,
|
||||
test::minimal::equal_to<test::minimal::movable1>,
|
||||
test::minimal::allocator<test::minimal::movable1> >
|
||||
multiset;
|
||||
|
||||
//unordered_equivalent_test(multiset, movable1);
|
||||
unordered_set_test(multiset, movable1);
|
||||
unordered_movable_test(multiset, movable1, movable1, hash, equal_to);
|
||||
// unordered_equivalent_test(multiset, movable1);
|
||||
unordered_set_test(multiset, movable1);
|
||||
unordered_movable_test(multiset, movable1, movable1, hash, equal_to);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(movable2_tests)
|
||||
{
|
||||
test::minimal::constructor_param x;
|
||||
UNORDERED_AUTO_TEST (movable2_tests) {
|
||||
test::minimal::constructor_param x;
|
||||
|
||||
test::minimal::movable2 movable2(x);
|
||||
test::minimal::hash<test::minimal::movable2> hash(x);
|
||||
test::minimal::equal_to<test::minimal::movable2> equal_to(x);
|
||||
test::minimal::movable2 movable2(x);
|
||||
test::minimal::hash<test::minimal::movable2> hash(x);
|
||||
test::minimal::equal_to<test::minimal::movable2> equal_to(x);
|
||||
|
||||
std::cout<<"Test unordered_set.\n";
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n";
|
||||
|
||||
boost::unordered_set<
|
||||
test::minimal::movable2,
|
||||
test::minimal::hash<test::minimal::movable2>,
|
||||
test::minimal::equal_to<test::minimal::movable2>,
|
||||
test::minimal::allocator<test::minimal::movable2> > set;
|
||||
boost::unordered_set<test::minimal::movable2,
|
||||
test::minimal::hash<test::minimal::movable2>,
|
||||
test::minimal::equal_to<test::minimal::movable2>,
|
||||
test::minimal::allocator<test::minimal::movable2> >
|
||||
set;
|
||||
|
||||
//unordered_unique_test(set, movable2);
|
||||
unordered_set_test(set, movable2);
|
||||
unordered_movable_test(set, movable2, movable2, hash, equal_to);
|
||||
// unordered_unique_test(set, movable2);
|
||||
unordered_set_test(set, movable2);
|
||||
unordered_movable_test(set, movable2, movable2, hash, equal_to);
|
||||
|
||||
std::cout<<"Test unordered_multiset.\n";
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n";
|
||||
|
||||
boost::unordered_multiset<
|
||||
test::minimal::movable2,
|
||||
test::minimal::hash<test::minimal::movable2>,
|
||||
test::minimal::equal_to<test::minimal::movable2>,
|
||||
test::minimal::allocator<test::minimal::movable2> > multiset;
|
||||
boost::unordered_multiset<test::minimal::movable2,
|
||||
test::minimal::hash<test::minimal::movable2>,
|
||||
test::minimal::equal_to<test::minimal::movable2>,
|
||||
test::minimal::allocator<test::minimal::movable2> >
|
||||
multiset;
|
||||
|
||||
//unordered_equivalent_test(multiset, movable2);
|
||||
unordered_set_test(multiset, movable2);
|
||||
unordered_movable_test(multiset, movable2, movable2, hash, equal_to);
|
||||
// unordered_equivalent_test(multiset, movable2);
|
||||
unordered_set_test(multiset, movable2);
|
||||
unordered_movable_test(multiset, movable2, movable2, hash, equal_to);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(destructible_tests)
|
||||
UNORDERED_AUTO_TEST (destructible_tests) {
|
||||
test::minimal::constructor_param x;
|
||||
|
||||
test::minimal::destructible destructible(x);
|
||||
test::minimal::hash<test::minimal::destructible> hash(x);
|
||||
test::minimal::equal_to<test::minimal::destructible> equal_to(x);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n";
|
||||
|
||||
boost::unordered_set<test::minimal::destructible,
|
||||
test::minimal::hash<test::minimal::destructible>,
|
||||
test::minimal::equal_to<test::minimal::destructible> >
|
||||
set;
|
||||
|
||||
unordered_destructible_test(set);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n";
|
||||
|
||||
boost::unordered_multiset<test::minimal::destructible,
|
||||
test::minimal::hash<test::minimal::destructible>,
|
||||
test::minimal::equal_to<test::minimal::destructible> >
|
||||
multiset;
|
||||
|
||||
unordered_destructible_test(multiset);
|
||||
}
|
||||
|
||||
// Test for ambiguity when using key convertible from iterator
|
||||
// See LWG2059
|
||||
|
||||
struct lwg2059_key
|
||||
{
|
||||
test::minimal::constructor_param x;
|
||||
int value;
|
||||
|
||||
test::minimal::destructible destructible(x);
|
||||
test::minimal::hash<test::minimal::destructible> hash(x);
|
||||
test::minimal::equal_to<test::minimal::destructible> equal_to(x);
|
||||
template <typename T> lwg2059_key(T v) : value(v) {}
|
||||
};
|
||||
|
||||
std::cout<<"Test unordered_set.\n";
|
||||
std::size_t hash_value(lwg2059_key x)
|
||||
{
|
||||
return static_cast<std::size_t>(x.value);
|
||||
}
|
||||
|
||||
boost::unordered_set<
|
||||
test::minimal::destructible,
|
||||
test::minimal::hash<test::minimal::destructible>,
|
||||
test::minimal::equal_to<test::minimal::destructible> > set;
|
||||
bool operator==(lwg2059_key x, lwg2059_key y) { return x.value == y.value; }
|
||||
|
||||
unordered_destructible_test(set);
|
||||
UNORDERED_AUTO_TEST (lwg2059) {
|
||||
{
|
||||
boost::unordered_set<lwg2059_key> x;
|
||||
x.emplace(lwg2059_key(10));
|
||||
x.erase(x.begin());
|
||||
}
|
||||
|
||||
std::cout<<"Test unordered_multiset.\n";
|
||||
|
||||
boost::unordered_multiset<
|
||||
test::minimal::destructible,
|
||||
test::minimal::hash<test::minimal::destructible>,
|
||||
test::minimal::equal_to<test::minimal::destructible> > multiset;
|
||||
|
||||
unordered_destructible_test(multiset);
|
||||
{
|
||||
boost::unordered_multiset<lwg2059_key> x;
|
||||
x.emplace(lwg2059_key(10));
|
||||
x.erase(x.begin());
|
||||
}
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -3,10 +3,12 @@
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../objects/test.hpp"
|
||||
@ -18,444 +20,427 @@
|
||||
|
||||
namespace constructor_tests {
|
||||
|
||||
test::seed_t initialize_seed(356730);
|
||||
test::seed_t initialize_seed(356730);
|
||||
|
||||
template <class T>
|
||||
void constructor_tests1(T*, test::random_generator generator)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf;
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq;
|
||||
BOOST_DEDUCED_TYPENAME T::allocator_type al;
|
||||
template <class T>
|
||||
void constructor_tests1(T*, test::random_generator generator)
|
||||
{
|
||||
typename T::hasher hf;
|
||||
typename T::key_equal eq;
|
||||
typename T::allocator_type al;
|
||||
|
||||
std::cerr<<"Construct 1\n";
|
||||
UNORDERED_SUB_TEST("Construct 1")
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
T x(0, hf, eq);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
T x(0, hf, eq);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 2\n";
|
||||
UNORDERED_SUB_TEST("Construct 2")
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
T x(100, hf);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 100);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
T x(100, hf);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 100);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 3\n";
|
||||
UNORDERED_SUB_TEST("Construct 3")
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
T x(2000);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 2000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
T x(2000);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 2000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 4\n";
|
||||
UNORDERED_SUB_TEST("Construct 4")
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
T x;
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
T x;
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 5\n";
|
||||
UNORDERED_SUB_TEST("Construct 5")
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v(1000, generator);
|
||||
T x(v.begin(), v.end(), 10000, hf, eq);
|
||||
BOOST_TEST(x.bucket_count() >= 10000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
test::random_values<T> v(1000, generator);
|
||||
T x(v.begin(), v.end(), 10000, hf, eq);
|
||||
BOOST_TEST(x.bucket_count() >= 10000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 6\n";
|
||||
UNORDERED_SUB_TEST("Construct 6")
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v(10, generator);
|
||||
T x(v.begin(), v.end(), 10000, hf);
|
||||
BOOST_TEST(x.bucket_count() >= 10000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
test::random_values<T> v(10, generator);
|
||||
T x(v.begin(), v.end(), 10000, hf);
|
||||
BOOST_TEST(x.bucket_count() >= 10000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 7\n";
|
||||
UNORDERED_SUB_TEST("Construct 7")
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(v.begin(), v.end(), 100);
|
||||
BOOST_TEST(x.bucket_count() >= 100);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(v.begin(), v.end(), 100);
|
||||
BOOST_TEST(x.bucket_count() >= 100);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 8\n";
|
||||
UNORDERED_SUB_TEST("Construct 8")
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v(1, generator);
|
||||
T x(v.begin(), v.end());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
test::random_values<T> v(1, generator);
|
||||
T x(v.begin(), v.end());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 9\n";
|
||||
UNORDERED_SUB_TEST("Construct 9")
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
T x(0, hf, eq, al);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
T x(0, hf, eq, al);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 10\n";
|
||||
UNORDERED_SUB_TEST("Construct 10")
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v(1000, generator);
|
||||
T x(v.begin(), v.end(), 10000, hf, eq, al);
|
||||
BOOST_TEST(x.bucket_count() >= 10000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
test::random_values<T> v(1000, generator);
|
||||
T x(v.begin(), v.end(), 10000, hf, eq, al);
|
||||
BOOST_TEST(x.bucket_count() >= 10000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 11\n";
|
||||
UNORDERED_SUB_TEST("Construct 11")
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
T x(al);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
T x(al);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void constructor_tests2(T*, test::random_generator const& generator)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf;
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf1(1);
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf2(2);
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq;
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq1(1);
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq2(2);
|
||||
BOOST_DEDUCED_TYPENAME T::allocator_type al;
|
||||
BOOST_DEDUCED_TYPENAME T::allocator_type al1(1);
|
||||
BOOST_DEDUCED_TYPENAME T::allocator_type al2(2);
|
||||
template <class T>
|
||||
void constructor_tests2(T*, test::random_generator const& generator)
|
||||
{
|
||||
typename T::hasher hf;
|
||||
typename T::hasher hf1(1);
|
||||
typename T::hasher hf2(2);
|
||||
typename T::key_equal eq;
|
||||
typename T::key_equal eq1(1);
|
||||
typename T::key_equal eq2(2);
|
||||
typename T::allocator_type al;
|
||||
typename T::allocator_type al1(1);
|
||||
typename T::allocator_type al2(2);
|
||||
|
||||
std::cerr<<"Construct 1\n";
|
||||
UNORDERED_SUB_TEST("Construct 1")
|
||||
{
|
||||
test::check_instances check_;
|
||||
T x(10000, hf1, eq1);
|
||||
BOOST_TEST(x.bucket_count() >= 10000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_instances check_;
|
||||
T x(10000, hf1, eq1);
|
||||
BOOST_TEST(x.bucket_count() >= 10000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 2\n";
|
||||
UNORDERED_SUB_TEST("Construct 2")
|
||||
{
|
||||
test::check_instances check_;
|
||||
T x(100, hf1);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 100);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_instances check_;
|
||||
T x(100, hf1);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 100);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 3\n";
|
||||
UNORDERED_SUB_TEST("Construct 3")
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(v.begin(), v.end(), 0, hf1, eq1);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_instances check_;
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(v.begin(), v.end(), 0, hf1, eq1);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 4\n";
|
||||
UNORDERED_SUB_TEST("Construct 4")
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::random_values<T> v(5, generator);
|
||||
T x(v.begin(), v.end(), 1000, hf1);
|
||||
BOOST_TEST(x.bucket_count() >= 1000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_instances check_;
|
||||
test::random_values<T> v(5, generator);
|
||||
T x(v.begin(), v.end(), 1000, hf1);
|
||||
BOOST_TEST(x.bucket_count() >= 1000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
|
||||
std::cerr<<"Construct 5\n";
|
||||
UNORDERED_SUB_TEST("Construct 5")
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(v.begin(), v.end(), 0, hf, eq, al1);
|
||||
T y(x.begin(), x.end(), 0, hf1, eq1, al2);
|
||||
test::check_container(x, v);
|
||||
test::check_container(y, x);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_equivalent_keys(y);
|
||||
test::check_instances check_;
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(v.begin(), v.end(), 0, hf, eq, al1);
|
||||
T y(x.begin(), x.end(), 0, hf1, eq1, al2);
|
||||
test::check_container(x, v);
|
||||
test::check_container(y, x);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 6\n";
|
||||
UNORDERED_SUB_TEST("Construct 6")
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(v.begin(), v.end(), 0, hf1, eq1);
|
||||
T y(x.begin(), x.end(), 0, hf, eq);
|
||||
test::check_container(x, v);
|
||||
test::check_container(y, x);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_equivalent_keys(y);
|
||||
test::check_instances check_;
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(v.begin(), v.end(), 0, hf1, eq1);
|
||||
T y(x.begin(), x.end(), 0, hf, eq);
|
||||
test::check_container(x, v);
|
||||
test::check_container(y, x);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 7\n";
|
||||
UNORDERED_SUB_TEST("Construct 7")
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(v.begin(), v.end(), 0, hf1, eq1);
|
||||
T y(x.begin(), x.end(), 0, hf2, eq2);
|
||||
test::check_container(x, v);
|
||||
test::check_container(y, x);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_equivalent_keys(y);
|
||||
test::check_instances check_;
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(v.begin(), v.end(), 0, hf1, eq1);
|
||||
T y(x.begin(), x.end(), 0, hf2, eq2);
|
||||
test::check_container(x, v);
|
||||
test::check_container(y, x);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 8 - from input iterator\n";
|
||||
UNORDERED_SUB_TEST("Construct 8 - from input iterator")
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::random_values<T> v(100, generator);
|
||||
BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
|
||||
v_begin = v.begin(), v_end = v.end();
|
||||
T x(test::input_iterator(v_begin),
|
||||
test::input_iterator(v_end), 0, hf1, eq1);
|
||||
BOOST_DEDUCED_TYPENAME T::const_iterator
|
||||
x_begin = x.begin(), x_end = x.end();
|
||||
T y(test::input_iterator(x_begin),
|
||||
test::input_iterator(x_end), 0, hf2, eq2);
|
||||
test::check_container(x, v);
|
||||
test::check_container(y, x);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_equivalent_keys(y);
|
||||
test::check_instances check_;
|
||||
test::random_values<T> v(100, generator);
|
||||
typename test::random_values<T>::const_iterator v_begin = v.begin(),
|
||||
v_end = v.end();
|
||||
T x(test::input_iterator(v_begin), test::input_iterator(v_end), 0, hf1,
|
||||
eq1);
|
||||
typename T::const_iterator x_begin = x.begin(), x_end = x.end();
|
||||
T y(test::input_iterator(x_begin), test::input_iterator(x_end), 0, hf2,
|
||||
eq2);
|
||||
test::check_container(x, v);
|
||||
test::check_container(y, x);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 8.5 - from copy iterator\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(test::copy_iterator(v.begin()),
|
||||
test::copy_iterator(v.end()), 0, hf1, eq1);
|
||||
T y(test::copy_iterator(x.begin()),
|
||||
test::copy_iterator(x.end()), 0, hf2, eq2);
|
||||
test::check_container(x, v);
|
||||
test::check_container(y, x);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
std::cerr<<"Construct 9\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(50);
|
||||
BOOST_TEST(x.bucket_count() >= 50);
|
||||
x.max_load_factor(10);
|
||||
BOOST_TEST(x.bucket_count() >= 50);
|
||||
x.insert(v.begin(), v.end());
|
||||
BOOST_TEST(x.bucket_count() >= 50);
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
UNORDERED_SUB_TEST("Construct 8.5 - from copy iterator")
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(test::copy_iterator(v.begin()), test::copy_iterator(v.end()), 0, hf1,
|
||||
eq1);
|
||||
T y(test::copy_iterator(x.begin()), test::copy_iterator(x.end()), 0, hf2,
|
||||
eq2);
|
||||
test::check_container(x, v);
|
||||
test::check_container(y, x);
|
||||
test::check_equivalent_keys(x);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
UNORDERED_SUB_TEST("Construct 9")
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v(100, generator);
|
||||
T x(50);
|
||||
BOOST_TEST(x.bucket_count() >= 50);
|
||||
x.max_load_factor(10);
|
||||
BOOST_TEST(x.bucket_count() >= 50);
|
||||
x.insert(v.begin(), v.end());
|
||||
BOOST_TEST(x.bucket_count() >= 50);
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
std::initializer_list<BOOST_DEDUCED_TYPENAME T::value_type> list;
|
||||
|
||||
std::cerr<<"Initializer list construct 1\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
std::initializer_list<typename T::value_type> list;
|
||||
|
||||
T x(list);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
UNORDERED_SUB_TEST("Initializer list construct 1")
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
T x(list);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
}
|
||||
|
||||
std::cerr<<"Initializer list construct 2\n";
|
||||
UNORDERED_SUB_TEST("Initializer list construct 2")
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
T x(list, 1000);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 1000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
T x(list, 1000);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 1000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
}
|
||||
|
||||
std::cerr<<"Initializer list construct 3\n";
|
||||
UNORDERED_SUB_TEST("Initializer list construct 3")
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
T x(list, 10, hf1);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 10);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
T x(list, 10, hf1);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 10);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
}
|
||||
|
||||
std::cerr<<"Initializer list construct 4\n";
|
||||
UNORDERED_SUB_TEST("Initializer list construct 4")
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
T x(list, 10, hf1, eq1);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 10);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
T x(list, 10, hf1, eq1);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 10);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
}
|
||||
|
||||
std::cerr<<"Initializer list construct 5\n";
|
||||
UNORDERED_SUB_TEST("Initializer list construct 5")
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
T x(list, 10, hf1, eq1, al1);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 10);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al1));
|
||||
T x(list, 10, hf1, eq1, al1);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 10);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al1));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void map_constructor_test(T*, test::random_generator const& generator)
|
||||
{
|
||||
std::cerr<<"map_constructor_test\n";
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void map_constructor_test(T*, test::random_generator const& generator)
|
||||
{
|
||||
typedef test::list<
|
||||
std::pair<
|
||||
BOOST_DEDUCED_TYPENAME T::key_type,
|
||||
BOOST_DEDUCED_TYPENAME T::mapped_type
|
||||
>
|
||||
> list;
|
||||
std::pair<typename T::key_type, typename T::mapped_type> >
|
||||
list;
|
||||
test::random_values<T> v(1000, generator);
|
||||
list l(v.begin(), v.end());
|
||||
T x(l.begin(), l.end());
|
||||
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
}
|
||||
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
std::allocator<test::object> >* test_map_std_alloc;
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_multimap;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator1<test::object> >* test_multimap;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
using test::limited_range;
|
||||
|
||||
UNORDERED_TEST(constructor_tests1,
|
||||
((test_map_std_alloc)(test_set)(test_multiset)(test_map)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
UNORDERED_TEST(constructor_tests1,
|
||||
((test_map_std_alloc)(test_set)(test_multiset)(test_map)(test_multimap))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(constructor_tests2,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
UNORDERED_TEST(constructor_tests2,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(map_constructor_test,
|
||||
((test_map_std_alloc)(test_map)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
UNORDERED_TEST(map_constructor_test,
|
||||
((test_map_std_alloc)(test_map)(test_multimap))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
|
||||
UNORDERED_AUTO_TEST(test_default_initializer_list) {
|
||||
std::cerr<<"Initializer List Tests\n";
|
||||
UNORDERED_AUTO_TEST (test_default_initializer_list) {
|
||||
std::initializer_list<int> init;
|
||||
boost::unordered_set<int> x1 = init;
|
||||
BOOST_TEST(x1.empty());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
|
||||
UNORDERED_AUTO_TEST(test_initializer_list) {
|
||||
std::cerr<<"Initializer List Tests\n";
|
||||
boost::unordered_set<int> x1 = { 2, 10, 45, -5 };
|
||||
UNORDERED_AUTO_TEST (test_initializer_list) {
|
||||
boost::unordered_set<int> x1 = {2, 10, 45, -5};
|
||||
BOOST_TEST(x1.find(10) != x1.end());
|
||||
BOOST_TEST(x1.find(46) == x1.end());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
RUN_TESTS_QUIET()
|
||||
|
@ -3,10 +3,12 @@
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../objects/test.hpp"
|
||||
@ -18,203 +20,190 @@
|
||||
|
||||
test::seed_t initialize_seed(9063);
|
||||
|
||||
namespace copy_tests
|
||||
{
|
||||
namespace copy_tests {
|
||||
|
||||
template <class T>
|
||||
void copy_construct_tests1(T*, test::random_generator const& generator)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
|
||||
template <class T>
|
||||
void copy_construct_tests1(T*, test::random_generator const& generator)
|
||||
{
|
||||
typedef typename T::allocator_type allocator_type;
|
||||
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf;
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq;
|
||||
BOOST_DEDUCED_TYPENAME T::allocator_type al;
|
||||
typename T::hasher hf;
|
||||
typename T::key_equal eq;
|
||||
typename T::allocator_type al;
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
T x;
|
||||
T y(x);
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) ==
|
||||
(allocator_type::is_select_on_copy));
|
||||
test::check_equivalent_keys(y);
|
||||
T x;
|
||||
T y(x);
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) ==
|
||||
(allocator_type::is_select_on_copy));
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v(1000, generator);
|
||||
test::random_values<T> v(1000, generator);
|
||||
|
||||
T x(v.begin(), v.end());
|
||||
T y(x);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
BOOST_TEST(equivalent(y));
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) ==
|
||||
(allocator_type::is_select_on_copy));
|
||||
test::check_equivalent_keys(y);
|
||||
T x(v.begin(), v.end());
|
||||
T y(x);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
BOOST_TEST(equivalent(y));
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) ==
|
||||
(allocator_type::is_select_on_copy));
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
// In this test I drop the original containers max load factor, so it
|
||||
// is much lower than the load factor. The hash table is not allowed
|
||||
// to rehash, but the destination container should probably allocate
|
||||
// enough buckets to decrease the load factor appropriately.
|
||||
test::random_values<T> v(1000, generator);
|
||||
T x(v.begin(), v.end());
|
||||
x.max_load_factor(x.load_factor() / 4);
|
||||
T y(x);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
BOOST_TEST(equivalent(y));
|
||||
// This isn't guaranteed:
|
||||
BOOST_TEST(y.load_factor() < y.max_load_factor());
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) ==
|
||||
(allocator_type::is_select_on_copy));
|
||||
test::check_equivalent_keys(y);
|
||||
// In this test I drop the original containers max load factor, so it
|
||||
// is much lower than the load factor. The hash table is not allowed
|
||||
// to rehash, but the destination container should probably allocate
|
||||
// enough buckets to decrease the load factor appropriately.
|
||||
test::random_values<T> v(1000, generator);
|
||||
T x(v.begin(), v.end());
|
||||
x.max_load_factor(x.load_factor() / 4);
|
||||
T y(x);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
BOOST_TEST(equivalent(y));
|
||||
// This isn't guaranteed:
|
||||
BOOST_TEST(y.load_factor() < y.max_load_factor());
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) ==
|
||||
(allocator_type::is_select_on_copy));
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void copy_construct_tests2(T*, test::random_generator const& generator)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf(1);
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq(1);
|
||||
BOOST_DEDUCED_TYPENAME T::allocator_type al(1);
|
||||
BOOST_DEDUCED_TYPENAME T::allocator_type al2(2);
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
|
||||
template <class T>
|
||||
void copy_construct_tests2(T*, test::random_generator const& generator)
|
||||
{
|
||||
typename T::hasher hf(1);
|
||||
typename T::key_equal eq(1);
|
||||
typename T::allocator_type al(1);
|
||||
typename T::allocator_type al2(2);
|
||||
|
||||
typedef typename T::allocator_type allocator_type;
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
T x(10000, hf, eq, al);
|
||||
T y(x);
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) ==
|
||||
(allocator_type::is_select_on_copy));
|
||||
test::check_equivalent_keys(y);
|
||||
T x(10000, hf, eq, al);
|
||||
T y(x);
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) ==
|
||||
(allocator_type::is_select_on_copy));
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
T x(1000, hf, eq, al);
|
||||
T y(x, al2);
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al2));
|
||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) == 0);
|
||||
test::check_equivalent_keys(y);
|
||||
T x(1000, hf, eq, al);
|
||||
T y(x, al2);
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al2));
|
||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) == 0);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v(1000, generator);
|
||||
test::random_values<T> v(1000, generator);
|
||||
|
||||
T x(v.begin(), v.end(), 0, hf, eq, al);
|
||||
T y(x);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
BOOST_TEST(equivalent(y));
|
||||
test::check_equivalent_keys(y);
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) ==
|
||||
(allocator_type::is_select_on_copy));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
T x(v.begin(), v.end(), 0, hf, eq, al);
|
||||
T y(x);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
BOOST_TEST(equivalent(y));
|
||||
test::check_equivalent_keys(y);
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) ==
|
||||
(allocator_type::is_select_on_copy));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v(500, generator);
|
||||
test::random_values<T> v(500, generator);
|
||||
|
||||
T x(v.begin(), v.end(), 0, hf, eq, al);
|
||||
T y(x, al2);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
BOOST_TEST(equivalent(y));
|
||||
test::check_equivalent_keys(y);
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) == 0);
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al2));
|
||||
T x(v.begin(), v.end(), 0, hf, eq, al);
|
||||
T y(x, al2);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
BOOST_TEST(equivalent(y));
|
||||
test::check_equivalent_keys(y);
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) == 0);
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_multimap;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator2<test::object> >* test_multimap;
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::select_copy> >*
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::select_copy> >*
|
||||
test_set_select_copy;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::select_copy> >*
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::select_copy> >*
|
||||
test_multiset_select_copy;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::select_copy> >*
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::select_copy> >*
|
||||
test_map_select_copy;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::select_copy> >*
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to, test::cxx11_allocator<test::object, test::select_copy> >*
|
||||
test_multimap_select_copy;
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_select_copy> >*
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_select_copy> >*
|
||||
test_set_no_select_copy;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_select_copy> >*
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_select_copy> >*
|
||||
test_multiset_no_select_copy;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_select_copy> >*
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_select_copy> >*
|
||||
test_map_no_select_copy;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_select_copy> >*
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to, test::cxx11_allocator<test::object, test::no_select_copy> >*
|
||||
test_multimap_no_select_copy;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
using test::limited_range;
|
||||
|
||||
UNORDERED_TEST(copy_construct_tests1, (
|
||||
(test_set)(test_multiset)(test_map)(test_multimap)
|
||||
(test_set_select_copy)(test_multiset_select_copy)(test_map_select_copy)(test_multimap_select_copy)
|
||||
(test_set_no_select_copy)(test_multiset_no_select_copy)(test_map_no_select_copy)(test_multimap_no_select_copy)
|
||||
)
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
|
||||
UNORDERED_TEST(copy_construct_tests2, (
|
||||
(test_set)(test_multiset)(test_map)(test_multimap)
|
||||
(test_set_select_copy)(test_multiset_select_copy)(test_map_select_copy)(test_multimap_select_copy)
|
||||
(test_set_no_select_copy)(test_multiset_no_select_copy)(test_map_no_select_copy)(test_multimap_no_select_copy)
|
||||
)
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
UNORDERED_TEST(copy_construct_tests1,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap)(test_set_select_copy)(
|
||||
test_multiset_select_copy)(test_map_select_copy)(
|
||||
test_multimap_select_copy)(test_set_no_select_copy)(
|
||||
test_multiset_no_select_copy)(test_map_no_select_copy)(
|
||||
test_multimap_no_select_copy))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(copy_construct_tests2,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap)(test_set_select_copy)(
|
||||
test_multiset_select_copy)(test_map_select_copy)(
|
||||
test_multimap_select_copy)(test_set_no_select_copy)(
|
||||
test_multiset_no_select_copy)(test_map_no_select_copy)(
|
||||
test_multimap_no_select_copy))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
352
test/unordered/deduction_tests.cpp
Normal file
352
test/unordered/deduction_tests.cpp
Normal file
@ -0,0 +1,352 @@
|
||||
|
||||
// Copyright 2017-2018 Daniel James.
|
||||
// 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 <boost/unordered_map.hpp>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
|
||||
struct hash_equals
|
||||
{
|
||||
template <typename T> bool operator()(T const& x) const
|
||||
{
|
||||
boost::hash<T> hf;
|
||||
return hf(x);
|
||||
}
|
||||
|
||||
template <typename T> bool operator()(T const& x, T const& y) const
|
||||
{
|
||||
std::equal_to<T> eq;
|
||||
return eq(x, y);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> struct test_allocator
|
||||
{
|
||||
typedef T value_type;
|
||||
test_allocator() = default;
|
||||
template <typename T2> test_allocator(test_allocator<T2> const&) {}
|
||||
T* allocate(std::size_t n) const { return (T*)malloc(sizeof(T) * n); }
|
||||
void deallocate(T* ptr, std::size_t) const { free(ptr); }
|
||||
bool operator==(test_allocator const&) { return true; }
|
||||
bool operator!=(test_allocator const&) { return false; }
|
||||
};
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << "BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES: "
|
||||
<< BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES << std::endl;
|
||||
|
||||
#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
|
||||
std::vector<std::pair<int, int> > x;
|
||||
x.push_back(std::make_pair(1, 3));
|
||||
x.push_back(std::make_pair(5, 10));
|
||||
test_allocator<std::pair<const int, int> > pair_allocator;
|
||||
hash_equals f;
|
||||
|
||||
// unordered_map
|
||||
|
||||
/*
|
||||
template<class InputIterator,
|
||||
class Hash = hash<iter_key_t<InputIterator>>,
|
||||
class Pred = equal_to<iter_key_t<InputIterator>>,
|
||||
class Allocator = allocator<iter_to_alloc_t<InputIterator>>>
|
||||
unordered_map(InputIterator, InputIterator, typename see below::size_type =
|
||||
see below,
|
||||
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
|
||||
-> unordered_map<iter_key_t<InputIterator>, iter_val_t<InputIterator>,
|
||||
Hash, Pred,
|
||||
Allocator>;
|
||||
*/
|
||||
|
||||
{
|
||||
boost::unordered_map m(x.begin(), x.end());
|
||||
static_assert(
|
||||
std::is_same<decltype(m), boost::unordered_map<int, int> >::value);
|
||||
}
|
||||
|
||||
/* Ambiguous:
|
||||
{
|
||||
boost::unordered_map m(x.begin(), x.end(), 0, std::hash<int>());
|
||||
static_assert(std::is_same<decltype(m),boost::unordered_map<int, int,
|
||||
std::hash<int>>>::value);
|
||||
}
|
||||
|
||||
{
|
||||
boost::unordered_map m(x.begin(), x.end(), 0, std::hash<int>(),
|
||||
std::equal_to<int>());
|
||||
static_assert(std::is_same<decltype(m),boost::unordered_map<int, int,
|
||||
std::hash<int>, std::equal_to<int>>>::value);
|
||||
}
|
||||
*/
|
||||
|
||||
{
|
||||
boost::unordered_map m(x.begin(), x.end(), 0, std::hash<int>(),
|
||||
std::equal_to<int>(), pair_allocator);
|
||||
static_assert(std::is_same<decltype(m),
|
||||
boost::unordered_map<int, int, std::hash<int>, std::equal_to<int>,
|
||||
test_allocator<std::pair<const int, int> > > >::value);
|
||||
}
|
||||
|
||||
/*
|
||||
template<class Key, class T, class Hash = hash<Key>,
|
||||
class Pred = equal_to<Key>, class Allocator = allocator<pair<const
|
||||
Key, T>>>
|
||||
unordered_map(initializer_list<pair<const Key, T>>,
|
||||
typename see below::size_type = see below, Hash = Hash(),
|
||||
Pred = Pred(), Allocator = Allocator())
|
||||
-> unordered_map<Key, T, Hash, Pred, Allocator>;
|
||||
*/
|
||||
|
||||
{
|
||||
boost::unordered_map m({std::pair<int const, int>(1, 2)});
|
||||
static_assert(
|
||||
std::is_same<decltype(m), boost::unordered_map<int, int> >::value);
|
||||
}
|
||||
|
||||
/* Ambiguous
|
||||
{
|
||||
boost::unordered_map m({std::pair<int const, int>(1,2)}, 0,
|
||||
std::hash<int>());
|
||||
static_assert(std::is_same<decltype(m),boost::unordered_map<int, int,
|
||||
std::hash<int>>>::value);
|
||||
}
|
||||
|
||||
{
|
||||
boost::unordered_map m({std::pair<int const, int>(1,2)}, 0,
|
||||
std::hash<int>(), std::equal_to<int>());
|
||||
static_assert(std::is_same<decltype(m),boost::unordered_map<int, int,
|
||||
std::hash<int>, std::equal_to<int>>>::value);
|
||||
}
|
||||
*/
|
||||
|
||||
{
|
||||
boost::unordered_map m(
|
||||
{std::pair<int const, int>(1, 2)}, 0, f, f, pair_allocator);
|
||||
static_assert(std::is_same<decltype(m),
|
||||
boost::unordered_map<int, int, hash_equals, hash_equals,
|
||||
test_allocator<std::pair<const int, int> > > >::value);
|
||||
}
|
||||
|
||||
/*
|
||||
template<class InputIterator, class Allocator>
|
||||
unordered_map(InputIterator, InputIterator, typename see below::size_type,
|
||||
Allocator)
|
||||
-> unordered_map<iter_key_t<InputIterator>, iter_val_t<InputIterator>,
|
||||
hash<iter_key_t<InputIterator>>,
|
||||
equal_to<iter_key_t<InputIterator>>,
|
||||
Allocator>;
|
||||
*/
|
||||
|
||||
/* Ambiguous
|
||||
{
|
||||
boost::unordered_map m(x.begin(), x.end(), 0u, pair_allocator);
|
||||
static_assert(std::is_same<decltype(m), boost::unordered_map<int, int,
|
||||
boost::hash<int>, std::equal_to<int>, test_allocator<std::pair<const int,
|
||||
int>>>>::value);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
template<class InputIterator, class Allocator>
|
||||
unordered_map(InputIterator, InputIterator, Allocator)
|
||||
-> unordered_map<iter_key_t<InputIterator>, iter_val_t<InputIterator>,
|
||||
hash<iter_key_t<InputIterator>>,
|
||||
equal_to<iter_key_t<InputIterator>>,
|
||||
Allocator>;
|
||||
*/
|
||||
|
||||
/* No constructor:
|
||||
{
|
||||
boost::unordered_map m(x.begin(), x.end(), pair_allocator);
|
||||
static_assert(std::is_same<decltype(m), boost::unordered_map<int, int,
|
||||
boost::hash<int>, std::equal_to<int>, test_allocator<std::pair<const int,
|
||||
int>>>>::value);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
template<class InputIterator, class Hash, class Allocator>
|
||||
unordered_map(InputIterator, InputIterator, typename see below::size_type,
|
||||
Hash, Allocator)
|
||||
-> unordered_map<iter_key_t<InputIterator>, iter_val_t<InputIterator>,
|
||||
Hash,
|
||||
equal_to<iter_key_t<InputIterator>>, Allocator>;
|
||||
*/
|
||||
|
||||
/* Ambiguous
|
||||
{
|
||||
boost::unordered_map m(x.begin(), x.end(), 0u, f, pair_allocator);
|
||||
static_assert(std::is_same<decltype(m), boost::unordered_map<int, int,
|
||||
hash_equals, std::equal_to<int>, test_allocator<std::pair<const int,
|
||||
int>>>>::value);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
template<class Key, class T, typename Allocator>
|
||||
unordered_map(initializer_list<pair<const Key, T>>, typename see
|
||||
below::size_type,
|
||||
Allocator)
|
||||
-> unordered_map<Key, T, hash<Key>, equal_to<Key>, Allocator>;
|
||||
*/
|
||||
|
||||
/* Ambiguous
|
||||
{
|
||||
boost::unordered_map m({std::pair<int const, int>(1,2)}, 0, pair_allocator);
|
||||
static_assert(std::is_same<decltype(m),boost::unordered_map<int, int,
|
||||
boost::hash<int>, std::equal_to<int>, test_allocator<std::pair<const int,
|
||||
int>>>>::value);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
template<class Key, class T, typename Allocator>
|
||||
unordered_map(initializer_list<pair<const Key, T>>, Allocator)
|
||||
-> unordered_map<Key, T, hash<Key>, equal_to<Key>, Allocator>;
|
||||
*/
|
||||
|
||||
{
|
||||
boost::unordered_map m({std::pair<int const, int>(1, 2)}, pair_allocator);
|
||||
static_assert(std::is_same<decltype(m),
|
||||
boost::unordered_map<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test_allocator<std::pair<const int, int> > > >::value);
|
||||
}
|
||||
|
||||
/*
|
||||
template<class Key, class T, class Hash, class Allocator>
|
||||
unordered_map(initializer_list<pair<const Key, T>>, typename see
|
||||
below::size_type, Hash,
|
||||
Allocator)
|
||||
-> unordered_map<Key, T, Hash, equal_to<Key>, Allocator>;
|
||||
*/
|
||||
|
||||
/* Ambiguous
|
||||
{
|
||||
boost::unordered_map m({std::pair<int const, int>(1,2)}, 0, f,
|
||||
pair_allocator);
|
||||
static_assert(std::is_same<decltype(m),boost::unordered_map<int, int,
|
||||
boost::hash<int>, std::equal_to<int>, test_allocator<std::pair<const int,
|
||||
int>>>>::value);
|
||||
}
|
||||
*/
|
||||
|
||||
// unordered_multimap
|
||||
|
||||
{
|
||||
boost::unordered_multimap m(x.begin(), x.end());
|
||||
static_assert(
|
||||
std::is_same<decltype(m), boost::unordered_multimap<int, int> >::value);
|
||||
}
|
||||
|
||||
/* Ambiguous:
|
||||
{
|
||||
boost::unordered_multimap m(x.begin(), x.end(), 0, std::hash<int>());
|
||||
static_assert(std::is_same<decltype(m),boost::unordered_multimap<int, int,
|
||||
std::hash<int>>>::value);
|
||||
}
|
||||
|
||||
{
|
||||
boost::unordered_multimap m(x.begin(), x.end(), 0, std::hash<int>(),
|
||||
std::equal_to<int>());
|
||||
static_assert(std::is_same<decltype(m),boost::unordered_multimap<int, int,
|
||||
std::hash<int>, std::equal_to<int>>>::value);
|
||||
}
|
||||
*/
|
||||
|
||||
{
|
||||
boost::unordered_multimap m(x.begin(), x.end(), 0, std::hash<int>(),
|
||||
std::equal_to<int>(), pair_allocator);
|
||||
static_assert(std::is_same<decltype(m),
|
||||
boost::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>,
|
||||
test_allocator<std::pair<const int, int> > > >::value);
|
||||
}
|
||||
|
||||
{
|
||||
boost::unordered_multimap m({std::pair<int const, int>(1, 2)});
|
||||
static_assert(
|
||||
std::is_same<decltype(m), boost::unordered_multimap<int, int> >::value);
|
||||
}
|
||||
|
||||
/* Ambiguous
|
||||
{
|
||||
boost::unordered_multimap m({std::pair<int const, int>(1,2)}, 0,
|
||||
std::hash<int>());
|
||||
static_assert(std::is_same<decltype(m),boost::unordered_multimap<int, int,
|
||||
std::hash<int>>>::value);
|
||||
}
|
||||
|
||||
{
|
||||
boost::unordered_multimap m({std::pair<int const, int>(1,2)}, 0,
|
||||
std::hash<int>(), std::equal_to<int>());
|
||||
static_assert(std::is_same<decltype(m),boost::unordered_multimap<int, int,
|
||||
std::hash<int>, std::equal_to<int>>>::value);
|
||||
}
|
||||
*/
|
||||
|
||||
{
|
||||
boost::unordered_multimap m(
|
||||
{std::pair<int const, int>(1, 2)}, 0, f, f, pair_allocator);
|
||||
static_assert(std::is_same<decltype(m),
|
||||
boost::unordered_multimap<int, int, hash_equals, hash_equals,
|
||||
test_allocator<std::pair<const int, int> > > >::value);
|
||||
}
|
||||
|
||||
/* Ambiguous
|
||||
{
|
||||
boost::unordered_multimap m(x.begin(), x.end(), 0u, pair_allocator);
|
||||
static_assert(std::is_same<decltype(m), boost::unordered_multimap<int, int,
|
||||
boost::hash<int>, std::equal_to<int>, test_allocator<std::pair<const int,
|
||||
int>>>>::value);
|
||||
}
|
||||
*/
|
||||
|
||||
/* No constructor:
|
||||
{
|
||||
boost::unordered_multimap m(x.begin(), x.end(), pair_allocator);
|
||||
static_assert(std::is_same<decltype(m), boost::unordered_multimap<int, int,
|
||||
boost::hash<int>, std::equal_to<int>, test_allocator<std::pair<const int,
|
||||
int>>>>::value);
|
||||
}
|
||||
*/
|
||||
|
||||
/* Ambiguous
|
||||
{
|
||||
boost::unordered_multimap m(x.begin(), x.end(), 0u, f, pair_allocator);
|
||||
static_assert(std::is_same<decltype(m), boost::unordered_multimap<int, int,
|
||||
hash_equals, std::equal_to<int>, test_allocator<std::pair<const int,
|
||||
int>>>>::value);
|
||||
}
|
||||
|
||||
{
|
||||
boost::unordered_multimap m({std::pair<int const, int>(1,2)}, 0,
|
||||
pair_allocator);
|
||||
static_assert(std::is_same<decltype(m),boost::unordered_multimap<int, int,
|
||||
boost::hash<int>, std::equal_to<int>, test_allocator<std::pair<const int,
|
||||
int>>>>::value);
|
||||
}
|
||||
*/
|
||||
|
||||
{
|
||||
boost::unordered_multimap m(
|
||||
{std::pair<int const, int>(1, 2)}, pair_allocator);
|
||||
static_assert(std::is_same<decltype(m),
|
||||
boost::unordered_multimap<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test_allocator<std::pair<const int, int> > > >::value);
|
||||
}
|
||||
|
||||
/* Ambiguous
|
||||
{
|
||||
boost::unordered_multimap m({std::pair<int const, int>(1,2)}, 0, f,
|
||||
pair_allocator);
|
||||
static_assert(std::is_same<decltype(m),boost::unordered_multimap<int, int,
|
||||
boost::hash<int>, std::equal_to<int>, test_allocator<std::pair<const int,
|
||||
int>>>>::value);
|
||||
}
|
||||
*/
|
||||
|
||||
#endif
|
||||
}
|
101
test/unordered/detail_tests.cpp
Normal file
101
test/unordered/detail_tests.cpp
Normal file
@ -0,0 +1,101 @@
|
||||
|
||||
// Copyright 2017 Daniel James.
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include <map>
|
||||
|
||||
// Pretty inefficient, but the test is fast enough.
|
||||
// Might be too slow if we had larger primes?
|
||||
bool is_prime(std::size_t x)
|
||||
{
|
||||
if (x == 2) {
|
||||
return true;
|
||||
} else if (x == 1 || x % 2 == 0) {
|
||||
return false;
|
||||
} else {
|
||||
// y*y <= x had rounding errors, so instead use y <= (x/y).
|
||||
for (std::size_t y = 3; y <= (x / y); y += 2) {
|
||||
if (x % y == 0) {
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void test_next_prime(std::size_t value)
|
||||
{
|
||||
std::size_t x = boost::unordered::detail::next_prime(value);
|
||||
BOOST_TEST(is_prime(x));
|
||||
BOOST_TEST(x >= value);
|
||||
}
|
||||
|
||||
void test_prev_prime(std::size_t value)
|
||||
{
|
||||
std::size_t x = boost::unordered::detail::prev_prime(value);
|
||||
BOOST_TEST(is_prime(x));
|
||||
BOOST_TEST(x <= value);
|
||||
if (x > value) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << x << "," << value << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (next_prime_test) {
|
||||
BOOST_TEST(!is_prime(0));
|
||||
BOOST_TEST(!is_prime(1));
|
||||
BOOST_TEST(is_prime(2));
|
||||
BOOST_TEST(is_prime(3));
|
||||
BOOST_TEST(is_prime(13));
|
||||
BOOST_TEST(!is_prime(4));
|
||||
BOOST_TEST(!is_prime(100));
|
||||
|
||||
BOOST_TEST(boost::unordered::detail::next_prime(0) > 0);
|
||||
|
||||
// test_prev_prime doesn't work for values less than 17.
|
||||
// Which should be okay, unless an allocator has a really tiny
|
||||
// max_size?
|
||||
const std::size_t min_prime = 17;
|
||||
|
||||
// test_next_prime doesn't work for values greater than this,
|
||||
// which might be a problem if you've got terrabytes of memory?
|
||||
// I seriously doubt the container would work well at such sizes
|
||||
// regardless.
|
||||
const std::size_t max_prime = 4294967291ul;
|
||||
|
||||
std::size_t i;
|
||||
|
||||
BOOST_TEST(is_prime(min_prime));
|
||||
BOOST_TEST(is_prime(max_prime));
|
||||
|
||||
for (i = 0; i < 10000; ++i) {
|
||||
if (i < min_prime) {
|
||||
BOOST_TEST(boost::unordered::detail::prev_prime(i) == min_prime);
|
||||
} else {
|
||||
test_prev_prime(i);
|
||||
}
|
||||
test_next_prime(i);
|
||||
}
|
||||
|
||||
std::size_t last = i - 1;
|
||||
for (; i > last; last = i, i += i / 5) {
|
||||
if (i > max_prime) {
|
||||
BOOST_TEST(boost::unordered::detail::next_prime(i) == max_prime);
|
||||
} else {
|
||||
test_next_prime(i);
|
||||
}
|
||||
test_prev_prime(i);
|
||||
}
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
514
test/unordered/emplace_tests.cpp
Normal file
514
test/unordered/emplace_tests.cpp
Normal file
@ -0,0 +1,514 @@
|
||||
//
|
||||
// Copyright 2016 Daniel James.
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include <boost/functional/hash/hash.hpp>
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../helpers/count.hpp"
|
||||
#include <string>
|
||||
|
||||
// Test that various emplace methods work with different numbers of
|
||||
// arguments.
|
||||
|
||||
namespace emplace_tests {
|
||||
// Constructible with 2 to 10 arguments
|
||||
struct emplace_value : private test::counted_object
|
||||
{
|
||||
typedef int A0;
|
||||
typedef std::string A1;
|
||||
typedef char A2;
|
||||
typedef int A3;
|
||||
typedef int A4;
|
||||
typedef int A5;
|
||||
typedef int A6;
|
||||
typedef int A7;
|
||||
typedef int A8;
|
||||
typedef int A9;
|
||||
|
||||
int arg_count;
|
||||
|
||||
A0 a0;
|
||||
A1 a1;
|
||||
A2 a2;
|
||||
A3 a3;
|
||||
A4 a4;
|
||||
A5 a5;
|
||||
A6 a6;
|
||||
A7 a7;
|
||||
A8 a8;
|
||||
A9 a9;
|
||||
|
||||
emplace_value(A0 const& b0, A1 const& b1) : arg_count(2), a0(b0), a1(b1) {}
|
||||
|
||||
emplace_value(A0 const& b0, A1 const& b1, A2 const& b2)
|
||||
: arg_count(3), a0(b0), a1(b1), a2(b2)
|
||||
{
|
||||
}
|
||||
|
||||
emplace_value(A0 const& b0, A1 const& b1, A2 const& b2, A3 const& b3)
|
||||
: arg_count(4), a0(b0), a1(b1), a2(b2), a3(b3)
|
||||
{
|
||||
}
|
||||
|
||||
emplace_value(
|
||||
A0 const& b0, A1 const& b1, A2 const& b2, A3 const& b3, A4 const& b4)
|
||||
: arg_count(5), a0(b0), a1(b1), a2(b2), a3(b3), a4(b4)
|
||||
{
|
||||
}
|
||||
|
||||
emplace_value(A0 const& b0, A1 const& b1, A2 const& b2, A3 const& b3,
|
||||
A4 const& b4, A5 const& b5)
|
||||
: arg_count(6), a0(b0), a1(b1), a2(b2), a3(b3), a4(b4), a5(b5)
|
||||
{
|
||||
}
|
||||
|
||||
emplace_value(A0 const& b0, A1 const& b1, A2 const& b2, A3 const& b3,
|
||||
A4 const& b4, A5 const& b5, A6 const& b6)
|
||||
: arg_count(7), a0(b0), a1(b1), a2(b2), a3(b3), a4(b4), a5(b5), a6(b6)
|
||||
{
|
||||
}
|
||||
|
||||
emplace_value(A0 const& b0, A1 const& b1, A2 const& b2, A3 const& b3,
|
||||
A4 const& b4, A5 const& b5, A6 const& b6, A7 const& b7)
|
||||
: arg_count(8), a0(b0), a1(b1), a2(b2), a3(b3), a4(b4), a5(b5), a6(b6),
|
||||
a7(b7)
|
||||
{
|
||||
}
|
||||
|
||||
emplace_value(A0 const& b0, A1 const& b1, A2 const& b2, A3 const& b3,
|
||||
A4 const& b4, A5 const& b5, A6 const& b6, A7 const& b7, A8 const& b8)
|
||||
: arg_count(9), a0(b0), a1(b1), a2(b2), a3(b3), a4(b4), a5(b5), a6(b6),
|
||||
a7(b7), a8(b8)
|
||||
{
|
||||
}
|
||||
|
||||
emplace_value(A0 const& b0, A1 const& b1, A2 const& b2, A3 const& b3,
|
||||
A4 const& b4, A5 const& b5, A6 const& b6, A7 const& b7, A8 const& b8,
|
||||
A9 const& b9)
|
||||
: arg_count(10), a0(b0), a1(b1), a2(b2), a3(b3), a4(b4), a5(b5), a6(b6),
|
||||
a7(b7), a8(b8), a9(b9)
|
||||
{
|
||||
}
|
||||
|
||||
friend std::size_t hash_value(emplace_value const& x)
|
||||
{
|
||||
std::size_t r1 = 23894278u;
|
||||
if (x.arg_count >= 1)
|
||||
boost::hash_combine(r1, x.a0);
|
||||
if (x.arg_count >= 2)
|
||||
boost::hash_combine(r1, x.a1);
|
||||
if (x.arg_count >= 3)
|
||||
boost::hash_combine(r1, x.a2);
|
||||
if (x.arg_count >= 4)
|
||||
boost::hash_combine(r1, x.a3);
|
||||
if (x.arg_count >= 5)
|
||||
boost::hash_combine(r1, x.a4);
|
||||
if (x.arg_count >= 6)
|
||||
boost::hash_combine(r1, x.a5);
|
||||
if (x.arg_count >= 7)
|
||||
boost::hash_combine(r1, x.a6);
|
||||
if (x.arg_count >= 8)
|
||||
boost::hash_combine(r1, x.a7);
|
||||
if (x.arg_count >= 9)
|
||||
boost::hash_combine(r1, x.a8);
|
||||
if (x.arg_count >= 10)
|
||||
boost::hash_combine(r1, x.a9);
|
||||
return r1;
|
||||
}
|
||||
|
||||
friend bool operator==(emplace_value const& x, emplace_value const& y)
|
||||
{
|
||||
if (x.arg_count != y.arg_count) {
|
||||
return false;
|
||||
}
|
||||
if (x.arg_count >= 1 && x.a0 != y.a0) {
|
||||
return false;
|
||||
}
|
||||
if (x.arg_count >= 2 && x.a1 != y.a1) {
|
||||
return false;
|
||||
}
|
||||
if (x.arg_count >= 3 && x.a2 != y.a2) {
|
||||
return false;
|
||||
}
|
||||
if (x.arg_count >= 4 && x.a3 != y.a3) {
|
||||
return false;
|
||||
}
|
||||
if (x.arg_count >= 5 && x.a4 != y.a4) {
|
||||
return false;
|
||||
}
|
||||
if (x.arg_count >= 6 && x.a5 != y.a5) {
|
||||
return false;
|
||||
}
|
||||
if (x.arg_count >= 7 && x.a6 != y.a6) {
|
||||
return false;
|
||||
}
|
||||
if (x.arg_count >= 8 && x.a7 != y.a7) {
|
||||
return false;
|
||||
}
|
||||
if (x.arg_count >= 9 && x.a8 != y.a8) {
|
||||
return false;
|
||||
}
|
||||
if (x.arg_count >= 10 && x.a9 != y.a9) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
emplace_value();
|
||||
emplace_value(emplace_value const&);
|
||||
};
|
||||
|
||||
UNORDERED_AUTO_TEST (emplace_set) {
|
||||
test::check_instances check_;
|
||||
|
||||
typedef boost::unordered_set<emplace_value, boost::hash<emplace_value> >
|
||||
container;
|
||||
typedef container::iterator iterator;
|
||||
typedef std::pair<iterator, bool> return_type;
|
||||
container x(10);
|
||||
iterator i1;
|
||||
return_type r1, r2;
|
||||
|
||||
// 2 args
|
||||
|
||||
emplace_value v1(10, "x");
|
||||
r1 = x.emplace(10, std::string("x"));
|
||||
BOOST_TEST_EQ(x.size(), 1u);
|
||||
BOOST_TEST(r1.second);
|
||||
BOOST_TEST(*r1.first == v1);
|
||||
BOOST_TEST(r1.first == x.find(v1));
|
||||
BOOST_TEST_EQ(check_.instances(), 2);
|
||||
BOOST_TEST_EQ(check_.constructions(), 2);
|
||||
|
||||
// 3 args
|
||||
|
||||
emplace_value v2(3, "foo", 'a');
|
||||
r1 = x.emplace(3, "foo", 'a');
|
||||
BOOST_TEST_EQ(x.size(), 2u);
|
||||
BOOST_TEST(r1.second);
|
||||
BOOST_TEST(*r1.first == v2);
|
||||
BOOST_TEST(r1.first == x.find(v2));
|
||||
BOOST_TEST_EQ(check_.instances(), 4);
|
||||
BOOST_TEST_EQ(check_.constructions(), 4);
|
||||
|
||||
// 7 args with hint + duplicate
|
||||
|
||||
emplace_value v3(25, "something", 'z', 4, 5, 6, 7);
|
||||
i1 = x.emplace_hint(r1.first, 25, "something", 'z', 4, 5, 6, 7);
|
||||
BOOST_TEST_EQ(x.size(), 3u);
|
||||
BOOST_TEST(*i1 == v3);
|
||||
BOOST_TEST(i1 == x.find(v3));
|
||||
BOOST_TEST_EQ(check_.instances(), 6);
|
||||
BOOST_TEST_EQ(check_.constructions(), 6);
|
||||
|
||||
r2 = x.emplace(25, "something", 'z', 4, 5, 6, 7);
|
||||
BOOST_TEST_EQ(x.size(), 3u);
|
||||
BOOST_TEST(!r2.second);
|
||||
BOOST_TEST(i1 == r2.first);
|
||||
// The container has to construct an object in order to check
|
||||
// whether it can emplace, so there's an extra cosntruction
|
||||
// here.
|
||||
BOOST_TEST_EQ(check_.instances(), 6);
|
||||
BOOST_TEST_EQ(check_.constructions(), 7);
|
||||
|
||||
// 10 args + hint duplicate
|
||||
|
||||
std::string s1;
|
||||
emplace_value v4(10, s1, 'a', 4, 5, 6, 7, 8, 9, 10);
|
||||
r1 = x.emplace(10, s1, 'a', 4, 5, 6, 7, 8, 9, 10);
|
||||
BOOST_TEST_EQ(x.size(), 4u);
|
||||
BOOST_TEST(r1.second);
|
||||
BOOST_TEST(*r1.first == v4);
|
||||
BOOST_TEST(r1.first == x.find(v4));
|
||||
BOOST_TEST_EQ(check_.instances(), 8);
|
||||
BOOST_TEST_EQ(check_.constructions(), 9);
|
||||
|
||||
BOOST_TEST(
|
||||
r1.first == x.emplace_hint(r1.first, 10, "", 'a', 4, 5, 6, 7, 8, 9, 10));
|
||||
BOOST_TEST(
|
||||
r1.first == x.emplace_hint(r2.first, 10, "", 'a', 4, 5, 6, 7, 8, 9, 10));
|
||||
BOOST_TEST(
|
||||
r1.first == x.emplace_hint(x.end(), 10, "", 'a', 4, 5, 6, 7, 8, 9, 10));
|
||||
BOOST_TEST_EQ(check_.instances(), 8);
|
||||
BOOST_TEST_EQ(check_.constructions(), 12);
|
||||
|
||||
BOOST_TEST_EQ(x.size(), 4u);
|
||||
BOOST_TEST(x.count(v1) == 1);
|
||||
BOOST_TEST(x.count(v2) == 1);
|
||||
BOOST_TEST(x.count(v3) == 1);
|
||||
BOOST_TEST(x.count(v4) == 1);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (emplace_multiset) {
|
||||
test::check_instances check_;
|
||||
|
||||
typedef boost::unordered_multiset<emplace_value,
|
||||
boost::hash<emplace_value> >
|
||||
container;
|
||||
typedef container::iterator iterator;
|
||||
container x(10);
|
||||
iterator i1, i2;
|
||||
|
||||
// 2 args.
|
||||
|
||||
emplace_value v1(10, "x");
|
||||
i1 = x.emplace(10, std::string("x"));
|
||||
BOOST_TEST_EQ(x.size(), 1u);
|
||||
BOOST_TEST(i1 == x.find(v1));
|
||||
BOOST_TEST_EQ(check_.instances(), 2);
|
||||
BOOST_TEST_EQ(check_.constructions(), 2);
|
||||
|
||||
// 4 args + duplicate
|
||||
|
||||
emplace_value v2(4, "foo", 'a', 15);
|
||||
i1 = x.emplace(4, "foo", 'a', 15);
|
||||
BOOST_TEST_EQ(x.size(), 2u);
|
||||
BOOST_TEST(i1 == x.find(v2));
|
||||
BOOST_TEST_EQ(check_.instances(), 4);
|
||||
BOOST_TEST_EQ(check_.constructions(), 4);
|
||||
|
||||
i2 = x.emplace(4, "foo", 'a', 15);
|
||||
BOOST_TEST_EQ(x.size(), 3u);
|
||||
BOOST_TEST(i1 != i2);
|
||||
BOOST_TEST(*i1 == *i2);
|
||||
BOOST_TEST(x.count(*i1) == 2);
|
||||
BOOST_TEST_EQ(check_.instances(), 5);
|
||||
BOOST_TEST_EQ(check_.constructions(), 5);
|
||||
|
||||
// 7 args + duplicate using hint.
|
||||
|
||||
emplace_value v3(7, "", 'z', 4, 5, 6, 7);
|
||||
i1 = x.emplace(7, "", 'z', 4, 5, 6, 7);
|
||||
BOOST_TEST_EQ(x.size(), 4u);
|
||||
BOOST_TEST_EQ(i1->a2, 'z');
|
||||
BOOST_TEST(x.count(*i1) == 1);
|
||||
BOOST_TEST(i1 == x.find(v3));
|
||||
BOOST_TEST_EQ(check_.instances(), 7);
|
||||
BOOST_TEST_EQ(check_.constructions(), 7);
|
||||
|
||||
i2 = x.emplace_hint(i1, 7, "", 'z', 4, 5, 6, 7);
|
||||
BOOST_TEST_EQ(x.size(), 5u);
|
||||
BOOST_TEST(*i1 == *i2);
|
||||
BOOST_TEST(i1 != i2);
|
||||
BOOST_TEST(x.count(*i1) == 2);
|
||||
BOOST_TEST_EQ(check_.instances(), 8);
|
||||
BOOST_TEST_EQ(check_.constructions(), 8);
|
||||
|
||||
// 10 args with bad hint + duplicate
|
||||
|
||||
emplace_value v4(10, "", 'a', 4, 5, 6, 7, 8, 9, 10);
|
||||
i1 = x.emplace_hint(i2, 10, "", 'a', 4, 5, 6, 7, 8, 9, 10);
|
||||
BOOST_TEST_EQ(x.size(), 6u);
|
||||
BOOST_TEST_EQ(i1->arg_count, 10);
|
||||
BOOST_TEST(i1 == x.find(v4));
|
||||
BOOST_TEST_EQ(check_.instances(), 10);
|
||||
BOOST_TEST_EQ(check_.constructions(), 10);
|
||||
|
||||
i2 = x.emplace_hint(x.end(), 10, "", 'a', 4, 5, 6, 7, 8, 9, 10);
|
||||
BOOST_TEST_EQ(x.size(), 7u);
|
||||
BOOST_TEST(*i1 == *i2);
|
||||
BOOST_TEST(i1 != i2);
|
||||
BOOST_TEST(x.count(*i1) == 2);
|
||||
BOOST_TEST_EQ(check_.instances(), 11);
|
||||
BOOST_TEST_EQ(check_.constructions(), 11);
|
||||
|
||||
BOOST_TEST_EQ(x.count(v1), 1u);
|
||||
BOOST_TEST_EQ(x.count(v2), 2u);
|
||||
BOOST_TEST_EQ(x.count(v3), 2u);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (emplace_map) {
|
||||
test::check_instances check_;
|
||||
|
||||
typedef boost::unordered_map<emplace_value, emplace_value,
|
||||
boost::hash<emplace_value> >
|
||||
container;
|
||||
typedef container::iterator iterator;
|
||||
typedef std::pair<iterator, bool> return_type;
|
||||
container x(10);
|
||||
return_type r1, r2;
|
||||
|
||||
// 5/8 args + duplicate
|
||||
|
||||
emplace_value k1(5, "", 'b', 4, 5);
|
||||
emplace_value m1(8, "xxx", 'z', 4, 5, 6, 7, 8);
|
||||
r1 = x.emplace(boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(5, "", 'b', 4, 5),
|
||||
boost::make_tuple(8, "xxx", 'z', 4, 5, 6, 7, 8));
|
||||
BOOST_TEST_EQ(x.size(), 1u);
|
||||
BOOST_TEST(r1.second);
|
||||
BOOST_TEST(x.find(k1) == r1.first);
|
||||
BOOST_TEST(x.find(k1)->second == m1);
|
||||
BOOST_TEST_EQ(check_.instances(), 4);
|
||||
BOOST_TEST_EQ(check_.constructions(), 4);
|
||||
|
||||
r2 = x.emplace(boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(5, "", 'b', 4, 5),
|
||||
boost::make_tuple(8, "xxx", 'z', 4, 5, 6, 7, 8));
|
||||
BOOST_TEST_EQ(x.size(), 1u);
|
||||
BOOST_TEST(!r2.second);
|
||||
BOOST_TEST(r1.first == r2.first);
|
||||
BOOST_TEST(x.find(k1)->second == m1);
|
||||
BOOST_TEST_EQ(check_.instances(), 4);
|
||||
// constructions could possibly be 5 if the implementation only
|
||||
// constructed the key.
|
||||
BOOST_TEST_EQ(check_.constructions(), 6);
|
||||
|
||||
// 9/3 args + duplicates with hints, different mapped value.
|
||||
|
||||
emplace_value k2(9, "", 'b', 4, 5, 6, 7, 8, 9);
|
||||
emplace_value m2(3, "aaa", 'm');
|
||||
r1 = x.emplace(boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
|
||||
boost::make_tuple(3, "aaa", 'm'));
|
||||
BOOST_TEST_EQ(x.size(), 2u);
|
||||
BOOST_TEST(r1.second);
|
||||
BOOST_TEST(r1.first->first.arg_count == 9);
|
||||
BOOST_TEST(r1.first->second.arg_count == 3);
|
||||
BOOST_TEST(x.find(k2) == r1.first);
|
||||
BOOST_TEST(x.find(k2)->second == m2);
|
||||
BOOST_TEST_EQ(check_.instances(), 8);
|
||||
BOOST_TEST_EQ(check_.constructions(), 10);
|
||||
|
||||
BOOST_TEST(r1.first ==
|
||||
x.emplace_hint(r1.first, boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
|
||||
boost::make_tuple(15, "jkjk")));
|
||||
BOOST_TEST(r1.first ==
|
||||
x.emplace_hint(r2.first, boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
|
||||
boost::make_tuple(275, "xxx", 'm', 6)));
|
||||
BOOST_TEST(r1.first ==
|
||||
x.emplace_hint(x.end(), boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
|
||||
boost::make_tuple(-10, "blah blah", '\0')));
|
||||
BOOST_TEST_EQ(x.size(), 2u);
|
||||
BOOST_TEST(x.find(k2)->second == m2);
|
||||
BOOST_TEST_EQ(check_.instances(), 8);
|
||||
BOOST_TEST_EQ(check_.constructions(), 16);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (emplace_multimap) {
|
||||
test::check_instances check_;
|
||||
|
||||
typedef boost::unordered_multimap<emplace_value, emplace_value,
|
||||
boost::hash<emplace_value> >
|
||||
container;
|
||||
typedef container::iterator iterator;
|
||||
container x(10);
|
||||
iterator i1, i2, i3, i4;
|
||||
|
||||
// 5/8 args + duplicate
|
||||
|
||||
emplace_value k1(5, "", 'b', 4, 5);
|
||||
emplace_value m1(8, "xxx", 'z', 4, 5, 6, 7, 8);
|
||||
i1 = x.emplace(boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(5, "", 'b', 4, 5),
|
||||
boost::make_tuple(8, "xxx", 'z', 4, 5, 6, 7, 8));
|
||||
BOOST_TEST_EQ(x.size(), 1u);
|
||||
BOOST_TEST(x.find(k1) == i1);
|
||||
BOOST_TEST(x.find(k1)->second == m1);
|
||||
BOOST_TEST_EQ(check_.instances(), 4);
|
||||
BOOST_TEST_EQ(check_.constructions(), 4);
|
||||
|
||||
emplace_value m1a(8, "xxx", 'z', 4, 5, 6, 7, 8);
|
||||
i2 = x.emplace(boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(5, "", 'b', 4, 5),
|
||||
boost::make_tuple(8, "xxx", 'z', 4, 5, 6, 7, 8));
|
||||
BOOST_TEST_EQ(x.size(), 2u);
|
||||
BOOST_TEST(i1 != i2);
|
||||
BOOST_TEST(i1->second == m1);
|
||||
BOOST_TEST(i2->second == m1a);
|
||||
BOOST_TEST_EQ(check_.instances(), 7);
|
||||
BOOST_TEST_EQ(check_.constructions(), 7);
|
||||
|
||||
// 9/3 args + duplicates with hints, different mapped value.
|
||||
|
||||
emplace_value k2(9, "", 'b', 4, 5, 6, 7, 8, 9);
|
||||
emplace_value m2(3, "aaa", 'm');
|
||||
i1 = x.emplace(boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
|
||||
boost::make_tuple(3, "aaa", 'm'));
|
||||
BOOST_TEST_EQ(x.size(), 3u);
|
||||
BOOST_TEST(i1->first.arg_count == 9);
|
||||
BOOST_TEST(i1->second.arg_count == 3);
|
||||
BOOST_TEST_EQ(check_.instances(), 11);
|
||||
BOOST_TEST_EQ(check_.constructions(), 11);
|
||||
|
||||
emplace_value m2a(15, "jkjk");
|
||||
i2 = x.emplace_hint(i2, boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
|
||||
boost::make_tuple(15, "jkjk"));
|
||||
emplace_value m2b(275, "xxx", 'm', 6);
|
||||
i3 = x.emplace_hint(i1, boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
|
||||
boost::make_tuple(275, "xxx", 'm', 6));
|
||||
emplace_value m2c(-10, "blah blah", '\0');
|
||||
i4 = x.emplace_hint(x.end(), boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
|
||||
boost::make_tuple(-10, "blah blah", '\0'));
|
||||
BOOST_TEST_EQ(x.size(), 6u);
|
||||
BOOST_TEST(x.find(k2)->second == m2);
|
||||
BOOST_TEST_EQ(check_.instances(), 20);
|
||||
BOOST_TEST_EQ(check_.constructions(), 20);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (try_emplace) {
|
||||
test::check_instances check_;
|
||||
|
||||
typedef boost::unordered_map<int, emplace_value> container;
|
||||
typedef container::iterator iterator;
|
||||
typedef std::pair<iterator, bool> return_type;
|
||||
container x(10);
|
||||
return_type r1, r2, r3;
|
||||
|
||||
int k1 = 3;
|
||||
emplace_value m1(414, "grr");
|
||||
r1 = x.try_emplace(3, 414, "grr");
|
||||
BOOST_TEST(r1.second);
|
||||
BOOST_TEST(r1.first->first == k1);
|
||||
BOOST_TEST(r1.first->second == m1);
|
||||
BOOST_TEST_EQ(x.size(), 1u);
|
||||
BOOST_TEST_EQ(check_.instances(), 2);
|
||||
BOOST_TEST_EQ(check_.constructions(), 2);
|
||||
|
||||
int k2 = 10;
|
||||
emplace_value m2(25, "", 'z');
|
||||
r2 = x.try_emplace(10, 25, std::string(""), 'z');
|
||||
BOOST_TEST(r2.second);
|
||||
BOOST_TEST(r2.first->first == k2);
|
||||
BOOST_TEST(r2.first->second == m2);
|
||||
BOOST_TEST_EQ(x.size(), 2u);
|
||||
BOOST_TEST_EQ(check_.instances(), 4);
|
||||
BOOST_TEST_EQ(check_.constructions(), 4);
|
||||
|
||||
BOOST_TEST(x.find(k1)->second == m1);
|
||||
BOOST_TEST(x.find(k2)->second == m2);
|
||||
|
||||
r3 = x.try_emplace(k2, 68, "jfeoj", 'p', 49309, 2323);
|
||||
BOOST_TEST(!r3.second);
|
||||
BOOST_TEST(r3.first == r2.first);
|
||||
BOOST_TEST(r3.first->second == m2);
|
||||
BOOST_TEST_EQ(x.size(), 2u);
|
||||
BOOST_TEST_EQ(check_.instances(), 4);
|
||||
BOOST_TEST_EQ(check_.constructions(), 4);
|
||||
|
||||
BOOST_TEST(r2.first == x.try_emplace(r2.first, k2, 808709, "what"));
|
||||
BOOST_TEST(
|
||||
r2.first ==
|
||||
x.try_emplace(r2.first, k2, 10, "xxx", 'a', 4, 5, 6, 7, 8, 9, 10));
|
||||
BOOST_TEST(r2.first->second == m2);
|
||||
BOOST_TEST_EQ(x.size(), 2u);
|
||||
}
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
@ -3,179 +3,154 @@
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include <boost/preprocessor/seq.hpp>
|
||||
#include <list>
|
||||
#include "../helpers/test.hpp"
|
||||
|
||||
namespace equality_tests
|
||||
{
|
||||
struct mod_compare
|
||||
namespace equality_tests {
|
||||
struct mod_compare
|
||||
{
|
||||
bool alt_hash_;
|
||||
|
||||
explicit mod_compare(bool alt_hash = false) : alt_hash_(alt_hash) {}
|
||||
|
||||
bool operator()(int x, int y) const { return x % 1000 == y % 1000; }
|
||||
|
||||
std::size_t operator()(int x) const
|
||||
{
|
||||
bool alt_hash_;
|
||||
|
||||
explicit mod_compare(bool alt_hash = false) : alt_hash_(alt_hash) {}
|
||||
|
||||
bool operator()(int x, int y) const
|
||||
{
|
||||
return x % 1000 == y % 1000;
|
||||
}
|
||||
|
||||
int operator()(int x) const
|
||||
{
|
||||
return alt_hash_ ? x % 250 : (x + 5) % 250;
|
||||
}
|
||||
};
|
||||
|
||||
#define UNORDERED_EQUALITY_SET_TEST(seq1, op, seq2) \
|
||||
{ \
|
||||
boost::unordered_set<int, mod_compare, mod_compare> set1, set2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \
|
||||
BOOST_TEST(set1 op set2); \
|
||||
return alt_hash_ ? static_cast<std::size_t>(x % 250)
|
||||
: static_cast<std::size_t>((x + 5) % 250);
|
||||
}
|
||||
};
|
||||
|
||||
#define UNORDERED_EQUALITY_MULTISET_TEST(seq1, op, seq2) \
|
||||
{ \
|
||||
boost::unordered_multiset<int, mod_compare, mod_compare> \
|
||||
set1, set2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \
|
||||
BOOST_TEST(set1 op set2); \
|
||||
}
|
||||
#define UNORDERED_EQUALITY_SET_TEST(seq1, op, seq2) \
|
||||
{ \
|
||||
boost::unordered_set<int, mod_compare, mod_compare> set1, set2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \
|
||||
BOOST_TEST(set1 op set2); \
|
||||
}
|
||||
|
||||
#define UNORDERED_EQUALITY_MAP_TEST(seq1, op, seq2) \
|
||||
{ \
|
||||
boost::unordered_map<int, int, mod_compare, mod_compare> \
|
||||
map1, map2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \
|
||||
BOOST_TEST(map1 op map2); \
|
||||
}
|
||||
#define UNORDERED_EQUALITY_MULTISET_TEST(seq1, op, seq2) \
|
||||
{ \
|
||||
boost::unordered_multiset<int, mod_compare, mod_compare> set1, set2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \
|
||||
BOOST_TEST(set1 op set2); \
|
||||
}
|
||||
|
||||
#define UNORDERED_EQUALITY_MULTIMAP_TEST(seq1, op, seq2) \
|
||||
{ \
|
||||
boost::unordered_multimap<int, int, mod_compare, mod_compare> \
|
||||
map1, map2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \
|
||||
BOOST_TEST(map1 op map2); \
|
||||
}
|
||||
#define UNORDERED_EQUALITY_MAP_TEST(seq1, op, seq2) \
|
||||
{ \
|
||||
boost::unordered_map<int, int, mod_compare, mod_compare> map1, map2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \
|
||||
BOOST_TEST(map1 op map2); \
|
||||
}
|
||||
|
||||
#define UNORDERED_EQUALITY_MULTIMAP_TEST(seq1, op, seq2) \
|
||||
{ \
|
||||
boost::unordered_multimap<int, int, mod_compare, mod_compare> map1, map2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \
|
||||
BOOST_TEST(map1 op map2); \
|
||||
}
|
||||
|
||||
#define UNORDERED_SET_INSERT(r, set, item) set.insert(item);
|
||||
#define UNORDERED_MAP_INSERT(r, map, item) \
|
||||
map.insert(std::pair<int const, int> BOOST_PP_SEQ_TO_TUPLE(item));
|
||||
#define UNORDERED_MAP_INSERT(r, map, item) \
|
||||
map.insert(std::pair<int const, int> BOOST_PP_SEQ_TO_TUPLE(item));
|
||||
|
||||
UNORDERED_AUTO_TEST(equality_size_tests)
|
||||
{
|
||||
boost::unordered_set<int> x1, x2;
|
||||
BOOST_TEST(x1 == x2);
|
||||
BOOST_TEST(!(x1 != x2));
|
||||
UNORDERED_AUTO_TEST (equality_size_tests) {
|
||||
boost::unordered_set<int> x1, x2;
|
||||
BOOST_TEST(x1 == x2);
|
||||
BOOST_TEST(!(x1 != x2));
|
||||
|
||||
x1.insert(1);
|
||||
BOOST_TEST(x1 != x2);
|
||||
BOOST_TEST(!(x1 == x2));
|
||||
BOOST_TEST(x2 != x1);
|
||||
BOOST_TEST(!(x2 == x1));
|
||||
|
||||
x2.insert(1);
|
||||
BOOST_TEST(x1 == x2);
|
||||
BOOST_TEST(!(x1 != x2));
|
||||
|
||||
x2.insert(2);
|
||||
BOOST_TEST(x1 != x2);
|
||||
BOOST_TEST(!(x1 == x2));
|
||||
BOOST_TEST(x2 != x1);
|
||||
BOOST_TEST(!(x2 == x1));
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(equality_key_value_tests)
|
||||
{
|
||||
UNORDERED_EQUALITY_MULTISET_TEST((1), !=, (2))
|
||||
UNORDERED_EQUALITY_SET_TEST((2), ==, (2))
|
||||
UNORDERED_EQUALITY_MAP_TEST(((1)(1))((2)(1)), !=, ((1)(1))((3)(1)))
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(equality_collision_test)
|
||||
{
|
||||
UNORDERED_EQUALITY_MULTISET_TEST(
|
||||
(1), !=, (501))
|
||||
UNORDERED_EQUALITY_MULTISET_TEST(
|
||||
(1)(251), !=, (1)(501))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((251)(1))((1)(1)), !=, ((501)(1))((1)(1)))
|
||||
UNORDERED_EQUALITY_MULTISET_TEST(
|
||||
(1)(501), ==, (1)(501))
|
||||
UNORDERED_EQUALITY_SET_TEST(
|
||||
(1)(501), ==, (501)(1))
|
||||
}
|
||||
x1.insert(1);
|
||||
BOOST_TEST(x1 != x2);
|
||||
BOOST_TEST(!(x1 == x2));
|
||||
BOOST_TEST(x2 != x1);
|
||||
BOOST_TEST(!(x2 == x1));
|
||||
|
||||
UNORDERED_AUTO_TEST(equality_group_size_test)
|
||||
{
|
||||
UNORDERED_EQUALITY_MULTISET_TEST(
|
||||
(10)(20)(20), !=, (10)(10)(20))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((10)(1))((20)(1))((20)(1)), !=,
|
||||
((10)(1))((20)(1))((10)(1)))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((20)(1))((10)(1))((10)(1)), ==,
|
||||
((10)(1))((20)(1))((10)(1)))
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(equality_map_value_test)
|
||||
{
|
||||
UNORDERED_EQUALITY_MAP_TEST(
|
||||
((1)(1)), !=, ((1)(2)))
|
||||
UNORDERED_EQUALITY_MAP_TEST(
|
||||
((1)(1)), ==, ((1)(1)))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((1)(1)), !=, ((1)(2)))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((1)(1))((1)(1)), !=, ((1)(1))((1)(2)))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((1)(2))((1)(1)), ==, ((1)(1))((1)(2)))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((1)(2))((1)(1)), !=, ((1)(1))((1)(3)))
|
||||
}
|
||||
x2.insert(1);
|
||||
BOOST_TEST(x1 == x2);
|
||||
BOOST_TEST(!(x1 != x2));
|
||||
|
||||
UNORDERED_AUTO_TEST(equality_predicate_test)
|
||||
{
|
||||
UNORDERED_EQUALITY_SET_TEST(
|
||||
(1), !=, (1001))
|
||||
UNORDERED_EQUALITY_MAP_TEST(
|
||||
((1)(2))((1001)(1)), !=, ((1001)(2))((1)(1)))
|
||||
}
|
||||
x2.insert(2);
|
||||
BOOST_TEST(x1 != x2);
|
||||
BOOST_TEST(!(x1 == x2));
|
||||
BOOST_TEST(x2 != x1);
|
||||
BOOST_TEST(!(x2 == x1));
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(equality_multiple_group_test)
|
||||
{
|
||||
UNORDERED_EQUALITY_MULTISET_TEST(
|
||||
(1)(1)(1)(1001)(2001)(2001)(2)(1002)(3)(1003)(2003), ==,
|
||||
(3)(1003)(2003)(1002)(2)(2001)(2001)(1)(1001)(1)(1)
|
||||
);
|
||||
}
|
||||
UNORDERED_AUTO_TEST (equality_key_value_tests) {
|
||||
UNORDERED_EQUALITY_MULTISET_TEST((1), !=, (2))
|
||||
UNORDERED_EQUALITY_SET_TEST((2), ==, (2))
|
||||
UNORDERED_EQUALITY_MAP_TEST(((1)(1))((2)(1)), !=, ((1)(1))((3)(1)))
|
||||
}
|
||||
|
||||
// Test that equality still works when the two containers have
|
||||
// different hash functions but the same equality predicate.
|
||||
UNORDERED_AUTO_TEST (equality_collision_test) {
|
||||
UNORDERED_EQUALITY_MULTISET_TEST((1), !=, (501))
|
||||
UNORDERED_EQUALITY_MULTISET_TEST((1)(251), !=, (1)(501))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(((251)(1))((1)(1)), !=, ((501)(1))((1)(1)))
|
||||
UNORDERED_EQUALITY_MULTISET_TEST((1)(501), ==, (1)(501))
|
||||
UNORDERED_EQUALITY_SET_TEST((1)(501), ==, (501)(1))
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(equality_different_hash_test)
|
||||
{
|
||||
typedef boost::unordered_set<int, mod_compare, mod_compare> set;
|
||||
set set1(0, mod_compare(false), mod_compare(false));
|
||||
set set2(0, mod_compare(true), mod_compare(true));
|
||||
BOOST_TEST(set1 == set2);
|
||||
set1.insert(1); set2.insert(2);
|
||||
BOOST_TEST(set1 != set2);
|
||||
set1.insert(2); set2.insert(1);
|
||||
BOOST_TEST(set1 == set2);
|
||||
set1.insert(10); set2.insert(20);
|
||||
BOOST_TEST(set1 != set2);
|
||||
set1.insert(20); set2.insert(10);
|
||||
BOOST_TEST(set1 == set2);
|
||||
}
|
||||
UNORDERED_AUTO_TEST (equality_group_size_test) {
|
||||
UNORDERED_EQUALITY_MULTISET_TEST((10)(20)(20), !=, (10)(10)(20))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((10)(1))((20)(1))((20)(1)), !=, ((10)(1))((20)(1))((10)(1)))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||
((20)(1))((10)(1))((10)(1)), ==, ((10)(1))((20)(1))((10)(1)))
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (equality_map_value_test) {
|
||||
UNORDERED_EQUALITY_MAP_TEST(((1)(1)), !=, ((1)(2)))
|
||||
UNORDERED_EQUALITY_MAP_TEST(((1)(1)), ==, ((1)(1)))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(((1)(1)), !=, ((1)(2)))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(((1)(1))((1)(1)), !=, ((1)(1))((1)(2)))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(((1)(2))((1)(1)), ==, ((1)(1))((1)(2)))
|
||||
UNORDERED_EQUALITY_MULTIMAP_TEST(((1)(2))((1)(1)), !=, ((1)(1))((1)(3)))
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (equality_predicate_test) {
|
||||
UNORDERED_EQUALITY_SET_TEST((1), !=, (1001))
|
||||
UNORDERED_EQUALITY_MAP_TEST(((1)(2))((1001)(1)), !=, ((1001)(2))((1)(1)))
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (equality_multiple_group_test) {
|
||||
UNORDERED_EQUALITY_MULTISET_TEST(
|
||||
(1)(1)(1)(1001)(2001)(2001)(2)(1002)(3)(1003)(2003), ==,
|
||||
(3)(1003)(2003)(1002)(2)(2001)(2001)(1)(1001)(1)(1))
|
||||
}
|
||||
|
||||
// Test that equality still works when the two containers have
|
||||
// different hash functions but the same equality predicate.
|
||||
|
||||
UNORDERED_AUTO_TEST (equality_different_hash_test) {
|
||||
typedef boost::unordered_set<int, mod_compare, mod_compare> set;
|
||||
set set1(0, mod_compare(false), mod_compare(false));
|
||||
set set2(0, mod_compare(true), mod_compare(true));
|
||||
BOOST_TEST(set1 == set2);
|
||||
set1.insert(1);
|
||||
set2.insert(2);
|
||||
BOOST_TEST(set1 != set2);
|
||||
set1.insert(2);
|
||||
set2.insert(1);
|
||||
BOOST_TEST(set1 == set2);
|
||||
set1.insert(10);
|
||||
set2.insert(20);
|
||||
BOOST_TEST(set1 != set2);
|
||||
set1.insert(20);
|
||||
set2.insert(10);
|
||||
BOOST_TEST(set1 == set2);
|
||||
}
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -3,10 +3,12 @@
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include <algorithm>
|
||||
@ -15,71 +17,61 @@
|
||||
#include "../helpers/tracker.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
template <class Container, class Iterator>
|
||||
void test_equal_insertion(Iterator begin, Iterator end)
|
||||
{
|
||||
typedef test::ordered<Container> tracker;
|
||||
typedef test::ordered<Container> tracker;
|
||||
|
||||
Container x1;
|
||||
tracker x2 = test::create_ordered(x1);
|
||||
Container x1;
|
||||
tracker x2 = test::create_ordered(x1);
|
||||
|
||||
for(Iterator it = begin; it != end; ++it) {
|
||||
x1.insert(*it);
|
||||
x2.insert(*it);
|
||||
x2.compare_key(x1, *it);
|
||||
}
|
||||
for (Iterator it = begin; it != end; ++it) {
|
||||
x1.insert(*it);
|
||||
x2.insert(*it);
|
||||
x2.compare_key(x1, *it);
|
||||
}
|
||||
|
||||
x2.compare(x1);
|
||||
test::check_equivalent_keys(x1);
|
||||
x2.compare(x1);
|
||||
test::check_equivalent_keys(x1);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(set_tests)
|
||||
{
|
||||
int values[][5] = {
|
||||
{1},
|
||||
{54, 23},
|
||||
{-13, 65},
|
||||
{77, 77},
|
||||
{986, 25, 986}
|
||||
};
|
||||
UNORDERED_AUTO_TEST (set_tests) {
|
||||
int values[][5] = {{1}, {54, 23}, {-13, 65}, {77, 77}, {986, 25, 986}};
|
||||
|
||||
typedef boost::unordered_set<int> set;
|
||||
typedef boost::unordered_multiset<int> multiset;
|
||||
typedef boost::unordered_set<int> set;
|
||||
typedef boost::unordered_multiset<int> multiset;
|
||||
|
||||
test_equal_insertion<set>(values[0], values[0] + 1);
|
||||
test_equal_insertion<set>(values[1], values[1] + 2);
|
||||
test_equal_insertion<set>(values[2], values[2] + 2);
|
||||
test_equal_insertion<set>(values[3], values[3] + 2);
|
||||
test_equal_insertion<set>(values[4], values[4] + 3);
|
||||
test_equal_insertion<set>(values[0], values[0] + 1);
|
||||
test_equal_insertion<set>(values[1], values[1] + 2);
|
||||
test_equal_insertion<set>(values[2], values[2] + 2);
|
||||
test_equal_insertion<set>(values[3], values[3] + 2);
|
||||
test_equal_insertion<set>(values[4], values[4] + 3);
|
||||
|
||||
test_equal_insertion<multiset>(values[0], values[0] + 1);
|
||||
test_equal_insertion<multiset>(values[1], values[1] + 2);
|
||||
test_equal_insertion<multiset>(values[2], values[2] + 2);
|
||||
test_equal_insertion<multiset>(values[3], values[3] + 2);
|
||||
test_equal_insertion<multiset>(values[4], values[4] + 3);
|
||||
test_equal_insertion<multiset>(values[0], values[0] + 1);
|
||||
test_equal_insertion<multiset>(values[1], values[1] + 2);
|
||||
test_equal_insertion<multiset>(values[2], values[2] + 2);
|
||||
test_equal_insertion<multiset>(values[3], values[3] + 2);
|
||||
test_equal_insertion<multiset>(values[4], values[4] + 3);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(map_tests)
|
||||
{
|
||||
typedef test::list<std::pair<int const, int> > values_type;
|
||||
values_type v[5];
|
||||
v[0].push_back(std::pair<int const, int>(1,1));
|
||||
v[1].push_back(std::pair<int const, int>(28,34));
|
||||
v[1].push_back(std::pair<int const, int>(16,58));
|
||||
v[1].push_back(std::pair<int const, int>(-124, 62));
|
||||
v[2].push_back(std::pair<int const, int>(432,12));
|
||||
v[2].push_back(std::pair<int const, int>(9,13));
|
||||
v[2].push_back(std::pair<int const, int>(432,24));
|
||||
UNORDERED_AUTO_TEST (map_tests) {
|
||||
typedef test::list<std::pair<int const, int> > values_type;
|
||||
values_type v[5];
|
||||
v[0].push_back(std::pair<int const, int>(1, 1));
|
||||
v[1].push_back(std::pair<int const, int>(28, 34));
|
||||
v[1].push_back(std::pair<int const, int>(16, 58));
|
||||
v[1].push_back(std::pair<int const, int>(-124, 62));
|
||||
v[2].push_back(std::pair<int const, int>(432, 12));
|
||||
v[2].push_back(std::pair<int const, int>(9, 13));
|
||||
v[2].push_back(std::pair<int const, int>(432, 24));
|
||||
|
||||
for(int i = 0; i < 5; ++i)
|
||||
test_equal_insertion<boost::unordered_map<int, int> >(
|
||||
v[i].begin(), v[i].end());
|
||||
for (int i = 0; i < 5; ++i)
|
||||
test_equal_insertion<boost::unordered_map<int, int> >(
|
||||
v[i].begin(), v[i].end());
|
||||
|
||||
for(int i2 = 0; i2 < 5; ++i2)
|
||||
test_equal_insertion<boost::unordered_multimap<int, int> >(
|
||||
v[i2].begin(), v[i2].end());
|
||||
for (int i2 = 0; i2 < 5; ++i2)
|
||||
test_equal_insertion<boost::unordered_multimap<int, int> >(
|
||||
v[i2].begin(), v[i2].end());
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -6,215 +6,212 @@
|
||||
// The code for erasing elements from containers with equivalent keys is very
|
||||
// hairy with several tricky edge cases - so explicitly test each one.
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../helpers/list.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/helpers.hpp"
|
||||
#include <set>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <boost/next_prior.hpp>
|
||||
#include "../objects/test.hpp"
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, < 1400)
|
||||
#pragma warning(disable:4267) // conversion from 'size_t' to 'unsigned int',
|
||||
// possible loss of data.
|
||||
#pragma warning(disable : 4267) // conversion from 'size_t' to 'unsigned int',
|
||||
// possible loss of data.
|
||||
#endif
|
||||
|
||||
struct write_pair_type
|
||||
{
|
||||
template <class X1, class X2>
|
||||
void operator()(std::pair<X1, X2> const& x) const
|
||||
{
|
||||
std::cout<<"("<<x.first<<","<<x.second<<")";
|
||||
}
|
||||
template <class X1, class X2>
|
||||
void operator()(std::pair<X1, X2> const& x) const
|
||||
{
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "(" << x.first << "," << x.second << ")";
|
||||
}
|
||||
} write_pair;
|
||||
|
||||
template <class Container>
|
||||
void write_container(Container const& x)
|
||||
template <class Container> void write_container(Container const& x)
|
||||
{
|
||||
std::for_each(x.begin(), x.end(), write_pair);
|
||||
std::cout<<"\n";
|
||||
std::for_each(x.begin(), x.end(), write_pair);
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n";
|
||||
}
|
||||
|
||||
// Make everything collide - for testing erase in a single bucket.
|
||||
struct collision_hash
|
||||
{
|
||||
int operator()(int) const { return 0; }
|
||||
std::size_t operator()(int) const { return 0; }
|
||||
};
|
||||
|
||||
// For testing erase in 2 buckets.
|
||||
struct collision2_hash
|
||||
{
|
||||
int operator()(int x) const { return x & 1; }
|
||||
std::size_t operator()(int x) const
|
||||
{
|
||||
return static_cast<std::size_t>(x & 1);
|
||||
}
|
||||
};
|
||||
|
||||
// For testing erase in lots of buckets.
|
||||
struct collision3_hash
|
||||
{
|
||||
int operator()(int x) const { return x; }
|
||||
std::size_t operator()(int x) const { return static_cast<std::size_t>(x); }
|
||||
};
|
||||
|
||||
typedef boost::unordered_multimap<int, int,
|
||||
collision_hash, std::equal_to<int>,
|
||||
test::allocator1<std::pair<int const, int> > > collide_map;
|
||||
typedef boost::unordered_multimap<int, int,
|
||||
collision2_hash, std::equal_to<int>,
|
||||
test::allocator2<std::pair<int const, int> > > collide_map2;
|
||||
typedef boost::unordered_multimap<int, int,
|
||||
collision3_hash, std::equal_to<int>,
|
||||
test::allocator2<std::pair<int const, int> > > collide_map3;
|
||||
typedef boost::unordered_multimap<int, int, collision_hash, std::equal_to<int>,
|
||||
test::allocator1<std::pair<int const, int> > >
|
||||
collide_map;
|
||||
typedef boost::unordered_multimap<int, int, collision2_hash, std::equal_to<int>,
|
||||
test::allocator2<std::pair<int const, int> > >
|
||||
collide_map2;
|
||||
typedef boost::unordered_multimap<int, int, collision3_hash, std::equal_to<int>,
|
||||
test::allocator2<std::pair<int const, int> > >
|
||||
collide_map3;
|
||||
typedef collide_map::value_type collide_value;
|
||||
typedef test::list<collide_value> collide_list;
|
||||
|
||||
UNORDERED_AUTO_TEST(empty_range_tests)
|
||||
{
|
||||
collide_map x;
|
||||
x.erase(x.begin(), x.end());
|
||||
x.erase(x.begin(), x.begin());
|
||||
x.erase(x.end(), x.end());
|
||||
test::check_equivalent_keys(x);
|
||||
UNORDERED_AUTO_TEST (empty_range_tests) {
|
||||
collide_map x;
|
||||
x.erase(x.begin(), x.end());
|
||||
x.erase(x.begin(), x.begin());
|
||||
x.erase(x.end(), x.end());
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(single_item_tests)
|
||||
{
|
||||
collide_list init;
|
||||
init.push_back(collide_value(1,1));
|
||||
UNORDERED_AUTO_TEST (single_item_tests) {
|
||||
collide_list init;
|
||||
init.push_back(collide_value(1, 1));
|
||||
|
||||
collide_map x(init.begin(), init.end());
|
||||
x.erase(x.begin(), x.begin());
|
||||
BOOST_TEST(x.count(1) == 1 && x.size() == 1);
|
||||
test::check_equivalent_keys(x);
|
||||
x.erase(x.end(), x.end());
|
||||
BOOST_TEST(x.count(1) == 1 && x.size() == 1);
|
||||
test::check_equivalent_keys(x);
|
||||
x.erase(x.begin(), x.end());
|
||||
BOOST_TEST(x.count(1) == 0 && x.size() == 0);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (two_equivalent_item_tests) {
|
||||
collide_list init;
|
||||
init.push_back(collide_value(1, 1));
|
||||
init.push_back(collide_value(1, 2));
|
||||
|
||||
{
|
||||
collide_map x(init.begin(), init.end());
|
||||
x.erase(x.begin(), x.begin());
|
||||
BOOST_TEST(x.count(1) == 1 && x.size() == 1);
|
||||
test::check_equivalent_keys(x);
|
||||
x.erase(x.end(), x.end());
|
||||
BOOST_TEST(x.count(1) == 1 && x.size() == 1);
|
||||
test::check_equivalent_keys(x);
|
||||
x.erase(x.begin(), x.end());
|
||||
BOOST_TEST(x.count(1) == 0 && x.size() == 0);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(two_equivalent_item_tests)
|
||||
{
|
||||
collide_list init;
|
||||
init.push_back(collide_value(1,1));
|
||||
init.push_back(collide_value(1,2));
|
||||
{
|
||||
collide_map x(init.begin(), init.end());
|
||||
int value = test::next(x.begin())->second;
|
||||
x.erase(x.begin(), test::next(x.begin()));
|
||||
BOOST_TEST(x.count(1) == 1 && x.size() == 1 && x.begin()->first == 1 &&
|
||||
x.begin()->second == value);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
{
|
||||
collide_map x(init.begin(), init.end());
|
||||
x.erase(x.begin(), x.end());
|
||||
BOOST_TEST(x.count(1) == 0 && x.size() == 0);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
{
|
||||
collide_map x(init.begin(), init.end());
|
||||
int value = boost::next(x.begin())->second;
|
||||
x.erase(x.begin(), boost::next(x.begin()));
|
||||
BOOST_TEST(x.count(1) == 1 && x.size() == 1 &&
|
||||
x.begin()->first == 1 && x.begin()->second == value);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
{
|
||||
collide_map x(init.begin(), init.end());
|
||||
int value = x.begin()->second;
|
||||
x.erase(boost::next(x.begin()), x.end());
|
||||
BOOST_TEST(x.count(1) == 1 && x.size() == 1 &&
|
||||
x.begin()->first == 1 && x.begin()->second == value);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
{
|
||||
collide_map x(init.begin(), init.end());
|
||||
int value = x.begin()->second;
|
||||
x.erase(test::next(x.begin()), x.end());
|
||||
BOOST_TEST(x.count(1) == 1 && x.size() == 1 && x.begin()->first == 1 &&
|
||||
x.begin()->second == value);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
}
|
||||
|
||||
// More automated tests...
|
||||
|
||||
template<class Range1, class Range2>
|
||||
template <class Range1, class Range2>
|
||||
bool compare(Range1 const& x, Range2 const& y)
|
||||
{
|
||||
collide_list a(x.begin(), x.end());
|
||||
collide_list b(y.begin(), y.end());
|
||||
a.sort();
|
||||
b.sort();
|
||||
return a == b;
|
||||
collide_list a(x.begin(), x.end());
|
||||
collide_list b(y.begin(), y.end());
|
||||
a.sort();
|
||||
b.sort();
|
||||
return a == b;
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
bool general_erase_range_test(Container& x, std::size_t start, std::size_t end)
|
||||
{
|
||||
collide_list l(x.begin(), x.end());
|
||||
l.erase(boost::next(l.begin(), start), boost::next(l.begin(), end));
|
||||
x.erase(boost::next(x.begin(), start), boost::next(x.begin(), end));
|
||||
collide_list l(x.begin(), x.end());
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
return compare(l, x);
|
||||
l.erase(test::next(l.begin(), start), test::next(l.begin(), end));
|
||||
x.erase(test::next(x.begin(), start), test::next(x.begin(), end));
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
return compare(l, x);
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
void erase_subrange_tests(Container const& x)
|
||||
template <class Container> void erase_subrange_tests(Container const& x)
|
||||
{
|
||||
for(std::size_t length = 0; length < x.size(); ++length) {
|
||||
for(std::size_t position = 0; position < x.size() - length; ++position)
|
||||
{
|
||||
Container y(x);
|
||||
collide_list init(y.begin(), y.end());
|
||||
if(!general_erase_range_test(y, position, position + length)) {
|
||||
BOOST_ERROR("general_erase_range_test failed.");
|
||||
std::cout<<"Erase: ["<<position<<","<<position + length<<")\n";
|
||||
write_container(init);
|
||||
write_container(y);
|
||||
}
|
||||
}
|
||||
for (std::size_t length = 0; length < x.size(); ++length) {
|
||||
for (std::size_t position = 0; position < x.size() - length; ++position) {
|
||||
Container y(x);
|
||||
collide_list init(y.begin(), y.end());
|
||||
if (!general_erase_range_test(y, position, position + length)) {
|
||||
BOOST_ERROR("general_erase_range_test failed.");
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Erase: [" << position << ","
|
||||
<< position + length << ")\n";
|
||||
write_container(init);
|
||||
write_container(y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
void x_by_y_erase_range_tests(Container*, int values, int duplicates)
|
||||
{
|
||||
Container y;
|
||||
Container y;
|
||||
|
||||
for(int i = 0; i < values; ++i) {
|
||||
for(int j = 0; j < duplicates; ++j) {
|
||||
y.insert(collide_value(i, j));
|
||||
}
|
||||
for (int i = 0; i < values; ++i) {
|
||||
for (int j = 0; j < duplicates; ++j) {
|
||||
y.insert(collide_value(i, j));
|
||||
}
|
||||
}
|
||||
|
||||
std::cout<<"Values: "<<values<<", Duplicates: "<<duplicates<<"\n";
|
||||
erase_subrange_tests(y);
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Values: " << values
|
||||
<< ", Duplicates: " << duplicates << "\n";
|
||||
erase_subrange_tests(y);
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
void exhaustive_erase_tests(Container* x, int num_values,
|
||||
int num_duplicated)
|
||||
void exhaustive_erase_tests(Container* x, int num_values, int num_duplicated)
|
||||
{
|
||||
for(int i = 0; i < num_values; ++i) {
|
||||
for(int j = 0; j < num_duplicated; ++j) {
|
||||
x_by_y_erase_range_tests(x, i, j);
|
||||
}
|
||||
for (int i = 0; i < num_values; ++i) {
|
||||
for (int j = 0; j < num_duplicated; ++j) {
|
||||
x_by_y_erase_range_tests(x, i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(exhaustive_collide_tests)
|
||||
{
|
||||
std::cout<<"exhaustive_collide_tests:\n";
|
||||
collide_map m;
|
||||
exhaustive_erase_tests((collide_map*) 0, 4, 4);
|
||||
std::cout<<"\n";
|
||||
UNORDERED_AUTO_TEST (exhaustive_collide_tests) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "exhaustive_collide_tests:\n";
|
||||
collide_map m;
|
||||
exhaustive_erase_tests((collide_map*)0, 4, 4);
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n";
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(exhaustive_collide2_tests)
|
||||
{
|
||||
std::cout<<"exhaustive_collide2_tests:\n";
|
||||
exhaustive_erase_tests((collide_map2*) 0, 8, 4);
|
||||
std::cout<<"\n";
|
||||
UNORDERED_AUTO_TEST (exhaustive_collide2_tests) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "exhaustive_collide2_tests:\n";
|
||||
exhaustive_erase_tests((collide_map2*)0, 8, 4);
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n";
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(exhaustive_collide3_tests)
|
||||
{
|
||||
std::cout<<"exhaustive_collide3_tests:\n";
|
||||
exhaustive_erase_tests((collide_map3*) 0, 8, 4);
|
||||
std::cout<<"\n";
|
||||
UNORDERED_AUTO_TEST (exhaustive_collide3_tests) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "exhaustive_collide3_tests:\n";
|
||||
exhaustive_erase_tests((collide_map3*)0, 8, 4);
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n";
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -3,231 +3,265 @@
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include <boost/next_prior.hpp>
|
||||
#include "../objects/test.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
#include "../helpers/equivalent.hpp"
|
||||
#include "../helpers/helpers.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <iostream>
|
||||
namespace erase_tests {
|
||||
|
||||
namespace erase_tests
|
||||
{
|
||||
test::seed_t initialize_seed(85638);
|
||||
|
||||
test::seed_t initialize_seed(85638);
|
||||
template <class Container>
|
||||
void erase_tests1(Container*, test::random_generator generator)
|
||||
{
|
||||
typedef typename Container::iterator iterator;
|
||||
typedef typename Container::const_iterator c_iterator;
|
||||
|
||||
template <class Container>
|
||||
void erase_tests1(Container*, test::random_generator generator)
|
||||
{
|
||||
std::cerr<<"Erase by key.\n";
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Erase by key.\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
int iterations = 0;
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<Container>::iterator
|
||||
it = v.begin(); it != v.end(); ++it)
|
||||
{
|
||||
std::size_t count = x.count(test::get_key<Container>(*it));
|
||||
std::size_t old_size = x.size();
|
||||
BOOST_TEST(count == x.erase(test::get_key<Container>(*it)));
|
||||
BOOST_TEST(x.size() == old_size - count);
|
||||
BOOST_TEST(x.count(test::get_key<Container>(*it)) == 0);
|
||||
BOOST_TEST(x.find(test::get_key<Container>(*it)) == x.end());
|
||||
if (++iterations % 20 == 0) test::check_equivalent_keys(x);
|
||||
}
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
int iterations = 0;
|
||||
for (typename test::random_values<Container>::iterator it = v.begin();
|
||||
it != v.end(); ++it) {
|
||||
std::size_t count = x.count(test::get_key<Container>(*it));
|
||||
std::size_t old_size = x.size();
|
||||
BOOST_TEST(count == x.erase(test::get_key<Container>(*it)));
|
||||
BOOST_TEST(x.size() == old_size - count);
|
||||
BOOST_TEST(x.count(test::get_key<Container>(*it)) == 0);
|
||||
BOOST_TEST(x.find(test::get_key<Container>(*it)) == x.end());
|
||||
if (++iterations % 20 == 0)
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
}
|
||||
|
||||
std::cerr<<"erase(begin()).\n";
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "erase(begin()).\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
std::size_t size = x.size();
|
||||
int iterations = 0;
|
||||
while(size > 0 && !x.empty())
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME Container::key_type
|
||||
key = test::get_key<Container>(*x.begin());
|
||||
std::size_t count = x.count(key);
|
||||
BOOST_DEDUCED_TYPENAME Container::iterator
|
||||
pos = x.erase(x.begin());
|
||||
--size;
|
||||
BOOST_TEST(pos == x.begin());
|
||||
BOOST_TEST(x.count(key) == count - 1);
|
||||
BOOST_TEST(x.size() == size);
|
||||
if (++iterations % 20 == 0) test::check_equivalent_keys(x);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
|
||||
std::cerr<<"erase(random position).\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
std::size_t size = x.size();
|
||||
int iterations = 0;
|
||||
while(size > 0 && !x.empty())
|
||||
{
|
||||
using namespace std;
|
||||
int index = rand() % (int) x.size();
|
||||
BOOST_DEDUCED_TYPENAME Container::const_iterator prev, pos, next;
|
||||
if(index == 0) {
|
||||
prev = pos = x.begin();
|
||||
}
|
||||
else {
|
||||
prev = boost::next(x.begin(), index - 1);
|
||||
pos = boost::next(prev);
|
||||
}
|
||||
next = boost::next(pos);
|
||||
BOOST_DEDUCED_TYPENAME Container::key_type
|
||||
key = test::get_key<Container>(*pos);
|
||||
std::size_t count = x.count(key);
|
||||
BOOST_TEST(next == x.erase(pos));
|
||||
--size;
|
||||
if(size > 0)
|
||||
BOOST_TEST(index == 0 ? next == x.begin() :
|
||||
next == boost::next(prev));
|
||||
BOOST_TEST(x.count(key) == count - 1);
|
||||
BOOST_TEST(x.size() == size);
|
||||
if (++iterations % 20 == 0) test::check_equivalent_keys(x);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
|
||||
std::cerr<<"erase(ranges).\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<Container> v(500, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
|
||||
std::size_t size = x.size();
|
||||
|
||||
// I'm actually stretching it a little here, as the standard says it
|
||||
// returns 'the iterator immediately following the erase elements'
|
||||
// and if nothing is erased, then there's nothing to follow. But I
|
||||
// think this is the only sensible option...
|
||||
BOOST_TEST(x.erase(x.end(), x.end()) == x.end());
|
||||
BOOST_TEST(x.erase(x.begin(), x.begin()) == x.begin());
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
std::size_t size = x.size();
|
||||
int iterations = 0;
|
||||
while (size > 0 && !x.empty()) {
|
||||
typename Container::key_type key = test::get_key<Container>(*x.begin());
|
||||
std::size_t count = x.count(key);
|
||||
iterator pos = x.erase(x.begin());
|
||||
--size;
|
||||
BOOST_TEST(pos == x.begin());
|
||||
BOOST_TEST(x.count(key) == count - 1);
|
||||
BOOST_TEST(x.size() == size);
|
||||
test::check_equivalent_keys(x);
|
||||
|
||||
BOOST_TEST(x.erase(x.begin(), x.end()) == x.end());
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.begin() == x.end());
|
||||
test::check_equivalent_keys(x);
|
||||
|
||||
BOOST_TEST(x.erase(x.begin(), x.end()) == x.begin());
|
||||
test::check_equivalent_keys(x);
|
||||
if (++iterations % 20 == 0)
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
|
||||
std::cerr<<"quick_erase(begin()).\n";
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "erase(random position).\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
std::size_t size = x.size();
|
||||
int iterations = 0;
|
||||
while (size > 0 && !x.empty()) {
|
||||
std::size_t index = test::random_value(x.size());
|
||||
c_iterator prev, pos, next;
|
||||
if (index == 0) {
|
||||
prev = pos = x.begin();
|
||||
} else {
|
||||
prev = test::next(x.begin(), index - 1);
|
||||
pos = test::next(prev);
|
||||
}
|
||||
next = test::next(pos);
|
||||
typename Container::key_type key = test::get_key<Container>(*pos);
|
||||
std::size_t count = x.count(key);
|
||||
BOOST_TEST(count > 0);
|
||||
BOOST_TEST(next == x.erase(pos));
|
||||
--size;
|
||||
if (size > 0)
|
||||
BOOST_TEST(index == 0 ? next == x.begin() : next == test::next(prev));
|
||||
BOOST_TEST(x.count(key) == count - 1);
|
||||
if (x.count(key) != count - 1) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << count << " => " << x.count(key)
|
||||
<< std::endl;
|
||||
}
|
||||
BOOST_TEST(x.size() == size);
|
||||
if (++iterations % 20 == 0)
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "erase(ranges).\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<Container> v(500, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
|
||||
std::size_t size = x.size();
|
||||
|
||||
// I'm actually stretching it a little here, as the standard says it
|
||||
// returns 'the iterator immediately following the erase elements'
|
||||
// and if nothing is erased, then there's nothing to follow. But I
|
||||
// think this is the only sensible option...
|
||||
BOOST_TEST(x.erase(x.end(), x.end()) == x.end());
|
||||
BOOST_TEST(x.erase(x.begin(), x.begin()) == x.begin());
|
||||
BOOST_TEST(x.size() == size);
|
||||
test::check_equivalent_keys(x);
|
||||
|
||||
BOOST_TEST(x.erase(x.begin(), x.end()) == x.end());
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.begin() == x.end());
|
||||
test::check_equivalent_keys(x);
|
||||
|
||||
BOOST_TEST(x.erase(x.begin(), x.end()) == x.begin());
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "erase(random ranges).\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
Container x;
|
||||
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
std::size_t size = x.size();
|
||||
int iterations = 0;
|
||||
while(size > 0 && !x.empty())
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME Container::key_type
|
||||
key = test::get_key<Container>(*x.begin());
|
||||
std::size_t count = x.count(key);
|
||||
x.quick_erase(x.begin());
|
||||
--size;
|
||||
BOOST_TEST(x.count(key) == count - 1);
|
||||
BOOST_TEST(x.size() == size);
|
||||
if (++iterations % 20 == 0) test::check_equivalent_keys(x);
|
||||
x.insert(v.begin(), v.end());
|
||||
|
||||
// Note that erase only invalidates the erased iterators.
|
||||
std::vector<c_iterator> iterators;
|
||||
for (c_iterator it = x.cbegin(); it != x.cend(); ++it) {
|
||||
iterators.push_back(it);
|
||||
}
|
||||
iterators.push_back(x.cend());
|
||||
|
||||
while (iterators.size() > 1) {
|
||||
std::size_t start = test::random_value(iterators.size());
|
||||
std::size_t length = test::random_value(iterators.size() - start);
|
||||
x.erase(iterators[start], iterators[start + length]);
|
||||
iterators.erase(test::next(iterators.begin(), start),
|
||||
test::next(iterators.begin(), start + length));
|
||||
|
||||
BOOST_TEST(x.size() == iterators.size() - 1);
|
||||
typename std::vector<c_iterator>::const_iterator i2 =
|
||||
iterators.begin();
|
||||
for (c_iterator i1 = x.cbegin(); i1 != x.cend(); ++i1) {
|
||||
BOOST_TEST(i1 == *i2);
|
||||
++i2;
|
||||
}
|
||||
BOOST_TEST(x.cend() == *i2);
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
}
|
||||
|
||||
std::cerr<<"quick_erase(random position).\n";
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "quick_erase(begin()).\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
std::size_t size = x.size();
|
||||
int iterations = 0;
|
||||
while(size > 0 && !x.empty())
|
||||
{
|
||||
using namespace std;
|
||||
int index = rand() % (int) x.size();
|
||||
BOOST_DEDUCED_TYPENAME Container::const_iterator prev, pos, next;
|
||||
if(index == 0) {
|
||||
prev = pos = x.begin();
|
||||
}
|
||||
else {
|
||||
prev = boost::next(x.begin(), index - 1);
|
||||
pos = boost::next(prev);
|
||||
}
|
||||
next = boost::next(pos);
|
||||
BOOST_DEDUCED_TYPENAME Container::key_type
|
||||
key = test::get_key<Container>(*pos);
|
||||
std::size_t count = x.count(key);
|
||||
x.quick_erase(pos);
|
||||
--size;
|
||||
if(size > 0)
|
||||
BOOST_TEST(index == 0 ? next == x.begin() :
|
||||
next == boost::next(prev));
|
||||
BOOST_TEST(x.count(key) == count - 1);
|
||||
BOOST_TEST(x.size() == size);
|
||||
if (++iterations % 20 == 0) test::check_equivalent_keys(x);
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
std::size_t size = x.size();
|
||||
int iterations = 0;
|
||||
while (size > 0 && !x.empty()) {
|
||||
typename Container::key_type key = test::get_key<Container>(*x.begin());
|
||||
std::size_t count = x.count(key);
|
||||
x.quick_erase(x.begin());
|
||||
--size;
|
||||
BOOST_TEST(x.count(key) == count - 1);
|
||||
BOOST_TEST(x.size() == size);
|
||||
if (++iterations % 20 == 0)
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "quick_erase(random position).\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
std::size_t size = x.size();
|
||||
int iterations = 0;
|
||||
while (size > 0 && !x.empty()) {
|
||||
std::size_t index = test::random_value(x.size());
|
||||
typename Container::const_iterator prev, pos, next;
|
||||
if (index == 0) {
|
||||
prev = pos = x.begin();
|
||||
} else {
|
||||
prev = test::next(x.begin(), index - 1);
|
||||
pos = test::next(prev);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
next = test::next(pos);
|
||||
typename Container::key_type key = test::get_key<Container>(*pos);
|
||||
std::size_t count = x.count(key);
|
||||
BOOST_TEST(count > 0);
|
||||
x.quick_erase(pos);
|
||||
--size;
|
||||
if (size > 0)
|
||||
BOOST_TEST(index == 0 ? next == x.begin() : next == test::next(prev));
|
||||
BOOST_TEST(x.count(key) == count - 1);
|
||||
if (x.count(key) != count - 1) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << count << " => " << x.count(key)
|
||||
<< std::endl;
|
||||
}
|
||||
BOOST_TEST(x.size() == size);
|
||||
if (++iterations % 20 == 0)
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
|
||||
|
||||
std::cerr<<"clear().\n";
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "clear().\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<Container> v(500, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
x.clear();
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.begin() == x.end());
|
||||
test::random_values<Container> v(500, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
x.clear();
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.begin() == x.end());
|
||||
}
|
||||
|
||||
std::cerr<<"\n";
|
||||
}
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n";
|
||||
}
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_multimap;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator2<test::object> >* test_multimap;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
|
||||
UNORDERED_TEST(erase_tests1,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
using test::limited_range;
|
||||
|
||||
UNORDERED_TEST(
|
||||
erase_tests1, ((test_set)(test_multiset)(test_map)(test_multimap))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
133
test/unordered/extract_tests.cpp
Normal file
133
test/unordered/extract_tests.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
|
||||
// Copyright 2016 Daniel James.
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include "../helpers/equivalent.hpp"
|
||||
#include "../helpers/helpers.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
#include "../objects/test.hpp"
|
||||
|
||||
namespace extract_tests {
|
||||
|
||||
test::seed_t initialize_seed(85638);
|
||||
|
||||
template <class Container>
|
||||
void extract_tests1(Container*, test::random_generator generator)
|
||||
{
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Extract by key.\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
int iterations = 0;
|
||||
for (typename test::random_values<Container>::iterator it = v.begin();
|
||||
it != v.end(); ++it) {
|
||||
std::size_t count = x.count(test::get_key<Container>(*it));
|
||||
std::size_t old_size = x.size();
|
||||
std::size_t new_count = count ? count - 1 : count;
|
||||
std::size_t new_size = count ? old_size - 1 : old_size;
|
||||
typename Container::node_type n =
|
||||
x.extract(test::get_key<Container>(*it));
|
||||
BOOST_TEST((n ? true : false) == (count ? true : false));
|
||||
BOOST_TEST(x.size() == new_size);
|
||||
BOOST_TEST(x.count(test::get_key<Container>(*it)) == new_count);
|
||||
if (!new_count) {
|
||||
BOOST_TEST(x.find(test::get_key<Container>(*it)) == x.end());
|
||||
} else {
|
||||
BOOST_TEST(x.find(test::get_key<Container>(*it)) != x.end());
|
||||
}
|
||||
if (++iterations % 20 == 0)
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "extract(begin()).\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
std::size_t size = x.size();
|
||||
int iterations = 0;
|
||||
while (size > 0 && !x.empty()) {
|
||||
typename Container::key_type key = test::get_key<Container>(*x.begin());
|
||||
std::size_t count = x.count(key);
|
||||
typename Container::node_type n = x.extract(x.begin());
|
||||
BOOST_TEST(n);
|
||||
--size;
|
||||
BOOST_TEST(x.count(key) == count - 1);
|
||||
BOOST_TEST(x.size() == size);
|
||||
if (++iterations % 20 == 0)
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "extract(random position).\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
std::size_t size = x.size();
|
||||
int iterations = 0;
|
||||
while (size > 0 && !x.empty()) {
|
||||
using namespace std;
|
||||
int index = rand() % (int)x.size();
|
||||
typename Container::const_iterator prev, pos, next;
|
||||
if (index == 0) {
|
||||
prev = pos = x.begin();
|
||||
} else {
|
||||
prev = test::next(x.begin(), index - 1);
|
||||
pos = test::next(prev);
|
||||
}
|
||||
next = test::next(pos);
|
||||
typename Container::key_type key = test::get_key<Container>(*pos);
|
||||
std::size_t count = x.count(key);
|
||||
typename Container::node_type n = x.extract(pos);
|
||||
BOOST_TEST(n);
|
||||
--size;
|
||||
if (size > 0)
|
||||
BOOST_TEST(index == 0 ? next == x.begin() : next == test::next(prev));
|
||||
BOOST_TEST(x.count(key) == count - 1);
|
||||
BOOST_TEST(x.size() == size);
|
||||
if (++iterations % 20 == 0)
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n";
|
||||
}
|
||||
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator2<test::object> >* test_multimap;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
|
||||
UNORDERED_TEST(
|
||||
extract_tests1, ((test_set)(test_multiset)(test_map)(test_multimap))(
|
||||
(default_generator)(generate_collisions)))
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
@ -3,10 +3,12 @@
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../objects/test.hpp"
|
||||
@ -14,156 +16,142 @@
|
||||
#include "../helpers/tracker.hpp"
|
||||
#include "../helpers/helpers.hpp"
|
||||
|
||||
namespace find_tests
|
||||
{
|
||||
namespace find_tests {
|
||||
|
||||
test::seed_t initialize_seed(78937);
|
||||
test::seed_t initialize_seed(78937);
|
||||
|
||||
template <class X>
|
||||
void find_tests1(X*, test::random_generator generator)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
|
||||
template <class X> void find_tests1(X*, test::random_generator generator)
|
||||
{
|
||||
typedef typename X::iterator iterator;
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<X> v(500, generator);
|
||||
X x(v.begin(), v.end());
|
||||
X const& x_const = x;
|
||||
test::ordered<X> tracker = test::create_ordered(x);
|
||||
tracker.insert_range(v.begin(), v.end());
|
||||
test::random_values<X> v(500, generator);
|
||||
X x(v.begin(), v.end());
|
||||
X const& x_const = x;
|
||||
test::ordered<X> tracker = test::create_ordered(x);
|
||||
tracker.insert_range(v.begin(), v.end());
|
||||
|
||||
for(BOOST_DEDUCED_TYPENAME test::ordered<X>::const_iterator it1 =
|
||||
tracker.begin(); it1 != tracker.end(); ++it1)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME X::key_type key = test::get_key<X>(*it1);
|
||||
iterator pos = x.find(key);
|
||||
BOOST_DEDUCED_TYPENAME X::const_iterator
|
||||
const_pos = x_const.find(key);
|
||||
BOOST_TEST(pos != x.end() &&
|
||||
x.key_eq()(key, test::get_key<X>(*pos)));
|
||||
BOOST_TEST(const_pos != x_const.end() &&
|
||||
x_const.key_eq()(key, test::get_key<X>(*const_pos)));
|
||||
for (typename test::ordered<X>::const_iterator it1 = tracker.begin();
|
||||
it1 != tracker.end(); ++it1) {
|
||||
typename X::key_type key = test::get_key<X>(*it1);
|
||||
typename X::const_iterator const_pos = x_const.find(key);
|
||||
iterator pos = x.find(key);
|
||||
BOOST_TEST(const_pos != x_const.end());
|
||||
BOOST_TEST(const_pos != x_const.end() &&
|
||||
x_const.key_eq()(key, test::get_key<X>(*const_pos)));
|
||||
BOOST_TEST(pos != x.end());
|
||||
BOOST_TEST(pos != x.end() && x.key_eq()(key, test::get_key<X>(*pos)));
|
||||
|
||||
BOOST_TEST(x.count(key) == tracker.count(key));
|
||||
BOOST_TEST(x.count(key) == tracker.count(key));
|
||||
|
||||
test::compare_pairs(x.equal_range(key),
|
||||
tracker.equal_range(key),
|
||||
(BOOST_DEDUCED_TYPENAME X::value_type*) 0);
|
||||
test::compare_pairs(x_const.equal_range(key),
|
||||
tracker.equal_range(key),
|
||||
(BOOST_DEDUCED_TYPENAME X::value_type*) 0);
|
||||
}
|
||||
|
||||
test::random_values<X> v2(500, generator);
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<X>::const_iterator it2 =
|
||||
v2.begin(); it2 != v2.end(); ++it2)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME X::key_type key = test::get_key<X>(*it2);
|
||||
if(tracker.find(test::get_key<X>(key)) == tracker.end())
|
||||
{
|
||||
BOOST_TEST(x.find(key) == x.end());
|
||||
BOOST_TEST(x_const.find(key) == x_const.end());
|
||||
BOOST_TEST(x.count(key) == 0);
|
||||
std::pair<iterator, iterator> range = x.equal_range(key);
|
||||
BOOST_TEST(range.first == range.second);
|
||||
}
|
||||
test::compare_pairs(x.equal_range(key), tracker.equal_range(key),
|
||||
(typename X::value_type*)0);
|
||||
test::compare_pairs(x_const.equal_range(key), tracker.equal_range(key),
|
||||
(typename X::value_type*)0);
|
||||
}
|
||||
|
||||
test::random_values<X> v2(500, generator);
|
||||
for (typename test::random_values<X>::const_iterator it2 = v2.begin();
|
||||
it2 != v2.end(); ++it2) {
|
||||
typename X::key_type key = test::get_key<X>(*it2);
|
||||
if (tracker.find(test::get_key<X>(key)) == tracker.end()) {
|
||||
BOOST_TEST(x.find(key) == x.end());
|
||||
BOOST_TEST(x_const.find(key) == x_const.end());
|
||||
BOOST_TEST(x.count(key) == 0);
|
||||
std::pair<iterator, iterator> range = x.equal_range(key);
|
||||
BOOST_TEST(range.first == range.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
test::check_instances check_;
|
||||
|
||||
X x;
|
||||
X x;
|
||||
|
||||
test::random_values<X> v2(5, generator);
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<X>::const_iterator it3 =
|
||||
v2.begin(); it3 != v2.end(); ++it3)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME X::key_type key = test::get_key<X>(*it3);
|
||||
BOOST_TEST(x.find(key) == x.end());
|
||||
BOOST_TEST(x.count(key) == 0);
|
||||
std::pair<iterator, iterator> range = x.equal_range(key);
|
||||
BOOST_TEST(range.first == range.second);
|
||||
}
|
||||
test::random_values<X> v2(5, generator);
|
||||
for (typename test::random_values<X>::const_iterator it3 = v2.begin();
|
||||
it3 != v2.end(); ++it3) {
|
||||
typename X::key_type key = test::get_key<X>(*it3);
|
||||
BOOST_TEST(x.find(key) == x.end());
|
||||
BOOST_TEST(x.count(key) == 0);
|
||||
std::pair<iterator, iterator> range = x.equal_range(key);
|
||||
BOOST_TEST(range.first == range.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct compatible_key
|
||||
{
|
||||
struct compatible_key
|
||||
{
|
||||
test::object o_;
|
||||
|
||||
compatible_key(test::object const& o) : o_(o) {}
|
||||
};
|
||||
|
||||
struct compatible_hash
|
||||
{
|
||||
compatible_key(test::object const& o) : o_(o) {}
|
||||
};
|
||||
|
||||
struct compatible_hash
|
||||
{
|
||||
test::hash hash_;
|
||||
|
||||
std::size_t operator()(compatible_key const& k) const {
|
||||
return hash_(k.o_);
|
||||
std::size_t operator()(compatible_key const& k) const
|
||||
{
|
||||
return hash_(k.o_);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
struct compatible_predicate
|
||||
{
|
||||
struct compatible_predicate
|
||||
{
|
||||
test::equal_to equal_;
|
||||
|
||||
bool operator()(compatible_key const& k1, compatible_key const& k2) const {
|
||||
return equal_(k1.o_, k2.o_);
|
||||
bool operator()(compatible_key const& k1, compatible_key const& k2) const
|
||||
{
|
||||
return equal_(k1.o_, k2.o_);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
template <class X>
|
||||
void find_compatible_keys_test(X*, test::random_generator generator)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
|
||||
typedef BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator
|
||||
value_iterator;
|
||||
template <class X>
|
||||
void find_compatible_keys_test(X*, test::random_generator generator)
|
||||
{
|
||||
typedef typename test::random_values<X>::iterator value_iterator;
|
||||
test::random_values<X> v(500, generator);
|
||||
X x(v.begin(), v.end());
|
||||
|
||||
|
||||
compatible_hash h;
|
||||
compatible_predicate eq;
|
||||
|
||||
for(value_iterator it = v.begin(), end = v.end(); it != end; ++it) {
|
||||
BOOST_DEDUCED_TYPENAME X::key_type key = test::get_key<X>(*it);
|
||||
BOOST_TEST(x.find(key) == x.find(compatible_key(key), h, eq));
|
||||
|
||||
for (value_iterator it = v.begin(), end = v.end(); it != end; ++it) {
|
||||
typename X::key_type key = test::get_key<X>(*it);
|
||||
BOOST_TEST(x.find(key) == x.find(compatible_key(key), h, eq));
|
||||
}
|
||||
|
||||
test::random_values<X> v2(20, generator);
|
||||
|
||||
for(value_iterator it = v2.begin(), end = v2.end(); it != end; ++it) {
|
||||
BOOST_DEDUCED_TYPENAME X::key_type key = test::get_key<X>(*it);
|
||||
BOOST_TEST(x.find(key) == x.find(compatible_key(key), h, eq));
|
||||
|
||||
for (value_iterator it = v2.begin(), end = v2.end(); it != end; ++it) {
|
||||
typename X::key_type key = test::get_key<X>(*it);
|
||||
BOOST_TEST(x.find(key) == x.find(compatible_key(key), h, eq));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_multimap;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator1<test::object> >* test_multimap;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
|
||||
UNORDERED_TEST(find_tests1,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
UNORDERED_TEST(find_compatible_keys_test,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
using test::limited_range;
|
||||
|
||||
UNORDERED_TEST(
|
||||
find_tests1, ((test_set)(test_multiset)(test_map)(test_multimap))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
UNORDERED_TEST(find_compatible_keys_test,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -3,50 +3,50 @@
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered/unordered_map_fwd.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
template <typename T>
|
||||
void call_swap(boost::unordered_map<T,T>& x,
|
||||
boost::unordered_map<T,T>& y)
|
||||
void call_swap(boost::unordered_map<T, T>& x, boost::unordered_map<T, T>& y)
|
||||
{
|
||||
swap(x,y);
|
||||
swap(x, y);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool call_equals(boost::unordered_map<T,T>& x,
|
||||
boost::unordered_map<T,T>& y)
|
||||
bool call_equals(boost::unordered_map<T, T>& x, boost::unordered_map<T, T>& y)
|
||||
{
|
||||
return x == y;
|
||||
return x == y;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool call_not_equals(boost::unordered_map<T,T>& x,
|
||||
boost::unordered_map<T,T>& y)
|
||||
bool call_not_equals(
|
||||
boost::unordered_map<T, T>& x, boost::unordered_map<T, T>& y)
|
||||
{
|
||||
return x != y;
|
||||
return x != y;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void call_swap(boost::unordered_multimap<T,T>& x,
|
||||
boost::unordered_multimap<T,T>& y)
|
||||
void call_swap(
|
||||
boost::unordered_multimap<T, T>& x, boost::unordered_multimap<T, T>& y)
|
||||
{
|
||||
swap(x,y);
|
||||
swap(x, y);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool call_equals(boost::unordered_multimap<T,T>& x,
|
||||
boost::unordered_multimap<T,T>& y)
|
||||
bool call_equals(
|
||||
boost::unordered_multimap<T, T>& x, boost::unordered_multimap<T, T>& y)
|
||||
{
|
||||
return x == y;
|
||||
return x == y;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool call_not_equals(boost::unordered_multimap<T,T>& x,
|
||||
boost::unordered_multimap<T,T>& y)
|
||||
bool call_not_equals(
|
||||
boost::unordered_multimap<T, T>& x, boost::unordered_multimap<T, T>& y)
|
||||
{
|
||||
return x != y;
|
||||
return x != y;
|
||||
}
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
@ -55,27 +55,27 @@ bool call_not_equals(boost::unordered_multimap<T,T>& x,
|
||||
typedef boost::unordered_map<int, int> int_map;
|
||||
typedef boost::unordered_multimap<int, int> int_multimap;
|
||||
|
||||
UNORDERED_AUTO_TEST(use_map_fwd_declared_function) {
|
||||
int_map x, y;
|
||||
x[1] = 2;
|
||||
y[2] = 1;
|
||||
call_swap(x, y);
|
||||
UNORDERED_AUTO_TEST (use_map_fwd_declared_function) {
|
||||
int_map x, y;
|
||||
x[1] = 2;
|
||||
y[2] = 1;
|
||||
call_swap(x, y);
|
||||
|
||||
BOOST_TEST(y.find(1) != y.end() && y.find(1)->second == 2);
|
||||
BOOST_TEST(y.find(2) == y.end());
|
||||
BOOST_TEST(y.find(1) != y.end() && y.find(1)->second == 2);
|
||||
BOOST_TEST(y.find(2) == y.end());
|
||||
|
||||
BOOST_TEST(x.find(1) == x.end());
|
||||
BOOST_TEST(x.find(2) != x.end() && x.find(2)->second == 1);
|
||||
BOOST_TEST(x.find(1) == x.end());
|
||||
BOOST_TEST(x.find(2) != x.end() && x.find(2)->second == 1);
|
||||
|
||||
BOOST_TEST(!call_equals(x, y));
|
||||
BOOST_TEST(call_not_equals(x, y));
|
||||
BOOST_TEST(!call_equals(x, y));
|
||||
BOOST_TEST(call_not_equals(x, y));
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(use_multimap_fwd_declared_function) {
|
||||
int_multimap x, y;
|
||||
call_swap(x, y);
|
||||
BOOST_TEST(call_equals(x, y));
|
||||
BOOST_TEST(!call_not_equals(x, y));
|
||||
UNORDERED_AUTO_TEST (use_multimap_fwd_declared_function) {
|
||||
int_multimap x, y;
|
||||
call_swap(x, y);
|
||||
BOOST_TEST(call_equals(x, y));
|
||||
BOOST_TEST(!call_not_equals(x, y));
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -3,59 +3,63 @@
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered/unordered_set_fwd.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
struct true_type { char x[100]; };
|
||||
struct false_type { char x; };
|
||||
struct true_type
|
||||
{
|
||||
char x[100];
|
||||
};
|
||||
struct false_type
|
||||
{
|
||||
char x;
|
||||
};
|
||||
|
||||
false_type is_unordered_set_impl(void*);
|
||||
|
||||
template <class Value, class Hash, class Pred, class Alloc>
|
||||
true_type is_unordered_set_impl(
|
||||
boost::unordered_set<Value, Hash, Pred, Alloc>*);
|
||||
boost::unordered_set<Value, Hash, Pred, Alloc>*);
|
||||
|
||||
template<typename T>
|
||||
void call_swap(boost::unordered_set<T>& x,
|
||||
boost::unordered_set<T>& y)
|
||||
template <typename T>
|
||||
void call_swap(boost::unordered_set<T>& x, boost::unordered_set<T>& y)
|
||||
{
|
||||
swap(x,y);
|
||||
swap(x, y);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool call_equals(boost::unordered_set<T>& x,
|
||||
boost::unordered_set<T>& y)
|
||||
template <typename T>
|
||||
bool call_equals(boost::unordered_set<T>& x, boost::unordered_set<T>& y)
|
||||
{
|
||||
return x == y;
|
||||
return x == y;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool call_not_equals(boost::unordered_set<T>& x,
|
||||
boost::unordered_set<T>& y)
|
||||
template <typename T>
|
||||
bool call_not_equals(boost::unordered_set<T>& x, boost::unordered_set<T>& y)
|
||||
{
|
||||
return x != y;
|
||||
return x != y;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void call_swap(boost::unordered_multiset<T>& x,
|
||||
boost::unordered_multiset<T>& y)
|
||||
template <typename T>
|
||||
void call_swap(boost::unordered_multiset<T>& x, boost::unordered_multiset<T>& y)
|
||||
{
|
||||
swap(x,y);
|
||||
swap(x, y);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool call_equals(boost::unordered_multiset<T>& x,
|
||||
boost::unordered_multiset<T>& y)
|
||||
template <typename T>
|
||||
bool call_equals(
|
||||
boost::unordered_multiset<T>& x, boost::unordered_multiset<T>& y)
|
||||
{
|
||||
return x == y;
|
||||
return x == y;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool call_not_equals(boost::unordered_multiset<T>& x,
|
||||
boost::unordered_multiset<T>& y)
|
||||
template <typename T>
|
||||
bool call_not_equals(
|
||||
boost::unordered_multiset<T>& x, boost::unordered_multiset<T>& y)
|
||||
{
|
||||
return x != y;
|
||||
return x != y;
|
||||
}
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
@ -63,41 +67,40 @@ bool call_not_equals(boost::unordered_multiset<T>& x,
|
||||
typedef boost::unordered_set<int> int_set;
|
||||
typedef boost::unordered_multiset<int> int_multiset;
|
||||
|
||||
UNORDERED_AUTO_TEST(use_fwd_declared_trait_without_definition) {
|
||||
BOOST_TEST(sizeof(is_unordered_set_impl((int_set*) 0))
|
||||
== sizeof(true_type));
|
||||
UNORDERED_AUTO_TEST (use_fwd_declared_trait_without_definition) {
|
||||
BOOST_TEST(sizeof(is_unordered_set_impl((int_set*)0)) == sizeof(true_type));
|
||||
}
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
|
||||
UNORDERED_AUTO_TEST(use_fwd_declared_trait) {
|
||||
boost::unordered_set<int> x;
|
||||
BOOST_TEST(sizeof(is_unordered_set_impl(&x)) == sizeof(true_type));
|
||||
UNORDERED_AUTO_TEST (use_fwd_declared_trait) {
|
||||
boost::unordered_set<int> x;
|
||||
BOOST_TEST(sizeof(is_unordered_set_impl(&x)) == sizeof(true_type));
|
||||
|
||||
BOOST_TEST(sizeof(is_unordered_set_impl((int*) 0)) == sizeof(false_type));
|
||||
BOOST_TEST(sizeof(is_unordered_set_impl((int*)0)) == sizeof(false_type));
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(use_set_fwd_declared_function) {
|
||||
int_set x, y;
|
||||
x.insert(1);
|
||||
y.insert(2);
|
||||
call_swap(x, y);
|
||||
UNORDERED_AUTO_TEST (use_set_fwd_declared_function) {
|
||||
int_set x, y;
|
||||
x.insert(1);
|
||||
y.insert(2);
|
||||
call_swap(x, y);
|
||||
|
||||
BOOST_TEST(y.find(1) != y.end());
|
||||
BOOST_TEST(y.find(2) == y.end());
|
||||
BOOST_TEST(y.find(1) != y.end());
|
||||
BOOST_TEST(y.find(2) == y.end());
|
||||
|
||||
BOOST_TEST(x.find(1) == x.end());
|
||||
BOOST_TEST(x.find(2) != x.end());
|
||||
BOOST_TEST(x.find(1) == x.end());
|
||||
BOOST_TEST(x.find(2) != x.end());
|
||||
|
||||
BOOST_TEST(!call_equals(x, y));
|
||||
BOOST_TEST(call_not_equals(x, y));
|
||||
BOOST_TEST(!call_equals(x, y));
|
||||
BOOST_TEST(call_not_equals(x, y));
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(use_multiset_fwd_declared_function) {
|
||||
int_multiset x, y;
|
||||
call_swap(x, y);
|
||||
BOOST_TEST(call_equals(x, y));
|
||||
BOOST_TEST(!call_not_equals(x, y));
|
||||
UNORDERED_AUTO_TEST (use_multiset_fwd_declared_function) {
|
||||
int_multiset x, y;
|
||||
call_swap(x, y);
|
||||
BOOST_TEST(call_equals(x, y));
|
||||
BOOST_TEST(!call_not_equals(x, y));
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -3,151 +3,171 @@
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace x
|
||||
{
|
||||
struct D { boost::unordered_map<D, D> x; };
|
||||
namespace x {
|
||||
struct D
|
||||
{
|
||||
boost::unordered_map<D, D> x;
|
||||
};
|
||||
}
|
||||
|
||||
namespace incomplete_test
|
||||
{
|
||||
// Declare, but don't define some types.
|
||||
namespace incomplete_test {
|
||||
// Declare, but don't define some types.
|
||||
|
||||
struct value;
|
||||
struct hash;
|
||||
struct equals;
|
||||
template <class T> struct allocator;
|
||||
struct value;
|
||||
struct hash;
|
||||
struct equals;
|
||||
template <class T> struct allocator;
|
||||
|
||||
// Declare some instances
|
||||
|
||||
typedef boost::unordered_map<value, value, hash, equals,
|
||||
allocator<std::pair<value const, value> > > map;
|
||||
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;
|
||||
typedef boost::unordered_multiset<value, hash, equals,
|
||||
allocator<value> > multiset;
|
||||
|
||||
// Now define the types which are stored as members, as they are needed for
|
||||
// declaring struct members.
|
||||
// Declare some instances
|
||||
|
||||
struct hash {
|
||||
template <typename T>
|
||||
std::size_t operator()(T const&) const { return 0; }
|
||||
};
|
||||
typedef boost::unordered_map<value, value, hash, equals,
|
||||
allocator<std::pair<value const, value> > >
|
||||
map;
|
||||
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;
|
||||
typedef boost::unordered_multiset<value, hash, equals, allocator<value> >
|
||||
multiset;
|
||||
|
||||
struct equals {
|
||||
template <typename T>
|
||||
bool operator()(T const&, T const&) const { return true; }
|
||||
};
|
||||
// Now define the types which are stored as members, as they are needed for
|
||||
// declaring struct members.
|
||||
|
||||
// This is a dubious way to implement an allocator, but good enough
|
||||
// for this test.
|
||||
template <typename T>
|
||||
struct allocator : std::allocator<T> {
|
||||
allocator() {}
|
||||
struct hash
|
||||
{
|
||||
template <typename T> std::size_t operator()(T const&) const { return 0; }
|
||||
};
|
||||
|
||||
template <typename T2>
|
||||
allocator(const allocator<T2>& other) :
|
||||
std::allocator<T>(other) {}
|
||||
};
|
||||
|
||||
// Declare some members of a structs.
|
||||
//
|
||||
// Incomplete hash, equals and allocator aren't here supported at the
|
||||
// moment.
|
||||
|
||||
struct struct1 {
|
||||
boost::unordered_map<struct1, struct1, hash, equals,
|
||||
allocator<std::pair<struct1 const, struct1> > > x;
|
||||
};
|
||||
struct struct2 {
|
||||
boost::unordered_multimap<struct2, struct2, hash, equals,
|
||||
allocator<std::pair<struct2 const, struct2> > > x;
|
||||
};
|
||||
struct struct3 {
|
||||
boost::unordered_set<struct3, hash, equals,
|
||||
allocator<struct3> > x;
|
||||
};
|
||||
struct struct4 {
|
||||
boost::unordered_multiset<struct4, hash, equals,
|
||||
allocator<struct4> > x;
|
||||
};
|
||||
|
||||
// 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::struct1 c1;
|
||||
incomplete_test::struct2 c2;
|
||||
incomplete_test::struct3 c3;
|
||||
incomplete_test::struct4 c4;
|
||||
|
||||
// Now declare, but don't define, the operators required for comparing
|
||||
// elements.
|
||||
|
||||
std::size_t hash_value(value const&);
|
||||
bool operator==(value const&, value const&);
|
||||
|
||||
std::size_t hash_value(struct1 const&);
|
||||
std::size_t hash_value(struct2 const&);
|
||||
std::size_t hash_value(struct3 const&);
|
||||
std::size_t hash_value(struct4 const&);
|
||||
|
||||
bool operator==(struct1 const&, struct1 const&);
|
||||
bool operator==(struct2 const&, struct2 const&);
|
||||
bool operator==(struct3 const&, struct3 const&);
|
||||
bool operator==(struct4 const&, struct4 const&);
|
||||
|
||||
// And finally use these
|
||||
|
||||
void use_types()
|
||||
struct equals
|
||||
{
|
||||
template <typename T> bool operator()(T const&, T const&) const
|
||||
{
|
||||
incomplete_test::value x;
|
||||
m1[x] = x;
|
||||
m2.insert(std::make_pair(x, x));
|
||||
s1.insert(x);
|
||||
s2.insert(x);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
c1.x.insert(std::make_pair(c1, c1));
|
||||
c2.x.insert(std::make_pair(c2, c2));
|
||||
c3.x.insert(c3);
|
||||
c4.x.insert(c4);
|
||||
// This is a dubious way to implement an allocator, but good enough
|
||||
// for this test.
|
||||
template <typename T> struct allocator : std::allocator<T>
|
||||
{
|
||||
allocator() {}
|
||||
|
||||
template <typename T2>
|
||||
allocator(const allocator<T2>& other) : std::allocator<T>(other)
|
||||
{
|
||||
}
|
||||
|
||||
// And finally define the operators required for comparing elements.
|
||||
template <typename T2>
|
||||
allocator(const std::allocator<T2>& other) : std::allocator<T>(other)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
std::size_t hash_value(value const&) { return 0; }
|
||||
bool operator==(value const&, value const&) { return true; }
|
||||
// Declare some members of a structs.
|
||||
//
|
||||
// Incomplete hash, equals and allocator aren't here supported at the
|
||||
// moment.
|
||||
|
||||
std::size_t hash_value(struct1 const&) { return 0; }
|
||||
std::size_t hash_value(struct2 const&) { return 0; }
|
||||
std::size_t hash_value(struct3 const&) { return 0; }
|
||||
std::size_t hash_value(struct4 const&) { return 0; }
|
||||
|
||||
bool operator==(struct1 const&, struct1 const&) { return true; }
|
||||
bool operator==(struct2 const&, struct2 const&) { return true; }
|
||||
bool operator==(struct3 const&, struct3 const&) { return true; }
|
||||
bool operator==(struct4 const&, struct4 const&) { return true; }
|
||||
struct struct1
|
||||
{
|
||||
boost::unordered_map<struct1, struct1, hash, equals,
|
||||
allocator<std::pair<struct1 const, struct1> > >
|
||||
x;
|
||||
};
|
||||
struct struct2
|
||||
{
|
||||
boost::unordered_multimap<struct2, struct2, hash, equals,
|
||||
allocator<std::pair<struct2 const, struct2> > >
|
||||
x;
|
||||
};
|
||||
struct struct3
|
||||
{
|
||||
boost::unordered_set<struct3, hash, equals, allocator<struct3> > x;
|
||||
};
|
||||
struct struct4
|
||||
{
|
||||
boost::unordered_multiset<struct4, hash, equals, allocator<struct4> > x;
|
||||
};
|
||||
|
||||
// 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::struct1 c1;
|
||||
incomplete_test::struct2 c2;
|
||||
incomplete_test::struct3 c3;
|
||||
incomplete_test::struct4 c4;
|
||||
|
||||
// Now declare, but don't define, the operators required for comparing
|
||||
// elements.
|
||||
|
||||
std::size_t hash_value(value const&);
|
||||
bool operator==(value const&, value const&);
|
||||
|
||||
std::size_t hash_value(struct1 const&);
|
||||
std::size_t hash_value(struct2 const&);
|
||||
std::size_t hash_value(struct3 const&);
|
||||
std::size_t hash_value(struct4 const&);
|
||||
|
||||
bool operator==(struct1 const&, struct1 const&);
|
||||
bool operator==(struct2 const&, struct2 const&);
|
||||
bool operator==(struct3 const&, struct3 const&);
|
||||
bool operator==(struct4 const&, struct4 const&);
|
||||
|
||||
// And finally use these
|
||||
|
||||
void use_types()
|
||||
{
|
||||
incomplete_test::value x;
|
||||
m1[x] = x;
|
||||
m2.insert(std::make_pair(x, x));
|
||||
s1.insert(x);
|
||||
s2.insert(x);
|
||||
|
||||
c1.x.insert(std::make_pair(c1, c1));
|
||||
c2.x.insert(std::make_pair(c2, c2));
|
||||
c3.x.insert(c3);
|
||||
c4.x.insert(c4);
|
||||
}
|
||||
|
||||
// And finally define the operators required for comparing elements.
|
||||
|
||||
std::size_t hash_value(value const&) { return 0; }
|
||||
bool operator==(value const&, value const&) { return true; }
|
||||
|
||||
std::size_t hash_value(struct1 const&) { return 0; }
|
||||
std::size_t hash_value(struct2 const&) { return 0; }
|
||||
std::size_t hash_value(struct3 const&) { return 0; }
|
||||
std::size_t hash_value(struct4 const&) { return 0; }
|
||||
|
||||
bool operator==(struct1 const&, struct1 const&) { return true; }
|
||||
bool operator==(struct2 const&, struct2 const&) { return true; }
|
||||
bool operator==(struct3 const&, struct3 const&) { return true; }
|
||||
bool operator==(struct4 const&, struct4 const&) { return true; }
|
||||
}
|
||||
|
||||
int main() {
|
||||
// This could just be a compile test, but I like to be able to run these
|
||||
// things. It's probably irrational, but I find it reassuring.
|
||||
int main()
|
||||
{
|
||||
// This could just be a compile test, but I like to be able to run these
|
||||
// things. It's probably irrational, but I find it reassuring.
|
||||
|
||||
incomplete_test::use_types();
|
||||
incomplete_test::use_types();
|
||||
}
|
||||
|
121
test/unordered/insert_hint_tests.cpp
Normal file
121
test/unordered/insert_hint_tests.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
|
||||
// Copyright 2016 Daniel James.
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace insert_hint {
|
||||
UNORDERED_AUTO_TEST (insert_hint_empty) {
|
||||
typedef boost::unordered_multiset<int> container;
|
||||
container x;
|
||||
x.insert(x.cbegin(), 10);
|
||||
BOOST_TEST_EQ(x.size(), 1u);
|
||||
BOOST_TEST_EQ(x.count(10), 1u);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (insert_hint_empty2) {
|
||||
typedef boost::unordered_multimap<std::string, int> container;
|
||||
container x;
|
||||
x.emplace_hint(x.cbegin(), "hello", 50);
|
||||
BOOST_TEST_EQ(x.size(), 1u);
|
||||
BOOST_TEST_EQ(x.count("hello"), 1u);
|
||||
BOOST_TEST_EQ(x.find("hello")->second, 50);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (insert_hint_single) {
|
||||
typedef boost::unordered_multiset<std::string> container;
|
||||
container x;
|
||||
x.insert("equal");
|
||||
x.insert(x.cbegin(), "equal");
|
||||
BOOST_TEST_EQ(x.size(), 2u);
|
||||
BOOST_TEST_EQ(x.count("equal"), 2u);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (insert_hint_single2) {
|
||||
typedef boost::unordered_multimap<int, std::string> container;
|
||||
container x;
|
||||
x.emplace(10, "one");
|
||||
x.emplace_hint(x.cbegin(), 10, "two");
|
||||
BOOST_TEST_EQ(x.size(), 2u);
|
||||
BOOST_TEST_EQ(x.count(10), 2u);
|
||||
|
||||
container::iterator it = x.find(10);
|
||||
std::string v0 = (it++)->second;
|
||||
std::string v1 = (it++)->second;
|
||||
|
||||
BOOST_TEST(v0 == "one" || v0 == "two");
|
||||
BOOST_TEST(v1 == "one" || v1 == "two");
|
||||
BOOST_TEST(v0 != v1);
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (insert_hint_multiple) {
|
||||
for (unsigned int size = 0; size < 10; ++size) {
|
||||
for (unsigned int offset = 0; offset <= size; ++offset) {
|
||||
typedef boost::unordered_multiset<std::string> container;
|
||||
container x;
|
||||
|
||||
for (unsigned int i = 0; i < size; ++i) {
|
||||
x.insert("multiple");
|
||||
}
|
||||
|
||||
BOOST_TEST_EQ(x.size(), size);
|
||||
|
||||
container::const_iterator position = x.cbegin();
|
||||
for (unsigned int i = 0; i < offset; ++i) {
|
||||
++position;
|
||||
}
|
||||
|
||||
x.insert(position, "multiple");
|
||||
|
||||
BOOST_TEST_EQ(x.size(), size + 1u);
|
||||
BOOST_TEST_EQ(x.count("multiple"), size + 1u);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (insert_hint_unique) {
|
||||
typedef boost::unordered_set<int> container;
|
||||
container x;
|
||||
x.insert(x.cbegin(), 10);
|
||||
BOOST_TEST_EQ(x.size(), 1u);
|
||||
BOOST_TEST_EQ(x.count(10), 1u);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (insert_hint_unique_single) {
|
||||
typedef boost::unordered_set<int> container;
|
||||
container x;
|
||||
x.insert(10);
|
||||
|
||||
x.insert(x.cbegin(), 10);
|
||||
BOOST_TEST_EQ(x.size(), 1u);
|
||||
BOOST_TEST_EQ(x.count(10), 1u);
|
||||
test::check_equivalent_keys(x);
|
||||
|
||||
x.insert(x.cbegin(), 20);
|
||||
BOOST_TEST_EQ(x.size(), 2u);
|
||||
BOOST_TEST_EQ(x.count(10), 1u);
|
||||
BOOST_TEST_EQ(x.count(20), 1u);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
34
test/unordered/insert_node_type_fail.cpp
Normal file
34
test/unordered/insert_node_type_fail.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
|
||||
// Copyright 2017 Daniel James.
|
||||
// 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 <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
|
||||
int main()
|
||||
{
|
||||
#if defined(UNORDERED_TEST_MAP)
|
||||
typedef boost::unordered_map<int, int> container;
|
||||
container x;
|
||||
x.emplace(1, 1);
|
||||
#elif defined(UNORDERED_TEST_MULTIMAP)
|
||||
typedef boost::unordered_multimap<int, int> container;
|
||||
container x;
|
||||
#elif defined(UNORDERED_TEST_SET)
|
||||
typedef boost::unordered_set<int> container;
|
||||
container x;
|
||||
x.emplace(1);
|
||||
#elif defined(UNORDERED_TEST_MULTISET)
|
||||
typedef boost::unordered_multiset<int> container;
|
||||
container x;
|
||||
x.emplace(1);
|
||||
#else
|
||||
#define UNORDERED_ERROR
|
||||
#endif
|
||||
|
||||
#if !defined(UNORDERED_ERROR)
|
||||
container::node_type n = x.extract(x.begin());
|
||||
x.insert(n);
|
||||
#endif
|
||||
}
|
@ -3,32 +3,34 @@
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
|
||||
#include <iostream>
|
||||
namespace insert_stable {
|
||||
struct member
|
||||
{
|
||||
int tag1_;
|
||||
int tag2_;
|
||||
|
||||
namespace insert_stable
|
||||
{
|
||||
struct member {
|
||||
int tag1_;
|
||||
int tag2_;
|
||||
|
||||
member() : tag1_(0), tag2_(0) {}
|
||||
member(int t1, int t2) : tag1_(t1), tag2_(t2) {}
|
||||
|
||||
friend bool operator==(member const& x, member const& y) {
|
||||
return x.tag1_ == y.tag1_;
|
||||
}
|
||||
|
||||
friend bool operator!=(member const& x, member const& y) {
|
||||
return x.tag1_ != y.tag1_;
|
||||
}
|
||||
};
|
||||
member() : tag1_(0), tag2_(0) {}
|
||||
member(int t1, int t2) : tag1_(t1), tag2_(t2) {}
|
||||
|
||||
friend bool operator==(member const& x, member const& y)
|
||||
{
|
||||
return x.tag1_ == y.tag1_;
|
||||
}
|
||||
|
||||
friend bool operator!=(member const& x, member const& y)
|
||||
{
|
||||
return x.tag1_ != y.tag1_;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP
|
||||
@ -37,49 +39,79 @@ namespace boost
|
||||
namespace insert_stable
|
||||
#endif
|
||||
{
|
||||
std::size_t hash_value(insert_stable::member const& x) {
|
||||
return static_cast<std::size_t>(x.tag1_);
|
||||
}
|
||||
std::size_t hash_value(insert_stable::member const& x)
|
||||
{
|
||||
return static_cast<std::size_t>(x.tag1_);
|
||||
}
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(stable_insert_test1) {
|
||||
// This is no longer supported, as there's no longer an efficient way to get to
|
||||
// the end of a group of equivalent nodes.
|
||||
#if 0
|
||||
|
||||
UNORDERED_AUTO_TEST(stable_insert_test1)
|
||||
{
|
||||
boost::unordered_multiset<insert_stable::member> x;
|
||||
|
||||
x.insert(insert_stable::member(1,1));
|
||||
x.insert(insert_stable::member(1,2));
|
||||
x.insert(insert_stable::member(1,3));
|
||||
x.insert(insert_stable::member(1, 1));
|
||||
x.insert(insert_stable::member(1, 2));
|
||||
x.insert(insert_stable::member(1, 3));
|
||||
|
||||
BOOST_TEST(x.count(insert_stable::member(1, 4)) == 3);
|
||||
|
||||
boost::unordered_multiset<insert_stable::member>::const_iterator
|
||||
it = x.begin(), end = x.end();
|
||||
it = x.begin(),
|
||||
end = x.end();
|
||||
BOOST_TEST(it != end);
|
||||
if(it != end) { BOOST_TEST(it->tag2_ == 1); ++it; }
|
||||
if (it != end) {
|
||||
BOOST_TEST(it->tag2_ == 1);
|
||||
++it;
|
||||
}
|
||||
BOOST_TEST(it != end);
|
||||
if(it != end) { BOOST_TEST(it->tag2_ == 2); ++it; }
|
||||
if (it != end) {
|
||||
BOOST_TEST(it->tag2_ == 2);
|
||||
++it;
|
||||
}
|
||||
BOOST_TEST(it != end);
|
||||
if(it != end) { BOOST_TEST(it->tag2_ == 3); ++it; }
|
||||
if (it != end) {
|
||||
BOOST_TEST(it->tag2_ == 3);
|
||||
++it;
|
||||
}
|
||||
BOOST_TEST(it == end);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(stable_insert_test2) {
|
||||
UNORDERED_AUTO_TEST(stable_insert_test2)
|
||||
{
|
||||
boost::unordered_multimap<insert_stable::member, int> x;
|
||||
typedef
|
||||
boost::unordered_multimap<insert_stable::member, int>::const_iterator
|
||||
iterator;
|
||||
typedef boost::unordered_multimap<insert_stable::member,
|
||||
int>::const_iterator iterator;
|
||||
|
||||
iterator it
|
||||
= x.insert(x.end(), std::make_pair(insert_stable::member(1,1), 1));
|
||||
it = x.insert(it, std::make_pair(insert_stable::member(1,2), 2));
|
||||
it = x.insert(it, std::make_pair(insert_stable::member(1,3), 3));
|
||||
iterator it = x.emplace(insert_stable::member(1, 1), 1);
|
||||
it = x.emplace(insert_stable::member(1, 2), 2);
|
||||
it = x.emplace(insert_stable::member(1, 3), 3);
|
||||
|
||||
BOOST_TEST(x.count(insert_stable::member(1, 4)) == 3);
|
||||
|
||||
it = x.begin();
|
||||
iterator end = x.end();
|
||||
BOOST_TEST(it != end);
|
||||
if(it != end) { BOOST_TEST(it->first.tag2_ == 1 && it->second == 1); ++it; }
|
||||
if (it != end) {
|
||||
BOOST_TEST(it->first.tag2_ == 1 && it->second == 1);
|
||||
++it;
|
||||
}
|
||||
BOOST_TEST(it != end);
|
||||
if(it != end) { BOOST_TEST(it->first.tag2_ == 2 && it->second == 2); ++it; }
|
||||
if (it != end) {
|
||||
BOOST_TEST(it->first.tag2_ == 2 && it->second == 2);
|
||||
++it;
|
||||
}
|
||||
BOOST_TEST(it != end);
|
||||
if(it != end) { BOOST_TEST(it->first.tag2_ == 3 && it->second == 3); ++it; }
|
||||
if (it != end) {
|
||||
BOOST_TEST(it->first.tag2_ == 3 && it->second == 3);
|
||||
++it;
|
||||
}
|
||||
BOOST_TEST(it == end);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
RUN_TESTS()
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -3,24 +3,24 @@
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
void foo(boost::unordered_set<int>&,
|
||||
boost::unordered_map<int, int>&,
|
||||
boost::unordered_multiset<int>&,
|
||||
boost::unordered_multimap<int, int>&);
|
||||
void foo(boost::unordered_set<int>&, boost::unordered_map<int, int>&,
|
||||
boost::unordered_multiset<int>&, boost::unordered_multimap<int, int>&);
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::unordered_set<int> x1;
|
||||
boost::unordered_map<int, int> x2;
|
||||
boost::unordered_multiset<int> x3;
|
||||
boost::unordered_multimap<int, int> x4;
|
||||
boost::unordered_set<int> x1;
|
||||
boost::unordered_map<int, int> x2;
|
||||
boost::unordered_multiset<int> x3;
|
||||
boost::unordered_multimap<int, int> x4;
|
||||
|
||||
foo(x1, x2, x3, x4);
|
||||
|
||||
return 0;
|
||||
foo(x1, x2, x3, x4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -3,27 +3,28 @@
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
void foo(boost::unordered_set<int>& x1,
|
||||
boost::unordered_map<int, int>& x2,
|
||||
boost::unordered_multiset<int>& x3,
|
||||
boost::unordered_multimap<int, int>& x4)
|
||||
void foo(boost::unordered_set<int>& x1, boost::unordered_map<int, int>& x2,
|
||||
boost::unordered_multiset<int>& x3, boost::unordered_multimap<int, int>& x4)
|
||||
{
|
||||
#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
|
||||
struct dummy {
|
||||
boost::unordered_set<int> x1;
|
||||
boost::unordered_map<int, int> x2;
|
||||
boost::unordered_multiset<int> x3;
|
||||
boost::unordered_multimap<int, int> x4;
|
||||
};
|
||||
struct dummy
|
||||
{
|
||||
boost::unordered_set<int> x1;
|
||||
boost::unordered_map<int, int> x2;
|
||||
boost::unordered_multiset<int> x3;
|
||||
boost::unordered_multimap<int, int> x4;
|
||||
};
|
||||
#endif
|
||||
|
||||
x1.insert(1);
|
||||
x2[2] = 2;
|
||||
x3.insert(3);
|
||||
x4.insert(std::make_pair(4, 5));
|
||||
x1.insert(1);
|
||||
x2[2] = 2;
|
||||
x3.insert(3);
|
||||
x4.insert(std::make_pair(4, 5));
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user