diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
commit | 483eb2f56657e8e7f419ab1a4fab8dce9ade8609 (patch) | |
tree | e5d88d25d870d5dedacb6bbdbe2a966086a0a5cf /src/boost/libs/unordered | |
parent | Initial commit. (diff) | |
download | ceph-483eb2f56657e8e7f419ab1a4fab8dce9ade8609.tar.xz ceph-483eb2f56657e8e7f419ab1a4fab8dce9ade8609.zip |
Adding upstream version 14.2.21.upstream/14.2.21upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/boost/libs/unordered')
79 files changed, 16326 insertions, 0 deletions
diff --git a/src/boost/libs/unordered/_clang-format b/src/boost/libs/unordered/_clang-format new file mode 100644 index 00000000..d892b414 --- /dev/null +++ b/src/boost/libs/unordered/_clang-format @@ -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 ] diff --git a/src/boost/libs/unordered/ci/download-boost-snapshot.py b/src/boost/libs/unordered/ci/download-boost-snapshot.py new file mode 100644 index 00000000..a9d8ba98 --- /dev/null +++ b/src/boost/libs/unordered/ci/download-boost-snapshot.py @@ -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]) diff --git a/src/boost/libs/unordered/examples/case_insensitive.hpp b/src/boost/libs/unordered/examples/case_insensitive.hpp new file mode 100644 index 00000000..83a388d8 --- /dev/null +++ b/src/boost/libs/unordered/examples/case_insensitive.hpp @@ -0,0 +1,58 @@ + +// 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) + +// This file implements a locale aware case insenstive equality predicate and +// hash function. Unfortunately it still falls short of full +// internationalization as it only deals with a single character at a time +// (some languages have tricky cases where the characters in an upper case +// string don't have a one-to-one correspondence with the lower case version of +// the text, eg. ) + +#if !defined(BOOST_HASH_EXAMPLES_CASE_INSENSITIVE_HEADER) +#define BOOST_HASH_EXAMPLES_CASE_INSENSITIVE_HEADER + +#include <boost/algorithm/string/predicate.hpp> +#include <boost/functional/hash.hpp> + +namespace hash_examples +{ + struct iequal_to + { + iequal_to() {} + explicit iequal_to(std::locale const& l) : locale_(l) {} + + template <typename String1, typename String2> + bool operator()(String1 const& x1, String2 const& x2) const + { + return boost::algorithm::iequals(x1, x2, locale_); + } + private: + std::locale locale_; + }; + + struct ihash + { + ihash() {} + explicit ihash(std::locale const& l) : locale_(l) {} + + template <typename String> + std::size_t operator()(String const& x) const + { + std::size_t seed = 0; + + for(typename String::const_iterator it = x.begin(); + it != x.end(); ++it) + { + boost::hash_combine(seed, std::toupper(*it, locale_)); + } + + return seed; + } + private: + std::locale locale_; + }; +} + +#endif diff --git a/src/boost/libs/unordered/examples/case_insensitive_test.cpp b/src/boost/libs/unordered/examples/case_insensitive_test.cpp new file mode 100644 index 00000000..b717c130 --- /dev/null +++ b/src/boost/libs/unordered/examples/case_insensitive_test.cpp @@ -0,0 +1,82 @@ + +// 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 "./case_insensitive.hpp" +#include <boost/core/lightweight_test.hpp> +#include <boost/unordered_map.hpp> + +struct word_info { + int tag; + explicit word_info(int t = 0) : tag(t) {} +}; + +void test1() { + boost::unordered_map<std::string, word_info, + hash_examples::ihash, hash_examples::iequal_to> idictionary; + + BOOST_TEST(idictionary.empty()); + + idictionary["one"] = word_info(1); + BOOST_TEST(idictionary.size() == 1); + BOOST_TEST(idictionary.find("ONE") != idictionary.end() && + idictionary.find("ONE") == idictionary.find("one")); + + idictionary.insert(std::make_pair("ONE", word_info(2))); + BOOST_TEST(idictionary.size() == 1); + BOOST_TEST(idictionary.find("ONE") != idictionary.end() && + idictionary.find("ONE")->first == "one" && + idictionary.find("ONE")->second.tag == 1); + + idictionary["One"] = word_info(3); + BOOST_TEST(idictionary.size() == 1); + BOOST_TEST(idictionary.find("ONE") != idictionary.end() && + idictionary.find("ONE")->first == "one" && + idictionary.find("ONE")->second.tag == 3); + + idictionary["two"] = word_info(4); + BOOST_TEST(idictionary.size() == 2); + BOOST_TEST(idictionary.find("two") != idictionary.end() && + idictionary.find("TWO")->first == "two" && + idictionary.find("Two")->second.tag == 4); + + +} + +void test2() { + boost::unordered_map<std::wstring, word_info, + hash_examples::ihash, hash_examples::iequal_to> idictionary; + + BOOST_TEST(idictionary.empty()); + + idictionary[L"one"] = word_info(1); + BOOST_TEST(idictionary.size() == 1); + BOOST_TEST(idictionary.find(L"ONE") != idictionary.end() && + idictionary.find(L"ONE") == idictionary.find(L"one")); + + idictionary.insert(std::make_pair(L"ONE", word_info(2))); + BOOST_TEST(idictionary.size() == 1); + BOOST_TEST(idictionary.find(L"ONE") != idictionary.end() && + idictionary.find(L"ONE")->first == L"one" && + idictionary.find(L"ONE")->second.tag == 1); + + idictionary[L"One"] = word_info(3); + BOOST_TEST(idictionary.size() == 1); + BOOST_TEST(idictionary.find(L"ONE") != idictionary.end() && + idictionary.find(L"ONE")->first == L"one" && + idictionary.find(L"ONE")->second.tag == 3); + + idictionary[L"two"] = word_info(4); + BOOST_TEST(idictionary.size() == 2); + BOOST_TEST(idictionary.find(L"two") != idictionary.end() && + idictionary.find(L"TWO")->first == L"two" && + idictionary.find(L"Two")->second.tag == 4); +} + +int main() { + test1(); + test2(); + + return boost::report_errors(); +} diff --git a/src/boost/libs/unordered/examples/fnv1.hpp b/src/boost/libs/unordered/examples/fnv1.hpp new file mode 100644 index 00000000..3337d136 --- /dev/null +++ b/src/boost/libs/unordered/examples/fnv1.hpp @@ -0,0 +1,69 @@ + +// Copyright 2008-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) + +// This code is also released into the public domain. + +// Algorithm from: http://www.isthe.com/chongo/tech/comp/fnv/ + +#include <string> + +namespace hash +{ + template <std::size_t FnvPrime, std::size_t OffsetBasis> + struct basic_fnv_1 + { + std::size_t operator()(std::string const& text) const + { + std::size_t hash = OffsetBasis; + for(std::string::const_iterator it = text.begin(), end = text.end(); + it != end; ++it) + { + hash *= FnvPrime; + hash ^= *it; + } + + return hash; + } + }; + + template <std::size_t FnvPrime, std::size_t OffsetBasis> + struct basic_fnv_1a + { + std::size_t operator()(std::string const& text) const + { + std::size_t hash = OffsetBasis; + for(std::string::const_iterator it = text.begin(), end = text.end(); + it != end; ++it) + { + hash ^= *it; + hash *= FnvPrime; + } + + return hash; + } + }; + + // For 32 bit machines: + const std::size_t fnv_prime = 16777619u; + const std::size_t fnv_offset_basis = 2166136261u; + + // For 64 bit machines: + // const std::size_t fnv_prime = 1099511628211u; + // const std::size_t fnv_offset_basis = 14695981039346656037u; + + // For 128 bit machines: + // const std::size_t fnv_prime = 309485009821345068724781401u; + // const std::size_t fnv_offset_basis = + // 275519064689413815358837431229664493455u; + + // For 256 bit machines: + // const std::size_t fnv_prime = + // 374144419156711147060143317175368453031918731002211u; + // const std::size_t fnv_offset_basis = + // 100029257958052580907070968620625704837092796014241193945225284501741471925557u; + + typedef basic_fnv_1<fnv_prime, fnv_offset_basis> fnv_1; + typedef basic_fnv_1a<fnv_prime, fnv_offset_basis> fnv_1a; +} diff --git a/src/boost/libs/unordered/index.html b/src/boost/libs/unordered/index.html new file mode 100644 index 00000000..a752386c --- /dev/null +++ b/src/boost/libs/unordered/index.html @@ -0,0 +1,16 @@ + +<!-- +Copyright 2005-2007 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) +--> + +<html> +<head> + <meta http-equiv="refresh" content="0; URL=../../doc/html/unordered.html"> +</head> +<body> +Automatic redirection failed, please go to +<a href="../../doc/html/unordered.html">../../doc/html/unordered.html</a> +</body> +</html> diff --git a/src/boost/libs/unordered/meta/explicit-failures-markup.xml b/src/boost/libs/unordered/meta/explicit-failures-markup.xml new file mode 100644 index 00000000..25a19e3d --- /dev/null +++ b/src/boost/libs/unordered/meta/explicit-failures-markup.xml @@ -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> + diff --git a/src/boost/libs/unordered/meta/libraries.json b/src/boost/libs/unordered/meta/libraries.json new file mode 100644 index 00000000..1cd5b6ce --- /dev/null +++ b/src/boost/libs/unordered/meta/libraries.json @@ -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" + ] +}
\ No newline at end of file diff --git a/src/boost/libs/unordered/test/Jamfile.v2 b/src/boost/libs/unordered/test/Jamfile.v2 new file mode 100644 index 00000000..67c31d98 --- /dev/null +++ b/src/boost/libs/unordered/test/Jamfile.v2 @@ -0,0 +1,97 @@ + +# 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 -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 ] + ; diff --git a/src/boost/libs/unordered/test/exception/assign_exception_tests.cpp b/src/boost/libs/unordered/test/exception/assign_exception_tests.cpp new file mode 100644 index 00000000..c62bf8ab --- /dev/null +++ b/src/boost/libs/unordered/test/exception/assign_exception_tests.cpp @@ -0,0 +1,185 @@ + +// 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) // assignment operator could not be generated +#endif + +test::seed_t initialize_seed(12847); + +template <class T> struct self_assign_base : public test::exception_base +{ + 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; + + 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> +{ + self_assign_test2() : self_assign_base<T>(100) {} +}; + +template <class T> struct 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; + + 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_values : assign_base<T> +{ + 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_test1 : assign_values<T> +{ + assign_test1() : assign_values<T>(0, 0, 0, 0) {} +}; + +template <class T> struct assign_test2 : assign_values<T> +{ + assign_test2() : assign_values<T>(60, 0, 0, 0) {} +}; + +template <class T> struct assign_test2a : assign_values<T> +{ + assign_test2a() : assign_values<T>(60, 0, 0, 0, test::limited_range) {} +}; + +template <class T> struct assign_test3 : assign_values<T> +{ + assign_test3() : assign_values<T>(0, 60, 0, 0) {} +}; + +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_test2a) + (assign_test3)(assign_test3a) + (assign_test4)(assign_test4a)(assign_test4b) + (assign_test5) + (equivalent_test1), + CONTAINER_SEQ) +// clang-format on + +RUN_TESTS() diff --git a/src/boost/libs/unordered/test/exception/constructor_exception_tests.cpp b/src/boost/libs/unordered/test/exception/constructor_exception_tests.cpp new file mode 100644 index 00000000..3dfebcef --- /dev/null +++ b/src/boost/libs/unordered/test/exception/constructor_exception_tests.cpp @@ -0,0 +1,212 @@ + +// 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/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&) {} + +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; +}; + +template <class T> struct construct_test1 : public objects, test::exception_base +{ + 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 +{ + 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 +{ + 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 +{ + 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 +{ + 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 +{ + 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 +{ + test::random_values<T> values; + + 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 +{ + 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 +{ + 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 +{ + 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 +{ + 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 +{ + range_construct_test5() : range<T>(60) {} + + 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 +{ + input_range_construct_test() : range<T>(60) {} + + 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 +{ + 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); + + 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) +// clang-format on + +RUN_TESTS() diff --git a/src/boost/libs/unordered/test/exception/containers.hpp b/src/boost/libs/unordered/test/exception/containers.hpp new file mode 100644 index 00000000..c3b34be2 --- /dev/null +++ b/src/boost/libs/unordered/test/exception/containers.hpp @@ -0,0 +1,44 @@ + +// 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) + +// 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< + 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< + 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) diff --git a/src/boost/libs/unordered/test/exception/copy_exception_tests.cpp b/src/boost/libs/unordered/test/exception/copy_exception_tests.cpp new file mode 100644 index 00000000..6149235a --- /dev/null +++ b/src/boost/libs/unordered/test/exception/copy_exception_tests.cpp @@ -0,0 +1,110 @@ + +// 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" + +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 +{ + T x; + + 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 +{ + test::random_values<T> values; + T x; + + copy_test2() : values(5, test::limited_range), x(values.begin(), values.end()) + { + } + + 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 +{ + test::random_values<T> values; + T x; + + copy_test3() : values(100), x(values.begin(), values.end()) {} + + void run() const + { + T y(x); + + DISABLE_EXCEPTIONS; + test::check_container(y, this->values); + test::check_equivalent_keys(y); + } +}; + +template <class T> struct copy_test3a : public test::exception_base +{ + test::random_values<T> values; + T x; + + copy_test3a() + : values(100, test::limited_range), x(values.begin(), values.end()) + { + } + + 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_test3a)(copy_with_allocator_test), + CONTAINER_SEQ) +// clang-format on + +RUN_TESTS() diff --git a/src/boost/libs/unordered/test/exception/erase_exception_tests.cpp b/src/boost/libs/unordered/test/exception/erase_exception_tests.cpp new file mode 100644 index 00000000..0f2c1eb6 --- /dev/null +++ b/src/boost/libs/unordered/test/exception/erase_exception_tests.cpp @@ -0,0 +1,55 @@ + +// 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/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 +{ + test::random_values<T> values; + erase_test_base(unsigned int count = 5) : values(count, test::limited_range) + { + } + + typedef T data_type; + + 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); + + BOOST_TEST(scope.find("hash::") != std::string::npos || + scope.find("equal_to::") != std::string::npos || + scope == "operator==(object, object)"); + + test::check_equivalent_keys(x); + } +}; + +template <class T> struct erase_by_key_test1 : public erase_test_base<T> +{ + 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)); + } + + DISABLE_EXCEPTIONS; + BOOST_TEST(x.empty()); + test::check_equivalent_keys(x); + } +}; + +EXCEPTION_TESTS((erase_by_key_test1), CONTAINER_SEQ) +RUN_TESTS() diff --git a/src/boost/libs/unordered/test/exception/insert_exception_tests.cpp b/src/boost/libs/unordered/test/exception/insert_exception_tests.cpp new file mode 100644 index 00000000..79074c5e --- /dev/null +++ b/src/boost/libs/unordered/test/exception/insert_exception_tests.cpp @@ -0,0 +1,416 @@ + +// 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/helpers.hpp" +#include "../helpers/invariants.hpp" +#include "../helpers/random_values.hpp" +#include "../helpers/strong.hpp" +#include "../helpers/tracker.hpp" +#include <cmath> +#include <string> + +test::seed_t initialize_seed(747373); + +// Fill in a container so that it's about to rehash +template <typename T> void rehash_prep(T& x) +{ + using namespace std; + typedef typename T::size_type size_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()); +} + +// 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; + } + + test::check_equivalent_keys(x); + insert.track(tracker, v.begin(), v.end()); + tracker.compare(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); + } +}; + +struct insert_lvalue_type : inserter_base +{ + template <typename T, typename Iterator> void operator()(T& x, Iterator it) + { + x.insert(*it); + } +} insert_lvalue; + +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)); + } +}; + +struct insert_lvalue_pos_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; + +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)); + } +}; + +struct emplace_lvalue_pos_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; + +// 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; + } + } +}; + +struct map_insert_operator_type : map_inserter_base +{ + template <typename T, typename Iterator> void operator()(T& x, Iterator it) + { + x[it->first] = it->second; + } +} map_insert_operator; + +struct map_insert_or_assign_type : map_inserter_base +{ + template <typename T, typename Iterator> void operator()(T& x, Iterator it) + { + x.insert_or_assign(it->first, it->second); + } +} map_insert_or_assign; + +// 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 + +// Range insert tests + +template <typename T, typename Values> +void insert_range_exception_test_impl(T x, Values const& v) +{ + test::ordered<T> tracker; + tracker.insert(x.begin(), x.end()); + + try { + ENABLE_EXCEPTIONS; + x.insert(v.begin(), v.end()); + } catch (...) { + test::check_equivalent_keys(x); + throw; + } + + test::check_equivalent_keys(x); + tracker.insert(v.begin(), v.end()); + tracker.compare(x); +} + +template <typename T> +void insert_range_exception_test(T*, test::random_generator gen) +{ + for (int i = 0; i < 5; ++i) { + test::random_values<T> v(10, gen); + T x; + + EXCEPTION_LOOP(insert_range_exception_test_impl(x, v)); + } +} + +template <typename T> +void insert_range_rehash_exception_test(T*, 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_range_exception_test_impl(x, v2)); + } +} + +// clang-format off +UNORDERED_TEST(insert_range_exception_test, + ((test_set_)(test_multiset_)(test_map_)(test_multimap_)) + ((default_generator)(limited_range)(generate_collisions)) +) + +UNORDERED_TEST(insert_range_rehash_exception_test, + ((test_set_)(test_multiset_)(test_map_)(test_multimap_)) + ((default_generator)(limited_range)(generate_collisions)) +) +// clang-format on + +RUN_TESTS() diff --git a/src/boost/libs/unordered/test/exception/merge_exception_tests.cpp b/src/boost/libs/unordered/test/exception/merge_exception_tests.cpp new file mode 100644 index 00000000..2cf7faf4 --- /dev/null +++ b/src/boost/libs/unordered/test/exception/merge_exception_tests.cpp @@ -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() diff --git a/src/boost/libs/unordered/test/exception/move_assign_exception_tests.cpp b/src/boost/libs/unordered/test/exception/move_assign_exception_tests.cpp new file mode 100644 index 00000000..6beb6820 --- /dev/null +++ b/src/boost/libs/unordered/test/exception/move_assign_exception_tests.cpp @@ -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() diff --git a/src/boost/libs/unordered/test/exception/rehash_exception_tests.cpp b/src/boost/libs/unordered/test/exception/rehash_exception_tests.cpp new file mode 100644 index 00000000..a927d136 --- /dev/null +++ b/src/boost/libs/unordered/test/exception/rehash_exception_tests.cpp @@ -0,0 +1,133 @@ + +// 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/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 +{ + 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; + + 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); + + 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); + } +}; + +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); + + DISABLE_EXCEPTIONS; + test::check_container(x, this->values); + test::check_equivalent_keys(x); + } +}; + +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); + + DISABLE_EXCEPTIONS; + test::check_container(x, this->values); + test::check_equivalent_keys(x); + } +}; + +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); + + DISABLE_EXCEPTIONS; + test::check_container(x, this->values); + test::check_equivalent_keys(x); + } +}; + +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); + + DISABLE_EXCEPTIONS; + test::check_container(x, this->values); + test::check_equivalent_keys(x); + } +}; + +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); + + 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) + (rehash_test5), + CONTAINER_SEQ) +// clang-format on + +RUN_TESTS() diff --git a/src/boost/libs/unordered/test/exception/swap_exception_tests.cpp b/src/boost/libs/unordered/test/exception/swap_exception_tests.cpp new file mode 100644 index 00000000..1569e814 --- /dev/null +++ b/src/boost/libs/unordered/test/exception/swap_exception_tests.cpp @@ -0,0 +1,145 @@ + +// 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) // assignment operator could not be generated +#endif + +test::seed_t initialize_seed(9387); + +template <class T> struct self_swap_base : public test::exception_base +{ + 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); + + 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> +{ + self_swap_test2() : self_swap_base<T>(100) {} +}; + +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; + + 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)), + 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)) + { + } + + struct data_type + { + data_type(T const& x_, T const& y_) : x(x_), y(y_) {} + + T x, 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&) { + } + + 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> +{ + swap_test1() : swap_base<T>(0, 0, 0, 0) {} +}; + +template <class T> struct swap_test2 : swap_base<T> +{ + swap_test2() : swap_base<T>(60, 0, 0, 0) {} +}; + +template <class T> struct swap_test3 : swap_base<T> +{ + swap_test3() : swap_base<T>(0, 60, 0, 0) {} +}; + +template <class T> struct swap_test4 : swap_base<T> +{ + 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) +// clang-format on + +RUN_TESTS() diff --git a/src/boost/libs/unordered/test/helpers/check_return_type.hpp b/src/boost/libs/unordered/test/helpers/check_return_type.hpp new file mode 100644 index 00000000..1c70a8c7 --- /dev/null +++ b/src/boost/libs/unordered/test/helpers/check_return_type.hpp @@ -0,0 +1,33 @@ + +// Copyright 2005-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) + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_CHECK_RETURN_TYPE_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_CHECK_RETURN_TYPE_HEADER + +#include <boost/static_assert.hpp> +#include <boost/type_traits/is_convertible.hpp> +#include <boost/type_traits/is_same.hpp> + +namespace test { + template <class T1> struct check_return_type + { + template <class T2> static void equals(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)); + } + }; +} + +#endif diff --git a/src/boost/libs/unordered/test/helpers/count.hpp b/src/boost/libs/unordered/test/helpers/count.hpp new file mode 100644 index 00000000..90372dca --- /dev/null +++ b/src/boost/libs/unordered/test/helpers/count.hpp @@ -0,0 +1,89 @@ + +// Copyright 2008-2009 Daniel James. +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or move at http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_COUNT_HEAD) +#define BOOST_UNORDERED_TEST_HELPERS_COUNT_HEAD + +#include <boost/core/lightweight_test.hpp> + +namespace test { + struct object_count + { + int instances; + int constructions; + + 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 + { + 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 diff --git a/src/boost/libs/unordered/test/helpers/equivalent.hpp b/src/boost/libs/unordered/test/helpers/equivalent.hpp new file mode 100644 index 00000000..bd27d8df --- /dev/null +++ b/src/boost/libs/unordered/test/helpers/equivalent.hpp @@ -0,0 +1,96 @@ + +// Copyright 2005-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) + +#if !defined(BOOST_UNORDERED_TESTS_EQUIVALENT_HEADER) +#define BOOST_UNORDERED_TESTS_EQUIVALENT_HEADER + +#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() {} + + template <class T1, class T2> + bool operator()(T1 const& x, T2 const& y) const + { + return equivalent_impl(x, y, derived); + } + }; + + 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()) + { + values_.sort(); + } + + 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(); + }; +} + +#endif diff --git a/src/boost/libs/unordered/test/helpers/exception_test.hpp b/src/boost/libs/unordered/test/helpers/exception_test.hpp new file mode 100644 index 00000000..8984eee9 --- /dev/null +++ b/src/boost/libs/unordered/test/helpers/exception_test.hpp @@ -0,0 +1,348 @@ + +// 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) + +#if !defined(BOOST_UNORDERED_EXCEPTION_TEST_HEADER) +#define BOOST_UNORDERED_EXCEPTION_TEST_HEADER + +#include "./count.hpp" +#include "./test.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_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_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_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 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 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) + +namespace test { + static char const* scope = ""; + bool exceptions_enabled = false; + + 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_; + } + + ~scope_guard() + { + if (dismissed_) + scope = old_scope_; + } + + 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) + { + exceptions_enabled = enable; + } + + ~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> + void exception_safety(Test const& f, char const* /*name*/) + { + test_runner<Test> runner(f); + + 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); + } + } + }; + +#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 diff --git a/src/boost/libs/unordered/test/helpers/fwd.hpp b/src/boost/libs/unordered/test/helpers/fwd.hpp new file mode 100644 index 00000000..a5657e01 --- /dev/null +++ b/src/boost/libs/unordered/test/helpers/fwd.hpp @@ -0,0 +1,32 @@ + +// 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) + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_FWD_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_FWD_HEADER + +#include <string> + +namespace test { + typedef enum { + default_generator, + generate_collisions, + limited_range + } random_generator; + + 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 diff --git a/src/boost/libs/unordered/test/helpers/generators.hpp b/src/boost/libs/unordered/test/helpers/generators.hpp new file mode 100644 index 00000000..c9ed42bd --- /dev/null +++ b/src/boost/libs/unordered/test/helpers/generators.hpp @@ -0,0 +1,93 @@ + +// Copyright 2005-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) + +// This uses std::rand to generate random values for tests. +// Which is not good as different platforms will be running different tests. +// It would be much better to use Boost.Random, but it doesn't +// support all the compilers that I want to test on. + +#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> + +namespace test { + struct seed_t + { + seed_t(unsigned int x) + { + 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); + } + } + + return result; + } + + 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 diff --git a/src/boost/libs/unordered/test/helpers/helpers.hpp b/src/boost/libs/unordered/test/helpers/helpers.hpp new file mode 100644 index 00000000..146dea4d --- /dev/null +++ b/src/boost/libs/unordered/test/helpers/helpers.hpp @@ -0,0 +1,56 @@ + +// 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) + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_HEADER + +#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) + { + 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 diff --git a/src/boost/libs/unordered/test/helpers/input_iterator.hpp b/src/boost/libs/unordered/test/helpers/input_iterator.hpp new file mode 100644 index 00000000..7a938a50 --- /dev/null +++ b/src/boost/libs/unordered/test/helpers/input_iterator.hpp @@ -0,0 +1,165 @@ + +// Copyright 2005-2010 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) + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_INPUT_ITERATOR_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_INPUT_ITERATOR_HEADER + +#include <boost/config.hpp> +#include <iterator> + +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++() + { + ++*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 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++() + { + ++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 diff --git a/src/boost/libs/unordered/test/helpers/invariants.hpp b/src/boost/libs/unordered/test/helpers/invariants.hpp new file mode 100644 index 00000000..a555da60 --- /dev/null +++ b/src/boost/libs/unordered/test/helpers/invariants.hpp @@ -0,0 +1,130 @@ + +// 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) + +// This header contains metafunctions/functions to get the equivalent +// associative container for an unordered container, and compare the contents. + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_INVARIANT_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_INVARIANT_HEADER + +#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', + // possible loss of data +#endif + +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_; + + 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)); + + // 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"; + } + + // 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; + } + + // 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) +#pragma warning(pop) +#endif + +#endif diff --git a/src/boost/libs/unordered/test/helpers/list.hpp b/src/boost/libs/unordered/test/helpers/list.hpp new file mode 100644 index 00000000..d39c766e --- /dev/null +++ b/src/boost/libs/unordered/test/helpers/list.hpp @@ -0,0 +1,327 @@ + +// Copyright 2008-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) + +// Gratuitous single linked list. +// +// Sadly some STL implementations aren't up to scratch and I need a simple +// cross-platform container. So here it is. + +#if !defined(UNORDERED_TEST_LIST_HEADER) +#define UNORDERED_TEST_LIST_HEADER + +#include <boost/limits.hpp> +#include <functional> +#include <iterator> + +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 + { + 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 + { + 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 diff --git a/src/boost/libs/unordered/test/helpers/memory.hpp b/src/boost/libs/unordered/test/helpers/memory.hpp new file mode 100644 index 00000000..22946cc2 --- /dev/null +++ b/src/boost/libs/unordered/test/helpers/memory.hpp @@ -0,0 +1,189 @@ + +// 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) + +#if !defined(BOOST_UNORDERED_TEST_MEMORY_HEADER) +#define BOOST_UNORDERED_TEST_MEMORY_HEADER + +#include "../helpers/test.hpp" +#include <boost/assert.hpp> +#include <boost/unordered/detail/implementation.hpp> +#include <map> +#include <memory> + +namespace test { + namespace detail { + struct memory_area + { + void const* start; + void const* 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; + 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 diff --git a/src/boost/libs/unordered/test/helpers/metafunctions.hpp b/src/boost/libs/unordered/test/helpers/metafunctions.hpp new file mode 100644 index 00000000..f5f13851 --- /dev/null +++ b/src/boost/libs/unordered/test/helpers/metafunctions.hpp @@ -0,0 +1,30 @@ + +// Copyright 2005-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) + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_METAFUNCTIONS_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_METAFUNCTIONS_HEADER + +#include <boost/config.hpp> +#include <boost/type_traits/is_same.hpp> + +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 + { + 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 diff --git a/src/boost/libs/unordered/test/helpers/postfix.hpp b/src/boost/libs/unordered/test/helpers/postfix.hpp new file mode 100644 index 00000000..ca14ae71 --- /dev/null +++ b/src/boost/libs/unordered/test/helpers/postfix.hpp @@ -0,0 +1,10 @@ + +// Copyright 2012 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 this after the boost headers, but before other test headers. + +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wfloat-equal" +#endif diff --git a/src/boost/libs/unordered/test/helpers/prefix.hpp b/src/boost/libs/unordered/test/helpers/prefix.hpp new file mode 100644 index 00000000..fe757025 --- /dev/null +++ b/src/boost/libs/unordered/test/helpers/prefix.hpp @@ -0,0 +1,11 @@ + +// Copyright 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) + +#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 : + // nameless struct/union +#endif diff --git a/src/boost/libs/unordered/test/helpers/random_values.hpp b/src/boost/libs/unordered/test/helpers/random_values.hpp new file mode 100644 index 00000000..d139d180 --- /dev/null +++ b/src/boost/libs/unordered/test/helpers/random_values.hpp @@ -0,0 +1,109 @@ + +// Copyright 2005-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) + +#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> + +namespace test { + template <class X> struct unordered_generator_set + { + typedef typename X::value_type value_type; + + random_generator type_; + + unordered_generator_set(random_generator type) : type_(type) {} + + template <class T> void fill(T& x, std::size_t len) + { + value_type* value_ptr = 0; + len += x.size(); + + for (std::size_t i = 0; i < len; ++i) { + value_type value = generate(value_ptr, type_); + + std::size_t count = + type_ == generate_collisions ? random_value(5) + 1 : 1; + + for (std::size_t j = 0; j < count; ++j) { + x.push_back(value); + } + } + } + }; + + 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) + { + key_type* key_ptr = 0; + mapped_type* mapped_ptr = 0; + + for (std::size_t i = 0; i < len; ++i) { + key_type key = generate(key_ptr, type_); + + std::size_t count = + type_ == generate_collisions ? random_value(5) + 1 : 1; + + 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 : 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 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) + { + fill(count, generator); + } + + void fill(std::size_t count, + test::random_generator const& generator = test::default_generator) + { + test::unordered_generator<X> gen(generator); + gen.fill(*this, count); + } + }; +} + +#endif diff --git a/src/boost/libs/unordered/test/helpers/strong.hpp b/src/boost/libs/unordered/test/helpers/strong.hpp new file mode 100644 index 00000000..3c936133 --- /dev/null +++ b/src/boost/libs/unordered/test/helpers/strong.hpp @@ -0,0 +1,42 @@ + +// Copyright 2005-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) + +#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> + +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) + { + 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."); + } + }; +} + +#endif diff --git a/src/boost/libs/unordered/test/helpers/test.hpp b/src/boost/libs/unordered/test/helpers/test.hpp new file mode 100644 index 00000000..5534f811 --- /dev/null +++ b/src/boost/libs/unordered/test/helpers/test.hpp @@ -0,0 +1,201 @@ + +// 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) + +#if !defined(BOOST_UNORDERED_TEST_TEST_HEADER) +#define BOOST_UNORDERED_TEST_TEST_HEADER + +#include <boost/core/lightweight_test.hpp> +#include <boost/preprocessor/cat.hpp> +#include <boost/preprocessor/stringize.hpp> + +#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**) \ + { \ + 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() {} + }; + + struct state + { + bool is_quiet; + registered_test_base* first_test; + registered_test_base* last_test; + + state() : is_quiet(false), first_test(0), last_test(0) {} + + 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; + } +} + +#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_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_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_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 diff --git a/src/boost/libs/unordered/test/helpers/tracker.hpp b/src/boost/libs/unordered/test/helpers/tracker.hpp new file mode 100644 index 00000000..0f86ba6f --- /dev/null +++ b/src/boost/libs/unordered/test/helpers/tracker.hpp @@ -0,0 +1,138 @@ + +// 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) + +// This header contains metafunctions/functions to get the equivalent +// associative container for an unordered container, and compare the contents. + +#if !defined(BOOST_UNORDERED_TEST_HELPERS_TRACKER_HEADER) +#define BOOST_UNORDERED_TEST_HELPERS_TRACKER_HEADER + +#include "../objects/fwd.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<typename X::first_argument_type> 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) + { + 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) + { + compare_pairs(x.equal_range(get_key<X>(val)), + this->equal_range(get_key<X>(val)), (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> + typename equals_to_compare<Equals>::type create_compare(Equals const&) + { + 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); + } +} + +#endif diff --git a/src/boost/libs/unordered/test/objects/cxx11_allocator.hpp b/src/boost/libs/unordered/test/objects/cxx11_allocator.hpp new file mode 100644 index 00000000..e96f8d94 --- /dev/null +++ b/src/boost/libs/unordered/test/objects/cxx11_allocator.hpp @@ -0,0 +1,344 @@ + +// Copyright 2006-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) + +#if !defined(BOOST_UNORDERED_TEST_CXX11_ALLOCATOR_HEADER) +#define BOOST_UNORDERED_TEST_CXX11_ALLOCATOR_HEADER + +#include <boost/config.hpp> +#include <boost/limits.hpp> +#include <cstddef> + +#include "../helpers/fwd.hpp" +#include "../helpers/memory.hpp" + +namespace test { + struct allocator_false + { + enum + { + 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 + { + enum + { + 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 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; + } + + ~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) + { + 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(cxx11_allocator_base const& x) + : tag_(x.tag_), selected_(x.selected_) + { + detail::tracker.allocator_ref(); + } + + ~cxx11_allocator_base() { detail::tracker.allocator_unref(); } + + pointer address(reference r) { return pointer(&r); } + + const_pointer address(const_reference r) { return const_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; + } + + 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; + } + + 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); + } + +#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)...); + } +#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 + { +#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> + 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 diff --git a/src/boost/libs/unordered/test/objects/exception.hpp b/src/boost/libs/unordered/test/objects/exception.hpp new file mode 100644 index 00000000..07f343fb --- /dev/null +++ b/src/boost/libs/unordered/test/objects/exception.hpp @@ -0,0 +1,752 @@ + +// 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) + +#if !defined(BOOST_UNORDERED_EXCEPTION_TEST_OBJECTS_HEADER) +#define BOOST_UNORDERED_EXCEPTION_TEST_OBJECTS_HEADER + +#include "../helpers/exception_test.hpp" + +#include "../helpers/count.hpp" +#include "../helpers/fwd.hpp" +#include "../helpers/generators.hpp" +#include "../helpers/memory.hpp" +#include "./fwd.hpp" +#include <boost/limits.hpp> +#include <cstddef> +#include <new> + +namespace test { + namespace exception { + class object; + class hash; + class equal_to; + template <class T> class allocator; + object generate(object const*, random_generator); + std::pair<object, object> generate( + std::pair<object, object> const*, random_generator); + + struct true_type + { + enum + { + value = true + }; + }; + + struct false_type + { + enum + { + value = false + }; + }; + + class object : private counted_object + { + public: + int tag1_, tag2_; + + explicit object() : tag1_(0), tag2_(0) + { + UNORDERED_SCOPE(object::object()) + { + UNORDERED_EPOINT("Mock object default constructor."); + } + } + + explicit object(int t1, int t2 = 0) : tag1_(t1), tag2_(t2) + { + UNORDERED_SCOPE(object::object(int)) + { + UNORDERED_EPOINT("Mock object constructor by value."); + } + } + + object(object const& x) + : counted_object(x), tag1_(x.tag1_), tag2_(x.tag2_) + { + UNORDERED_SCOPE(object::object(object)) + { + UNORDERED_EPOINT("Mock object copy constructor."); + } + } + + ~object() + { + tag1_ = -1; + tag2_ = -1; + } + + object& operator=(object const& x) + { + UNORDERED_SCOPE(object::operator=(object)) + { + tag1_ = x.tag1_; + UNORDERED_EPOINT("Mock object assign operator 1."); + tag2_ = x.tag2_; + // UNORDERED_EPOINT("Mock object assign operator 2."); + } + return *this; + } + + friend bool operator==(object const& x1, object const& x2) + { + UNORDERED_SCOPE(operator==(object, object)) + { + UNORDERED_EPOINT("Mock object equality operator."); + } + + return x1.tag1_ == x2.tag1_ && x1.tag2_ == x2.tag2_; + } + + friend bool operator!=(object const& x1, object const& x2) + { + UNORDERED_SCOPE(operator!=(object, object)) + { + UNORDERED_EPOINT("Mock object inequality operator."); + } + + return !(x1.tag1_ == x2.tag1_ && x1.tag2_ == x2.tag2_); + } + + // None of the last few functions are used by the unordered associative + // containers - so there aren't any exception points. + friend bool operator<(object const& x1, object const& x2) + { + return x1.tag1_ < x2.tag1_ || + (x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_); + } + + friend object generate(object const*, random_generator g) + { + int* x = 0; + return object(::test::generate(x, g), ::test::generate(x, g)); + } + + friend std::ostream& operator<<(std::ostream& out, object const& o) + { + return out << "(" << o.tag1_ << "," << o.tag2_ << ")"; + } + }; + + std::pair<object, object> generate( + std::pair<object, object> const*, random_generator g) + { + int* x = 0; + return std::make_pair( + object(::test::generate(x, g), ::test::generate(x, g)), + object(::test::generate(x, g), ::test::generate(x, g))); + } + + class hash + { + int tag_; + + public: + hash(int t = 0) : tag_(t) + { + UNORDERED_SCOPE(hash::object()) + { + UNORDERED_EPOINT("Mock hash default constructor."); + } + } + + hash(hash const& x) : tag_(x.tag_) + { + UNORDERED_SCOPE(hash::hash(hash)) + { + UNORDERED_EPOINT("Mock hash copy constructor."); + } + } + + hash& operator=(hash const& x) + { + UNORDERED_SCOPE(hash::operator=(hash)) + { + UNORDERED_EPOINT("Mock hash assign operator 1."); + tag_ = x.tag_; + UNORDERED_EPOINT("Mock hash assign operator 2."); + } + return *this; + } + + std::size_t operator()(object const& x) const + { + UNORDERED_SCOPE(hash::operator()(object)) + { + UNORDERED_EPOINT("Mock hash function."); + } + + return hash_impl(x); + } + + std::size_t operator()(std::pair<object, object> const& x) const + { + UNORDERED_SCOPE(hash::operator()(std::pair<object, object>)) + { + UNORDERED_EPOINT("Mock hash pair function."); + } + + return hash_impl(x.first) * 193ul + hash_impl(x.second) * 97ul + 29ul; + } + + std::size_t hash_impl(object const& x) const + { + int result; + switch (tag_) { + case 1: + result = x.tag1_; + break; + case 2: + result = x.tag2_; + break; + default: + result = x.tag1_ + x.tag2_; + } + return static_cast<std::size_t>(result); + } + + friend bool operator==(hash const& x1, hash const& x2) + { + UNORDERED_SCOPE(operator==(hash, hash)) + { + UNORDERED_EPOINT("Mock hash equality function."); + } + return x1.tag_ == x2.tag_; + } + + friend bool operator!=(hash const& x1, hash const& x2) + { + UNORDERED_SCOPE(hash::operator!=(hash, hash)) + { + UNORDERED_EPOINT("Mock hash inequality function."); + } + return x1.tag_ != x2.tag_; + } + }; + + class less + { + int tag_; + + public: + less(int t = 0) : tag_(t) {} + + less(less const& x) : tag_(x.tag_) {} + + bool operator()(object const& x1, object const& x2) const + { + return less_impl(x1, x2); + } + + bool operator()(std::pair<object, object> const& x1, + std::pair<object, object> const& x2) const + { + if (less_impl(x1.first, x2.first)) { + return true; + } + if (!less_impl(x1.first, x2.first)) { + return false; + } + return less_impl(x1.second, x2.second); + } + + bool less_impl(object const& x1, object const& x2) const + { + switch (tag_) { + case 1: + return x1.tag1_ < x2.tag1_; + case 2: + return x1.tag2_ < x2.tag2_; + default: + return x1 < x2; + } + } + + friend bool operator==(less const& x1, less const& x2) + { + return x1.tag_ == x2.tag_; + } + + friend bool operator!=(less const& x1, less const& x2) + { + return x1.tag_ != x2.tag_; + } + }; + + class equal_to + { + int tag_; + + public: + equal_to(int t = 0) : tag_(t) + { + UNORDERED_SCOPE(equal_to::equal_to()) + { + UNORDERED_EPOINT("Mock equal_to default constructor."); + } + } + + equal_to(equal_to const& x) : tag_(x.tag_) + { + UNORDERED_SCOPE(equal_to::equal_to(equal_to)) + { + UNORDERED_EPOINT("Mock equal_to copy constructor."); + } + } + + equal_to& operator=(equal_to const& x) + { + UNORDERED_SCOPE(equal_to::operator=(equal_to)) + { + UNORDERED_EPOINT("Mock equal_to assign operator 1."); + tag_ = x.tag_; + UNORDERED_EPOINT("Mock equal_to assign operator 2."); + } + return *this; + } + + bool operator()(object const& x1, object const& x2) const + { + UNORDERED_SCOPE(equal_to::operator()(object, object)) + { + UNORDERED_EPOINT("Mock equal_to function."); + } + + return equal_impl(x1, x2); + } + + bool operator()(std::pair<object, object> const& x1, + std::pair<object, object> const& x2) const + { + UNORDERED_SCOPE(equal_to::operator()( + std::pair<object, object>, std::pair<object, object>)) + { + UNORDERED_EPOINT("Mock equal_to function."); + } + + return equal_impl(x1.first, x2.first) && + equal_impl(x1.second, x2.second); + } + + bool equal_impl(object const& x1, object const& x2) const + { + switch (tag_) { + case 1: + return x1.tag1_ == x2.tag1_; + case 2: + return x1.tag2_ == x2.tag2_; + default: + return x1 == x2; + } + } + + friend bool operator==(equal_to const& x1, equal_to const& x2) + { + UNORDERED_SCOPE(operator==(equal_to, equal_to)) + { + UNORDERED_EPOINT("Mock equal_to equality function."); + } + return x1.tag_ == x2.tag_; + } + + friend bool operator!=(equal_to const& x1, equal_to const& x2) + { + UNORDERED_SCOPE(operator!=(equal_to, equal_to)) + { + UNORDERED_EPOINT("Mock equal_to inequality function."); + } + return x1.tag_ != x2.tag_; + } + + friend less create_compare(equal_to x) { return less(x.tag_); } + }; + + template <class T> class allocator + { + public: + int tag_; + 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; + + template <class U> struct rebind + { + typedef allocator<U> other; + }; + + explicit allocator(int t = 0) : tag_(t) + { + UNORDERED_SCOPE(allocator::allocator()) + { + UNORDERED_EPOINT("Mock allocator default constructor."); + } + test::detail::tracker.allocator_ref(); + } + + template <class Y> allocator(allocator<Y> const& x) : tag_(x.tag_) + { + test::detail::tracker.allocator_ref(); + } + + allocator(allocator const& x) : tag_(x.tag_) + { + test::detail::tracker.allocator_ref(); + } + + ~allocator() { test::detail::tracker.allocator_unref(); } + + allocator& operator=(allocator const& x) + { + tag_ = x.tag_; + return *this; + } + + // If address throws, then it can't be used in erase or the + // destructor, which is very limiting. I need to check up on + // this. + + pointer address(reference r) + { + // UNORDERED_SCOPE(allocator::address(reference)) { + // UNORDERED_EPOINT("Mock allocator address function."); + //} + return pointer(&r); + } + + const_pointer address(const_reference r) + { + // UNORDERED_SCOPE(allocator::address(const_reference)) { + // UNORDERED_EPOINT("Mock allocator const address function."); + //} + return const_pointer(&r); + } + + pointer allocate(size_type n) + { + T* ptr = 0; + UNORDERED_SCOPE(allocator::allocate(size_type)) + { + UNORDERED_EPOINT("Mock allocator allocate function."); + + using namespace std; + ptr = (T*)malloc(n * sizeof(T)); + if (!ptr) + throw std::bad_alloc(); + } + test::detail::tracker.track_allocate((void*)ptr, n, sizeof(T), tag_); + return pointer(ptr); + + // return pointer(static_cast<T*>(::operator new(n * sizeof(T)))); + } + + pointer allocate(size_type n, void const*) + { + T* ptr = 0; + UNORDERED_SCOPE(allocator::allocate(size_type, const_pointer)) + { + UNORDERED_EPOINT("Mock allocator allocate function."); + + using namespace std; + ptr = (T*)malloc(n * sizeof(T)); + if (!ptr) + throw std::bad_alloc(); + } + test::detail::tracker.track_allocate((void*)ptr, n, sizeof(T), tag_); + return pointer(ptr); + + // return pointer(static_cast<T*>(::operator new(n * sizeof(T)))); + } + + void deallocate(pointer p, size_type n) + { + //::operator delete((void*) p); + if (p) { + test::detail::tracker.track_deallocate((void*)p, n, sizeof(T), tag_); + using namespace std; + free(p); + } + } + + void construct(pointer p, T const& t) + { + UNORDERED_SCOPE(allocator::construct(T*, T)) + { + UNORDERED_EPOINT("Mock allocator construct function."); + new (p) T(t); + } + test::detail::tracker.track_construct((void*)p, sizeof(T), tag_); + } + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template <class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args) + { + UNORDERED_SCOPE(allocator::construct(pointer, BOOST_FWD_REF(Args)...)) + { + UNORDERED_EPOINT("Mock allocator construct function."); + new (p) T(boost::forward<Args>(args)...); + } + test::detail::tracker.track_construct((void*)p, sizeof(T), tag_); + } +#endif + + void destroy(T* p) + { + test::detail::tracker.track_destroy((void*)p, sizeof(T), tag_); + p->~T(); + } + + size_type max_size() const + { + UNORDERED_SCOPE(allocator::construct(pointer, T)) + { + UNORDERED_EPOINT("Mock allocator max_size function."); + } + return (std::numeric_limits<std::size_t>::max)(); + } + + typedef true_type propagate_on_container_copy_assignment; + typedef true_type propagate_on_container_move_assignment; + typedef true_type propagate_on_container_swap; + }; + + template <class T> void swap(allocator<T>& x, allocator<T>& y) + { + std::swap(x.tag_, y.tag_); + } + + // It's pretty much impossible to write a compliant swap when these + // two can throw. So they don't. + + template <class T> + inline bool operator==(allocator<T> const& x, allocator<T> const& y) + { + // UNORDERED_SCOPE(operator==(allocator, allocator)) { + // UNORDERED_EPOINT("Mock allocator equality operator."); + //} + return x.tag_ == y.tag_; + } + + template <class T> + inline bool operator!=(allocator<T> const& x, allocator<T> const& y) + { + // UNORDERED_SCOPE(operator!=(allocator, allocator)) { + // UNORDERED_EPOINT("Mock allocator inequality operator."); + //} + return x.tag_ != y.tag_; + } + + template <class T> class allocator2 + { + public: + int tag_; + 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; + + template <class U> struct rebind + { + typedef allocator2<U> other; + }; + + explicit allocator2(int t = 0) : tag_(t) + { + UNORDERED_SCOPE(allocator2::allocator2()) + { + UNORDERED_EPOINT("Mock allocator2 default constructor."); + } + test::detail::tracker.allocator_ref(); + } + + allocator2(allocator<T> const& x) : tag_(x.tag_) + { + test::detail::tracker.allocator_ref(); + } + + template <class Y> allocator2(allocator2<Y> const& x) : tag_(x.tag_) + { + test::detail::tracker.allocator_ref(); + } + + allocator2(allocator2 const& x) : tag_(x.tag_) + { + test::detail::tracker.allocator_ref(); + } + + ~allocator2() { test::detail::tracker.allocator_unref(); } + + allocator2& operator=(allocator2 const&) { return *this; } + + // If address throws, then it can't be used in erase or the + // destructor, which is very limiting. I need to check up on + // this. + + pointer address(reference r) + { + // UNORDERED_SCOPE(allocator2::address(reference)) { + // UNORDERED_EPOINT("Mock allocator2 address function."); + //} + return pointer(&r); + } + + const_pointer address(const_reference r) + { + // UNORDERED_SCOPE(allocator2::address(const_reference)) { + // UNORDERED_EPOINT("Mock allocator2 const address function."); + //} + return const_pointer(&r); + } + + pointer allocate(size_type n) + { + T* ptr = 0; + UNORDERED_SCOPE(allocator2::allocate(size_type)) + { + UNORDERED_EPOINT("Mock allocator2 allocate function."); + + using namespace std; + ptr = (T*)malloc(n * sizeof(T)); + if (!ptr) + throw std::bad_alloc(); + } + test::detail::tracker.track_allocate((void*)ptr, n, sizeof(T), tag_); + return pointer(ptr); + + // return pointer(static_cast<T*>(::operator new(n * sizeof(T)))); + } + + pointer allocate(size_type n, void const*) + { + T* ptr = 0; + UNORDERED_SCOPE(allocator2::allocate(size_type, const_pointer)) + { + UNORDERED_EPOINT("Mock allocator2 allocate function."); + + using namespace std; + ptr = (T*)malloc(n * sizeof(T)); + if (!ptr) + throw std::bad_alloc(); + } + test::detail::tracker.track_allocate((void*)ptr, n, sizeof(T), tag_); + return pointer(ptr); + + // return pointer(static_cast<T*>(::operator new(n * sizeof(T)))); + } + + void deallocate(pointer p, size_type n) + { + //::operator delete((void*) p); + if (p) { + test::detail::tracker.track_deallocate((void*)p, n, sizeof(T), tag_); + using namespace std; + free(p); + } + } + + void construct(pointer p, T const& t) + { + UNORDERED_SCOPE(allocator2::construct(T*, T)) + { + UNORDERED_EPOINT("Mock allocator2 construct function."); + new (p) T(t); + } + test::detail::tracker.track_construct((void*)p, sizeof(T), tag_); + } + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template <class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args) + { + UNORDERED_SCOPE(allocator2::construct(pointer, BOOST_FWD_REF(Args)...)) + { + UNORDERED_EPOINT("Mock allocator2 construct function."); + new (p) T(boost::forward<Args>(args)...); + } + test::detail::tracker.track_construct((void*)p, sizeof(T), tag_); + } +#endif + + void destroy(T* p) + { + test::detail::tracker.track_destroy((void*)p, sizeof(T), tag_); + p->~T(); + } + + size_type max_size() const + { + UNORDERED_SCOPE(allocator2::construct(pointer, T)) + { + UNORDERED_EPOINT("Mock allocator2 max_size function."); + } + return (std::numeric_limits<std::size_t>::max)(); + } + + typedef false_type propagate_on_container_copy_assignment; + typedef false_type propagate_on_container_move_assignment; + typedef false_type propagate_on_container_swap; + }; + + template <class T> void swap(allocator2<T>& x, allocator2<T>& y) + { + std::swap(x.tag_, y.tag_); + } + + // It's pretty much impossible to write a compliant swap when these + // two can throw. So they don't. + + template <class T> + inline bool operator==(allocator2<T> const& x, allocator2<T> const& y) + { + // UNORDERED_SCOPE(operator==(allocator2, allocator2)) { + // UNORDERED_EPOINT("Mock allocator2 equality operator."); + //} + return x.tag_ == y.tag_; + } + + template <class T> + inline bool operator!=(allocator2<T> const& x, allocator2<T> const& y) + { + // UNORDERED_SCOPE(operator!=(allocator2, allocator2)) { + // UNORDERED_EPOINT("Mock allocator2 inequality operator."); + //} + return x.tag_ != y.tag_; + } + } +} + +namespace test { + template <typename X> struct equals_to_compare; + template <> struct equals_to_compare<test::exception::equal_to> + { + typedef test::exception::less type; + }; +} + +// Workaround for ADL deficient compilers +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) +namespace test { + test::exception::object generate( + test::exception::object const* x, random_generator g) + { + return test::exception::generate(x, g); + } + + std::pair<test::exception::object, test::exception::object> generate( + std::pair<test::exception::object, test::exception::object> const* x, + random_generator g) + { + return test::exception::generate(x, g); + } +} +#endif + +#endif diff --git a/src/boost/libs/unordered/test/objects/fwd.hpp b/src/boost/libs/unordered/test/objects/fwd.hpp new file mode 100644 index 00000000..802b95af --- /dev/null +++ b/src/boost/libs/unordered/test/objects/fwd.hpp @@ -0,0 +1,17 @@ + +// 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) + +#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; +} + +#endif diff --git a/src/boost/libs/unordered/test/objects/minimal.hpp b/src/boost/libs/unordered/test/objects/minimal.hpp new file mode 100644 index 00000000..b89e0af8 --- /dev/null +++ b/src/boost/libs/unordered/test/objects/minimal.hpp @@ -0,0 +1,627 @@ + +// 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) + +// Define some minimal classes which provide the bare minimum concepts to +// test that the containers don't rely on something that they shouldn't. +// They are not intended to be good examples of how to implement the concepts. + +#if !defined(BOOST_UNORDERED_OBJECTS_MINIMAL_HEADER) +#define BOOST_UNORDERED_OBJECTS_MINIMAL_HEADER + +#include <boost/move/move.hpp> +#include <cstddef> +#include <utility> + +#if defined(BOOST_MSVC) +#pragma warning(push) +#pragma warning(disable : 4100) // unreferenced formal parameter +#endif + +#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 + { + ampersand_operator_used() { BOOST_TEST(false); } + }; + + template <class T> class hash; + template <class T> class equal_to; + template <class T> class ptr; + template <class T> class const_ptr; + template <class T> class allocator; + template <class T> class cxx11_allocator; + + struct constructor_param + { + operator int() const { return 0; } + }; + + class destructible + { + public: + destructible(constructor_param const&) {} + ~destructible() {} + void dummy_member() const {} + + private: + destructible(destructible const&); + destructible& operator=(destructible const&); + }; + + class copy_constructible + { + public: + 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() {} + }; + + class copy_constructible_equality_comparable + { + public: + copy_constructible_equality_comparable(constructor_param const&) {} + + copy_constructible_equality_comparable( + copy_constructible_equality_comparable const&) + { + } + + ~copy_constructible_equality_comparable() {} + + void dummy_member() const {} + + private: + 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) + { + return true; + } + + bool operator!=(copy_constructible_equality_comparable, + copy_constructible_equality_comparable) + { + return false; + } + + class default_assignable + { + public: + default_assignable(constructor_param const&) {} + + default_assignable() {} + + default_assignable(default_assignable const&) {} + + default_assignable& operator=(default_assignable const&) { return *this; } + + ~default_assignable() {} + + 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() {} + void dummy_member() const {} + + private: + assignable() {} +#if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED + ampersand_operator_used operator&() const + { + return ampersand_operator_used(); + } +#endif + }; + + struct movable_init + { + }; + + class 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() {} + 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; } + void dummy_member() const {} + + private: + movable2() {} + movable2(movable2 const&); + movable2& operator=(movable2 const&); + }; +#else + typedef movable1 movable2; +#endif + + template <class T> class hash + { + public: + hash(constructor_param const&) {} + hash() {} + hash(hash const&) {} + hash& operator=(hash const&) { return *this; } + ~hash() {} + + 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 + { + public: + 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; } +#if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED + ampersand_operator_used operator&() const + { + return ampersand_operator_used(); + } +#endif + }; + + template <class T> class ptr; + template <class T> class const_ptr; + + struct void_ptr + { +#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) + template <typename T> friend class ptr; + + private: +#endif + + void* ptr_; + + public: + void_ptr() : ptr_(0) {} + + 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_; } + + 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; + + private: +#endif + + void* ptr_; + + public: + void_const_ptr() : ptr_(0) {} + + 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_; } + + 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 + { + friend class allocator<T>; + friend class const_ptr<T>; + friend struct void_ptr; + + T* ptr_; + + ptr(T* x) : ptr_(x) {} + + public: + 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_; } + + 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 + { + friend class allocator<T>; + friend struct const_void_ptr; + + T const* 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_) {} + + 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_; } +#if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED + ampersand_operator_used operator&() const + { + return ampersand_operator_used(); + } +#endif + }; + + 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; + + template <class U> struct rebind + { + typedef allocator<U> other; + }; + + 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 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>) + { + return pointer(static_cast<T*>(::operator new(n * sizeof(T)))); + } + + void deallocate(pointer p, size_type) + { + ::operator delete((void*)p.ptr_); + } + + 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)...); + } +#endif + + void destroy(T* 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> 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; + } + + template <class T> + inline bool operator!=(allocator<T> const&, allocator<T> const&) + { + return false; + } + + 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 + { + public: + 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() {} + + 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))); + } + + 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 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)...); + } +#endif + + void destroy(T* p) { p->~T(); } + + std::size_t max_size() const { return 1000u; } + }; + + template <class T> + inline bool operator==(cxx11_allocator<T> const&, cxx11_allocator<T> const&) + { + return true; + } + + template <class T> + inline bool operator!=(cxx11_allocator<T> const&, cxx11_allocator<T> const&) + { + return false; + } + + 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 { +#endif + std::size_t hash_value(test::minimal::copy_constructible_equality_comparable) + { + return 1; + } +#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) +} +} +#else + } +#endif + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + +#endif diff --git a/src/boost/libs/unordered/test/objects/test.hpp b/src/boost/libs/unordered/test/objects/test.hpp new file mode 100644 index 00000000..7ce21fa9 --- /dev/null +++ b/src/boost/libs/unordered/test/objects/test.hpp @@ -0,0 +1,700 @@ + +// 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) + +#if !defined(BOOST_UNORDERED_TEST_OBJECTS_HEADER) +#define BOOST_UNORDERED_TEST_OBJECTS_HEADER + +#include "../helpers/count.hpp" +#include "../helpers/fwd.hpp" +#include "../helpers/memory.hpp" +#include <boost/config.hpp> +#include <boost/limits.hpp> +#include <cstddef> + +namespace test { + // Note that the default hash function will work for any equal_to (but not + // very well). + class object; + class movable; + class implicitly_convertible; + class hash; + class less; + class equal_to; + template <class T> class allocator1; + template <class T> class allocator2; + object generate(object const*, random_generator); + movable generate(movable const*, random_generator); + implicitly_convertible generate( + implicitly_convertible const*, random_generator); + + inline void ignore_variable(void const*) {} + + class object : private counted_object + { + friend class hash; + friend class equal_to; + friend class less; + int tag1_, tag2_; + + public: + explicit object(int t1 = 0, int t2 = 0) : tag1_(t1), tag2_(t2) {} + + ~object() + { + tag1_ = -1; + tag2_ = -1; + } + + friend bool operator==(object const& x1, object const& x2) + { + return x1.tag1_ == x2.tag1_ && x1.tag2_ == x2.tag2_; + } + + friend bool operator!=(object const& x1, object const& x2) + { + return x1.tag1_ != x2.tag1_ || x1.tag2_ != x2.tag2_; + } + + friend bool operator<(object const& x1, object const& x2) + { + return x1.tag1_ < x2.tag1_ || + (x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_); + } + + friend object generate(object const*, random_generator g) + { + int* x = 0; + return object(generate(x, g), generate(x, g)); + } + + friend std::ostream& operator<<(std::ostream& out, object const& o) + { + return out << "(" << o.tag1_ << "," << o.tag2_ << ")"; + } + }; + + class movable : private counted_object + { + friend class hash; + friend class equal_to; + friend class less; + int tag1_, tag2_; + + BOOST_COPYABLE_AND_MOVABLE(movable) + public: + explicit movable(int t1 = 0, int t2 = 0) : tag1_(t1), tag2_(t2) {} + + movable(movable const& x) + : counted_object(x), tag1_(x.tag1_), tag2_(x.tag2_) + { + BOOST_TEST(x.tag1_ != -1); + } + + movable(BOOST_RV_REF(movable) x) + : counted_object(x), tag1_(x.tag1_), tag2_(x.tag2_) + { + BOOST_TEST(x.tag1_ != -1); + x.tag1_ = -1; + x.tag2_ = -1; + } + + movable& operator=(BOOST_COPY_ASSIGN_REF(movable) x) // Copy assignment + { + BOOST_TEST(x.tag1_ != -1); + tag1_ = x.tag1_; + tag2_ = x.tag2_; + return *this; + } + + movable& operator=(BOOST_RV_REF(movable) x) // Move assignment + { + BOOST_TEST(x.tag1_ != -1); + tag1_ = x.tag1_; + tag2_ = x.tag2_; + x.tag1_ = -1; + x.tag2_ = -1; + return *this; + } + + ~movable() + { + tag1_ = -1; + tag2_ = -1; + } + + friend bool operator==(movable const& x1, movable const& x2) + { + BOOST_TEST(x1.tag1_ != -1 && x2.tag1_ != -1); + return x1.tag1_ == x2.tag1_ && x1.tag2_ == x2.tag2_; + } + + friend bool operator!=(movable const& x1, movable const& x2) + { + BOOST_TEST(x1.tag1_ != -1 && x2.tag1_ != -1); + return x1.tag1_ != x2.tag1_ || x1.tag2_ != x2.tag2_; + } + + friend bool operator<(movable const& x1, movable const& x2) + { + BOOST_TEST(x1.tag1_ != -1 && x2.tag1_ != -1); + return x1.tag1_ < x2.tag1_ || + (x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_); + } + + friend movable generate(movable const*, random_generator g) + { + int* x = 0; + return movable(generate(x, g), generate(x, g)); + } + + friend std::ostream& operator<<(std::ostream& out, movable const& o) + { + return out << "(" << o.tag1_ << "," << o.tag2_ << ")"; + } + }; + + class implicitly_convertible : private counted_object + { + int tag1_, tag2_; + + public: + explicit implicitly_convertible(int t1 = 0, int t2 = 0) + : tag1_(t1), tag2_(t2) + { + } + + operator object() const { return object(tag1_, tag2_); } + + operator movable() const { return movable(tag1_, tag2_); } + + friend implicitly_convertible generate( + implicitly_convertible const*, random_generator g) + { + int* x = 0; + return implicitly_convertible(generate(x, g), generate(x, g)); + } + + friend std::ostream& operator<<( + std::ostream& out, implicitly_convertible const& o) + { + return out << "(" << o.tag1_ << "," << o.tag2_ << ")"; + } + }; + + // Note: This is a deliberately bad hash function. + class hash + { + int type_; + + public: + hash() : type_(0) {} + + explicit hash(int t) : type_(t) {} + + std::size_t operator()(object const& x) const + { + int result; + switch (type_) { + case 1: + result = x.tag1_; + break; + case 2: + result = x.tag2_; + break; + default: + result = x.tag1_ + x.tag2_; + } + return static_cast<std::size_t>(result); + } + + std::size_t operator()(movable const& x) const + { + int result; + switch (type_) { + case 1: + result = x.tag1_; + break; + case 2: + result = x.tag2_; + break; + default: + result = x.tag1_ + x.tag2_; + } + return static_cast<std::size_t>(result); + } + + std::size_t operator()(int x) const + { + int result; + switch (type_) { + case 1: + result = x; + break; + case 2: + result = x * 7; + break; + default: + result = x * 256; + } + return static_cast<std::size_t>(result); + } + + friend bool operator==(hash const& x1, hash const& x2) + { + return x1.type_ == x2.type_; + } + + friend bool operator!=(hash const& x1, hash const& x2) + { + return x1.type_ != x2.type_; + } + }; + + std::size_t hash_value(test::object const& x) { return hash()(x); } + + std::size_t hash_value(test::movable const& x) { return hash()(x); } + + class less + { + int type_; + + public: + explicit less(int t = 0) : type_(t) {} + + bool operator()(object const& x1, object const& x2) const + { + switch (type_) { + case 1: + return x1.tag1_ < x2.tag1_; + case 2: + return x1.tag2_ < x2.tag2_; + default: + return x1 < x2; + } + } + + bool operator()(movable const& x1, movable const& x2) const + { + switch (type_) { + case 1: + return x1.tag1_ < x2.tag1_; + case 2: + return x1.tag2_ < x2.tag2_; + default: + return x1 < x2; + } + } + + std::size_t operator()(int x1, int x2) const { return x1 < x2; } + + friend bool operator==(less const& x1, less const& x2) + { + return x1.type_ == x2.type_; + } + }; + + class equal_to + { + int type_; + + public: + equal_to() : type_(0) {} + + explicit equal_to(int t) : type_(t) {} + + bool operator()(object const& x1, object const& x2) const + { + switch (type_) { + case 1: + return x1.tag1_ == x2.tag1_; + case 2: + return x1.tag2_ == x2.tag2_; + default: + return x1 == x2; + } + } + + bool operator()(movable const& x1, movable const& x2) const + { + switch (type_) { + case 1: + return x1.tag1_ == x2.tag1_; + case 2: + return x1.tag2_ == x2.tag2_; + default: + return x1 == x2; + } + } + + std::size_t operator()(int x1, int x2) const { return x1 == x2; } + + friend bool operator==(equal_to const& x1, equal_to const& x2) + { + return x1.type_ == x2.type_; + } + + friend bool operator!=(equal_to const& x1, equal_to const& x2) + { + return x1.type_ != x2.type_; + } + + friend less create_compare(equal_to x) { return less(x.type_); } + }; + + // allocator1 only has the old fashioned 'construct' method and has + // a few less typedefs. allocator2 uses a custom pointer class. + + template <class T> class allocator1 + { + public: + int tag_; + + typedef T value_type; + + template <class U> struct rebind + { + typedef allocator1<U> other; + }; + + allocator1() : tag_(0) { detail::tracker.allocator_ref(); } + + explicit allocator1(int t) : tag_(t) { detail::tracker.allocator_ref(); } + + template <class Y> allocator1(allocator1<Y> const& x) : tag_(x.tag_) + { + detail::tracker.allocator_ref(); + } + + allocator1(allocator1 const& x) : tag_(x.tag_) + { + detail::tracker.allocator_ref(); + } + + ~allocator1() { detail::tracker.allocator_unref(); } + + T* allocate(std::size_t n) + { + T* ptr(static_cast<T*>(::operator new(n * sizeof(T)))); + detail::tracker.track_allocate((void*)ptr, n, sizeof(T), tag_); + return ptr; + } + + T* allocate(std::size_t n, void const*) + { + T* ptr(static_cast<T*>(::operator new(n * sizeof(T)))); + detail::tracker.track_allocate((void*)ptr, n, sizeof(T), tag_); + return ptr; + } + + void deallocate(T* p, std::size_t n) + { + detail::tracker.track_deallocate((void*)p, n, sizeof(T), tag_); + ::operator delete((void*)p); + } + +#if BOOST_UNORDERED_CXX11_CONSTRUCTION + template <typename U, typename... Args> void construct(U* p, Args&&... args) + { + detail::tracker.track_construct((void*)p, sizeof(U), tag_); + new (p) U(boost::forward<Args>(args)...); + } + + template <typename U> void destroy(U* p) + { + detail::tracker.track_destroy((void*)p, sizeof(U), tag_); + p->~U(); + + // Work around MSVC buggy unused parameter warning. + ignore_variable(&p); + } +#else + private: + // I'm going to claim in the documentation that construct/destroy + // is never used when C++11 support isn't available, so might as + // well check that in the text. + // TODO: Or maybe just disallow them for values? + template <typename U> void construct(U* p); + template <typename U, typename A0> void construct(U* p, A0 const&); + template <typename U, typename A0, typename A1> + void construct(U* p, A0 const&, A1 const&); + template <typename U, typename A0, typename A1, typename A2> + void construct(U* p, A0 const&, A1 const&, A2 const&); + template <typename U> void destroy(U* p); + + public: +#endif + + bool operator==(allocator1 const& x) const { return tag_ == x.tag_; } + + bool operator!=(allocator1 const& x) const { return tag_ != x.tag_; } + + enum + { + is_select_on_copy = false, + is_propagate_on_swap = false, + is_propagate_on_assign = false, + is_propagate_on_move = false + }; + }; + + template <class T> class ptr; + template <class T> class const_ptr; + + struct void_ptr + { +#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) + template <typename T> friend class ptr; + + private: +#endif + + void* ptr_; + + public: + void_ptr() : ptr_(0) {} + + 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_; } + + 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; + + private: +#endif + + void* ptr_; + + public: + void_const_ptr() : ptr_(0) {} + + 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_; } + + 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 + { + friend class allocator2<T>; + friend class const_ptr<T>; + friend struct void_ptr; + + T* ptr_; + + ptr(T* x) : ptr_(x) {} + + public: + 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_; } + + 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_; } + }; + + template <class T> class const_ptr + { + friend class allocator2<T>; + friend struct const_void_ptr; + + T const* 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_) {} + + 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_; } + }; + + template <class T> class allocator2 + { +#ifdef BOOST_NO_MEMBER_TEMPLATE_FRIENDS + public: +#else + template <class> friend class allocator2; +#endif + int tag_; + + 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; + + template <class U> struct rebind + { + typedef allocator2<U> other; + }; + + allocator2() : tag_(0) { detail::tracker.allocator_ref(); } + + explicit allocator2(int t) : tag_(t) { detail::tracker.allocator_ref(); } + + template <class Y> allocator2(allocator2<Y> const& x) : tag_(x.tag_) + { + detail::tracker.allocator_ref(); + } + + allocator2(allocator2 const& x) : tag_(x.tag_) + { + detail::tracker.allocator_ref(); + } + + ~allocator2() { detail::tracker.allocator_unref(); } + + pointer address(reference r) { return pointer(&r); } + + const_pointer address(const_reference r) { return const_pointer(&r); } + + pointer allocate(size_type n) + { + pointer p(static_cast<T*>(::operator new(n * sizeof(T)))); + detail::tracker.track_allocate((void*)p.ptr_, n, sizeof(T), tag_); + return p; + } + + 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; + } + + void deallocate(pointer p, size_type n) + { + detail::tracker.track_deallocate((void*)p.ptr_, n, sizeof(T), tag_); + ::operator delete((void*)p.ptr_); + } + + 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 <class... 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)(); + } + + bool operator==(allocator2 const& x) const { return tag_ == x.tag_; } + + bool operator!=(allocator2 const& x) const { return tag_ != x.tag_; } + + enum + { + is_select_on_copy = false, + is_propagate_on_swap = false, + is_propagate_on_assign = false, + is_propagate_on_move = false + }; + }; + + template <class T> + bool equivalent_impl( + allocator1<T> const& x, allocator1<T> const& y, test::derived_type) + { + return x == y; + } + + template <class T> + bool equivalent_impl( + allocator2<T> const& x, allocator2<T> const& y, test::derived_type) + { + return x == y; + } +} + +#endif diff --git a/src/boost/libs/unordered/test/unordered/allocator_traits.cpp b/src/boost/libs/unordered/test/unordered/allocator_traits.cpp new file mode 100644 index 00000000..476205b7 --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/allocator_traits.cpp @@ -0,0 +1,288 @@ + +// Copyright 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) + +#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*) \ + { \ + 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*) \ + { \ + 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 + }; +}; + +// For tracking calls... + +static int selected; +void reset() { selected = 0; } + +template <typename Allocator> int call_select() +{ + typedef boost::unordered::detail::allocator_traits<Allocator> traits; + Allocator a; + + reset(); + BOOST_TEST(traits::select_on_container_copy_construction(a) == a); + return selected; +} + +// Empty allocator test + +template <typename T> struct 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; +#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1 + 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)); +#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(traits::is_always_equal::value); + BOOST_TEST(call_select<allocator>() == 0); +} + +// allocator 1 + +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; + 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; +#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1 + 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)); +#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(traits::is_always_equal::value); + BOOST_TEST(call_select<allocator>() == 1); +} + +// allocator 2 + +template <typename Alloc> struct allocator2_base +{ + Alloc select_on_container_copy_construction() const + { + ++selected; + return Alloc(); + } +}; + +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 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(!traits::is_always_equal::value); + BOOST_TEST(call_select<allocator>() == 1); +} + +// allocator 3 + +template <typename T> struct ptr +{ + T* value_; + + ptr(void* v) : value_((T*)v) {} + T& operator*() const { return *value_; } +}; + +template <> struct ptr<void> +{ + void* value_; + ptr(void* v) : value_(v) {} +}; + +template <> struct ptr<const void> +{ + void const* value_; + ptr(void const* v) : value_(v) {} +}; + +template <typename T> struct allocator3 +{ + typedef T value_type; + typedef ptr<T> pointer; + typedef ptr<T const> const_pointer; + typedef unsigned short size_type; + + int x; // Just to make it non-empty, so that is_always_equal is false. + + 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(!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(); +} diff --git a/src/boost/libs/unordered/test/unordered/assign_tests.cpp b/src/boost/libs/unordered/test/unordered/assign_tests.cpp new file mode 100644 index 00000000..f3d633b0 --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/assign_tests.cpp @@ -0,0 +1,297 @@ + +// 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) + +// 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" +#include "../helpers/random_values.hpp" +#include "../helpers/tracker.hpp" +#include "../helpers/equivalent.hpp" + +#if defined(BOOST_MSVC) +#pragma warning(disable : 4127) // conditional expression is constant +#endif + +namespace assign_tests { + + test::seed_t initialize_seed(96785); + + template <class T> void assign_tests1(T*, test::random_generator generator) + { + typename T::hasher hf; + typename T::key_equal eq; + + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests1.1\n"; + { + 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)); + } + + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests1.2\n"; + { + test::check_instances check_; + + 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()); + + 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()); + } + } + + 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_; + + 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); + } + + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.1\n"; + { + 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()); + } + + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.1a\n"; + { + 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()); + } + + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.2\n"; + { + 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()); + } + + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "assign_tests2.3\n"; + { + 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()); + } + + 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, + 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::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_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> >* + test_multiset_prop_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> >* + test_multimap_prop_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> >* + 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> >* + 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> >* + test_multimap_no_prop_assign; + + using test::default_generator; + using test::generate_collisions; + using test::limited_range; + + template <typename T> bool is_propagate(T*) + { + return T::allocator_type::is_propagate_on_assign; + } + + 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)(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)(limited_range))) + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + + 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; + x1[16] = 10; + 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) { + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Initializer List Tests\n"; + + boost::unordered_set<int> x; + x.insert(10); + x.insert(20); + x = {1, 2, -10}; + BOOST_TEST(x.find(10) == x.end()); + BOOST_TEST(x.find(-10) != x.end()); + } + +#endif +} + +RUN_TESTS() diff --git a/src/boost/libs/unordered/test/unordered/at_tests.cpp b/src/boost/libs/unordered/test/unordered/at_tests.cpp new file mode 100644 index 00000000..25b0951a --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/at_tests.cpp @@ -0,0 +1,67 @@ + +// Copyright 2007-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) + +// 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) { + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Create Map" << std::endl; + + boost::unordered_map<std::string, int> x; + 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; + + x["one"] = 1; + x["two"] = 2; + + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Check existing elements" << std::endl; + + 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."); + } 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() diff --git a/src/boost/libs/unordered/test/unordered/bucket_tests.cpp b/src/boost/libs/unordered/test/unordered/bucket_tests.cpp new file mode 100644 index 00000000..c314d2c5 --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/bucket_tests.cpp @@ -0,0 +1,94 @@ + +// 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) + +// 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> +#include "../objects/test.hpp" +#include "../helpers/random_values.hpp" +#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. +#endif + +namespace bucket_tests { + + test::seed_t initialize_seed(54635); + + template <class X> void tests(X*, test::random_generator generator) + { + test::check_instances check_; + + 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()); + if (!(x.bucket_count() <= x.max_bucket_count())) { + BOOST_LIGHTWEIGHT_TEST_OSTREAM << x.bucket_count() + << "<=" << x.max_bucket_count() << "\n"; + } + + 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.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)))); + } + } + + 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, + test::allocator2<test::object> >* test_set; + 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, + 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; + 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() diff --git a/src/boost/libs/unordered/test/unordered/compile_map.cpp b/src/boost/libs/unordered/test/unordered/compile_map.cpp new file mode 100644 index 00000000..6a84d595 --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/compile_map.cpp @@ -0,0 +1,248 @@ + +// 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) + +// 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 "../helpers/test.hpp" +#include "../objects/minimal.hpp" +#include "./compile_tests.hpp" + +// Explicit instantiation to catch compile-time errors + +#define INSTANTIATE(type) \ + template class boost::unordered::detail::instantiate_##type + +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<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<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); + unordered_map_member_test(multimap, map_value); +} + +// Test for ambiguity when using key convertible from iterator +// See LWG2059 + +struct lwg2059_key +{ + int value; + + template <typename T> lwg2059_key(T v) : value(v) {} +}; + +std::size_t hash_value(lwg2059_key x) +{ + return static_cast<std::size_t>(x.value); +} + +bool operator==(lwg2059_key x, lwg2059_key y) { return x.value == y.value; } + +UNORDERED_AUTO_TEST (lwg2059) { + { + boost::unordered_map<lwg2059_key, int> x; + x.emplace(lwg2059_key(10), 5); + x.erase(x.begin()); + } + + { + boost::unordered_multimap<lwg2059_key, int> x; + x.emplace(lwg2059_key(10), 5); + x.erase(x.begin()); + } +} + +RUN_TESTS() diff --git a/src/boost/libs/unordered/test/unordered/compile_set.cpp b/src/boost/libs/unordered/test/unordered/compile_set.cpp new file mode 100644 index 00000000..727294f3 --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/compile_set.cpp @@ -0,0 +1,313 @@ + +// 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) + +// 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 "../helpers/test.hpp" +#include "../objects/minimal.hpp" +#include "./compile_tests.hpp" + +// Explicit instantiation to catch compile-time errors + +#define INSTANTIATE(type) \ + template class boost::unordered::detail::instantiate_##type + +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> > + 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> > + multiset; + + 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; + + 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::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); + + 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::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); +} + +UNORDERED_AUTO_TEST (test1) { + boost::hash<int> hash; + std::equal_to<int> equal_to; + int value = 0; + + 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; + + unordered_unique_test(set, value); + unordered_set_test(set, value); + unordered_copyable_test(set, value, value, hash, equal_to); + + unordered_unique_test(set2, value); + unordered_set_test(set2, value); + unordered_copyable_test(set2, value, value, hash, equal_to); + + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset." << std::endl; + + boost::unordered_multiset<int> multiset; + + 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); + + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n"; + + 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; + + 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_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n"; + + 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; + + test::minimal::movable1 movable1(x); + test::minimal::hash<test::minimal::movable1> hash(x); + test::minimal::equal_to<test::minimal::movable1> equal_to(x); + + 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; + + // unordered_unique_test(set, movable1); + unordered_set_test(set, movable1); + unordered_movable_test(set, movable1, movable1, hash, equal_to); + + 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; + + // 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; + + test::minimal::movable2 movable2(x); + test::minimal::hash<test::minimal::movable2> hash(x); + test::minimal::equal_to<test::minimal::movable2> equal_to(x); + + 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; + + // unordered_unique_test(set, movable2); + unordered_set_test(set, movable2); + unordered_movable_test(set, movable2, movable2, hash, equal_to); + + 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; + + // unordered_equivalent_test(multiset, movable2); + unordered_set_test(multiset, movable2); + unordered_movable_test(multiset, movable2, movable2, hash, equal_to); +} + +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 +{ + int value; + + template <typename T> lwg2059_key(T v) : value(v) {} +}; + +std::size_t hash_value(lwg2059_key x) +{ + return static_cast<std::size_t>(x.value); +} + +bool operator==(lwg2059_key x, lwg2059_key y) { return x.value == y.value; } + +UNORDERED_AUTO_TEST (lwg2059) { + { + boost::unordered_set<lwg2059_key> x; + x.emplace(lwg2059_key(10)); + x.erase(x.begin()); + } + + { + boost::unordered_multiset<lwg2059_key> x; + x.emplace(lwg2059_key(10)); + x.erase(x.begin()); + } +} + +RUN_TESTS() diff --git a/src/boost/libs/unordered/test/unordered/compile_tests.hpp b/src/boost/libs/unordered/test/unordered/compile_tests.hpp new file mode 100644 index 00000000..bb5256f8 --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/compile_tests.hpp @@ -0,0 +1,913 @@ + +// Copyright 2005-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) + +#if defined(BOOST_MSVC) +#pragma warning(push) +#pragma warning(disable : 4100) // unreferenced formal parameter +#pragma warning(disable : 4610) // class can never be instantiated +#pragma warning(disable : 4510) // default constructor could not be generated +#endif + +#include <boost/concept_check.hpp> + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + +#include "../helpers/check_return_type.hpp" +#include <boost/core/pointer_traits.hpp> +#include <boost/limits.hpp> +#include <boost/predef.h> +#include <boost/static_assert.hpp> +#include <boost/type_traits/cv_traits.hpp> +#include <boost/type_traits/is_const.hpp> +#include <boost/type_traits/is_convertible.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/utility/swap.hpp> + +typedef long double comparison_type; + +template <class T> void sink(T const&) {} +template <class T> T rvalue(T const& v) { return v; } +template <class T> T rvalue_default() { return T(); } + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) +template <class T> T implicit_construct() { return {}; } +#else +template <class T> int implicit_construct() +{ + T x; + sink(x); + return 0; +} +#endif + +#if !defined(BOOST_NO_CXX11_NOEXCEPT) +#define TEST_NOEXCEPT_EXPR(x) BOOST_STATIC_ASSERT((BOOST_NOEXCEPT_EXPR(x))); +#else +#define TEST_NOEXCEPT_EXPR(x) +#endif + +template <class X, class T> void container_test(X& r, T const&) +{ + typedef typename X::iterator iterator; + typedef typename X::const_iterator const_iterator; + typedef typename X::difference_type difference_type; + typedef typename X::size_type size_type; + + typedef + typename std::iterator_traits<iterator>::value_type iterator_value_type; + typedef typename std::iterator_traits<const_iterator>::value_type + const_iterator_value_type; + typedef typename std::iterator_traits<iterator>::difference_type + iterator_difference_type; + typedef typename std::iterator_traits<const_iterator>::difference_type + const_iterator_difference_type; + + typedef typename X::value_type value_type; + typedef typename X::reference reference; + typedef typename X::const_reference const_reference; + + typedef typename X::node_type node_type; + + typedef typename X::allocator_type allocator_type; + + // value_type + + BOOST_STATIC_ASSERT((boost::is_same<T, value_type>::value)); + boost::function_requires<boost::CopyConstructibleConcept<X> >(); + + // reference_type / const_reference_type + + BOOST_STATIC_ASSERT((boost::is_same<T&, reference>::value)); + BOOST_STATIC_ASSERT((boost::is_same<T const&, const_reference>::value)); + + // iterator + + boost::function_requires<boost::InputIteratorConcept<iterator> >(); + BOOST_STATIC_ASSERT((boost::is_same<T, iterator_value_type>::value)); + BOOST_STATIC_ASSERT((boost::is_convertible<iterator, const_iterator>::value)); + + // const_iterator + + boost::function_requires<boost::InputIteratorConcept<const_iterator> >(); + BOOST_STATIC_ASSERT((boost::is_same<T, const_iterator_value_type>::value)); + + // node_type + + BOOST_STATIC_ASSERT(( + boost::is_same<allocator_type, typename node_type::allocator_type>::value)); + + // difference_type + + BOOST_STATIC_ASSERT(std::numeric_limits<difference_type>::is_signed); + BOOST_STATIC_ASSERT(std::numeric_limits<difference_type>::is_integer); + BOOST_STATIC_ASSERT( + (boost::is_same<difference_type, iterator_difference_type>::value)); + BOOST_STATIC_ASSERT( + (boost::is_same<difference_type, const_iterator_difference_type>::value)); + + // size_type + + BOOST_STATIC_ASSERT(!std::numeric_limits<size_type>::is_signed); + BOOST_STATIC_ASSERT(std::numeric_limits<size_type>::is_integer); + + // size_type can represent any non-negative value type of difference_type + // I'm not sure about either of these tests... + size_type max_diff = + static_cast<size_type>((std::numeric_limits<difference_type>::max)()); + difference_type converted_diff(static_cast<difference_type>(max_diff)); + BOOST_TEST((std::numeric_limits<difference_type>::max)() == converted_diff); + + BOOST_TEST( + static_cast<comparison_type>((std::numeric_limits<size_type>::max)()) > + static_cast<comparison_type>( + (std::numeric_limits<difference_type>::max)())); + +// Constructors + +// I don't test the runtime post-conditions here. + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + // It isn't specified in the container requirements that the no argument + // constructor is implicit, but it is defined that way in the concrete + // container specification. + X u_implicit = {}; + sink(u_implicit); +#endif + + X u; + BOOST_TEST(u.size() == 0); + BOOST_TEST(X().size() == 0); + + X a, b; + X a_const; + + sink(X(a)); + X u2(a); + X u3 = a; + X u4(rvalue(a_const)); + X u5 = rvalue(a_const); + + a.swap(b); + boost::swap(a, b); + test::check_return_type<X>::equals_ref(r = a); + + // Allocator + + test::check_return_type<allocator_type>::equals(a_const.get_allocator()); + + allocator_type m = a.get_allocator(); + sink(X(m)); + X c(m); + sink(X(a_const, m)); + X c2(a_const, m); + sink(X(rvalue(a_const), m)); + X c3(rvalue(a_const), m); + + // node_type + + implicit_construct<node_type const>(); +#if !BOOST_COMP_GNUC || BOOST_COMP_GNUC >= BOOST_VERSION_NUMBER(4, 8, 0) + TEST_NOEXCEPT_EXPR(node_type()); +#endif + + node_type n1; + node_type n2(rvalue_default<node_type>()); +#if !BOOST_COMP_GNUC || BOOST_COMP_GNUC >= BOOST_VERSION_NUMBER(4, 8, 0) + TEST_NOEXCEPT_EXPR(node_type(boost::move(n1))); +#endif + node_type n3; + n3 = boost::move(n2); + n1.swap(n3); + swap(n1, n3); + // TODO: noexcept for swap? + // value, key, mapped tests in map and set specific testing. + + node_type const n_const; + BOOST_TEST(n_const ? 0 : 1); + TEST_NOEXCEPT_EXPR(n_const ? 0 : 1); + test::check_return_type<bool>::equals(!n_const); + test::check_return_type<bool>::equals(n_const.empty()); + TEST_NOEXCEPT_EXPR(!n_const); + TEST_NOEXCEPT_EXPR(n_const.empty()); + + // Avoid unused variable warnings: + + sink(u); + sink(u2); + sink(u3); + sink(u4); + sink(u5); + sink(c); + sink(c2); + sink(c3); +} + +template <class X> void unordered_destructible_test(X&) +{ + typedef typename X::iterator iterator; + typedef typename X::const_iterator const_iterator; + typedef typename X::size_type size_type; + + X x1; + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + X x2(rvalue_default<X>()); + X x3 = rvalue_default<X>(); +// This can only be done if propagate_on_container_move_assignment::value +// is true. +// x2 = rvalue_default<X>(); +#endif + + X* ptr = new X(); + X& a1 = *ptr; + (&a1)->~X(); + ::operator delete((void*)(&a1)); + + X a, b; + X const a_const; + test::check_return_type<iterator>::equals(a.begin()); + test::check_return_type<const_iterator>::equals(a_const.begin()); + test::check_return_type<const_iterator>::equals(a.cbegin()); + test::check_return_type<const_iterator>::equals(a_const.cbegin()); + test::check_return_type<iterator>::equals(a.end()); + test::check_return_type<const_iterator>::equals(a_const.end()); + test::check_return_type<const_iterator>::equals(a.cend()); + test::check_return_type<const_iterator>::equals(a_const.cend()); + + a.swap(b); + boost::swap(a, b); + + test::check_return_type<size_type>::equals(a.size()); + test::check_return_type<size_type>::equals(a.max_size()); + test::check_return_type<bool>::convertible(a.empty()); + + // Allocator + + typedef typename X::allocator_type allocator_type; + test::check_return_type<allocator_type>::equals(a_const.get_allocator()); +} + +template <class X, class Key> void unordered_set_test(X& r, Key const&) +{ + typedef typename X::value_type value_type; + typedef typename X::key_type key_type; + + BOOST_STATIC_ASSERT((boost::is_same<value_type, key_type>::value)); + + // iterator pointer / const_pointer_type + + typedef typename X::iterator iterator; + typedef typename X::const_iterator const_iterator; + typedef typename X::local_iterator local_iterator; + typedef typename X::const_local_iterator const_local_iterator; + typedef typename std::iterator_traits<iterator>::pointer iterator_pointer; + typedef typename std::iterator_traits<const_iterator>::pointer + const_iterator_pointer; + typedef typename std::iterator_traits<local_iterator>::pointer + local_iterator_pointer; + typedef typename std::iterator_traits<const_local_iterator>::pointer + const_local_iterator_pointer; + + BOOST_STATIC_ASSERT( + (boost::is_same<value_type const*, iterator_pointer>::value)); + BOOST_STATIC_ASSERT( + (boost::is_same<value_type const*, const_iterator_pointer>::value)); + BOOST_STATIC_ASSERT( + (boost::is_same<value_type const*, local_iterator_pointer>::value)); + BOOST_STATIC_ASSERT( + (boost::is_same<value_type const*, const_local_iterator_pointer>::value)); + + // pointer_traits<iterator> + + BOOST_STATIC_ASSERT((boost::is_same<iterator, + typename boost::pointer_traits<iterator>::pointer>::value)); + BOOST_STATIC_ASSERT((boost::is_same<value_type const, + typename boost::pointer_traits<iterator>::element_type>::value)); + BOOST_STATIC_ASSERT((boost::is_same<std::ptrdiff_t, + typename boost::pointer_traits<iterator>::difference_type>::value)); + + // pointer_traits<const_iterator> + + BOOST_STATIC_ASSERT((boost::is_same<const_iterator, + typename boost::pointer_traits<const_iterator>::pointer>::value)); + BOOST_STATIC_ASSERT((boost::is_same<value_type const, + typename boost::pointer_traits<const_iterator>::element_type>::value)); + BOOST_STATIC_ASSERT((boost::is_same<std::ptrdiff_t, + typename boost::pointer_traits<const_iterator>::difference_type>::value)); + + // pointer_traits<local_iterator> + + BOOST_STATIC_ASSERT((boost::is_same<local_iterator, + typename boost::pointer_traits<local_iterator>::pointer>::value)); + BOOST_STATIC_ASSERT((boost::is_same<value_type const, + typename boost::pointer_traits<local_iterator>::element_type>::value)); + BOOST_STATIC_ASSERT((boost::is_same<std::ptrdiff_t, + typename boost::pointer_traits<local_iterator>::difference_type>::value)); + + // pointer_traits<const_local_iterator> + + BOOST_STATIC_ASSERT((boost::is_same<const_local_iterator, + typename boost::pointer_traits<const_local_iterator>::pointer>::value)); + BOOST_STATIC_ASSERT((boost::is_same<value_type const, + typename boost::pointer_traits<const_local_iterator>::element_type>:: + value)); + BOOST_STATIC_ASSERT((boost::is_same<std::ptrdiff_t, + typename boost::pointer_traits<const_local_iterator>::difference_type>:: + value)); + + typedef typename X::node_type node_type; + typedef typename node_type::value_type node_value_type; + BOOST_STATIC_ASSERT((boost::is_same<value_type, node_value_type>::value)); + + // Call node_type functions. + + test::minimal::constructor_param v; + Key k_lvalue(v); + r.emplace(boost::move(k_lvalue)); + node_type n1 = r.extract(r.begin()); + test::check_return_type<value_type>::equals_ref(n1.value()); +} + +template <class X, class Key, class T> +void unordered_map_test(X& r, Key const& k, T const& v) +{ + typedef typename X::value_type value_type; + typedef typename X::key_type key_type; + + BOOST_STATIC_ASSERT( + (boost::is_same<value_type, std::pair<key_type const, T> >::value)); + + // iterator pointer / const_pointer_type + + typedef typename X::iterator iterator; + typedef typename X::const_iterator const_iterator; + typedef typename X::local_iterator local_iterator; + typedef typename X::const_local_iterator const_local_iterator; + typedef typename std::iterator_traits<iterator>::pointer iterator_pointer; + typedef typename std::iterator_traits<const_iterator>::pointer + const_iterator_pointer; + typedef typename std::iterator_traits<local_iterator>::pointer + local_iterator_pointer; + typedef typename std::iterator_traits<const_local_iterator>::pointer + const_local_iterator_pointer; + + BOOST_STATIC_ASSERT((boost::is_same<value_type*, iterator_pointer>::value)); + BOOST_STATIC_ASSERT( + (boost::is_same<value_type const*, const_iterator_pointer>::value)); + BOOST_STATIC_ASSERT( + (boost::is_same<value_type*, local_iterator_pointer>::value)); + BOOST_STATIC_ASSERT( + (boost::is_same<value_type const*, const_local_iterator_pointer>::value)); + + // pointer_traits<iterator> + + BOOST_STATIC_ASSERT((boost::is_same<iterator, + typename boost::pointer_traits<iterator>::pointer>::value)); + BOOST_STATIC_ASSERT((boost::is_same<value_type, + typename boost::pointer_traits<iterator>::element_type>::value)); + BOOST_STATIC_ASSERT((boost::is_same<std::ptrdiff_t, + typename boost::pointer_traits<iterator>::difference_type>::value)); + + // pointer_traits<const_iterator> + + BOOST_STATIC_ASSERT((boost::is_same<const_iterator, + typename boost::pointer_traits<const_iterator>::pointer>::value)); + BOOST_STATIC_ASSERT((boost::is_same<value_type const, + typename boost::pointer_traits<const_iterator>::element_type>::value)); + BOOST_STATIC_ASSERT((boost::is_same<std::ptrdiff_t, + typename boost::pointer_traits<const_iterator>::difference_type>::value)); + + // pointer_traits<local_iterator> + + BOOST_STATIC_ASSERT((boost::is_same<local_iterator, + typename boost::pointer_traits<local_iterator>::pointer>::value)); + BOOST_STATIC_ASSERT((boost::is_same<value_type, + typename boost::pointer_traits<local_iterator>::element_type>::value)); + BOOST_STATIC_ASSERT((boost::is_same<std::ptrdiff_t, + typename boost::pointer_traits<local_iterator>::difference_type>::value)); + + // pointer_traits<const_local_iterator> + + BOOST_STATIC_ASSERT((boost::is_same<const_local_iterator, + typename boost::pointer_traits<const_local_iterator>::pointer>::value)); + BOOST_STATIC_ASSERT((boost::is_same<value_type const, + typename boost::pointer_traits<const_local_iterator>::element_type>:: + value)); + BOOST_STATIC_ASSERT((boost::is_same<std::ptrdiff_t, + typename boost::pointer_traits<const_local_iterator>::difference_type>:: + value)); + + typedef typename X::node_type node_type; + typedef typename node_type::key_type node_key_type; + typedef typename node_type::mapped_type node_mapped_type; + + BOOST_STATIC_ASSERT((boost::is_same<Key, node_key_type>::value)); + BOOST_STATIC_ASSERT((boost::is_same<T, node_mapped_type>::value)); + // Superfluous,but just to make sure. + BOOST_STATIC_ASSERT((!boost::is_const<node_key_type>::value)); + + // Calling functions + + r.insert(std::pair<Key const, T>(k, v)); + r.insert(r.begin(), std::pair<Key const, T>(k, v)); + std::pair<Key const, T> const value(k, v); + r.insert(value); + r.insert(r.end(), value); + + Key k_lvalue(k); + T v_lvalue(v); + + // Emplace + + r.emplace(k, v); + r.emplace(k_lvalue, v_lvalue); + r.emplace(rvalue(k), rvalue(v)); + + r.emplace(boost::unordered::piecewise_construct, boost::make_tuple(k), + boost::make_tuple(v)); + + // Emplace with hint + + r.emplace_hint(r.begin(), k, v); + r.emplace_hint(r.begin(), k_lvalue, v_lvalue); + r.emplace_hint(r.begin(), rvalue(k), rvalue(v)); + + r.emplace_hint(r.begin(), boost::unordered::piecewise_construct, + boost::make_tuple(k), boost::make_tuple(v)); + + // Extract + + test::check_return_type<node_type>::equals(r.extract(r.begin())); + + r.emplace(k, v); + test::check_return_type<node_type>::equals(r.extract(k)); + + r.emplace(k, v); + node_type n1 = r.extract(r.begin()); + test::check_return_type<key_type>::equals_ref(n1.key()); + test::check_return_type<T>::equals_ref(n1.mapped()); + + node_type n2 = boost::move(n1); + r.insert(boost::move(n2)); + r.insert(r.extract(r.begin())); + n2 = r.extract(r.begin()); + r.insert(r.begin(), boost::move(n2)); + r.insert(r.end(), r.extract(r.begin())); + + node_type n = r.extract(r.begin()); + test::check_return_type<node_key_type>::equals_ref(n.key()); + test::check_return_type<node_mapped_type>::equals_ref(n.mapped()); +} + +template <class X> void equality_test(X& r) +{ + X const a = r, b = r; + + test::check_return_type<bool>::equals(a == b); + test::check_return_type<bool>::equals(a != b); + test::check_return_type<bool>::equals(boost::operator==(a, b)); + test::check_return_type<bool>::equals(boost::operator!=(a, b)); +} + +template <class X, class T> void unordered_unique_test(X& r, T const& t) +{ + typedef typename X::iterator iterator; + test::check_return_type<std::pair<iterator, bool> >::equals(r.insert(t)); + test::check_return_type<std::pair<iterator, bool> >::equals(r.emplace(t)); + + typedef typename X::node_type node_type; + typedef typename X::insert_return_type insert_return_type; + + // insert_return_type + + // TODO; + // boost::function_requires< + // boost::MoveConstructibleConcept<insert_return_type> + // >(); + // TODO; + // boost::function_requires< + // boost::MoveAssignableConcept<insert_return_type> + // >(); + boost::function_requires< + boost::DefaultConstructibleConcept<insert_return_type> >(); + // TODO: + // boost::function_requires< + // boost::DestructibleConcept<insert_return_type> + // >(); + insert_return_type insert_return, insert_return2; + test::check_return_type<bool>::equals(insert_return.inserted); + test::check_return_type<iterator>::equals(insert_return.position); + test::check_return_type<node_type>::equals_ref(insert_return.node); + boost::swap(insert_return, insert_return2); +} + +template <class X, class T> void unordered_equivalent_test(X& r, T const& t) +{ + typedef typename X::iterator iterator; + test::check_return_type<iterator>::equals(r.insert(t)); + test::check_return_type<iterator>::equals(r.emplace(t)); +} + +template <class X, class Key, class T> +void unordered_map_functions(X&, Key const& k, T const& v) +{ + typedef typename X::mapped_type mapped_type; + typedef typename X::iterator iterator; + + X a; + test::check_return_type<mapped_type>::equals_ref(a[k]); + test::check_return_type<mapped_type>::equals_ref(a[rvalue(k)]); + test::check_return_type<mapped_type>::equals_ref(a.at(k)); + test::check_return_type<std::pair<iterator, bool> >::equals( + a.try_emplace(k, v)); + test::check_return_type<std::pair<iterator, bool> >::equals( + a.try_emplace(rvalue(k), v)); + test::check_return_type<iterator>::equals(a.try_emplace(a.begin(), k, v)); + test::check_return_type<iterator>::equals( + a.try_emplace(a.begin(), rvalue(k), v)); + test::check_return_type<std::pair<iterator, bool> >::equals( + a.insert_or_assign(k, v)); + test::check_return_type<std::pair<iterator, bool> >::equals( + a.insert_or_assign(rvalue(k), v)); + test::check_return_type<iterator>::equals( + a.insert_or_assign(a.begin(), k, v)); + test::check_return_type<iterator>::equals( + a.insert_or_assign(a.begin(), rvalue(k), v)); + + X const b = a; + test::check_return_type<mapped_type const>::equals_ref(b.at(k)); +} + +template <class X, class Key, class Hash, class Pred> +void unordered_test(X& x, Key& k, Hash& hf, Pred& eq) +{ + unordered_destructible_test(x); + + typedef typename X::key_type key_type; + typedef typename X::hasher hasher; + typedef typename X::key_equal key_equal; + typedef typename X::size_type size_type; + + typedef typename X::iterator iterator; + typedef typename X::const_iterator const_iterator; + typedef typename X::local_iterator local_iterator; + typedef typename X::const_local_iterator const_local_iterator; + + typedef typename std::iterator_traits<iterator>::iterator_category + iterator_category; + typedef typename std::iterator_traits<iterator>::difference_type + iterator_difference; + typedef typename std::iterator_traits<iterator>::pointer iterator_pointer; + typedef typename std::iterator_traits<iterator>::reference iterator_reference; + + typedef typename std::iterator_traits<local_iterator>::iterator_category + local_iterator_category; + typedef typename std::iterator_traits<local_iterator>::difference_type + local_iterator_difference; + typedef typename std::iterator_traits<local_iterator>::pointer + local_iterator_pointer; + typedef typename std::iterator_traits<local_iterator>::reference + local_iterator_reference; + + typedef typename std::iterator_traits<const_iterator>::iterator_category + const_iterator_category; + typedef typename std::iterator_traits<const_iterator>::difference_type + const_iterator_difference; + typedef typename std::iterator_traits<const_iterator>::pointer + const_iterator_pointer; + typedef typename std::iterator_traits<const_iterator>::reference + const_iterator_reference; + + typedef typename std::iterator_traits<const_local_iterator>::iterator_category + const_local_iterator_category; + typedef typename std::iterator_traits<const_local_iterator>::difference_type + const_local_iterator_difference; + typedef typename std::iterator_traits<const_local_iterator>::pointer + const_local_iterator_pointer; + typedef typename std::iterator_traits<const_local_iterator>::reference + const_local_iterator_reference; + typedef typename X::allocator_type allocator_type; + + BOOST_STATIC_ASSERT((boost::is_same<Key, key_type>::value)); + // boost::function_requires<boost::CopyConstructibleConcept<key_type> >(); + // boost::function_requires<boost::AssignableConcept<key_type> >(); + + BOOST_STATIC_ASSERT((boost::is_same<Hash, hasher>::value)); + test::check_return_type<std::size_t>::equals(hf(k)); + + BOOST_STATIC_ASSERT((boost::is_same<Pred, key_equal>::value)); + test::check_return_type<bool>::convertible(eq(k, k)); + + boost::function_requires<boost::InputIteratorConcept<local_iterator> >(); + BOOST_STATIC_ASSERT( + (boost::is_same<local_iterator_category, iterator_category>::value)); + BOOST_STATIC_ASSERT( + (boost::is_same<local_iterator_difference, iterator_difference>::value)); + BOOST_STATIC_ASSERT( + (boost::is_same<local_iterator_pointer, iterator_pointer>::value)); + BOOST_STATIC_ASSERT( + (boost::is_same<local_iterator_reference, iterator_reference>::value)); + + boost::function_requires< + boost::InputIteratorConcept<const_local_iterator> >(); + BOOST_STATIC_ASSERT((boost::is_same<const_local_iterator_category, + const_iterator_category>::value)); + BOOST_STATIC_ASSERT((boost::is_same<const_local_iterator_difference, + const_iterator_difference>::value)); + BOOST_STATIC_ASSERT((boost::is_same<const_local_iterator_pointer, + const_iterator_pointer>::value)); + BOOST_STATIC_ASSERT((boost::is_same<const_local_iterator_reference, + const_iterator_reference>::value)); + + X a; + allocator_type m = a.get_allocator(); + + // Constructors + + X(10, hf, eq); + X a1(10, hf, eq); + X(10, hf); + X a2(10, hf); + X(10); + X a3(10); + X(); + X a4; + + X(10, hf, eq, m); + X a1a(10, hf, eq, m); + X(10, hf, m); + X a2a(10, hf, m); + X(10, m); + X a3a(10, m); + (X(m)); + X a4a(m); + + test::check_return_type<size_type>::equals(a.erase(k)); + + const_iterator q1 = a.cbegin(), q2 = a.cend(); + test::check_return_type<iterator>::equals(a.erase(q1, q2)); + + TEST_NOEXCEPT_EXPR(a.clear()); + a.clear(); + + X const b; + + test::check_return_type<hasher>::equals(b.hash_function()); + test::check_return_type<key_equal>::equals(b.key_eq()); + + test::check_return_type<iterator>::equals(a.find(k)); + test::check_return_type<const_iterator>::equals(b.find(k)); + test::check_return_type<size_type>::equals(b.count(k)); + test::check_return_type<std::pair<iterator, iterator> >::equals( + a.equal_range(k)); + test::check_return_type<std::pair<const_iterator, const_iterator> >::equals( + b.equal_range(k)); + test::check_return_type<size_type>::equals(b.bucket_count()); + test::check_return_type<size_type>::equals(b.max_bucket_count()); + test::check_return_type<size_type>::equals(b.bucket(k)); + test::check_return_type<size_type>::equals(b.bucket_size(0)); + + test::check_return_type<local_iterator>::equals(a.begin(0)); + test::check_return_type<const_local_iterator>::equals(b.begin(0)); + test::check_return_type<local_iterator>::equals(a.end(0)); + test::check_return_type<const_local_iterator>::equals(b.end(0)); + + test::check_return_type<const_local_iterator>::equals(a.cbegin(0)); + test::check_return_type<const_local_iterator>::equals(b.cbegin(0)); + test::check_return_type<const_local_iterator>::equals(a.cend(0)); + test::check_return_type<const_local_iterator>::equals(b.cend(0)); + + test::check_return_type<float>::equals(b.load_factor()); + test::check_return_type<float>::equals(b.max_load_factor()); + a.max_load_factor((float)2.0); + a.rehash(100); + + a.merge(a2); +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + a.merge(rvalue_default<X>()); +#endif + + // Avoid unused variable warnings: + + sink(a); + sink(a1); + sink(a2); + sink(a3); + sink(a4); + sink(a1a); + sink(a2a); + sink(a3a); + sink(a4a); +} + +template <class X, class Key, class T, class Hash, class Pred> +void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq) +{ + unordered_test(x, k, hf, eq); + + typedef typename X::iterator iterator; + typedef typename X::const_iterator const_iterator; + typedef typename X::allocator_type allocator_type; + + X a; + allocator_type m = a.get_allocator(); + + typename X::value_type* i = 0; + typename X::value_type* j = 0; + + // Constructors + + X(i, j, 10, hf, eq); + X a5(i, j, 10, hf, eq); + X(i, j, 10, hf); + X a6(i, j, 10, hf); + X(i, j, 10); + X a7(i, j, 10); + X(i, j); + X a8(i, j); + + X(i, j, 10, hf, eq, m); + X a5a(i, j, 10, hf, eq, m); + X(i, j, 10, hf, m); + X a6a(i, j, 10, hf, m); + X(i, j, 10, m); + X a7a(i, j, 10, m); + +// Not specified for some reason (maybe ambiguity with another constructor?) +// X(i, j, m); +// X a8a(i, j, m); +// sink(a8a); + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + std::size_t min_buckets = 10; + X({t}); + X({t}, min_buckets); + X({t}, min_buckets, hf); + X({t}, min_buckets, hf, eq); + // X({t}, m); + X({t}, min_buckets, m); + X({t}, min_buckets, hf, m); + X({t}, min_buckets, hf, eq, m); +#endif + + X const b; + sink(X(b)); + X a9(b); + a = b; + + sink(X(b, m)); + X a9a(b, m); + + X b1; + b1.insert(t); + X a9b(b1); + sink(a9b); + X a9c(b1, m); + sink(a9c); + + const_iterator q = a.cbegin(); + + test::check_return_type<iterator>::equals(a.insert(q, t)); + test::check_return_type<iterator>::equals(a.emplace_hint(q, t)); + + a.insert(i, j); +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + std::initializer_list<T> list = {t}; + a.insert(list); + a.insert({t, t, t}); + +#if !BOOST_WORKAROUND(BOOST_MSVC, < 1900) && \ + (!defined(__clang__) || __clang_major__ >= 4 || \ + (__clang_major__ == 3 && __clang_minor__ >= 4)) + a.insert({}); + a.insert({t}); + a.insert({t, t}); +#endif +#endif + + X a10; + a10.insert(t); + q = a10.cbegin(); + test::check_return_type<iterator>::equals(a10.erase(q)); + + // Avoid unused variable warnings: + + sink(a); + sink(a5); + sink(a6); + sink(a7); + sink(a8); + sink(a9); + sink(a5a); + sink(a6a); + sink(a7a); + sink(a9a); + + typedef typename X::node_type node_type; + typedef typename X::allocator_type allocator_type; + node_type const n_const = a.extract(a.begin()); + test::check_return_type<allocator_type>::equals(n_const.get_allocator()); +} + +template <class X, class Key, class T, class Hash, class Pred> +void unordered_movable_test(X& x, Key& k, T& /* t */, Hash& hf, Pred& eq) +{ + unordered_test(x, k, hf, eq); + + typedef typename X::iterator iterator; + typedef typename X::const_iterator const_iterator; + typedef typename X::allocator_type allocator_type; + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + X x1(rvalue_default<X>()); + X x2(boost::move(x1)); + x1 = rvalue_default<X>(); + x2 = boost::move(x1); +#endif + + X a; + allocator_type m = a.get_allocator(); + + test::minimal::constructor_param* i = 0; + test::minimal::constructor_param* j = 0; + + // Constructors + + X(i, j, 10, hf, eq); + X a5(i, j, 10, hf, eq); + X(i, j, 10, hf); + X a6(i, j, 10, hf); + X(i, j, 10); + X a7(i, j, 10); + X(i, j); + X a8(i, j); + + X(i, j, 10, hf, eq, m); + X a5a(i, j, 10, hf, eq, m); + X(i, j, 10, hf, m); + X a6a(i, j, 10, hf, m); + X(i, j, 10, m); + X a7a(i, j, 10, m); + + // Not specified for some reason (maybe ambiguity with another constructor?) + // X(i, j, m); + // X a8a(i, j, m); + // sink(a8a); + + const_iterator q = a.cbegin(); + + test::minimal::constructor_param v; + a.emplace(v); + test::check_return_type<iterator>::equals(a.emplace_hint(q, v)); + + T v1(v); + a.emplace(boost::move(v1)); + T v2(v); + a.insert(boost::move(v2)); + T v3(v); + test::check_return_type<iterator>::equals(a.emplace_hint(q, boost::move(v3))); + T v4(v); + test::check_return_type<iterator>::equals(a.insert(q, boost::move(v4))); + + a.insert(i, j); + + X a10; + T v5(v); + a10.insert(boost::move(v5)); + q = a10.cbegin(); + test::check_return_type<iterator>::equals(a10.erase(q)); + + // Avoid unused variable warnings: + + sink(a); + sink(a5); + sink(a6); + sink(a7); + sink(a8); + sink(a5a); + sink(a6a); + sink(a7a); + sink(a10); +} + +template <class X, class T> void unordered_set_member_test(X& x, T& t) +{ + X x1(x); + x1.insert(t); + x1.begin()->dummy_member(); + x1.cbegin()->dummy_member(); +} + +template <class X, class T> void unordered_map_member_test(X& x, T& t) +{ + X x1(x); + x1.insert(t); + x1.begin()->first.dummy_member(); + x1.cbegin()->first.dummy_member(); + x1.begin()->second.dummy_member(); + x1.cbegin()->second.dummy_member(); +} diff --git a/src/boost/libs/unordered/test/unordered/constructor_tests.cpp b/src/boost/libs/unordered/test/unordered/constructor_tests.cpp new file mode 100644 index 00000000..5f571986 --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/constructor_tests.cpp @@ -0,0 +1,446 @@ + +// Copyright 2006-2010 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 "../objects/test.hpp" +#include "../helpers/random_values.hpp" +#include "../helpers/tracker.hpp" +#include "../helpers/equivalent.hpp" +#include "../helpers/input_iterator.hpp" +#include "../helpers/invariants.hpp" + +namespace constructor_tests { + + test::seed_t initialize_seed(356730); + + 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; + + UNORDERED_SUB_TEST("Construct 1") + { + 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); + } + + UNORDERED_SUB_TEST("Construct 2") + { + 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); + } + + UNORDERED_SUB_TEST("Construct 3") + { + 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); + } + + UNORDERED_SUB_TEST("Construct 4") + { + 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); + } + + UNORDERED_SUB_TEST("Construct 5") + { + 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); + } + + UNORDERED_SUB_TEST("Construct 6") + { + 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); + } + + UNORDERED_SUB_TEST("Construct 7") + { + 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); + } + + UNORDERED_SUB_TEST("Construct 8") + { + 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); + } + + UNORDERED_SUB_TEST("Construct 9") + { + 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); + } + + UNORDERED_SUB_TEST("Construct 10") + { + 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); + } + + UNORDERED_SUB_TEST("Construct 11") + { + 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); + } + } + + 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); + + 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); + } + + 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); + } + + 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); + } + + 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); + } + + 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); + } + + 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); + } + + 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); + } + + UNORDERED_SUB_TEST("Construct 8 - from input iterator") + { + 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); + } + + 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<typename T::value_type> list; + + 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)); + } + + UNORDERED_SUB_TEST("Initializer list construct 2") + { + 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)); + } + + UNORDERED_SUB_TEST("Initializer list construct 3") + { + 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)); + } + + UNORDERED_SUB_TEST("Initializer list construct 4") + { + 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)); + } + + UNORDERED_SUB_TEST("Initializer list construct 5") + { + 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)); + } +#endif + } + + template <class T> + void map_constructor_test(T*, test::random_generator const& generator) + { + typedef test::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, + std::allocator<test::object> >* test_map_std_alloc; + + 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::allocator2<test::object> >* test_map; + 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::limited_range; + + 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)(limited_range))) + + 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::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) { + 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_QUIET() diff --git a/src/boost/libs/unordered/test/unordered/copy_tests.cpp b/src/boost/libs/unordered/test/unordered/copy_tests.cpp new file mode 100644 index 00000000..1f1ac8f5 --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/copy_tests.cpp @@ -0,0 +1,209 @@ + +// 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) + +// 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" +#include "../helpers/random_values.hpp" +#include "../helpers/tracker.hpp" +#include "../helpers/equivalent.hpp" +#include "../helpers/invariants.hpp" + +test::seed_t initialize_seed(9063); + +namespace copy_tests { + + template <class T> + void copy_construct_tests1(T*, test::random_generator const& generator) + { + typedef typename T::allocator_type allocator_type; + + typename T::hasher hf; + typename T::key_equal eq; + typename T::allocator_type al; + + { + 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); + } + + { + test::check_instances check_; + + 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); + } + + { + 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); + } + } + + 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_; + + 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_; + + 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::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)); + } + + { + test::check_instances check_; + + 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)); + } + } + + 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; + + 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> >* + test_multiset_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> >* + test_multimap_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> >* + 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> >* + 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> >* + test_multimap_no_select_copy; + + 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)(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() diff --git a/src/boost/libs/unordered/test/unordered/deduction_tests.cpp b/src/boost/libs/unordered/test/unordered/deduction_tests.cpp new file mode 100644 index 00000000..673c0609 --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/deduction_tests.cpp @@ -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 +} diff --git a/src/boost/libs/unordered/test/unordered/detail_tests.cpp b/src/boost/libs/unordered/test/unordered/detail_tests.cpp new file mode 100644 index 00000000..545c8381 --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/detail_tests.cpp @@ -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() diff --git a/src/boost/libs/unordered/test/unordered/emplace_tests.cpp b/src/boost/libs/unordered/test/unordered/emplace_tests.cpp new file mode 100644 index 00000000..b424d3d7 --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/emplace_tests.cpp @@ -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() diff --git a/src/boost/libs/unordered/test/unordered/equality_tests.cpp b/src/boost/libs/unordered/test/unordered/equality_tests.cpp new file mode 100644 index 00000000..b1029af4 --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/equality_tests.cpp @@ -0,0 +1,156 @@ + +// Copyright 2008-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) + +// 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 + { + 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 + { + return alt_hash_ ? static_cast<std::size_t>(x % 250) + : static_cast<std::size_t>((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); \ + } + +#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_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)); + + 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)) + } + + 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() diff --git a/src/boost/libs/unordered/test/unordered/equivalent_keys_tests.cpp b/src/boost/libs/unordered/test/unordered/equivalent_keys_tests.cpp new file mode 100644 index 00000000..f040819d --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/equivalent_keys_tests.cpp @@ -0,0 +1,77 @@ + +// 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) + +// 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> +#include <map> +#include "../helpers/list.hpp" +#include "../helpers/tracker.hpp" +#include "../helpers/invariants.hpp" + +template <class Container, class Iterator> +void test_equal_insertion(Iterator begin, Iterator end) +{ + typedef test::ordered<Container> tracker; + + 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); + } + + 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}}; + + 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<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)); + + 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()); +} + +RUN_TESTS() diff --git a/src/boost/libs/unordered/test/unordered/erase_equiv_tests.cpp b/src/boost/libs/unordered/test/unordered/erase_equiv_tests.cpp new file mode 100644 index 00000000..effe0cd5 --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/erase_equiv_tests.cpp @@ -0,0 +1,217 @@ + +// 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) + +// 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 <iterator> +#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. +#endif + +struct write_pair_type +{ + 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) +{ + 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 +{ + std::size_t operator()(int) const { return 0; } +}; + +// For testing erase in 2 buckets. +struct collision2_hash +{ + 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 +{ + 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 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 (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.end()); + BOOST_TEST(x.count(1) == 0 && x.size() == 0); + test::check_equivalent_keys(x); + } + + { + 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()); + 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> +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; +} + +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(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) +{ + 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; + + for (int i = 0; i < values; ++i) { + for (int j = 0; j < duplicates; ++j) { + y.insert(collide_value(i, j)); + } + } + + 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) +{ + 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) { + 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) { + 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) { + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "exhaustive_collide3_tests:\n"; + exhaustive_erase_tests((collide_map3*)0, 8, 4); + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n"; +} + +RUN_TESTS() diff --git a/src/boost/libs/unordered/test/unordered/erase_tests.cpp b/src/boost/libs/unordered/test/unordered/erase_tests.cpp new file mode 100644 index 00000000..fecb7dc0 --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/erase_tests.cpp @@ -0,0 +1,267 @@ + +// 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) + +// 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 "../helpers/random_values.hpp" +#include "../helpers/tracker.hpp" +#include "../helpers/equivalent.hpp" +#include "../helpers/helpers.hpp" +#include "../helpers/invariants.hpp" +#include <vector> +#include <cstdlib> + +namespace erase_tests { + + 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; + + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Erase 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(); + 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); + } + } + + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "erase(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); + 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()); + } + + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "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()); + 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); + 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()); + } + } + + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "quick_erase(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); + 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); + } + 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()); + } + + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "clear().\n"; + { + 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()); + } + + 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; + using test::limited_range; + + UNORDERED_TEST( + erase_tests1, ((test_set)(test_multiset)(test_map)(test_multimap))( + (default_generator)(generate_collisions)(limited_range))) +} + +RUN_TESTS() diff --git a/src/boost/libs/unordered/test/unordered/extract_tests.cpp b/src/boost/libs/unordered/test/unordered/extract_tests.cpp new file mode 100644 index 00000000..14338738 --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/extract_tests.cpp @@ -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() diff --git a/src/boost/libs/unordered/test/unordered/find_tests.cpp b/src/boost/libs/unordered/test/unordered/find_tests.cpp new file mode 100644 index 00000000..031371c3 --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/find_tests.cpp @@ -0,0 +1,157 @@ + +// 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) + +// 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 "../helpers/random_values.hpp" +#include "../helpers/tracker.hpp" +#include "../helpers/helpers.hpp" + +namespace find_tests { + + test::seed_t initialize_seed(78937); + + template <class X> void find_tests1(X*, test::random_generator generator) + { + typedef typename X::iterator iterator; + + { + 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()); + + 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)); + + 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_; + + X x; + + 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 + { + test::object o_; + + 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_); + } + }; + + struct compatible_predicate + { + test::equal_to equal_; + + 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 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) { + 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) { + 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, + test::allocator2<test::object> >* test_set; + 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, + test::allocator2<test::object> >* test_map; + 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::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() diff --git a/src/boost/libs/unordered/test/unordered/fwd_map_test.cpp b/src/boost/libs/unordered/test/unordered/fwd_map_test.cpp new file mode 100644 index 00000000..0c7df04f --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/fwd_map_test.cpp @@ -0,0 +1,81 @@ + +// Copyright 2008-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) + +// 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) +{ + swap(x, y); +} + +template <typename T> +bool call_equals(boost::unordered_map<T, T>& x, boost::unordered_map<T, T>& y) +{ + return x == y; +} + +template <typename T> +bool call_not_equals( + boost::unordered_map<T, T>& x, boost::unordered_map<T, T>& y) +{ + return x != y; +} + +template <typename T> +void call_swap( + boost::unordered_multimap<T, T>& x, boost::unordered_multimap<T, T>& y) +{ + swap(x, y); +} + +template <typename T> +bool call_equals( + boost::unordered_multimap<T, T>& x, boost::unordered_multimap<T, T>& y) +{ + return x == y; +} + +template <typename T> +bool call_not_equals( + boost::unordered_multimap<T, T>& x, boost::unordered_multimap<T, T>& y) +{ + return x != y; +} + +#include <boost/unordered_map.hpp> +#include "../helpers/test.hpp" + +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); + + 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(!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() diff --git a/src/boost/libs/unordered/test/unordered/fwd_set_test.cpp b/src/boost/libs/unordered/test/unordered/fwd_set_test.cpp new file mode 100644 index 00000000..6512522a --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/fwd_set_test.cpp @@ -0,0 +1,106 @@ + +// Copyright 2008-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) + +// 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; +}; + +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>*); + +template <typename T> +void call_swap(boost::unordered_set<T>& x, boost::unordered_set<T>& y) +{ + swap(x, y); +} + +template <typename T> +bool call_equals(boost::unordered_set<T>& x, boost::unordered_set<T>& y) +{ + return x == y; +} + +template <typename T> +bool call_not_equals(boost::unordered_set<T>& x, boost::unordered_set<T>& y) +{ + return x != y; +} + +template <typename T> +void call_swap(boost::unordered_multiset<T>& x, boost::unordered_multiset<T>& y) +{ + swap(x, y); +} + +template <typename T> +bool call_equals( + boost::unordered_multiset<T>& x, boost::unordered_multiset<T>& y) +{ + return x == y; +} + +template <typename T> +bool call_not_equals( + boost::unordered_multiset<T>& x, boost::unordered_multiset<T>& y) +{ + return x != y; +} + +#include "../helpers/test.hpp" + +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)); +} + +#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)); + + 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); + + 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(!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() diff --git a/src/boost/libs/unordered/test/unordered/incomplete_test.cpp b/src/boost/libs/unordered/test/unordered/incomplete_test.cpp new file mode 100644 index 00000000..09afcba6 --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/incomplete_test.cpp @@ -0,0 +1,173 @@ + +// Copyright 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) + +// 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 incomplete_test { + // Declare, but don't define some types. + + 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. + + struct hash + { + template <typename T> std::size_t operator()(T const&) const { return 0; } + }; + + struct equals + { + template <typename T> bool operator()(T const&, T const&) const + { + return true; + } + }; + + // 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) + { + } + + template <typename T2> + allocator(const std::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() + { + 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. + + incomplete_test::use_types(); +} diff --git a/src/boost/libs/unordered/test/unordered/insert_hint_tests.cpp b/src/boost/libs/unordered/test/unordered/insert_hint_tests.cpp new file mode 100644 index 00000000..c77fc2dc --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/insert_hint_tests.cpp @@ -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() diff --git a/src/boost/libs/unordered/test/unordered/insert_node_type_fail.cpp b/src/boost/libs/unordered/test/unordered/insert_node_type_fail.cpp new file mode 100644 index 00000000..eb34930f --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/insert_node_type_fail.cpp @@ -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 +} diff --git a/src/boost/libs/unordered/test/unordered/insert_stable_tests.cpp b/src/boost/libs/unordered/test/unordered/insert_stable_tests.cpp new file mode 100644 index 00000000..4ea6a84b --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/insert_stable_tests.cpp @@ -0,0 +1,117 @@ + +// Copyright 2007-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) + +// 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" + +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_; + } + }; +} + +#ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP +namespace boost +#else +namespace insert_stable +#endif +{ + std::size_t hash_value(insert_stable::member const& x) + { + return static_cast<std::size_t>(x.tag1_); + } +} + +// 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)); + + BOOST_TEST(x.count(insert_stable::member(1, 4)) == 3); + + boost::unordered_multiset<insert_stable::member>::const_iterator + it = x.begin(), + end = x.end(); + BOOST_TEST(it != end); + if (it != end) { + BOOST_TEST(it->tag2_ == 1); + ++it; + } + BOOST_TEST(it != end); + if (it != end) { + BOOST_TEST(it->tag2_ == 2); + ++it; + } + BOOST_TEST(it != end); + if (it != end) { + BOOST_TEST(it->tag2_ == 3); + ++it; + } + BOOST_TEST(it == end); +} + +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; + + 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; + } + BOOST_TEST(it != end); + 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; + } + BOOST_TEST(it == end); +} + +#endif + +RUN_TESTS() diff --git a/src/boost/libs/unordered/test/unordered/insert_tests.cpp b/src/boost/libs/unordered/test/unordered/insert_tests.cpp new file mode 100644 index 00000000..7ddb41fd --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/insert_tests.cpp @@ -0,0 +1,1425 @@ + +// Copyright 2006-2010 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) + +#if !defined(PIECEWISE_TEST_NAME) + +// 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 "../helpers/random_values.hpp" +#include "../helpers/tracker.hpp" +#include "../helpers/equivalent.hpp" +#include "../helpers/invariants.hpp" +#include "../helpers/input_iterator.hpp" +#include "../helpers/helpers.hpp" + +namespace insert_tests { + + test::seed_t initialize_seed(243432); + + template <class X> + void unique_insert_tests1(X*, test::random_generator generator) + { + test::check_instances check_; + + typedef typename X::iterator iterator; + typedef test::ordered<X> ordered; + + UNORDERED_SUB_TEST("insert(value) tests for containers with unique keys") + { + X x; + test::ordered<X> tracker = test::create_ordered(x); + + test::random_values<X> v(1000, generator); + + for (typename test::random_values<X>::iterator it = v.begin(); + it != v.end(); ++it) { + + typename X::size_type old_bucket_count = x.bucket_count(); + float b = x.max_load_factor(); + + std::pair<iterator, bool> r1 = x.insert(*it); + std::pair<typename ordered::iterator, bool> r2 = tracker.insert(*it); + + BOOST_TEST(r1.second == r2.second); + BOOST_TEST(*r1.first == *r2.first); + + tracker.compare_key(x, *it); + + if (static_cast<double>(x.size()) <= + b * static_cast<double>(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + + test::check_equivalent_keys(x); + } + + UNORDERED_SUB_TEST("insert(rvalue) tests for containers with unique keys") + { + X x; + test::ordered<X> tracker = test::create_ordered(x); + + test::random_values<X> v(1000, generator); + + for (typename test::random_values<X>::iterator it = v.begin(); + it != v.end(); ++it) { + + typename X::size_type old_bucket_count = x.bucket_count(); + float b = x.max_load_factor(); + + typename X::value_type value = *it; + std::pair<iterator, bool> r1 = x.insert(boost::move(value)); + std::pair<typename ordered::iterator, bool> r2 = tracker.insert(*it); + + BOOST_TEST(r1.second == r2.second); + BOOST_TEST(*r1.first == *r2.first); + + tracker.compare_key(x, *it); + + if (static_cast<double>(x.size()) <= + b * static_cast<double>(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + + test::check_equivalent_keys(x); + } + } + + template <class X> + void equivalent_insert_tests1(X*, test::random_generator generator) + { + test::check_instances check_; + + UNORDERED_SUB_TEST( + "insert(value) tests for containers with equivalent keys") + { + X x; + test::ordered<X> tracker = test::create_ordered(x); + + test::random_values<X> v(1000, generator); + for (typename test::random_values<X>::iterator it = v.begin(); + it != v.end(); ++it) { + typename X::size_type old_bucket_count = x.bucket_count(); + float b = x.max_load_factor(); + + typename X::iterator r1 = x.insert(*it); + typename test::ordered<X>::iterator r2 = tracker.insert(*it); + + BOOST_TEST(*r1 == *r2); + + tracker.compare_key(x, *it); + + if (static_cast<double>(x.size()) <= + b * static_cast<double>(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + + test::check_equivalent_keys(x); + } + + UNORDERED_SUB_TEST( + "insert(rvalue) tests for containers with equivalent keys") + { + X x; + test::ordered<X> tracker = test::create_ordered(x); + + test::random_values<X> v(1000, generator); + for (typename test::random_values<X>::iterator it = v.begin(); + it != v.end(); ++it) { + typename X::size_type old_bucket_count = x.bucket_count(); + float b = x.max_load_factor(); + + typename X::value_type value = *it; + typename X::iterator r1 = x.insert(boost::move(value)); + typename test::ordered<X>::iterator r2 = tracker.insert(*it); + + BOOST_TEST(*r1 == *r2); + + tracker.compare_key(x, *it); + + if (static_cast<double>(x.size()) <= + b * static_cast<double>(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + + test::check_equivalent_keys(x); + } + } + + template <class X> void insert_tests2(X*, test::random_generator generator) + { + typedef typename test::ordered<X> tracker_type; + typedef typename X::iterator iterator; + typedef typename X::const_iterator const_iterator; + typedef typename tracker_type::iterator tracker_iterator; + + UNORDERED_SUB_TEST("insert(begin(), value) tests") + { + test::check_instances check_; + + X x; + tracker_type tracker = test::create_ordered(x); + + test::random_values<X> v(1000, generator); + for (typename test::random_values<X>::iterator it = v.begin(); + it != v.end(); ++it) { + typename X::size_type old_bucket_count = x.bucket_count(); + float b = x.max_load_factor(); + + iterator r1 = x.insert(x.begin(), *it); + tracker_iterator r2 = tracker.insert(tracker.begin(), *it); + BOOST_TEST(*r1 == *r2); + tracker.compare_key(x, *it); + + if (static_cast<double>(x.size()) <= + b * static_cast<double>(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + + tracker.compare(x); + test::check_equivalent_keys(x); + } + + UNORDERED_SUB_TEST("insert(end(), value) tests") + { + test::check_instances check_; + + X x; + X const& x_const = x; + tracker_type tracker = test::create_ordered(x); + + test::random_values<X> v(100, generator); + for (typename test::random_values<X>::iterator it = v.begin(); + it != v.end(); ++it) { + typename X::size_type old_bucket_count = x.bucket_count(); + float b = x.max_load_factor(); + + const_iterator r1 = x.insert(x_const.end(), *it); + tracker_iterator r2 = tracker.insert(tracker.end(), *it); + BOOST_TEST(*r1 == *r2); + tracker.compare_key(x, *it); + + if (static_cast<double>(x.size()) <= + b * static_cast<double>(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + + tracker.compare(x); + test::check_equivalent_keys(x); + } + + UNORDERED_SUB_TEST("insert(pos, value) tests") + { + test::check_instances check_; + + X x; + const_iterator pos = x.begin(); + tracker_type tracker = test::create_ordered(x); + + test::random_values<X> v(1000, generator); + for (typename test::random_values<X>::iterator it = v.begin(); + it != v.end(); ++it) { + typename X::size_type old_bucket_count = x.bucket_count(); + float b = x.max_load_factor(); + + pos = x.insert(pos, *it); + tracker_iterator r2 = tracker.insert(tracker.begin(), *it); + BOOST_TEST(*pos == *r2); + tracker.compare_key(x, *it); + + if (static_cast<double>(x.size()) <= + b * static_cast<double>(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + + tracker.compare(x); + test::check_equivalent_keys(x); + } + + UNORDERED_SUB_TEST("insert(pos, rvalue) tests") + { + test::check_instances check_; + + X x; + const_iterator pos = x.begin(); + tracker_type tracker = test::create_ordered(x); + + test::random_values<X> v(1000, generator); + for (typename test::random_values<X>::iterator it = v.begin(); + it != v.end(); ++it) { + typename X::size_type old_bucket_count = x.bucket_count(); + float b = x.max_load_factor(); + + typename X::value_type value = *it; + pos = x.insert(pos, boost::move(value)); + tracker_iterator r2 = tracker.insert(tracker.begin(), *it); + BOOST_TEST(*pos == *r2); + tracker.compare_key(x, *it); + + if (static_cast<double>(x.size()) <= + b * static_cast<double>(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + + tracker.compare(x); + test::check_equivalent_keys(x); + } + + UNORDERED_SUB_TEST("insert single item range tests") + { + test::check_instances check_; + + X x; + tracker_type tracker = test::create_ordered(x); + + test::random_values<X> v(1000, generator); + for (typename test::random_values<X>::iterator it = v.begin(); + it != v.end(); ++it) { + typename X::size_type old_bucket_count = x.bucket_count(); + float b = x.max_load_factor(); + + x.insert(it, test::next(it)); + tracker.insert(*it); + tracker.compare_key(x, *it); + + if (static_cast<double>(x.size()) <= + b * static_cast<double>(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + + tracker.compare(x); + test::check_equivalent_keys(x); + } + + UNORDERED_SUB_TEST("insert range tests") + { + test::check_instances check_; + + X x; + + test::random_values<X> v(1000, generator); + x.insert(v.begin(), v.end()); + + test::check_container(x, v); + test::check_equivalent_keys(x); + } + + UNORDERED_SUB_TEST("insert range with rehash tests") + { + test::check_instances check_; + + X x; + + test::random_values<X> v(1000, generator); + + x.insert(*v.begin()); + x.clear(); + + x.insert(v.begin(), v.end()); + + test::check_container(x, v); + test::check_equivalent_keys(x); + } + + UNORDERED_SUB_TEST("insert input iterator range tests") + { + test::check_instances check_; + + X x; + + test::random_values<X> v(1000, generator); + typename test::random_values<X>::const_iterator begin = v.begin(), + end = v.end(); + x.insert(test::input_iterator(begin), test::input_iterator(end)); + test::check_container(x, v); + + test::check_equivalent_keys(x); + } + + UNORDERED_SUB_TEST("insert copy iterator range tests") + { + test::check_instances check_; + + X x; + + test::random_values<X> v(1000, generator); + x.insert(test::copy_iterator(v.begin()), test::copy_iterator(v.end())); + test::check_container(x, v); + + test::check_equivalent_keys(x); + } + + UNORDERED_SUB_TEST("insert copy iterator range test 2") + { + test::check_instances check_; + + X x; + + test::random_values<X> v1(500, generator); + test::random_values<X> v2(500, generator); + x.insert(test::copy_iterator(v1.begin()), test::copy_iterator(v1.end())); + x.insert(test::copy_iterator(v2.begin()), test::copy_iterator(v2.end())); + + test::check_equivalent_keys(x); + } + + UNORDERED_SUB_TEST("insert various ranges") + { + for (int i = 0; i < 100; ++i) { + X x; + test::ordered<X> tracker = test::create_ordered(x); + + test::random_values<X> v(1000, generator); + + for (typename test::random_values<X>::iterator it = v.begin(); + it != v.end();) { + typename X::size_type old_bucket_count = x.bucket_count(); + float b = x.max_load_factor(); + + typename test::random_values<X>::iterator next = it; + for (std::size_t j = test::random_value(20); j > 0; ++j) { + ++next; + if (next == v.end()) { + break; + } + } + + x.insert(it, next); + tracker.insert(it, next); + it = next; + + tracker.compare(x); // Slow, but I can't see any other way. + + if (static_cast<double>(x.size()) <= + b * static_cast<double>(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + + test::check_equivalent_keys(x); + } + } + } + + template <class X> + void unique_emplace_tests1(X*, test::random_generator generator) + { + typedef typename X::iterator iterator; + typedef test::ordered<X> ordered; + + X x; + test::ordered<X> tracker = test::create_ordered(x); + + test::random_values<X> v(1000, generator); + + for (typename test::random_values<X>::iterator it = v.begin(); + it != v.end(); ++it) { + + typename X::size_type old_bucket_count = x.bucket_count(); + float b = x.max_load_factor(); + + std::pair<iterator, bool> r1 = x.emplace(*it); + std::pair<typename ordered::iterator, bool> r2 = tracker.insert(*it); + + BOOST_TEST(r1.second == r2.second); + BOOST_TEST(*r1.first == *r2.first); + + tracker.compare_key(x, *it); + + if (static_cast<double>(x.size()) <= + b * static_cast<double>(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + + tracker.compare(x); + test::check_equivalent_keys(x); + } + + template <class X> + void equivalent_emplace_tests1(X*, test::random_generator generator) + { + X x; + test::ordered<X> tracker = test::create_ordered(x); + + test::random_values<X> v(1000, generator); + for (typename test::random_values<X>::iterator it = v.begin(); + it != v.end(); ++it) { + typename X::size_type old_bucket_count = x.bucket_count(); + float b = x.max_load_factor(); + + typename X::iterator r1 = x.emplace(*it); + typename test::ordered<X>::iterator r2 = tracker.insert(*it); + + BOOST_TEST(*r1 == *r2); + + tracker.compare_key(x, *it); + + if (static_cast<double>(x.size()) <= + b * static_cast<double>(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + + tracker.compare(x); + test::check_equivalent_keys(x); + } + + template <class X> + void move_emplace_tests(X*, test::random_generator generator) + { + X x; + test::ordered<X> tracker = test::create_ordered(x); + + test::random_values<X> v(1000, generator); + + for (typename test::random_values<X>::iterator it = v.begin(); + it != v.end(); ++it) { + + typename X::size_type old_bucket_count = x.bucket_count(); + float b = x.max_load_factor(); + + typename X::value_type value = *it; + x.emplace(boost::move(value)); + tracker.insert(*it); + tracker.compare_key(x, *it); + + if (static_cast<double>(x.size()) <= + b * static_cast<double>(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + + tracker.compare(x); + test::check_equivalent_keys(x); + } + + template <class X> void default_emplace_tests(X*, test::random_generator) + { +#if !BOOST_UNORDERED_SUN_WORKAROUNDS1 + bool is_unique = test::has_unique_keys<X>::value; + + X x; + + x.emplace(); + BOOST_TEST(x.size() == 1); + x.emplace(); + BOOST_TEST(x.size() == (is_unique ? 1u : 2u)); + x.emplace(); + BOOST_TEST(x.size() == (is_unique ? 1u : 3u)); + + typename X::value_type y; + BOOST_TEST(x.count(test::get_key<X>(y)) == (is_unique ? 1u : 3u)); + BOOST_TEST(*x.equal_range(test::get_key<X>(y)).first == y); + + x.emplace(y); + BOOST_TEST(x.size() == (is_unique ? 1u : 4u)); + BOOST_TEST(x.count(test::get_key<X>(y)) == (is_unique ? 1u : 4u)); + BOOST_TEST(*x.equal_range(test::get_key<X>(y)).first == y); + + x.clear(); + BOOST_TEST(x.empty()); + x.emplace(y); + BOOST_TEST(x.size() == 1); + x.emplace(y); + BOOST_TEST(x.size() == (is_unique ? 1u : 2u)); + + BOOST_TEST(x.count(test::get_key<X>(y)) == (is_unique ? 1u : 2u)); + BOOST_TEST(*x.equal_range(test::get_key<X>(y)).first == y); +#endif + } + + template <class X> void map_tests(X*, test::random_generator generator) + { + X x; + test::ordered<X> tracker = test::create_ordered(x); + + test::random_values<X> v(1000, generator); + for (typename test::random_values<X>::iterator it = v.begin(); + it != v.end(); ++it) { + typename X::size_type old_bucket_count = x.bucket_count(); + float b = x.max_load_factor(); + + x[it->first] = it->second; + tracker[it->first] = it->second; + + tracker.compare_key(x, *it); + + if (static_cast<double>(x.size()) <= + b * static_cast<double>(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + + tracker.compare(x); + test::check_equivalent_keys(x); + } + + template <class X> void map_tests2(X*, test::random_generator generator) + { + typedef typename X::iterator iterator; + + UNORDERED_SUB_TEST("insert_or_assign") + { + test::check_instances check_; + + X x; + test::ordered<X> tracker = test::create_ordered(x); + + test::random_values<X> v(1000, generator); + for (typename test::random_values<X>::iterator it = v.begin(); + it != v.end(); ++it) { + typename X::size_type old_bucket_count = x.bucket_count(); + float b = x.max_load_factor(); + + std::pair<iterator, bool> r = x.insert_or_assign(it->first, it->second); + BOOST_TEST(*r.first == *it); + + tracker[it->first] = it->second; + tracker.compare_key(x, *it); + + if (static_cast<double>(x.size()) < + b * static_cast<double>(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + + tracker.compare(x); + test::check_equivalent_keys(x); + } + + UNORDERED_SUB_TEST("insert_or_assign(begin)") + { + test::check_instances check_; + + X x; + test::ordered<X> tracker = test::create_ordered(x); + + test::random_values<X> v(1000, generator); + for (typename test::random_values<X>::iterator it = v.begin(); + it != v.end(); ++it) { + typename X::size_type old_bucket_count = x.bucket_count(); + float b = x.max_load_factor(); + + iterator r = x.insert_or_assign(x.begin(), it->first, it->second); + BOOST_TEST(*r == *it); + + tracker[it->first] = it->second; + tracker.compare_key(x, *it); + + if (static_cast<double>(x.size()) < + b * static_cast<double>(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + + tracker.compare(x); + test::check_equivalent_keys(x); + } + + UNORDERED_SUB_TEST("insert_or_assign(end)") + { + test::check_instances check_; + + X x; + test::ordered<X> tracker = test::create_ordered(x); + + test::random_values<X> v(1000, generator); + for (typename test::random_values<X>::iterator it = v.begin(); + it != v.end(); ++it) { + typename X::size_type old_bucket_count = x.bucket_count(); + float b = x.max_load_factor(); + + iterator r = x.insert_or_assign(x.end(), it->first, it->second); + BOOST_TEST(*r == *it); + + tracker[it->first] = it->second; + tracker.compare_key(x, *it); + + if (static_cast<double>(x.size()) < + b * static_cast<double>(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + + tracker.compare(x); + test::check_equivalent_keys(x); + } + + UNORDERED_SUB_TEST("insert_or_assign(last)") + { + test::check_instances check_; + + X x; + test::ordered<X> tracker = test::create_ordered(x); + iterator last = x.begin(); + + test::random_values<X> v(1000, generator); + for (typename test::random_values<X>::iterator it = v.begin(); + it != v.end(); ++it) { + typename X::size_type old_bucket_count = x.bucket_count(); + float b = x.max_load_factor(); + + iterator r = x.insert_or_assign(last, it->first, it->second); + BOOST_TEST(*r == *it); + + tracker[it->first] = it->second; + tracker.compare_key(x, *it); + + if (static_cast<double>(x.size()) < + b * static_cast<double>(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + + last = r; + } + + tracker.compare(x); + test::check_equivalent_keys(x); + } + } + + template <class X> + void try_emplace_tests(X*, test::random_generator generator) + { + typedef typename X::iterator iterator; + + UNORDERED_SUB_TEST("try_emplace(key, value)") + { + test::check_instances check_; + + X x; + test::ordered<X> tracker = test::create_ordered(x); + + test::random_values<X> v(1000, generator); + for (typename test::random_values<X>::iterator it = v.begin(); + it != v.end(); ++it) { + typename X::size_type old_bucket_count = x.bucket_count(); + float b = x.max_load_factor(); + + iterator pos = x.find(it->first); + bool found = pos != x.end(); + + std::pair<typename X::iterator, bool> r = + x.try_emplace(it->first, it->second); + if (found) { + BOOST_TEST(pos == r.first); + BOOST_TEST(!r.second); + } else { + BOOST_TEST(r.second); + } + BOOST_TEST_EQ(r.first->first, it->first); + BOOST_TEST_EQ(r.first->second, it->second); + + tracker.insert(*it); + tracker.compare_key(x, *it); + + if (static_cast<double>(x.size()) < + b * static_cast<double>(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + + test::check_equivalent_keys(x); + } + + typedef typename X::iterator iterator; + + UNORDERED_SUB_TEST("try_emplace(begin(), key, value)") + { + test::check_instances check_; + + X x; + test::ordered<X> tracker = test::create_ordered(x); + + test::random_values<X> v(1000, generator); + for (typename test::random_values<X>::iterator it = v.begin(); + it != v.end(); ++it) { + typename X::size_type old_bucket_count = x.bucket_count(); + float b = x.max_load_factor(); + + iterator pos = x.find(it->first); + bool found = pos != x.end(); + + typename X::iterator r = + x.try_emplace(r.begin(), it->first, it->second); + if (found) { + BOOST_TEST(pos == r); + } + BOOST_TEST_EQ(r->first, it->first); + BOOST_TEST_EQ(r->second, it->second); + + tracker.insert(*it); + tracker.compare_key(x, *it); + + if (static_cast<double>(x.size()) < + b * static_cast<double>(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + + test::check_equivalent_keys(x); + } + + typedef typename X::iterator iterator; + + UNORDERED_SUB_TEST("try_emplace(end(), key, value)") + { + test::check_instances check_; + + X x; + test::ordered<X> tracker = test::create_ordered(x); + + test::random_values<X> v(1000, generator); + for (typename test::random_values<X>::iterator it = v.begin(); + it != v.end(); ++it) { + typename X::size_type old_bucket_count = x.bucket_count(); + float b = x.max_load_factor(); + + iterator pos = x.find(it->first); + bool found = pos != x.end(); + + typename X::iterator r = x.try_emplace(r.end(), it->first, it->second); + if (found) { + BOOST_TEST(pos == r); + } + BOOST_TEST_EQ(r->first, it->first); + BOOST_TEST_EQ(r->second, it->second); + + tracker.insert(*it); + tracker.compare_key(x, *it); + + if (static_cast<double>(x.size()) < + b * static_cast<double>(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + + test::check_equivalent_keys(x); + } + + typedef typename X::iterator iterator; + + UNORDERED_SUB_TEST("try_emplace(pos, key, value)") + { + test::check_instances check_; + + X x; + test::ordered<X> tracker = test::create_ordered(x); + + test::random_values<X> v(1000, generator); + for (typename test::random_values<X>::iterator it = v.begin(); + it != v.end(); ++it) { + typename X::size_type old_bucket_count = x.bucket_count(); + float b = x.max_load_factor(); + + iterator pos = x.find(it->first); + bool found = pos != x.end(); + + typename X::iterator r = x.try_emplace(pos, it->first, it->second); + if (found) { + BOOST_TEST(pos == r); + } + BOOST_TEST_EQ(r->first, it->first); + BOOST_TEST_EQ(r->second, it->second); + + tracker.insert(*it); + tracker.compare_key(x, *it); + + if (static_cast<double>(x.size()) < + b * static_cast<double>(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + + test::check_equivalent_keys(x); + } + } + + // Some tests for when the range's value type doesn't match the container's + // value type. + + template <class X> + void map_insert_range_test1(X*, test::random_generator generator) + { + test::check_instances check_; + + typedef test::list< + std::pair<typename X::key_type, typename X::mapped_type> > + list; + test::random_values<X> v(1000, generator); + list l(v.begin(), v.end()); + + X x; + x.insert(l.begin(), l.end()); + + test::check_equivalent_keys(x); + } + + template <class X> + void map_insert_range_test2(X*, test::random_generator generator) + { + test::check_instances check_; + + typedef test::list< + std::pair<typename X::key_type const, test::implicitly_convertible> > + list; + test::random_values< + boost::unordered_map<typename X::key_type, test::implicitly_convertible> > + v(1000, generator); + list l(v.begin(), v.end()); + + X x; + x.insert(l.begin(), l.end()); + + test::check_equivalent_keys(x); + } + + boost::unordered_set<test::movable, test::hash, test::equal_to, + std::allocator<test::movable> >* test_set_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, + test::allocator1<test::object> >* test_set; + boost::unordered_multiset<test::movable, test::hash, test::equal_to, + test::allocator2<test::movable> >* test_multiset; + boost::unordered_map<test::movable, test::movable, test::hash, test::equal_to, + test::allocator2<test::movable> >* test_map; + 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::limited_range; + + UNORDERED_TEST(unique_insert_tests1, + ((test_set_std_alloc)(test_set)(test_map))( + (default_generator)(generate_collisions)(limited_range))) + + UNORDERED_TEST(equivalent_insert_tests1, + ((test_multimap_std_alloc)(test_multiset)(test_multimap))( + (default_generator)(generate_collisions)(limited_range))) + + UNORDERED_TEST(insert_tests2, + ((test_multimap_std_alloc)(test_set)(test_multiset)(test_map)( + test_multimap))((default_generator)(generate_collisions)(limited_range))) + + UNORDERED_TEST(unique_emplace_tests1, + ((test_set_std_alloc)(test_set)(test_map))( + (default_generator)(generate_collisions)(limited_range))) + + UNORDERED_TEST(equivalent_emplace_tests1, + ((test_multimap_std_alloc)(test_multiset)(test_multimap))( + (default_generator)(generate_collisions)(limited_range))) + + UNORDERED_TEST(move_emplace_tests, + ((test_set_std_alloc)(test_multimap_std_alloc)(test_set)(test_map)( + test_multiset)(test_multimap))( + (default_generator)(generate_collisions)(limited_range))) + + UNORDERED_TEST(default_emplace_tests, + ((test_set_std_alloc)(test_multimap_std_alloc)(test_set)(test_map)( + test_multiset)(test_multimap))( + (default_generator)(generate_collisions)(limited_range))) + + UNORDERED_TEST(map_tests, + ((test_map))((default_generator)(generate_collisions)(limited_range))) + + UNORDERED_TEST( + map_tests2, ((test_map))((default_generator)(generate_collisions))) + + UNORDERED_TEST(map_insert_range_test1, + ((test_multimap_std_alloc)(test_map)(test_multimap))( + (default_generator)(generate_collisions)(limited_range))) + + UNORDERED_TEST(map_insert_range_test2, + ((test_multimap_std_alloc)(test_map)(test_multimap))( + (default_generator)(generate_collisions)(limited_range))) + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + + struct initialize_from_two_ints + { + int a, b; + + friend std::size_t hash_value(initialize_from_two_ints const& x) + { + return static_cast<std::size_t>(x.a + x.b); + } + + bool operator==(initialize_from_two_ints const& x) const + { + return a == x.a && b == x.b; + } + }; + + UNORDERED_AUTO_TEST (insert_initializer_list_set) { + boost::unordered_set<int> set; + set.insert({1, 2, 3, 1}); + BOOST_TEST_EQ(set.size(), 3u); + BOOST_TEST(set.find(1) != set.end()); + BOOST_TEST(set.find(4) == set.end()); + + boost::unordered_set<initialize_from_two_ints> set2; + +#if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5)) + set2.insert({{1, 2}}); +#else + set2.insert({1, 2}); +#endif + BOOST_TEST(set2.size() == 1); + BOOST_TEST(set2.find({1, 2}) != set2.end()); + BOOST_TEST(set2.find({2, 1}) == set2.end()); + + set2.insert({{3, 4}, {5, 6}, {7, 8}}); + BOOST_TEST(set2.size() == 4); + BOOST_TEST(set2.find({1, 2}) != set2.end()); + BOOST_TEST(set2.find({3, 4}) != set2.end()); + BOOST_TEST(set2.find({5, 6}) != set2.end()); + BOOST_TEST(set2.find({7, 8}) != set2.end()); + BOOST_TEST(set2.find({8, 7}) == set2.end()); + + set2.insert({{2, 1}, {3, 4}}); + BOOST_TEST(set2.size() == 5); + BOOST_TEST(set2.find({1, 2}) != set2.end()); + BOOST_TEST(set2.find({2, 1}) != set2.end()); + BOOST_TEST(set2.find({3, 4}) != set2.end()); + BOOST_TEST(set2.find({5, 6}) != set2.end()); + BOOST_TEST(set2.find({7, 8}) != set2.end()); + BOOST_TEST(set2.find({8, 7}) == set2.end()); + } + +#if !BOOST_WORKAROUND(BOOST_MSVC, == 1800) + + UNORDERED_AUTO_TEST (insert_initializer_list_multiset) { + boost::unordered_multiset<std::string> multiset; + // multiset.insert({}); + BOOST_TEST(multiset.empty()); + multiset.insert({"a"}); + BOOST_TEST_EQ(multiset.size(), 1u); + BOOST_TEST(multiset.find("a") != multiset.end()); + BOOST_TEST(multiset.find("b") == multiset.end()); + multiset.insert({"a", "b"}); + BOOST_TEST(multiset.size() == 3); + BOOST_TEST_EQ(multiset.count("a"), 2u); + BOOST_TEST_EQ(multiset.count("b"), 1u); + BOOST_TEST_EQ(multiset.count("c"), 0u); + } + +#endif + + UNORDERED_AUTO_TEST (insert_initializer_list_map) { + boost::unordered_map<std::string, std::string> map; + // map.insert({}); + BOOST_TEST(map.empty()); + map.insert({{"a", "b"}, {"a", "b"}, {"d", ""}}); + BOOST_TEST_EQ(map.size(), 2u); + } + + UNORDERED_AUTO_TEST (insert_initializer_list_multimap) { + boost::unordered_multimap<std::string, std::string> multimap; + // multimap.insert({}); + BOOST_TEST(multimap.empty()); + multimap.insert({{"a", "b"}, {"a", "b"}, {"d", ""}}); + BOOST_TEST_EQ(multimap.size(), 3u); + BOOST_TEST_EQ(multimap.count("a"), 2u); + } + +#endif + + struct overloaded_constructor + { + overloaded_constructor(int x1_ = 1, int x2_ = 2, int x3_ = 3, int x4_ = 4) + : x1(x1_), x2(x2_), x3(x3_), x4(x4_) + { + } + + int x1, x2, x3, x4; + + bool operator==(overloaded_constructor const& rhs) const + { + return x1 == rhs.x1 && x2 == rhs.x2 && x3 == rhs.x3 && x4 == rhs.x4; + } + + friend std::size_t hash_value(overloaded_constructor const& x) + { + std::size_t hash = 0; + boost::hash_combine(hash, x.x1); + boost::hash_combine(hash, x.x2); + boost::hash_combine(hash, x.x3); + boost::hash_combine(hash, x.x4); + return hash; + } + }; + + UNORDERED_AUTO_TEST (map_emplace_test) { + { + boost::unordered_map<int, overloaded_constructor, test::hash, + test::equal_to, + test::allocator1<std::pair<int const, overloaded_constructor> > > + x; + +#if !BOOST_UNORDERED_SUN_WORKAROUNDS1 + x.emplace(); + BOOST_TEST( + x.find(0) != x.end() && x.find(0)->second == overloaded_constructor()); +#endif + + x.emplace(2, 3); + BOOST_TEST( + x.find(2) != x.end() && x.find(2)->second == overloaded_constructor(3)); + + x.try_emplace(5); + BOOST_TEST( + x.find(5) != x.end() && x.find(5)->second == overloaded_constructor()); + } + + { + boost::unordered_multimap<int, overloaded_constructor, test::hash, + test::equal_to, + test::allocator1<std::pair<int const, overloaded_constructor> > > + x; + +#if !BOOST_UNORDERED_SUN_WORKAROUNDS1 + x.emplace(); + BOOST_TEST( + x.find(0) != x.end() && x.find(0)->second == overloaded_constructor()); +#endif + + x.emplace(2, 3); + BOOST_TEST( + x.find(2) != x.end() && x.find(2)->second == overloaded_constructor(3)); + } + } + + UNORDERED_AUTO_TEST (set_emplace_test) { + boost::unordered_set<overloaded_constructor> x; + overloaded_constructor check; + +#if !BOOST_UNORDERED_SUN_WORKAROUNDS1 + x.emplace(); + BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check); +#endif + + x.clear(); + x.emplace(1); + check = overloaded_constructor(1); + BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check); + + x.clear(); + x.emplace(2, 3); + check = overloaded_constructor(2, 3); + BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check); + + x.clear(); + x.emplace(4, 5, 6); + check = overloaded_constructor(4, 5, 6); + BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check); + + x.clear(); + x.emplace(7, 8, 9, 10); + check = overloaded_constructor(7, 8, 9, 10); + BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check); + } + + struct derived_from_piecewise_construct_t + : boost::unordered::piecewise_construct_t + { + }; + + derived_from_piecewise_construct_t piecewise_rvalue() + { + return derived_from_piecewise_construct_t(); + } + + struct convertible_to_piecewise + { + operator boost::unordered::piecewise_construct_t() const + { + return boost::unordered::piecewise_construct; + } + }; + + UNORDERED_AUTO_TEST (map_emplace_test2) { + // Emulating piecewise construction with boost::tuple bypasses the + // allocator's construct method, but still uses test destroy method. + test::detail::disable_construction_tracking _scoped; + + { + boost::unordered_map<overloaded_constructor, overloaded_constructor, + boost::hash<overloaded_constructor>, + std::equal_to<overloaded_constructor>, + test::allocator1< + std::pair<overloaded_constructor const, overloaded_constructor> > > + x; + + x.emplace(boost::unordered::piecewise_construct, boost::make_tuple(), + boost::make_tuple()); + BOOST_TEST( + x.find(overloaded_constructor()) != x.end() && + x.find(overloaded_constructor())->second == overloaded_constructor()); + + x.emplace( + convertible_to_piecewise(), boost::make_tuple(1), boost::make_tuple()); + BOOST_TEST( + x.find(overloaded_constructor(1)) != x.end() && + x.find(overloaded_constructor(1))->second == overloaded_constructor()); + + x.emplace(piecewise_rvalue(), boost::make_tuple(2, 3), + boost::make_tuple(4, 5, 6)); + BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() && + x.find(overloaded_constructor(2, 3))->second == + overloaded_constructor(4, 5, 6)); + + derived_from_piecewise_construct_t d; + x.emplace(d, boost::make_tuple(9, 3, 1), boost::make_tuple(10)); + BOOST_TEST(x.find(overloaded_constructor(9, 3, 1)) != x.end() && + x.find(overloaded_constructor(9, 3, 1))->second == + overloaded_constructor(10)); + + x.clear(); + + x.try_emplace(overloaded_constructor()); + BOOST_TEST( + x.find(overloaded_constructor()) != x.end() && + x.find(overloaded_constructor())->second == overloaded_constructor()); + + x.try_emplace(1); + BOOST_TEST( + x.find(overloaded_constructor(1)) != x.end() && + x.find(overloaded_constructor(1))->second == overloaded_constructor()); + + x.try_emplace(overloaded_constructor(2, 3), 4, 5, 6); + BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() && + x.find(overloaded_constructor(2, 3))->second == + overloaded_constructor(4, 5, 6)); + + x.clear(); + + x.try_emplace(x.begin(), overloaded_constructor()); + BOOST_TEST( + x.find(overloaded_constructor()) != x.end() && + x.find(overloaded_constructor())->second == overloaded_constructor()); + + x.try_emplace(x.end(), 1); + BOOST_TEST( + x.find(overloaded_constructor(1)) != x.end() && + x.find(overloaded_constructor(1))->second == overloaded_constructor()); + + x.try_emplace(x.begin(), overloaded_constructor(2, 3), 4, 5, 6); + BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() && + x.find(overloaded_constructor(2, 3))->second == + overloaded_constructor(4, 5, 6)); + } + + { + boost::unordered_multimap<overloaded_constructor, overloaded_constructor, + boost::hash<overloaded_constructor>, + std::equal_to<overloaded_constructor>, + test::allocator1< + std::pair<overloaded_constructor const, overloaded_constructor> > > + x; + + x.emplace(boost::unordered::piecewise_construct, boost::make_tuple(), + boost::make_tuple()); + BOOST_TEST( + x.find(overloaded_constructor()) != x.end() && + x.find(overloaded_constructor())->second == overloaded_constructor()); + + x.emplace( + convertible_to_piecewise(), boost::make_tuple(1), boost::make_tuple()); + BOOST_TEST( + x.find(overloaded_constructor(1)) != x.end() && + x.find(overloaded_constructor(1))->second == overloaded_constructor()); + + x.emplace(piecewise_rvalue(), boost::make_tuple(2, 3), + boost::make_tuple(4, 5, 6)); + BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() && + x.find(overloaded_constructor(2, 3))->second == + overloaded_constructor(4, 5, 6)); + + derived_from_piecewise_construct_t d; + x.emplace(d, boost::make_tuple(9, 3, 1), boost::make_tuple(10)); + BOOST_TEST(x.find(overloaded_constructor(9, 3, 1)) != x.end() && + x.find(overloaded_constructor(9, 3, 1))->second == + overloaded_constructor(10)); + } + } + + UNORDERED_AUTO_TEST (set_emplace_test2) { + boost::unordered_set< + std::pair<overloaded_constructor, overloaded_constructor> > + x; + std::pair<overloaded_constructor, overloaded_constructor> check; + + x.emplace(boost::unordered::piecewise_construct, boost::make_tuple(), + boost::make_tuple()); + BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check); + + x.clear(); + x.emplace(boost::unordered::piecewise_construct, boost::make_tuple(1), + boost::make_tuple(2, 3)); + check = + std::make_pair(overloaded_constructor(1), overloaded_constructor(2, 3)); + BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check); + } + +// Use the preprocessor to generate tests using different combinations of +// boost/std piecewise_construct_t/tuple. + +#define PIECEWISE_TEST_NAME boost_tuple_piecewise_tests +#define PIECEWISE_NAMESPACE boost::unordered +#define TUPLE_NAMESPACE boost +#define EMULATING_PIECEWISE_CONSTRUCTION 1 +#include "./insert_tests.cpp" + +#if BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT + +#define PIECEWISE_TEST_NAME boost_tuple_std_piecewise_tests +#define PIECEWISE_NAMESPACE std +#define TUPLE_NAMESPACE boost +#define EMULATING_PIECEWISE_CONSTRUCTION 1 +#include "./insert_tests.cpp" + +#endif + +#if !defined(BOOST_NO_CXX11_HDR_TUPLE) + +#define PIECEWISE_TEST_NAME std_tuple_boost_piecewise_tests +#define PIECEWISE_NAMESPACE boost::unordered +#define TUPLE_NAMESPACE std +#define EMULATING_PIECEWISE_CONSTRUCTION 0 +#include "./insert_tests.cpp" + +#endif + +#if !defined(BOOST_NO_CXX11_HDR_TUPLE) && \ + BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT + +#define PIECEWISE_TEST_NAME std_piecewise_tests +#define PIECEWISE_NAMESPACE std +#define TUPLE_NAMESPACE std +#define EMULATING_PIECEWISE_CONSTRUCTION 0 +#include "./insert_tests.cpp" + +#endif +} + +RUN_TESTS_QUIET() + +#else // PIECEWISE_TEST_NAME + +UNORDERED_AUTO_TEST (PIECEWISE_TEST_NAME) { +#if EMULATING_PIECEWISE_CONSTRUCTION + test::detail::disable_construction_tracking _scoped; +#endif + + { + boost::unordered_map<overloaded_constructor, overloaded_constructor, + boost::hash<overloaded_constructor>, + std::equal_to<overloaded_constructor>, + test::allocator1< + std::pair<overloaded_constructor const, overloaded_constructor> > > + x; + + x.emplace(PIECEWISE_NAMESPACE::piecewise_construct, + TUPLE_NAMESPACE::make_tuple(), TUPLE_NAMESPACE::make_tuple()); + BOOST_TEST( + x.find(overloaded_constructor()) != x.end() && + x.find(overloaded_constructor())->second == overloaded_constructor()); + + x.emplace(convertible_to_piecewise(), TUPLE_NAMESPACE::make_tuple(1), + TUPLE_NAMESPACE::make_tuple()); + BOOST_TEST( + x.find(overloaded_constructor(1)) != x.end() && + x.find(overloaded_constructor(1))->second == overloaded_constructor()); + + x.emplace(piecewise_rvalue(), TUPLE_NAMESPACE::make_tuple(2, 3), + TUPLE_NAMESPACE::make_tuple(4, 5, 6)); + BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() && + x.find(overloaded_constructor(2, 3))->second == + overloaded_constructor(4, 5, 6)); + + derived_from_piecewise_construct_t d; + x.emplace( + d, TUPLE_NAMESPACE::make_tuple(9, 3, 1), TUPLE_NAMESPACE::make_tuple(10)); + BOOST_TEST(x.find(overloaded_constructor(9, 3, 1)) != x.end() && + x.find(overloaded_constructor(9, 3, 1))->second == + overloaded_constructor(10)); + + x.clear(); + + x.try_emplace(overloaded_constructor()); + BOOST_TEST( + x.find(overloaded_constructor()) != x.end() && + x.find(overloaded_constructor())->second == overloaded_constructor()); + + x.try_emplace(1); + BOOST_TEST( + x.find(overloaded_constructor(1)) != x.end() && + x.find(overloaded_constructor(1))->second == overloaded_constructor()); + + x.try_emplace(overloaded_constructor(2, 3), 4, 5, 6); + BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() && + x.find(overloaded_constructor(2, 3))->second == + overloaded_constructor(4, 5, 6)); + } + { + boost::unordered_multimap<overloaded_constructor, overloaded_constructor, + boost::hash<overloaded_constructor>, + std::equal_to<overloaded_constructor>, + test::allocator1< + std::pair<overloaded_constructor const, overloaded_constructor> > > + x; + + x.emplace(PIECEWISE_NAMESPACE::piecewise_construct, + TUPLE_NAMESPACE::make_tuple(), TUPLE_NAMESPACE::make_tuple()); + BOOST_TEST( + x.find(overloaded_constructor()) != x.end() && + x.find(overloaded_constructor())->second == overloaded_constructor()); + + x.emplace(convertible_to_piecewise(), TUPLE_NAMESPACE::make_tuple(1), + TUPLE_NAMESPACE::make_tuple()); + BOOST_TEST( + x.find(overloaded_constructor(1)) != x.end() && + x.find(overloaded_constructor(1))->second == overloaded_constructor()); + + x.emplace(piecewise_rvalue(), TUPLE_NAMESPACE::make_tuple(2, 3), + TUPLE_NAMESPACE::make_tuple(4, 5, 6)); + BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() && + x.find(overloaded_constructor(2, 3))->second == + overloaded_constructor(4, 5, 6)); + + derived_from_piecewise_construct_t d; + x.emplace( + d, TUPLE_NAMESPACE::make_tuple(9, 3, 1), TUPLE_NAMESPACE::make_tuple(10)); + BOOST_TEST(x.find(overloaded_constructor(9, 3, 1)) != x.end() && + x.find(overloaded_constructor(9, 3, 1))->second == + overloaded_constructor(10)); + } +} + +UNORDERED_AUTO_TEST (BOOST_PP_CAT(PIECEWISE_TEST_NAME, 2)) { +#if EMULATING_PIECEWISE_CONSTRUCTION + test::detail::disable_construction_tracking _scoped; +#endif + + boost::unordered_set< + std::pair<overloaded_constructor, overloaded_constructor> > + x; + std::pair<overloaded_constructor, overloaded_constructor> check; + + x.emplace(PIECEWISE_NAMESPACE::piecewise_construct, + TUPLE_NAMESPACE::make_tuple(), TUPLE_NAMESPACE::make_tuple()); + BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check); + + x.clear(); + x.emplace(PIECEWISE_NAMESPACE::piecewise_construct, + TUPLE_NAMESPACE::make_tuple(1), TUPLE_NAMESPACE::make_tuple(2, 3)); + check = + std::make_pair(overloaded_constructor(1), overloaded_constructor(2, 3)); + BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check); +} + +#undef PIECEWISE_TEST_NAME +#undef PIECEWISE_NAMESPACE +#undef TUPLE_NAMESPACE +#undef EMULATING_PIECEWISE_CONSTRUCTION + +#endif diff --git a/src/boost/libs/unordered/test/unordered/link_test_1.cpp b/src/boost/libs/unordered/test/unordered/link_test_1.cpp new file mode 100644 index 00000000..c32c3ac9 --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/link_test_1.cpp @@ -0,0 +1,26 @@ + +// 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) + +// 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>&); + +int main() +{ + 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; +} diff --git a/src/boost/libs/unordered/test/unordered/link_test_2.cpp b/src/boost/libs/unordered/test/unordered/link_test_2.cpp new file mode 100644 index 00000000..5ccf60d5 --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/link_test_2.cpp @@ -0,0 +1,30 @@ + +// 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) + +// 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) +{ +#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; + }; +#endif + + x1.insert(1); + x2[2] = 2; + x3.insert(3); + x4.insert(std::make_pair(4, 5)); +} diff --git a/src/boost/libs/unordered/test/unordered/load_factor_tests.cpp b/src/boost/libs/unordered/test/unordered/load_factor_tests.cpp new file mode 100644 index 00000000..9006c1bd --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/load_factor_tests.cpp @@ -0,0 +1,97 @@ + +// 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) + +// 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/limits.hpp> +#include "../helpers/random_values.hpp" + +#if defined(BOOST_MSVC) +#pragma warning(push) +#pragma warning(disable : 4127) // conditional expression is constant +#endif + +namespace load_factor_tests { + + test::seed_t initialize_seed(783656); + + template <class X> void set_load_factor_tests(X*) + { + X x; + + BOOST_TEST(x.max_load_factor() == 1.0); + BOOST_TEST(x.load_factor() == 0); + + // A valid implementation could fail these tests, but I think they're + // reasonable. + x.max_load_factor(2.0); + BOOST_TEST(x.max_load_factor() == 2.0); + x.max_load_factor(0.5); + BOOST_TEST(x.max_load_factor() == 0.5); + } + + template <class X> + void insert_test(X*, float mlf, test::random_generator generator) + { + X x; + x.max_load_factor(mlf); + float b = x.max_load_factor(); + + test::random_values<X> values(1000, generator); + + for (typename test::random_values<X>::const_iterator it = values.begin(), + end = values.end(); + it != end; ++it) { + typename X::size_type old_size = x.size(), + old_bucket_count = x.bucket_count(); + x.insert(*it); + if (static_cast<double>(old_size + 1) <= + b * static_cast<double>(old_bucket_count)) + BOOST_TEST(x.bucket_count() == old_bucket_count); + } + } + + template <class X> + void load_factor_insert_tests(X* ptr, test::random_generator generator) + { + insert_test(ptr, 1.0f, generator); + insert_test(ptr, 0.1f, generator); + insert_test(ptr, 100.0f, generator); + + insert_test(ptr, (std::numeric_limits<float>::min)(), generator); + + if (std::numeric_limits<float>::has_infinity) + insert_test(ptr, std::numeric_limits<float>::infinity(), generator); + } + + boost::unordered_set<int>* int_set_ptr; + boost::unordered_multiset<int>* int_multiset_ptr; + boost::unordered_map<int, int>* int_map_ptr; + boost::unordered_multimap<int, int>* int_multimap_ptr; + + using test::default_generator; + using test::generate_collisions; + using test::limited_range; + + UNORDERED_TEST(set_load_factor_tests, + ((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))) + + UNORDERED_TEST(load_factor_insert_tests, + ((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))( + (default_generator)(generate_collisions)(limited_range))) +} + +RUN_TESTS() + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#pragma warning(disable : 4127) // conditional expression is constant +#endif diff --git a/src/boost/libs/unordered/test/unordered/merge_tests.cpp b/src/boost/libs/unordered/test/unordered/merge_tests.cpp new file mode 100644 index 00000000..897abb34 --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/merge_tests.cpp @@ -0,0 +1,337 @@ + +// 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) + +#include "../helpers/postfix.hpp" +#include "../helpers/prefix.hpp" +#include <boost/unordered_map.hpp> +#include <boost/unordered_set.hpp> + +#include "../helpers/count.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 merge_tests { + + UNORDERED_AUTO_TEST (merge_set) { + boost::unordered_set<int> x; + boost::unordered_set<int> y; + + x.merge(y); + BOOST_TEST(x.empty()); + BOOST_TEST(y.empty()); + + x.insert(10); + x.merge(y); + BOOST_TEST(x.size() == 1); + BOOST_TEST(x.count(10) == 1); + BOOST_TEST(y.empty()); + + y.merge(x); + BOOST_TEST(x.empty()); + BOOST_TEST(y.size() == 1); + BOOST_TEST(y.count(10) == 1); + + x.insert(10); + x.insert(50); + y.insert(70); + y.insert(80); + x.merge(y); + BOOST_TEST_EQ(x.size(), 4u); + BOOST_TEST_EQ(y.size(), 1u); + BOOST_TEST_EQ(x.count(10), 1u); + BOOST_TEST_EQ(x.count(50), 1u); + BOOST_TEST_EQ(x.count(70), 1u); + BOOST_TEST_EQ(x.count(80), 1u); + BOOST_TEST_EQ(y.count(10), 1u); + BOOST_TEST_EQ(y.count(50), 0u); + BOOST_TEST_EQ(y.count(70), 0u); + BOOST_TEST_EQ(y.count(80), 0u); + + test::check_equivalent_keys(x); + test::check_equivalent_keys(y); + } + + UNORDERED_AUTO_TEST (merge_multiset) { + boost::unordered_multiset<int> x; + boost::unordered_multiset<int> y; + + x.merge(y); + BOOST_TEST(x.empty()); + BOOST_TEST(y.empty()); + + x.insert(10); + x.merge(y); + BOOST_TEST(x.size() == 1); + BOOST_TEST(x.count(10) == 1); + BOOST_TEST(y.empty()); + + y.merge(x); + BOOST_TEST(x.empty()); + BOOST_TEST(y.size() == 1); + BOOST_TEST(y.count(10) == 1); + + x.insert(10); + x.insert(50); + y.insert(70); + y.insert(80); + x.merge(y); + BOOST_TEST_EQ(x.size(), 5u); + BOOST_TEST_EQ(y.size(), 0u); + BOOST_TEST_EQ(x.count(10), 2u); + BOOST_TEST_EQ(x.count(50), 1u); + BOOST_TEST_EQ(x.count(70), 1u); + BOOST_TEST_EQ(x.count(80), 1u); + BOOST_TEST_EQ(y.count(10), 0u); + BOOST_TEST_EQ(y.count(50), 0u); + BOOST_TEST_EQ(y.count(70), 0u); + BOOST_TEST_EQ(y.count(80), 0u); + + test::check_equivalent_keys(x); + test::check_equivalent_keys(y); + } + + UNORDERED_AUTO_TEST (merge_set_and_multiset) { + boost::unordered_set<int> x; + boost::unordered_multiset<int> y; + + x.merge(y); + BOOST_TEST(x.empty()); + BOOST_TEST(y.empty()); + + x.insert(10); + x.merge(y); + BOOST_TEST(x.size() == 1); + BOOST_TEST(x.count(10) == 1); + BOOST_TEST(y.empty()); + + y.merge(x); + BOOST_TEST(x.empty()); + BOOST_TEST(y.size() == 1); + BOOST_TEST(y.count(10) == 1); + + x.insert(10); + x.insert(50); + y.insert(70); + y.insert(80); + x.merge(y); + BOOST_TEST_EQ(x.size(), 4u); + BOOST_TEST_EQ(y.size(), 1u); + BOOST_TEST_EQ(x.count(10), 1u); + BOOST_TEST_EQ(x.count(50), 1u); + BOOST_TEST_EQ(x.count(70), 1u); + BOOST_TEST_EQ(x.count(80), 1u); + BOOST_TEST_EQ(y.count(10), 1u); + BOOST_TEST_EQ(y.count(50), 0u); + BOOST_TEST_EQ(y.count(70), 0u); + BOOST_TEST_EQ(y.count(80), 0u); + + test::check_equivalent_keys(x); + test::check_equivalent_keys(y); + } + + template <class X1, class X2> + void merge_empty_test(X1*, X2*, test::random_generator generator) + { + test::check_instances check_; + + test::random_values<X1> v(1000, generator); + X1 x1(v.begin(), v.end()); + X2 x2; + x1.merge(x2); + test::check_container(x1, v); + BOOST_TEST(x2.empty()); + test::check_equivalent_keys(x1); + test::check_equivalent_keys(x2); + } + + template <class X> + void merge_into_empty_test(X*, test::random_generator generator) + { + test::check_instances check_; + + test::random_values<X> v(1000, generator); + X x1; + X x2(v.begin(), v.end()); + x1.merge(x2); + test::check_container(x1, v); + BOOST_TEST(x2.empty()); + test::check_equivalent_keys(x1); + test::check_equivalent_keys(x2); + } + + template <class X1, class X2> + void merge_into_unique_keys_test(X1*, X2*, int hash_equal1, int hash_equal2, + test::random_generator generator) + { + test::check_instances check_; + + test::random_values<X1> v1(1000, generator); + test::random_values<X2> v2(1000, generator); + v1.insert(v2.begin(), test::next(v2.begin(), 100)); + v2.insert(v1.begin(), test::next(v1.begin(), 100)); + + X1 x1(v1.begin(), v1.end(), 0, test::hash(hash_equal1), + test::equal_to(hash_equal1)); + X2 x2(v2.begin(), v2.end(), 0, test::hash(hash_equal2), + test::equal_to(hash_equal2)); + + test::ordered<X1> tracker1 = test::create_ordered(x1); + test::ordered<X2> tracker2 = test::create_ordered(x2); + tracker1.insert(v1.begin(), v1.end()); + for (typename X2::iterator it = x2.begin(); it != x2.end(); ++it) { + if (!tracker1.insert(*it).second) { + tracker2.insert(*it); + } + } + + x1.merge(x2); + + tracker1.compare(x1); + tracker2.compare(x2); + test::check_equivalent_keys(x1); + test::check_equivalent_keys(x2); + } + + template <class X1, class X2> + void merge_into_equiv_keys_test(X1*, X2*, int hash_equal1, int hash_equal2, + test::random_generator generator) + { + test::check_instances check_; + + test::random_values<X1> v1(1000, generator); + test::random_values<X2> v2(1000, generator); + v1.insert(v2.begin(), test::next(v2.begin(), 100)); + v2.insert(v1.begin(), test::next(v1.begin(), 100)); + + X1 x1(v1.begin(), v1.end(), 0, test::hash(hash_equal1), + test::equal_to(hash_equal1)); + X2 x2(v2.begin(), v2.end(), 0, test::hash(hash_equal2), + test::equal_to(hash_equal2)); + x1.merge(x2); + + test::ordered<X1> tracker1 = test::create_ordered(x1); + test::ordered<X2> tracker2 = test::create_ordered(x2); + tracker1.insert(v1.begin(), v1.end()); + tracker2.insert(v2.begin(), v2.end()); + tracker1.insert(tracker2.begin(), tracker2.end()); + tracker2.clear(); + + tracker1.compare(x1); + tracker2.compare(x2); + test::check_equivalent_keys(x1); + test::check_equivalent_keys(x2); + } + + boost::unordered_set<test::movable, test::hash, test::equal_to, + std::allocator<test::movable> >* test_set_std_alloc; + boost::unordered_multiset<test::movable, test::hash, test::equal_to, + std::allocator<test::movable> >* test_multiset_std_alloc; + + boost::unordered_map<test::object, test::object, test::hash, test::equal_to, + std::allocator<test::object> >* test_map_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, + test::allocator1<test::object> >* test_set; + boost::unordered_multiset<test::object, test::hash, test::equal_to, + test::allocator1<test::object> >* test_multiset; + + boost::unordered_map<test::movable, test::movable, test::hash, test::equal_to, + test::allocator2<test::movable> >* test_map; + boost::unordered_multimap<test::movable, test::movable, test::hash, + test::equal_to, test::allocator2<test::movable> >* test_multimap; + + using test::default_generator; + using test::generate_collisions; + + // clang-format off +UNORDERED_TEST(merge_empty_test, + ((test_set_std_alloc)(test_multiset_std_alloc)) + ((test_set_std_alloc)(test_multiset_std_alloc)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_empty_test, + ((test_map_std_alloc)(test_multimap_std_alloc)) + ((test_map_std_alloc)(test_multimap_std_alloc)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_empty_test, + ((test_set)(test_multiset)) + ((test_set)(test_multiset)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_empty_test, + ((test_map)(test_multimap)) + ((test_map)(test_multimap)) + ((default_generator)(generate_collisions))) + +UNORDERED_TEST(merge_into_empty_test, + ((test_set_std_alloc)(test_multiset_std_alloc)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_into_empty_test, + ((test_map_std_alloc)(test_multimap_std_alloc)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_into_empty_test, + ((test_set)(test_multiset)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_into_empty_test, + ((test_map)(test_multimap)) + ((default_generator)(generate_collisions))) + +UNORDERED_TEST(merge_into_unique_keys_test, + ((test_set_std_alloc)) + ((test_set_std_alloc)(test_multiset_std_alloc)) + ((0)(1)(2)) + ((0)(1)(2)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_into_unique_keys_test, + ((test_map_std_alloc)) + ((test_map_std_alloc)(test_multimap_std_alloc)) + ((0)(1)(2)) + ((0)(1)(2)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_into_unique_keys_test, + ((test_set)) + ((test_set)(test_multiset)) + ((0)(1)(2)) + ((0)(1)(2)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_into_unique_keys_test, + ((test_map)) + ((test_map)(test_multimap)) + ((0)(1)(2)) + ((0)(1)(2)) + ((default_generator)(generate_collisions))) + +UNORDERED_TEST(merge_into_equiv_keys_test, + ((test_multiset_std_alloc)) + ((test_set_std_alloc)(test_multiset_std_alloc)) + ((0)(1)(2)) + ((0)(1)(2)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_into_equiv_keys_test, + ((test_multimap_std_alloc)) + ((test_map_std_alloc)(test_multimap_std_alloc)) + ((0)(1)(2)) + ((0)(1)(2)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_into_equiv_keys_test, + ((test_multiset)) + ((test_set)(test_multiset)) + ((0)(1)(2)) + ((0)(1)(2)) + ((default_generator)(generate_collisions))) +UNORDERED_TEST(merge_into_equiv_keys_test, + ((test_multimap)) + ((test_map)(test_multimap)) + ((0)(1)(2)) + ((0)(1)(2)) + ((default_generator)(generate_collisions))) + // clang-format on +} + +RUN_TESTS() diff --git a/src/boost/libs/unordered/test/unordered/minimal_allocator.cpp b/src/boost/libs/unordered/test/unordered/minimal_allocator.cpp new file mode 100644 index 00000000..a692443e --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/minimal_allocator.cpp @@ -0,0 +1,92 @@ + +// Copyright 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) + +#include "../objects/test.hpp" +#include <boost/core/lightweight_test.hpp> +#include <boost/static_assert.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/unordered/detail/implementation.hpp> + +template <class Tp> struct SimpleAllocator +{ + typedef Tp value_type; + + SimpleAllocator() {} + + template <class T> SimpleAllocator(const SimpleAllocator<T>&) {} + + Tp* allocate(std::size_t n) + { + return static_cast<Tp*>(::operator new(n * sizeof(Tp))); + } + + void deallocate(Tp* p, std::size_t) { ::operator delete((void*)p); } +}; + +template <typename T> void test_simple_allocator() +{ + test::check_instances check_; + + typedef boost::unordered::detail::allocator_traits<SimpleAllocator<T> > + traits; + + BOOST_STATIC_ASSERT((boost::is_same<typename traits::allocator_type, + SimpleAllocator<T> >::value)); + + BOOST_STATIC_ASSERT((boost::is_same<typename traits::value_type, T>::value)); + + BOOST_STATIC_ASSERT((boost::is_same<typename traits::pointer, T*>::value)); + BOOST_STATIC_ASSERT( + (boost::is_same<typename traits::const_pointer, T const*>::value)); + // BOOST_STATIC_ASSERT((boost::is_same<typename traits::void_pointer, void* + // >::value)); + // BOOST_STATIC_ASSERT((boost::is_same<typename traits::const_void_pointer, + // void const*>::value)); + + BOOST_STATIC_ASSERT( + (boost::is_same<typename traits::difference_type, std::ptrdiff_t>::value)); + +#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1 + BOOST_STATIC_ASSERT((boost::is_same<typename traits::size_type, + std::make_unsigned<std::ptrdiff_t>::type>::value)); +#else + BOOST_STATIC_ASSERT( + (boost::is_same<typename traits::size_type, std::size_t>::value)); +#endif + + 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); + + // rebind_alloc + // rebind_traits + + SimpleAllocator<T> a; + + T* ptr1 = traits::allocate(a, 1); + // T* ptr2 = traits::allocate(a, 1, static_cast<void const*>(ptr1)); + + traits::construct(a, ptr1, T(10)); + // traits::construct(a, ptr2, T(30), ptr1); + + BOOST_TEST(*ptr1 == T(10)); + // BOOST_TEST(*ptr2 == T(30)); + + traits::destroy(a, ptr1); + // traits::destroy(a, ptr2); + + // traits::deallocate(a, ptr2, 1); + traits::deallocate(a, ptr1, 1); + + traits::max_size(a); +} + +int main() +{ + test_simple_allocator<int>(); + test_simple_allocator<test::object>(); + + return boost::report_errors(); +} diff --git a/src/boost/libs/unordered/test/unordered/move_tests.cpp b/src/boost/libs/unordered/test/unordered/move_tests.cpp new file mode 100644 index 00000000..82ba6011 --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/move_tests.cpp @@ -0,0 +1,372 @@ + +// Copyright 2008-2009 Daniel James. +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or move 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" +#include "../helpers/random_values.hpp" +#include "../helpers/tracker.hpp" +#include "../helpers/equivalent.hpp" +#include "../helpers/invariants.hpp" + +#if defined(BOOST_MSVC) +#pragma warning(disable : 4127) // conditional expression is constant +#endif + +namespace move_tests { + test::seed_t initialize_seed(98624); +#if defined(BOOST_UNORDERED_USE_MOVE) || \ + !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +#define BOOST_UNORDERED_TEST_MOVING 1 +#else +#define BOOST_UNORDERED_TEST_MOVING 0 +#endif + + template <class T> T empty(T*) { return T(); } + + template <class T> + T create(test::random_values<T> const& v, test::object_count& count) + { + T x(v.begin(), v.end()); + count = test::global_object_count; + return x; + } + + template <class T> + T create(test::random_values<T> const& v, test::object_count& count, + typename T::hasher hf, typename T::key_equal eq, + typename T::allocator_type al, float mlf) + { + T x(0, hf, eq, al); + x.max_load_factor(mlf); + x.insert(v.begin(), v.end()); + count = test::global_object_count; + return x; + } + + template <class T> + void move_construct_tests1(T* ptr, test::random_generator const& generator) + { + typename T::hasher hf; + typename T::key_equal eq; + typename T::allocator_type al; + + { + test::check_instances check_; + + T y(empty(ptr)); + 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(y.max_load_factor() == 1.0); + test::check_equivalent_keys(y); + } + + { + test::check_instances check_; + + test::random_values<T> v(1000, generator); + test::object_count count; + T y(create(v, count)); +#if defined(BOOST_HAS_NRVO) + BOOST_TEST(count == test::global_object_count); +#endif + test::check_container(y, v); + test::check_equivalent_keys(y); + } + } + + template <class T> + void move_assign_tests1(T*, test::random_generator const& generator) + { + { + test::check_instances check_; + + test::random_values<T> v(500, generator); + test::object_count count; + T y; + y = create(v, count); +#if BOOST_UNORDERED_TEST_MOVING && defined(BOOST_HAS_NRVO) + BOOST_TEST(count == test::global_object_count); +#endif + test::check_container(y, v); + test::check_equivalent_keys(y); + } + } + + template <class T> + void move_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); + + test::object_count count; + + { + test::check_instances check_; + + test::random_values<T> v(500, generator); + T y(create(v, count, hf, eq, al, 0.5)); +#if defined(BOOST_HAS_NRVO) + BOOST_TEST(count == test::global_object_count); +#endif + test::check_container(y, v); + 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(y.max_load_factor() == 0.5); // Not necessarily required. + test::check_equivalent_keys(y); + } + + { + test::check_instances check_; + + // TODO: To do this correctly requires the fancy new allocator + // stuff. + test::random_values<T> v(500, generator); + T y(create(v, count, hf, eq, al, 2.0), al2); + BOOST_TEST(count != test::global_object_count); + test::check_container(y, v); + 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(y.max_load_factor() == 2.0); // Not necessarily required. + test::check_equivalent_keys(y); + } + + { + test::check_instances check_; + + test::random_values<T> v(25, generator); + T y(create(v, count, hf, eq, al, 1.0), al); +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + BOOST_TEST(count == test::global_object_count); +#elif defined(BOOST_HAS_NRVO) + BOOST_TEST( + static_cast<std::size_t>( + test::global_object_count.constructions - count.constructions) <= + (test::is_set<T>::value ? 1 : 2) * + (test::has_unique_keys<T>::value ? 25 : v.size())); + BOOST_TEST(count.instances == test::global_object_count.instances); +#else + BOOST_TEST( + static_cast<std::size_t>( + test::global_object_count.constructions - count.constructions) <= + (test::is_set<T>::value ? 2 : 4) * + (test::has_unique_keys<T>::value ? 25 : v.size())); + BOOST_TEST(count.instances == test::global_object_count.instances); +#endif + test::check_container(y, v); + 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(y.max_load_factor() == 1.0); // Not necessarily required. + test::check_equivalent_keys(y); + } + } + + template <class T> + void move_assign_tests2(T*, test::random_generator const& generator) + { + typename T::hasher hf(1); + typename T::key_equal eq(1); + typename T::allocator_type al1(1); + typename T::allocator_type al2(2); + typedef typename T::allocator_type allocator_type; + + { + test::random_values<T> v(500, generator); + test::random_values<T> v2(0, generator); + T y(v.begin(), v.end(), 0, hf, eq, al1); + test::object_count count; + y = create(v2, count, hf, eq, al2, 2.0); + BOOST_TEST(y.empty()); + test::check_container(y, v2); + test::check_equivalent_keys(y); + BOOST_TEST(y.max_load_factor() == 2.0); + +#if defined(BOOST_HAS_NRVO) + if (BOOST_UNORDERED_TEST_MOVING + ? (bool)allocator_type::is_propagate_on_move + : (bool)allocator_type::is_propagate_on_assign) { + BOOST_TEST(test::equivalent(y.get_allocator(), al2)); + } else { + BOOST_TEST(test::equivalent(y.get_allocator(), al1)); + } +#endif + } + + { + test::random_values<T> v(500, generator); + test::object_count count; + T y(0, hf, eq, al1); + y = create(v, count, hf, eq, al2, 0.5); +#if defined(BOOST_HAS_NRVO) + if (BOOST_UNORDERED_TEST_MOVING && allocator_type::is_propagate_on_move) { + BOOST_TEST(count == test::global_object_count); + } +#endif + test::check_container(y, v); + test::check_equivalent_keys(y); + BOOST_TEST(y.max_load_factor() == 0.5); + +#if defined(BOOST_HAS_NRVO) + if (BOOST_UNORDERED_TEST_MOVING + ? (bool)allocator_type::is_propagate_on_move + : (bool)allocator_type::is_propagate_on_assign) { + BOOST_TEST(test::equivalent(y.get_allocator(), al2)); + } else { + BOOST_TEST(test::equivalent(y.get_allocator(), al1)); + } +#endif + } + + { + test::check_instances check_; + + test::random_values<T> v(500, generator); + T y(0, hf, eq, al1); + + T x(0, hf, eq, al2); + x.max_load_factor(0.25); + x.insert(v.begin(), v.end()); + + test::object_count count = test::global_object_count; + y = boost::move(x); + if (BOOST_UNORDERED_TEST_MOVING && allocator_type::is_propagate_on_move) { + BOOST_TEST(count == test::global_object_count); + } + test::check_container(y, v); + test::check_equivalent_keys(y); + BOOST_TEST(y.max_load_factor() == 0.25); + + if (BOOST_UNORDERED_TEST_MOVING + ? (bool)allocator_type::is_propagate_on_move + : (bool)allocator_type::is_propagate_on_assign) { + BOOST_TEST(test::equivalent(y.get_allocator(), al2)); + } else { + BOOST_TEST(test::equivalent(y.get_allocator(), al1)); + } + } + + { + test::check_instances check_; + + test::random_values<T> v1(1000, generator); + test::random_values<T> v2(200, generator); + + T x(0, hf, eq, al2); + x.max_load_factor(0.5); + x.insert(v2.begin(), v2.end()); + + test::object_count count1 = test::global_object_count; + + T y(v1.begin(), v1.end(), 0, hf, eq, al1); + y = boost::move(x); + + test::object_count count2 = test::global_object_count; + + if (BOOST_UNORDERED_TEST_MOVING && allocator_type::is_propagate_on_move) { + BOOST_TEST(count1.instances == test::global_object_count.instances); + BOOST_TEST( + count2.constructions == test::global_object_count.constructions); + } + + test::check_container(y, v2); + test::check_equivalent_keys(y); + BOOST_TEST(y.max_load_factor() == 0.5); + + if (BOOST_UNORDERED_TEST_MOVING + ? (bool)allocator_type::is_propagate_on_move + : (bool)allocator_type::is_propagate_on_assign) { + BOOST_TEST(test::equivalent(y.get_allocator(), al2)); + } else { + BOOST_TEST(test::equivalent(y.get_allocator(), al1)); + } + } + } + + 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, + test::allocator2<test::object> >* test_set; + 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, + 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_set<test::object, test::hash, test::equal_to, + test::cxx11_allocator<test::object, test::propagate_move> >* + test_set_prop_move; + boost::unordered_multiset<test::object, test::hash, test::equal_to, + test::cxx11_allocator<test::object, test::propagate_move> >* + test_multiset_prop_move; + boost::unordered_map<test::object, test::object, test::hash, test::equal_to, + test::cxx11_allocator<test::object, test::propagate_move> >* + test_map_prop_move; + boost::unordered_multimap<test::object, test::object, test::hash, + test::equal_to, test::cxx11_allocator<test::object, test::propagate_move> >* + test_multimap_prop_move; + + boost::unordered_set<test::object, test::hash, test::equal_to, + test::cxx11_allocator<test::object, test::no_propagate_move> >* + test_set_no_prop_move; + boost::unordered_multiset<test::object, test::hash, test::equal_to, + test::cxx11_allocator<test::object, test::no_propagate_move> >* + test_multiset_no_prop_move; + boost::unordered_map<test::object, test::object, test::hash, test::equal_to, + test::cxx11_allocator<test::object, test::no_propagate_move> >* + test_map_no_prop_move; + boost::unordered_multimap<test::object, test::object, test::hash, + test::equal_to, + test::cxx11_allocator<test::object, test::no_propagate_move> >* + test_multimap_no_prop_move; + + using test::default_generator; + using test::generate_collisions; + using test::limited_range; + + UNORDERED_TEST(move_construct_tests1, + ((test_map_std_alloc)(test_set)(test_multiset)(test_map)(test_multimap)( + test_set_prop_move)(test_multiset_prop_move)(test_map_prop_move)( + test_multimap_prop_move)(test_set_no_prop_move)( + test_multiset_no_prop_move)(test_map_no_prop_move)( + test_multimap_no_prop_move))( + (default_generator)(generate_collisions)(limited_range))) + UNORDERED_TEST(move_assign_tests1, + ((test_map_std_alloc)(test_set)(test_multiset)(test_map)(test_multimap)( + test_set_prop_move)(test_multiset_prop_move)(test_map_prop_move)( + test_multimap_prop_move)(test_set_no_prop_move)( + test_multiset_no_prop_move)(test_map_no_prop_move)( + test_multimap_no_prop_move))( + (default_generator)(generate_collisions)(limited_range))) + UNORDERED_TEST(move_construct_tests2, + ((test_set)(test_multiset)(test_map)(test_multimap)(test_set_prop_move)( + test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)( + test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)( + test_multimap_no_prop_move))( + (default_generator)(generate_collisions)(limited_range))) + UNORDERED_TEST(move_assign_tests2, + ((test_set)(test_multiset)(test_map)(test_multimap)(test_set_prop_move)( + test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)( + test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)( + test_multimap_no_prop_move))( + (default_generator)(generate_collisions)(limited_range))) +} + +RUN_TESTS() diff --git a/src/boost/libs/unordered/test/unordered/node_handle_tests.cpp b/src/boost/libs/unordered/test/unordered/node_handle_tests.cpp new file mode 100644 index 00000000..2d5b1eab --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/node_handle_tests.cpp @@ -0,0 +1,424 @@ + +// 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) + +#include "../helpers/postfix.hpp" +#include "../helpers/prefix.hpp" +#include <boost/unordered_map.hpp> +#include <boost/unordered_set.hpp> + +#include "../helpers/helpers.hpp" +#include "../helpers/metafunctions.hpp" +#include "../helpers/test.hpp" +#include <boost/core/pointer_traits.hpp> +#include <boost/static_assert.hpp> +#include <boost/type_traits/is_same.hpp> +#include <set> +#include <string> + +UNORDERED_AUTO_TEST (example1) { + typedef boost::unordered_map<int, std::string>::insert_return_type + insert_return_type; + + boost::unordered_map<int, std::string> src; + src.emplace(1, "one"); + src.emplace(2, "two"); + src.emplace(3, "buckle my shoe"); + boost::unordered_map<int, std::string> dst; + dst.emplace(3, "three"); + + dst.insert(src.extract(src.find(1))); + dst.insert(src.extract(2)); + insert_return_type r = dst.insert(src.extract(3)); + + BOOST_TEST(src.empty()); + BOOST_TEST(dst.size() == 3); + BOOST_TEST(dst[1] == "one"); + BOOST_TEST(dst[2] == "two"); + BOOST_TEST(dst[3] == "three"); + BOOST_TEST(!r.inserted); + BOOST_TEST(r.position == dst.find(3)); + BOOST_TEST(r.node.mapped() == "buckle my shoe"); +} + +UNORDERED_AUTO_TEST (example2) { + boost::unordered_set<int> src; + src.insert(1); + src.insert(3); + src.insert(5); + boost::unordered_set<int> dst; + dst.insert(2); + dst.insert(4); + dst.insert(5); + // dst.merge(src); + // Merge src into dst. + // src == {5} + // dst == {1, 2, 3, 4, 5} +} + +UNORDERED_AUTO_TEST (example3) { + typedef boost::unordered_set<int>::iterator iterator; + + boost::unordered_set<int> src; + src.insert(1); + src.insert(3); + src.insert(5); + boost::unordered_set<int> dst; + dst.insert(2); + dst.insert(4); + dst.insert(5); + for (iterator i = src.begin(); i != src.end();) { + std::pair<iterator, iterator> p = dst.equal_range(*i); + if (p.first == p.second) + dst.insert(p.first, src.extract(i++)); + else + ++i; + } + BOOST_TEST(src.size() == 1); + BOOST_TEST(*src.begin() == 5); + + std::set<int> dst2(dst.begin(), dst.end()); + std::set<int>::iterator it = dst2.begin(); + BOOST_TEST(*it++ == 1); + BOOST_TEST(*it++ == 2); + BOOST_TEST(*it++ == 3); + BOOST_TEST(*it++ == 4); + BOOST_TEST(*it++ == 5); + BOOST_TEST(it == dst2.end()); +} + +UNORDERED_AUTO_TEST (failed_insertion_with_hint) { + { + boost::unordered_set<int> src; + boost::unordered_set<int> dst; + src.emplace(10); + src.emplace(20); + dst.emplace(10); + dst.emplace(20); + + boost::unordered_set<int>::node_type nh = src.extract(10); + + BOOST_TEST(dst.insert(dst.find(10), boost::move(nh)) == dst.find(10)); + BOOST_TEST(nh); + BOOST_TEST(!nh.empty()); + BOOST_TEST(nh.value() == 10); + + BOOST_TEST(dst.insert(dst.find(20), boost::move(nh)) == dst.find(10)); + BOOST_TEST(nh); + BOOST_TEST(!nh.empty()); + BOOST_TEST(nh.value() == 10); + + BOOST_TEST(src.count(10) == 0); + BOOST_TEST(src.count(20) == 1); + BOOST_TEST(dst.count(10) == 1); + BOOST_TEST(dst.count(20) == 1); + } + + { + boost::unordered_map<int, int> src; + boost::unordered_map<int, int> dst; + src.emplace(10, 30); + src.emplace(20, 5); + dst.emplace(10, 20); + dst.emplace(20, 2); + + boost::unordered_map<int, int>::node_type nh = src.extract(10); + BOOST_TEST(dst.insert(dst.find(10), boost::move(nh)) == dst.find(10)); + BOOST_TEST(nh); + BOOST_TEST(!nh.empty()); + BOOST_TEST(nh.key() == 10); + BOOST_TEST(nh.mapped() == 30); + BOOST_TEST(dst[10] == 20); + + BOOST_TEST(dst.insert(dst.find(20), boost::move(nh)) == dst.find(10)); + BOOST_TEST(nh); + BOOST_TEST(!nh.empty()); + BOOST_TEST(nh.key() == 10); + BOOST_TEST(nh.mapped() == 30); + BOOST_TEST(dst[10] == 20); + + BOOST_TEST(src.count(10) == 0); + BOOST_TEST(src.count(20) == 1); + BOOST_TEST(dst.count(10) == 1); + BOOST_TEST(dst.count(20) == 1); + } +} + +template <typename NodeHandle> +bool node_handle_compare( + NodeHandle const& nh, typename NodeHandle::value_type const& x) +{ + return x == nh.value(); +} + +template <typename NodeHandle> +bool node_handle_compare( + NodeHandle const& nh, std::pair<typename NodeHandle::key_type const, + typename NodeHandle::mapped_type> const& x) +{ + return x.first == nh.key() && x.second == nh.mapped(); +} + +template <typename Container> void node_handle_tests_impl(Container& c) +{ + typedef typename Container::node_type node_type; + + typename Container::value_type value = *c.begin(); + + node_type n1; + BOOST_TEST(!n1); + BOOST_TEST(n1.empty()); + + node_type n2 = c.extract(c.begin()); + BOOST_TEST(n2); + BOOST_TEST(!n2.empty()); + node_handle_compare(n2, value); + + node_type n3 = boost::move(n2); + BOOST_TEST(n3); + BOOST_TEST(!n2); + node_handle_compare(n3, value); + // TODO: Check that n2 doesn't have an allocator? + // Maybe by swapping and observing that the allocator is + // swapped rather than moved? + + n1 = boost::move(n3); + BOOST_TEST(n1); + BOOST_TEST(!n3); + node_handle_compare(n1, value); + + // Self move-assignment empties the node_handle. + n1 = boost::move(n1); + BOOST_TEST(!n1); + + n3 = boost::move(n3); + BOOST_TEST(!n3); + + typename Container::value_type value1 = *c.begin(); + n1 = c.extract(c.begin()); + typename Container::value_type value2 = *c.begin(); + n2 = c.extract(c.begin()); + n3 = node_type(); + + node_handle_compare(n1, value1); + node_handle_compare(n2, value2); + n1.swap(n2); + BOOST_TEST(n1); + BOOST_TEST(n2); + node_handle_compare(n1, value2); + node_handle_compare(n2, value1); + + BOOST_TEST(n1); + BOOST_TEST(!n3); + n1.swap(n3); + BOOST_TEST(!n1); + BOOST_TEST(n3); + node_handle_compare(n3, value2); + + BOOST_TEST(!n1); + BOOST_TEST(n2); + n1.swap(n2); + BOOST_TEST(n1); + BOOST_TEST(!n2); + node_handle_compare(n1, value1); + + node_type n4; + BOOST_TEST(!n2); + BOOST_TEST(!n4); + n2.swap(n4); + BOOST_TEST(!n2); + BOOST_TEST(!n4); +} + +UNORDERED_AUTO_TEST (node_handle_tests) { + boost::unordered_set<int> x1; + x1.emplace(100); + x1.emplace(140); + x1.emplace(-55); + node_handle_tests_impl(x1); + + boost::unordered_map<int, std::string> x2; + x2.emplace(10, "ten"); + x2.emplace(-23, "twenty"); + x2.emplace(-76, "thirty"); + node_handle_tests_impl(x2); +} + +template <typename Container1, typename Container2> +void insert_node_handle_unique(Container1& c1, Container2& c2) +{ + typedef typename Container1::node_type node_type; + typedef typename Container1::value_type value_type; + BOOST_STATIC_ASSERT( + (boost::is_same<node_type, typename Container2::node_type>::value)); + + typedef typename Container1::insert_return_type insert_return_type1; + typedef typename Container2::insert_return_type insert_return_type2; + + insert_return_type1 r1 = c1.insert(node_type()); + insert_return_type2 r2 = c2.insert(node_type()); + BOOST_TEST(!r1.inserted); + BOOST_TEST(!r1.node); + BOOST_TEST(r1.position == c1.end()); + BOOST_TEST(!r2.inserted); + BOOST_TEST(!r2.node); + BOOST_TEST(r2.position == c2.end()); + + while (!c1.empty()) { + value_type v = *c1.begin(); + value_type const* v_ptr = boost::to_address(c1.begin()); + std::size_t count = c2.count(test::get_key<Container1>(v)); + insert_return_type2 r = c2.insert(c1.extract(c1.begin())); + if (!count) { + BOOST_TEST(r.inserted); + BOOST_TEST_EQ(c2.count(test::get_key<Container1>(v)), count + 1); + BOOST_TEST(r.position != c2.end()); + BOOST_TEST(boost::to_address(r.position) == v_ptr); + BOOST_TEST(!r.node); + } else { + BOOST_TEST(!r.inserted); + BOOST_TEST_EQ(c2.count(test::get_key<Container1>(v)), count); + BOOST_TEST(r.position != c2.end()); + BOOST_TEST( + test::get_key<Container2>(*r.position) == test::get_key<Container2>(v)); + BOOST_TEST(r.node); + node_handle_compare(r.node, v); + } + } +} + +template <typename Container1, typename Container2> +void insert_node_handle_unique2(Container1& c1, Container2& c2) +{ + typedef typename Container1::node_type node_type; + typedef typename Container1::value_type value_type; + BOOST_STATIC_ASSERT( + (boost::is_same<node_type, typename Container2::node_type>::value)); + + // typedef typename Container1::insert_return_type + // insert_return_type1; + typedef typename Container2::insert_return_type insert_return_type2; + + while (!c1.empty()) { + value_type v = *c1.begin(); + value_type const* v_ptr = boost::to_address(c1.begin()); + std::size_t count = c2.count(test::get_key<Container1>(v)); + insert_return_type2 r = c2.insert(c1.extract(test::get_key<Container1>(v))); + if (r.inserted) { + BOOST_TEST_EQ(c2.count(test::get_key<Container1>(v)), count + 1); + BOOST_TEST(r.position != c2.end()); + BOOST_TEST(boost::to_address(r.position) == v_ptr); + BOOST_TEST(!r.node); + } else { + BOOST_TEST_EQ(c2.count(test::get_key<Container1>(v)), count); + BOOST_TEST(r.position != c2.end()); + BOOST_TEST( + test::get_key<Container2>(*r.position) == test::get_key<Container2>(v)); + BOOST_TEST(r.node); + node_handle_compare(r.node, v); + } + } +} + +template <typename Container1, typename Container2> +void insert_node_handle_equiv(Container1& c1, Container2& c2) +{ + typedef typename Container1::node_type node_type; + typedef typename Container1::value_type value_type; + BOOST_STATIC_ASSERT( + (boost::is_same<node_type, typename Container2::node_type>::value)); + + typedef typename Container1::iterator iterator1; + typedef typename Container2::iterator iterator2; + + iterator1 r1 = c1.insert(node_type()); + iterator2 r2 = c2.insert(node_type()); + BOOST_TEST(r1 == c1.end()); + BOOST_TEST(r2 == c2.end()); + + while (!c1.empty()) { + value_type v = *c1.begin(); + value_type const* v_ptr = boost::to_address(c1.begin()); + std::size_t count = c2.count(test::get_key<Container1>(v)); + iterator2 r = c2.insert(c1.extract(c1.begin())); + BOOST_TEST_EQ(c2.count(test::get_key<Container1>(v)), count + 1); + BOOST_TEST(r != c2.end()); + BOOST_TEST(boost::to_address(r) == v_ptr); + } +} + +struct hash_thing +{ + std::size_t operator()(int x) const + { + return static_cast<std::size_t>(x * 13 + 5); + } +}; + +UNORDERED_AUTO_TEST (insert_node_handle_unique_tests) { + { + boost::unordered_set<int> x1; + boost::unordered_set<int> x2; + x1.emplace(100); + x1.emplace(140); + x1.emplace(-55); + x2.emplace(140); + insert_node_handle_unique(x1, x2); + BOOST_TEST(x2.size() == 3); + } + + { + boost::unordered_map<int, int, hash_thing> x1; + boost::unordered_map<int, int> x2; + x1.emplace(67, 50); + x1.emplace(23, 45); + x1.emplace(18, 19); + x2.emplace(23, 50); + x2.emplace(12, 49); + insert_node_handle_unique(x1, x2); + BOOST_TEST(x2.size() == 4); + } +} + +UNORDERED_AUTO_TEST (insert_node_handle_equiv_tests) { + { + boost::unordered_multimap<int, int, hash_thing> x1; + boost::unordered_multimap<int, int> x2; + x1.emplace(67, 50); + x1.emplace(67, 100); + x1.emplace(23, 45); + x1.emplace(18, 19); + x2.emplace(23, 50); + x2.emplace(12, 49); + insert_node_handle_equiv(x1, x2); + BOOST_TEST(x2.size() == 6); + } +} + +UNORDERED_AUTO_TEST (insert_node_handle_unique_tests2) { + { + boost::unordered_set<int> x1; + boost::unordered_set<int> x2; + x1.emplace(100); + x1.emplace(140); + x1.emplace(-55); + x2.emplace(140); + insert_node_handle_unique2(x1, x2); + BOOST_TEST(x2.size() == 3); + } + + { + boost::unordered_map<int, int, hash_thing> x1; + boost::unordered_map<int, int> x2; + x1.emplace(67, 50); + x1.emplace(23, 45); + x1.emplace(18, 19); + x2.emplace(23, 50); + x2.emplace(12, 49); + insert_node_handle_unique2(x1, x2); + BOOST_TEST(x2.size() == 4); + } +} + +RUN_TESTS() diff --git a/src/boost/libs/unordered/test/unordered/noexcept_tests.cpp b/src/boost/libs/unordered/test/unordered/noexcept_tests.cpp new file mode 100644 index 00000000..454e7c23 --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/noexcept_tests.cpp @@ -0,0 +1,320 @@ + +// Copyright 2013 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" + +#if defined(BOOST_MSVC) +#pragma warning(push) +// conditional expression is constant +#pragma warning(disable : 4127) +#endif + +namespace noexcept_tests { + // Test the noexcept is set correctly for the move constructor. + + struct hash_possible_exception : boost::hash<int> + { + hash_possible_exception(hash_possible_exception const&) {} + hash_possible_exception& operator=(hash_possible_exception const&) + { + return *this; + } + }; + + struct equal_to_possible_exception : std::equal_to<int> + { + equal_to_possible_exception(equal_to_possible_exception const&) {} + equal_to_possible_exception& operator=(equal_to_possible_exception const&) + { + return *this; + } + }; + + // Test that the move constructor does actually move without throwing + // an exception when it claims to. + + struct test_exception + { + }; + + bool throwing_test_exception = false; + void test_throw(char const* name) + { + if (throwing_test_exception) { + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Throw exception in: " << name + << std::endl; + throw test_exception(); + } + } + + template <bool nothrow_move_construct, bool nothrow_move_assign, + bool nothrow_swap> + class hash_nothrow : boost::hash<int> + { + BOOST_COPYABLE_AND_MOVABLE(hash_nothrow) + + typedef boost::hash<int> base; + + public: + hash_nothrow(BOOST_RV_REF(hash_nothrow)) + BOOST_NOEXCEPT_IF(nothrow_move_construct) + { + if (!nothrow_move_construct) { + test_throw("Move Constructor"); + } + } + + hash_nothrow() { test_throw("Constructor"); } + hash_nothrow(hash_nothrow const&) { test_throw("Copy"); } + hash_nothrow& operator=(BOOST_COPY_ASSIGN_REF(hash_nothrow)) + { + test_throw("Assign"); + return *this; + } + hash_nothrow& operator=(BOOST_RV_REF(hash_nothrow)) + BOOST_NOEXCEPT_IF(nothrow_move_assign) + { + if (!nothrow_move_assign) { + test_throw("Move Assign"); + } + return *this; + } + std::size_t operator()(int x) const + { + test_throw("Operator"); + return static_cast<base const&>(*this)(x); + } + friend void swap(hash_nothrow&, hash_nothrow&) + BOOST_NOEXCEPT_IF(nothrow_swap) + { + if (!nothrow_swap) { + test_throw("Swap"); + } + } + }; + + typedef hash_nothrow<true, false, false> hash_nothrow_move_construct; + typedef hash_nothrow<false, true, false> hash_nothrow_move_assign; + typedef hash_nothrow<false, false, true> hash_nothrow_swap; + + template <bool nothrow_move_construct, bool nothrow_move_assign, + bool nothrow_swap> + class equal_to_nothrow + { + BOOST_COPYABLE_AND_MOVABLE(equal_to_nothrow) + + typedef boost::hash<int> base; + + public: + equal_to_nothrow(BOOST_RV_REF(equal_to_nothrow)) + BOOST_NOEXCEPT_IF(nothrow_move_construct) + { + if (!nothrow_move_construct) { + test_throw("Move Constructor"); + } + } + + equal_to_nothrow() { test_throw("Constructor"); } + equal_to_nothrow(equal_to_nothrow const&) { test_throw("Copy"); } + equal_to_nothrow& operator=(BOOST_COPY_ASSIGN_REF(equal_to_nothrow)) + { + test_throw("Assign"); + return *this; + } + equal_to_nothrow& operator=(BOOST_RV_REF(equal_to_nothrow)) + BOOST_NOEXCEPT_IF(nothrow_move_assign) + { + if (!nothrow_move_assign) { + test_throw("Move Assign"); + } + return *this; + } + std::size_t operator()(int x, int y) const + { + test_throw("Operator"); + return x == y; + } + friend void swap(equal_to_nothrow&, equal_to_nothrow&) + BOOST_NOEXCEPT_IF(nothrow_swap) + { + if (!nothrow_swap) { + test_throw("Swap"); + } + } + }; + + typedef equal_to_nothrow<true, false, false> equal_to_nothrow_move_construct; + typedef equal_to_nothrow<false, true, false> equal_to_nothrow_move_assign; + typedef equal_to_nothrow<false, false, true> equal_to_nothrow_swap; + + bool have_is_nothrow_move = false; + bool have_is_nothrow_move_assign = false; + bool have_is_nothrow_swap = false; + + UNORDERED_AUTO_TEST (check_is_nothrow_move) { + BOOST_TEST( + !boost::is_nothrow_move_constructible<hash_possible_exception>::value); + BOOST_TEST( + !boost::is_nothrow_move_assignable<hash_possible_exception>::value); + BOOST_TEST(!boost::is_nothrow_swappable<hash_possible_exception>::value); + BOOST_TEST((!boost::is_nothrow_move_constructible< + equal_to_nothrow<false, false, false> >::value)); + BOOST_TEST((!boost::is_nothrow_move_assignable< + equal_to_nothrow<false, false, false> >::value)); + BOOST_TEST((!boost::is_nothrow_swappable< + equal_to_nothrow<false, false, false> >::value)); + + have_is_nothrow_move = + boost::is_nothrow_move_constructible<hash_nothrow_move_construct>::value; + have_is_nothrow_move_assign = + boost::is_nothrow_move_assignable<hash_nothrow_move_assign>::value; + have_is_nothrow_swap = + boost::is_nothrow_swappable<hash_nothrow_swap>::value; + +// Check that the traits work when expected. +#if !defined(BOOST_NO_CXX11_NOEXCEPT) && !defined(BOOST_NO_SFINAE_EXPR) && \ + !BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40800) + BOOST_TEST(have_is_nothrow_move); + BOOST_TEST(have_is_nothrow_move_assign); +#endif + +#if !defined(BOOST_NO_SFINAE_EXPR) && !defined(BOOST_NO_CXX11_NOEXCEPT) && \ + !defined(BOOST_NO_CXX11_DECLTYPE) && \ + !defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) + BOOST_TEST(have_is_nothrow_swap); +#endif + + BOOST_LIGHTWEIGHT_TEST_OSTREAM + << "have_is_nothrow_move: " << have_is_nothrow_move << std::endl + << "have_is_nothrow_swap: " << have_is_nothrow_swap << std::endl; + } + + UNORDERED_AUTO_TEST (test_noexcept) { + if (have_is_nothrow_move) { + BOOST_TEST((boost::is_nothrow_move_constructible< + boost::unordered_set<int> >::value)); + BOOST_TEST((boost::is_nothrow_move_constructible< + boost::unordered_multiset<int> >::value)); + BOOST_TEST((boost::is_nothrow_move_constructible< + boost::unordered_map<int, int> >::value)); + BOOST_TEST((boost::is_nothrow_move_constructible< + boost::unordered_multimap<int, int> >::value)); + } + + BOOST_TEST((!boost::is_nothrow_move_constructible< + boost::unordered_set<int, hash_possible_exception> >::value)); + BOOST_TEST( + (!boost::is_nothrow_move_constructible<boost::unordered_multiset<int, + boost::hash<int>, equal_to_possible_exception> >::value)); + } + + UNORDERED_AUTO_TEST (test_nothrow_move_when_noexcept) { + typedef boost::unordered_set<int, hash_nothrow_move_construct, + equal_to_nothrow_move_construct> + throwing_set; + + if (have_is_nothrow_move) { + BOOST_TEST(boost::is_nothrow_move_constructible<throwing_set>::value); + } + + throwing_test_exception = false; + + throwing_set x1; + x1.insert(10); + x1.insert(50); + + try { + throwing_test_exception = true; + + throwing_set x2 = boost::move(x1); + BOOST_TEST(x2.size() == 2); + BOOST_TEST(*x2.begin() == 10 || *x2.begin() == 50); + BOOST_TEST(have_is_nothrow_move); + } catch (test_exception) { + BOOST_TEST(!have_is_nothrow_move); + } + + throwing_test_exception = false; + } + + UNORDERED_AUTO_TEST (test_nothrow_move_assign_when_noexcept) { + typedef boost::unordered_set<int, hash_nothrow_move_assign, + equal_to_nothrow_move_assign> + throwing_set; + + if (have_is_nothrow_move_assign) { + BOOST_TEST(boost::is_nothrow_move_assignable<throwing_set>::value); + } + + throwing_test_exception = false; + + throwing_set x1; + throwing_set x2; + x1.insert(10); + x1.insert(50); + for (int i = 0; i < 100; ++i) { + x2.insert(i); + } + + try { + throwing_test_exception = true; + + x2 = boost::move(x1); + BOOST_TEST(x2.size() == 2); + BOOST_TEST(*x2.begin() == 10 || *x2.begin() == 50); + BOOST_TEST(have_is_nothrow_move_assign); + } catch (test_exception) { + BOOST_TEST(!have_is_nothrow_move_assign); + } + + throwing_test_exception = false; + } + + UNORDERED_AUTO_TEST (test_nothrow_swap_when_noexcept) { + typedef boost::unordered_set<int, hash_nothrow_swap, equal_to_nothrow_swap> + throwing_set; + + if (have_is_nothrow_swap) { + BOOST_TEST(boost::is_nothrow_swappable<throwing_set>::value); + } + + throwing_test_exception = false; + + throwing_set x1; + throwing_set x2; + x1.insert(10); + x1.insert(50); + for (int i = 0; i < 100; ++i) { + x2.insert(i); + } + + try { + throwing_test_exception = true; + + x1.swap(x2); + BOOST_TEST(x1.size() == 100); + BOOST_TEST(x2.size() == 2); + BOOST_TEST(*x2.begin() == 10 || *x2.begin() == 50); + BOOST_TEST(have_is_nothrow_swap); + } catch (test_exception) { + BOOST_TEST(!have_is_nothrow_swap); + } + + throwing_test_exception = false; + } +} + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + +RUN_TESTS() diff --git a/src/boost/libs/unordered/test/unordered/rehash_tests.cpp b/src/boost/libs/unordered/test/unordered/rehash_tests.cpp new file mode 100644 index 00000000..65c08936 --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/rehash_tests.cpp @@ -0,0 +1,229 @@ + +// 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) + +// 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/random_values.hpp" +#include "../helpers/tracker.hpp" +#include "../helpers/metafunctions.hpp" +#include "../objects/test.hpp" + +namespace rehash_tests { + + test::seed_t initialize_seed(2974); + + template <class X> bool postcondition(X const& x, typename X::size_type n) + { + return static_cast<double>(x.bucket_count()) >= + static_cast<double>(x.size()) / x.max_load_factor() && + x.bucket_count() >= n; + } + + template <class X> void rehash_empty_test1(X*) + { + X x; + + x.rehash(10000); + BOOST_TEST(postcondition(x, 10000)); + + x.rehash(0); + BOOST_TEST(postcondition(x, 0)); + + x.rehash(10000000); + BOOST_TEST(postcondition(x, 10000000)); + } + + template <class X> + void rehash_empty_test2(X*, test::random_generator generator) + { + test::random_values<X> v(1000, generator); + test::ordered<X> tracker; + + X x; + + x.rehash(10000); + BOOST_TEST(postcondition(x, 10000)); + + tracker.insert_range(v.begin(), v.end()); + x.insert(v.begin(), v.end()); + tracker.compare(x); + + BOOST_TEST(postcondition(x, 10000)); + + x.rehash(10000000); + tracker.compare(x); + BOOST_TEST(postcondition(x, 10000000)); + } + + template <class X> + void rehash_empty_test3(X*, test::random_generator generator) + { + test::random_values<X> v(1000, generator); + test::ordered<X> tracker; + + X x; + + x.rehash(0); + BOOST_TEST(postcondition(x, 0)); + + tracker.insert_range(v.begin(), v.end()); + x.insert(v.begin(), v.end()); + tracker.compare(x); + + BOOST_TEST(postcondition(x, 0)); + } + + template <class X> void rehash_test1(X*, test::random_generator generator) + { + test::random_values<X> v(1000, generator); + test::ordered<X> tracker; + tracker.insert_range(v.begin(), v.end()); + X x(v.begin(), v.end()); + + x.rehash(0); + BOOST_TEST(postcondition(x, 0)); + tracker.compare(x); + + x.max_load_factor(0.25); + x.rehash(0); + BOOST_TEST(postcondition(x, 0)); + tracker.compare(x); + + x.max_load_factor(50.0); + x.rehash(0); + BOOST_TEST(postcondition(x, 0)); + tracker.compare(x); + + x.rehash(1000); + BOOST_TEST(postcondition(x, 1000)); + tracker.compare(x); + } + + template <class X> void reserve_empty_test1(X*) + { + X x; + + x.reserve(10000); + BOOST_TEST(x.bucket_count() >= 10000); + + x.reserve(0); + + x.reserve(10000000); + BOOST_TEST(x.bucket_count() >= 10000000); + } + + template <class X> void reserve_empty_test2(X*) + { + X x; + x.max_load_factor(0.25); + + x.reserve(10000); + BOOST_TEST(x.bucket_count() >= 40000); + + x.reserve(0); + + x.reserve(10000000); + BOOST_TEST(x.bucket_count() >= 40000000); + } + + template <class X> void reserve_test1(X*, test::random_generator generator) + { + for (int random_mlf = 0; random_mlf < 2; ++random_mlf) { + for (std::size_t i = 1; i < 2000; i += i < 50 ? 1 : 13) { + test::random_values<X> v(i, generator); + + test::ordered<X> tracker; + tracker.insert_range(v.begin(), v.end()); + + X x; + x.max_load_factor( + random_mlf ? static_cast<float>(std::rand() % 1000) / 500.0f + 0.5f + : 1.0f); + x.reserve(test::has_unique_keys<X>::value ? i : v.size()); + + // Insert an element before the range insert, otherwise there are + // no iterators to invalidate in the range insert, and it can + // rehash. + typename test::random_values<X>::iterator it = v.begin(); + x.insert(*it); + ++it; + + std::size_t bucket_count = x.bucket_count(); + x.insert(it, v.end()); + BOOST_TEST(bucket_count == x.bucket_count()); + tracker.compare(x); + } + } + } + + template <class X> void reserve_test2(X*, test::random_generator generator) + { + for (int random_mlf = 0; random_mlf < 2; ++random_mlf) { + for (std::size_t i = 0; i < 2000; i += i < 50 ? 1 : 13) { + test::random_values<X> v(i, generator); + + test::ordered<X> tracker; + tracker.insert_range(v.begin(), v.end()); + + X x; + x.max_load_factor( + random_mlf ? static_cast<float>(std::rand() % 1000) / 500.0f + 0.5f + : 1.0f); + + x.reserve(test::has_unique_keys<X>::value ? i : v.size()); + + std::size_t bucket_count = x.bucket_count(); + for (typename test::random_values<X>::iterator it = v.begin(); + it != v.end(); ++it) { + x.insert(*it); + } + + BOOST_TEST(bucket_count == x.bucket_count()); + tracker.compare(x); + } + } + } + + boost::unordered_set<int>* int_set_ptr; + boost::unordered_multiset<test::object, test::hash, test::equal_to, + test::allocator2<test::object> >* test_multiset_ptr; + boost::unordered_map<test::movable, test::movable, test::hash, test::equal_to, + test::allocator2<test::movable> >* test_map_ptr; + boost::unordered_multimap<int, int>* int_multimap_ptr; + + using test::default_generator; + using test::generate_collisions; + using test::limited_range; + + UNORDERED_TEST(rehash_empty_test1, + ((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))) + UNORDERED_TEST(rehash_empty_test2, + ((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))( + (default_generator)(generate_collisions)(limited_range))) + UNORDERED_TEST(rehash_empty_test3, + ((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))( + (default_generator)(generate_collisions)(limited_range))) + UNORDERED_TEST(rehash_test1, + ((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))( + (default_generator)(generate_collisions)(limited_range))) + UNORDERED_TEST(reserve_empty_test1, + ((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))) + UNORDERED_TEST(reserve_empty_test2, + ((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))) + UNORDERED_TEST(reserve_test1, + ((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))( + (default_generator)(generate_collisions)(limited_range))) + UNORDERED_TEST(reserve_test2, + ((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))( + (default_generator)(generate_collisions)(limited_range))) +} + +RUN_TESTS() diff --git a/src/boost/libs/unordered/test/unordered/simple_tests.cpp b/src/boost/libs/unordered/test/unordered/simple_tests.cpp new file mode 100644 index 00000000..d8a9ce41 --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/simple_tests.cpp @@ -0,0 +1,134 @@ + +// 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) + +// This test checks the runtime requirements of containers. + +// 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 <cstdlib> +#include <algorithm> +#include "../helpers/equivalent.hpp" + +template <class X> void simple_test(X const& a) +{ + test::unordered_equivalence_tester<X> equivalent(a); + + { + X u; + BOOST_TEST(u.size() == 0); + BOOST_TEST(X().size() == 0); + } + + { + BOOST_TEST(equivalent(X(a))); + } + + { + X u(a); + BOOST_TEST(equivalent(u)); + } + + { + X u = a; + BOOST_TEST(equivalent(u)); + } + + { + X b(a); + BOOST_TEST(b.begin() == const_cast<X const&>(b).cbegin()); + BOOST_TEST(b.end() == const_cast<X const&>(b).cend()); + } + + { + X b(a); + X c; + BOOST_TEST(equivalent(b)); + BOOST_TEST(c.empty()); + b.swap(c); + BOOST_TEST(b.empty()); + BOOST_TEST(equivalent(c)); + b.swap(c); + BOOST_TEST(c.empty()); + BOOST_TEST(equivalent(b)); + } + + { + X u; + X& r = u; + BOOST_TEST(&(r = r) == &r); + + BOOST_TEST(r.empty()); + BOOST_TEST(&(r = a) == &r); + BOOST_TEST(equivalent(r)); + BOOST_TEST(&(r = r) == &r); + BOOST_TEST(equivalent(r)); + } + + { + BOOST_TEST(a.size() == static_cast<typename X::size_type>( + std::distance(a.begin(), a.end()))); + } + + { + BOOST_TEST(a.empty() == (a.size() == 0)); + } + + { + BOOST_TEST(a.empty() == (a.begin() == a.end())); + X u; + BOOST_TEST(u.begin() == u.end()); + } +} + +UNORDERED_AUTO_TEST (simple_tests) { + using namespace std; + srand(14878); + + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n"; + boost::unordered_set<int> set; + simple_test(set); + + set.insert(1); + set.insert(2); + set.insert(1456); + simple_test(set); + + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n"; + boost::unordered_multiset<int> multiset; + simple_test(multiset); + + for (int i1 = 0; i1 < 1000; ++i1) { + int count = rand() % 10, index = rand(); + for (int j = 0; j < count; ++j) + multiset.insert(index); + } + simple_test(multiset); + + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_map.\n"; + boost::unordered_map<int, int> map; + + for (int i2 = 0; i2 < 1000; ++i2) { + map.insert(std::pair<const int, int>(rand(), rand())); + } + simple_test(map); + + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multimap.\n"; + boost::unordered_multimap<int, int> multimap; + + for (int i3 = 0; i3 < 1000; ++i3) { + int count = rand() % 10, index = rand(); + for (int j = 0; j < count; ++j) + multimap.insert(std::pair<const int, int>(index, rand())); + } + simple_test(multimap); +} + +RUN_TESTS() diff --git a/src/boost/libs/unordered/test/unordered/swap_tests.cpp b/src/boost/libs/unordered/test/unordered/swap_tests.cpp new file mode 100644 index 00000000..9a7106ef --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/swap_tests.cpp @@ -0,0 +1,211 @@ + +// 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) + +// 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/config.hpp> +#include <algorithm> +#include <iterator> +#include "../helpers/test.hpp" +#include "../objects/test.hpp" +#include "../objects/cxx11_allocator.hpp" +#include "../helpers/random_values.hpp" +#include "../helpers/tracker.hpp" +#include "../helpers/invariants.hpp" + +#if defined(BOOST_MSVC) +#pragma warning(disable : 4127) // conditional expression is constant +#endif + +namespace swap_tests { + + test::seed_t initialize_seed(783472); + + template <class X> void swap_test_impl(X& x1, X& x2) + { + test::ordered<X> tracker1 = test::create_ordered(x1); + test::ordered<X> tracker2 = test::create_ordered(x2); + tracker1.insert_range(x1.begin(), x1.end()); + tracker2.insert_range(x2.begin(), x2.end()); + x1.swap(x2); + tracker1.compare(x2); + tracker2.compare(x1); + } + + template <class X> void swap_tests1(X*, test::random_generator generator) + { + { + test::check_instances check_; + + X x; + swap_test_impl(x, x); + } + + { + test::check_instances check_; + + X x, y; + swap_test_impl(x, y); + } + + { + test::check_instances check_; + + test::random_values<X> v(1000, generator); + X x, y(v.begin(), v.end()); + swap_test_impl(x, y); + swap_test_impl(x, y); + } + + { + test::check_instances check_; + + test::random_values<X> vx(1000, generator), vy(1000, generator); + X x(vx.begin(), vx.end()), y(vy.begin(), vy.end()); + swap_test_impl(x, y); + swap_test_impl(x, y); + } + } + + template <class X> void swap_tests2(X* ptr, test::random_generator generator) + { + swap_tests1(ptr, generator); + + typedef typename X::hasher hasher; + typedef typename X::key_equal key_equal; + typedef typename X::allocator_type allocator_type; + + { + test::check_instances check_; + + X x(0, hasher(1), key_equal(1)); + X y(0, hasher(2), key_equal(2)); + swap_test_impl(x, y); + } + + { + test::check_instances check_; + + test::random_values<X> v(1000, generator); + X x(v.begin(), v.end(), 0, hasher(1), key_equal(1)); + X y(0, hasher(2), key_equal(2)); + swap_test_impl(x, y); + } + + { + test::check_instances check_; + + test::random_values<X> vx(100, generator), vy(50, generator); + X x(vx.begin(), vx.end(), 0, hasher(1), key_equal(1)); + X y(vy.begin(), vy.end(), 0, hasher(2), key_equal(2)); + swap_test_impl(x, y); + swap_test_impl(x, y); + } + + { + test::force_equal_allocator force_(!allocator_type::is_propagate_on_swap); + test::check_instances check_; + + test::random_values<X> vx(50, generator), vy(100, generator); + X x(vx.begin(), vx.end(), 0, hasher(), key_equal(), allocator_type(1)); + X y(vy.begin(), vy.end(), 0, hasher(), key_equal(), allocator_type(2)); + + if (allocator_type::is_propagate_on_swap || + x.get_allocator() == y.get_allocator()) { + swap_test_impl(x, y); + } + } + + { + test::force_equal_allocator force_(!allocator_type::is_propagate_on_swap); + test::check_instances check_; + + test::random_values<X> vx(100, generator), vy(100, generator); + X x(vx.begin(), vx.end(), 0, hasher(1), key_equal(1), allocator_type(1)); + X y(vy.begin(), vy.end(), 0, hasher(2), key_equal(2), allocator_type(2)); + + if (allocator_type::is_propagate_on_swap || + x.get_allocator() == y.get_allocator()) { + swap_test_impl(x, y); + swap_test_impl(x, y); + } + } + } + + 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, + 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; + + boost::unordered_set<test::object, test::hash, test::equal_to, + test::cxx11_allocator<test::object, test::propagate_swap> >* + test_set_prop_swap; + boost::unordered_multiset<test::object, test::hash, test::equal_to, + test::cxx11_allocator<test::object, test::propagate_swap> >* + test_multiset_prop_swap; + boost::unordered_map<test::object, test::object, test::hash, test::equal_to, + test::cxx11_allocator<test::object, test::propagate_swap> >* + test_map_prop_swap; + boost::unordered_multimap<test::object, test::object, test::hash, + test::equal_to, test::cxx11_allocator<test::object, test::propagate_swap> >* + test_multimap_prop_swap; + + boost::unordered_set<test::object, test::hash, test::equal_to, + test::cxx11_allocator<test::object, test::no_propagate_swap> >* + test_set_no_prop_swap; + boost::unordered_multiset<test::object, test::hash, test::equal_to, + test::cxx11_allocator<test::object, test::no_propagate_swap> >* + test_multiset_no_prop_swap; + boost::unordered_map<test::object, test::object, test::hash, test::equal_to, + test::cxx11_allocator<test::object, test::no_propagate_swap> >* + test_map_no_prop_swap; + boost::unordered_multimap<test::object, test::object, test::hash, + test::equal_to, + test::cxx11_allocator<test::object, test::no_propagate_swap> >* + test_multimap_no_prop_swap; + + template <typename T> bool is_propagate(T*) + { + return T::allocator_type::is_propagate_on_swap; + } + + using test::default_generator; + using test::generate_collisions; + using test::limited_range; + + UNORDERED_AUTO_TEST (check_traits) { + BOOST_TEST(!is_propagate(test_set)); + BOOST_TEST(is_propagate(test_set_prop_swap)); + BOOST_TEST(!is_propagate(test_set_no_prop_swap)); + } + + UNORDERED_TEST( + swap_tests1, ((test_map_std_alloc)(test_set)(test_multiset)(test_map)( + test_multimap)(test_set_prop_swap)(test_multiset_prop_swap)( + test_map_prop_swap)(test_multimap_prop_swap)( + test_set_no_prop_swap)(test_multiset_no_prop_swap)( + test_map_no_prop_swap)(test_multimap_no_prop_swap))( + (default_generator)(generate_collisions)(limited_range))) + + UNORDERED_TEST(swap_tests2, + ((test_set)(test_multiset)(test_map)(test_multimap)(test_set_prop_swap)( + test_multiset_prop_swap)(test_map_prop_swap)(test_multimap_prop_swap)( + test_set_no_prop_swap)(test_multiset_no_prop_swap)(test_map_no_prop_swap)( + test_multimap_no_prop_swap))( + (default_generator)(generate_collisions)(limited_range))) +} +RUN_TESTS() diff --git a/src/boost/libs/unordered/test/unordered/unnecessary_copy_tests.cpp b/src/boost/libs/unordered/test/unordered/unnecessary_copy_tests.cpp new file mode 100644 index 00000000..1c5ff4b7 --- /dev/null +++ b/src/boost/libs/unordered/test/unordered/unnecessary_copy_tests.cpp @@ -0,0 +1,582 @@ + +// 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) + +// 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" + +namespace unnecessary_copy_tests { + struct count_copies + { + private: + BOOST_COPYABLE_AND_MOVABLE(count_copies) + public: + static int copies; + static int moves; + static int id_count; + + count_copies() : tag_(0), id_(++id_count) + { + ++copies; + trace_op("Default construct"); + } + + explicit count_copies(int tag) : tag_(tag), id_(++id_count) + { + ++copies; + trace_op("Tag construct"); + } + + // This bizarre constructor is an attempt to confuse emplace. + // + // unordered_map<count_copies, count_copies> x: + // x.emplace(count_copies(1), count_copies(2)); + // x.emplace(count_copies(1), count_copies(2), count_copies(3)); + // + // The first emplace should use the single argument constructor twice. + // The second emplace should use the single argument contructor for + // the key, and this constructor for the value. + count_copies(count_copies const&, count_copies const& x) + : tag_(x.tag_), id_(++id_count) + { + ++copies; + trace_op("Pair construct"); + } + + count_copies(count_copies const& x) : tag_(x.tag_), id_(++id_count) + { + ++copies; + trace_op("Copy construct"); + } + + count_copies(BOOST_RV_REF(count_copies) x) : tag_(x.tag_), id_(++id_count) + { + x.tag_ = -1; + ++moves; + trace_op("Move construct"); + } + + count_copies& operator=( + BOOST_COPY_ASSIGN_REF(count_copies) p) // Copy assignment + { + tag_ = p.tag_; + ++copies; + trace_op("Copy assign"); + return *this; + } + + count_copies& operator=(BOOST_RV_REF(count_copies) p) // Move assignment + { + tag_ = p.tag_; + ++moves; + trace_op("Move assign"); + return *this; + } + + ~count_copies() { trace_op("Destruct"); } + + void trace_op(char const* str) + { + BOOST_LIGHTWEIGHT_TEST_OSTREAM << str << ": " << tag_ << " (#" << id_ + << ")" << std::endl; + } + + int tag_; + int id_; + }; + + bool operator==(count_copies const& x, count_copies const& y) + { + return x.tag_ == y.tag_; + } + + template <class T> T source() { return T(); } + + void reset() + { + count_copies::copies = 0; + count_copies::moves = 0; + + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\nReset\n" << std::endl; + } +} + +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) +namespace boost +#else +namespace unnecessary_copy_tests +#endif +{ + std::size_t hash_value(unnecessary_copy_tests::count_copies const& x) + { + return static_cast<std::size_t>(x.tag_); + } +} + +// Boost.Move doesn't seem to work very well on this compiler. +// For example for: +// +// T x; +// +// It will default construct T, and then move it in. +// For 'T const' it seems to copy. + +#if defined(__IBMCPP__) && __IBMCPP__ <= 1210 +#define EXTRA_CONSTRUCT_COST 1 +#else +#define EXTRA_CONSTRUCT_COST 0 +#endif + +#define COPY_COUNT(n) \ + if (::unnecessary_copy_tests::count_copies::copies != n) { \ + BOOST_ERROR("Wrong number of copies."); \ + BOOST_LIGHTWEIGHT_TEST_OSTREAM \ + << "Number of copies: " \ + << ::unnecessary_copy_tests::count_copies::copies << " expecting: " << n \ + << std::endl; \ + } +#define MOVE_COUNT(n) \ + if (::unnecessary_copy_tests::count_copies::moves != n) { \ + BOOST_ERROR("Wrong number of moves."); \ + BOOST_LIGHTWEIGHT_TEST_OSTREAM \ + << "Number of moves: " << ::unnecessary_copy_tests::count_copies::moves \ + << " expecting: " << n << std::endl; \ + } +#define COPY_COUNT_RANGE(a, b) \ + if (::unnecessary_copy_tests::count_copies::copies < a || \ + ::unnecessary_copy_tests::count_copies::copies > b) { \ + BOOST_ERROR("Wrong number of copies."); \ + BOOST_LIGHTWEIGHT_TEST_OSTREAM \ + << "Number of copies: " \ + << ::unnecessary_copy_tests::count_copies::copies << " expecting: [" \ + << a << ", " << b << "]" << std::endl; \ + } +#define MOVE_COUNT_RANGE(a, b) \ + if (::unnecessary_copy_tests::count_copies::moves < a || \ + ::unnecessary_copy_tests::count_copies::moves > b) { \ + BOOST_ERROR("Wrong number of moves."); \ + BOOST_LIGHTWEIGHT_TEST_OSTREAM \ + << "Number of moves: " << ::unnecessary_copy_tests::count_copies::moves \ + << " expecting: [" << a << ", " << b << "]" << std::endl; \ + } +#define COPY_COUNT_EXTRA(a, b) COPY_COUNT_RANGE(a, a + b * EXTRA_CONSTRUCT_COST) +#define MOVE_COUNT_EXTRA(a, b) MOVE_COUNT_RANGE(a, a + b * EXTRA_CONSTRUCT_COST) + +namespace unnecessary_copy_tests { + int count_copies::copies; + int count_copies::moves; + int count_copies::id_count; + + template <class T> void unnecessary_copy_insert_test(T*) + { + T x; + typename T::value_type a; + reset(); + x.insert(a); + COPY_COUNT(1); + MOVE_COUNT(0); + } + + template <class T> void unnecessary_copy_insert_rvalue_set_test(T*) + { + T x; + typename T::value_type a; + reset(); + x.insert(boost::move(a)); + COPY_COUNT(0); + MOVE_COUNT(1); + + typename T::value_type a2; + reset(); + x.insert(boost::move(a)); + COPY_COUNT(0); + MOVE_COUNT((x.size() == 2 ? 1 : 0)); + } + + template <class T> void unnecessary_copy_insert_rvalue_map_test(T*) + { + // Doesn't currently try to emulate std::pair move construction, + // so std::pair's require a copy. Could try emulating it in + // construct_from_args. + + T x; + typename T::value_type a; + reset(); + x.insert(boost::move(a)); +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + COPY_COUNT(1); + MOVE_COUNT(0); +#else + COPY_COUNT(0); + MOVE_COUNT(1); +#endif + + typename T::value_type a2; + reset(); + x.insert(boost::move(a)); +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + COPY_COUNT((x.size() == 2 ? 1 : 0)); + MOVE_COUNT(0); +#else + COPY_COUNT(0); + MOVE_COUNT((x.size() == 2 ? 1 : 0)); +#endif + } + + boost::unordered_set<count_copies>* set; + boost::unordered_multiset<count_copies>* multiset; + boost::unordered_map<int, count_copies>* map; + boost::unordered_multimap<int, count_copies>* multimap; + + UNORDERED_TEST(unnecessary_copy_insert_test, ((set)(multiset)(map)(multimap))) + UNORDERED_TEST(unnecessary_copy_insert_rvalue_set_test, ((set)(multiset))) + UNORDERED_TEST(unnecessary_copy_insert_rvalue_map_test, ((map)(multimap))) + + template <class T> void unnecessary_copy_emplace_test(T*) + { + reset(); + T x; + typename T::value_type a; + COPY_COUNT(1); + x.emplace(a); + COPY_COUNT(2); + } + + template <class T> void unnecessary_copy_emplace_rvalue_test(T*) + { + reset(); + T x; + x.emplace(source<typename T::value_type>()); +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + COPY_COUNT(1); +#else + COPY_COUNT(2); +#endif + } + + UNORDERED_TEST( + unnecessary_copy_emplace_test, ((set)(multiset)(map)(multimap))) + UNORDERED_TEST( + unnecessary_copy_emplace_rvalue_test, ((set)(multiset)(map)(multimap))) + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template <class T> void unnecessary_copy_emplace_std_move_test(T*) + { + reset(); + T x; + typename T::value_type a; + COPY_COUNT(1); + MOVE_COUNT(0); + x.emplace(std::move(a)); + COPY_COUNT(1); + MOVE_COUNT(1); + } + + UNORDERED_TEST( + unnecessary_copy_emplace_std_move_test, ((set)(multiset)(map)(multimap))) +#endif + + template <class T> void unnecessary_copy_emplace_boost_move_test(T*) + { + reset(); + T x; + typename T::value_type a; + COPY_COUNT(1); + MOVE_COUNT_EXTRA(0, 1); + x.emplace(boost::move(a)); +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + COPY_COUNT(1); + MOVE_COUNT(1); +#else + // Since std::pair isn't movable, move only works for sets. + COPY_COUNT_RANGE(1, 2); + MOVE_COUNT_RANGE(0, 1); +#endif + } + + UNORDERED_TEST( + unnecessary_copy_emplace_boost_move_test, ((set)(multiset)(map)(multimap))) + + template <class T> void unnecessary_copy_emplace_boost_move_set_test(T*) + { + reset(); + T x; + typename T::value_type a; + COPY_COUNT(1); + MOVE_COUNT(0); + x.emplace(boost::move(a)); + COPY_COUNT(1); + MOVE_COUNT(1); + } + + UNORDERED_TEST( + unnecessary_copy_emplace_boost_move_set_test, ((set)(multiset))) + + template <class T> void unnecessary_copy_emplace_boost_move_map_test(T*) + { + reset(); + T x; + COPY_COUNT(0); + MOVE_COUNT(0); + typename T::value_type a; + COPY_COUNT(1); + MOVE_COUNT_EXTRA(0, 1); + x.emplace(boost::move(a)); +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + COPY_COUNT(2); + MOVE_COUNT_EXTRA(0, 1); +#else + COPY_COUNT(1); + MOVE_COUNT(1); +#endif + } + + UNORDERED_TEST( + unnecessary_copy_emplace_boost_move_map_test, ((map)(multimap))) + + UNORDERED_AUTO_TEST (unnecessary_copy_emplace_set_test) { + // When calling 'source' the object is moved on some compilers, but not + // others. So count that here to adjust later. + + reset(); + source<count_copies>(); + int source_cost = ::unnecessary_copy_tests::count_copies::moves; + + // + + reset(); + boost::unordered_set<count_copies> x; + count_copies a; + x.insert(a); + COPY_COUNT(2); + MOVE_COUNT(0); + +// +// 0 arguments +// + +#if !BOOST_UNORDERED_SUN_WORKAROUNDS1 + // The container will have to create a copy in order to compare with + // the existing element. + reset(); + x.emplace(); + + // source_cost doesn't make much sense here, but it seems to fit. + COPY_COUNT(1); + MOVE_COUNT(source_cost); +#endif + + // + // 1 argument + // + + // Emplace should be able to tell that there already is an element + // without creating a new one. + reset(); + x.emplace(a); + COPY_COUNT(0); + MOVE_COUNT(0); + + // A new object is created by source, but it shouldn't be moved or + // copied. + reset(); + x.emplace(source<count_copies>()); + COPY_COUNT(1); + MOVE_COUNT(source_cost); + + // No move should take place. + reset(); + x.emplace(boost::move(a)); + COPY_COUNT(0); + MOVE_COUNT(0); + + // Use a new value for cases where a did get moved... + count_copies b; + + // The container will have to create a copy in order to compare with + // the existing element. + reset(); + x.emplace(b.tag_); + COPY_COUNT(1); + MOVE_COUNT(0); + + // + // 2 arguments + // + + // The container will have to create b copy in order to compare with + // the existing element. + // + // Note to self: If copy_count == 0 it's an error not an optimization. + // TODO: Devise a better test. + + reset(); + + x.emplace(b, b); + COPY_COUNT(1); + MOVE_COUNT(0); + } + + UNORDERED_AUTO_TEST (unnecessary_copy_emplace_map_test) { + // When calling 'source' the object is moved on some compilers, but not + // others. So count that here to adjust later. + + reset(); + source<count_copies>(); + int source_cost = ::unnecessary_copy_tests::count_copies::moves; + + reset(); + source<std::pair<count_copies, count_copies> >(); + int source_pair_cost = ::unnecessary_copy_tests::count_copies::moves; + + // + + reset(); + boost::unordered_map<count_copies, count_copies> x; + // TODO: Run tests for pairs without const etc. + std::pair<count_copies const, count_copies> a; + x.emplace(a); + COPY_COUNT_EXTRA(4, 1); + MOVE_COUNT_EXTRA(0, 1); + +// +// 0 arguments +// + +#if !BOOST_UNORDERED_SUN_WORKAROUNDS1 + // COPY_COUNT(1) would be okay here. + reset(); + x.emplace(); +#if BOOST_WORKAROUND(BOOST_MSVC, == 1700) + // This is a little odd, Visual C++ 11 seems to move the pair, which + // results in one copy (for the const key) and one move (for the + // non-const mapped value). Since 'emplace(boost::move(a))' (see below) + // has the normal result, it must be some odd consequence of how + // Visual C++ 11 handles calling move for default arguments. + COPY_COUNT(3); + MOVE_COUNT(1); +#else + COPY_COUNT_EXTRA(2, 1); + MOVE_COUNT_EXTRA(0, 1); +#endif +#endif + + reset(); + x.emplace(boost::unordered::piecewise_construct, boost::make_tuple(), + boost::make_tuple()); + COPY_COUNT(2); + MOVE_COUNT(0); + + // + // 1 argument + // + + reset(); + x.emplace(a); + COPY_COUNT(0); + MOVE_COUNT(0); + + // A new object is created by source, but it shouldn't be moved or + // copied. + reset(); + x.emplace(source<std::pair<count_copies, count_copies> >()); + COPY_COUNT(2); + MOVE_COUNT(source_pair_cost); + +#if !(defined(__GNUC__) && __cplusplus < 199900L) && \ + !(defined(_MSC_VER) && _MSC_VER < 1600) + count_copies part; + reset(); + std::pair<count_copies const&, count_copies const&> a_ref(part, part); + x.emplace(a_ref); + COPY_COUNT(2); + MOVE_COUNT(0); + +#endif + + // No move should take place. + // (since a is already in the container) + reset(); + x.emplace(boost::move(a)); + COPY_COUNT(0); + MOVE_COUNT(0); + + // + // 2 arguments + // + + std::pair<count_copies const, count_copies> b; + + reset(); + x.emplace(b.first, b.second); + COPY_COUNT(0); + MOVE_COUNT(0); + + reset(); + x.emplace(source<count_copies>(), source<count_copies>()); + COPY_COUNT(2); + MOVE_COUNT(source_cost * 2); + + // source<count_copies> creates a single copy. + reset(); + x.emplace(b.first, source<count_copies>()); + COPY_COUNT(1); + MOVE_COUNT(source_cost); + + reset(); + x.emplace(count_copies(b.first.tag_), count_copies(b.second.tag_)); + COPY_COUNT(2); + MOVE_COUNT(0); + + reset(); + x.emplace(boost::unordered::piecewise_construct, + boost::make_tuple(boost::ref(b.first)), + boost::make_tuple(boost::ref(b.second))); + COPY_COUNT(0); + MOVE_COUNT(0); + +#if BOOST_UNORDERED_TUPLE_ARGS + + reset(); + x.emplace(boost::unordered::piecewise_construct, + std::make_tuple(std::ref(b.first)), std::make_tuple(std::ref(b.second))); + COPY_COUNT(0); + MOVE_COUNT(0); + + std::pair<count_copies const, count_copies> move_source_trial; + reset(); + std::make_tuple(std::move(move_source_trial.first)); + std::make_tuple(std::move(move_source_trial.second)); + int tuple_move_cost = ::unnecessary_copy_tests::count_copies::moves; + int tuple_copy_cost = ::unnecessary_copy_tests::count_copies::copies; + + std::pair<count_copies const, count_copies> move_source; + reset(); + x.emplace(boost::unordered::piecewise_construct, + std::make_tuple(std::move(move_source.first)), + std::make_tuple(std::move(move_source.second))); + COPY_COUNT(tuple_copy_cost); + MOVE_COUNT(tuple_move_cost); + +#if !defined(BOOST_NO_CXX11_HDR_TUPLE) && \ + !(defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ < 6) && \ + !(defined(BOOST_MSVC) && BOOST_MSVC < 1700) + reset(); + x.emplace(boost::unordered::piecewise_construct, + std::forward_as_tuple(b.first), std::forward_as_tuple(b.second)); + COPY_COUNT(0); + MOVE_COUNT(0); +#endif + +#endif + } +} + +RUN_TESTS() |