diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1468292..ff5241f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,124 +18,148 @@ jobs: matrix: include: - toolset: gcc-4.8 - cxxstd: "03,11" + cxxstd: "11" os: ubuntu-latest container: ubuntu:18.04 install: g++-4.8-multilib address-model: 32,64 - toolset: gcc-5 - cxxstd: "03,11,14,1z" + cxxstd: "11,14,1z" os: ubuntu-latest container: ubuntu:18.04 install: g++-5-multilib address-model: 32,64 - toolset: gcc-6 - cxxstd: "03,11,14,1z" + cxxstd: "11,14,1z" os: ubuntu-latest container: ubuntu:18.04 install: g++-6-multilib address-model: 32,64 - toolset: gcc-7 - cxxstd: "03,11,14,17" + cxxstd: "11,14,17" os: ubuntu-20.04 install: g++-7-multilib address-model: 32,64 - toolset: gcc-8 - cxxstd: "03,11,14,17,2a" + cxxstd: "11,14,17,2a" os: ubuntu-20.04 install: g++-8-multilib address-model: 32,64 - toolset: gcc-9 - cxxstd: "03,11,14,17,2a" + cxxstd: "11,14,17,2a" os: ubuntu-20.04 install: g++-9-multilib address-model: 32,64 - toolset: gcc-10 - cxxstd: "03,11,14,17,2a" + cxxstd: "11,14,17,2a" os: ubuntu-20.04 install: g++-10-multilib address-model: 32,64 - toolset: gcc-11 - cxxstd: "03,11,14,17,20" + cxxstd: "11,14,17,20" os: ubuntu-20.04 install: g++-11-multilib address-model: 32,64 - toolset: gcc-12 - cxxstd: "03,11,14,17,20,2b" + cxxstd: "11,14,17,20,2b" os: ubuntu-22.04 install: g++-12-multilib address-model: 32,64 + - toolset: gcc-13 + cxxstd: "11,14,17,20,2b" + container: ubuntu:23.04 + os: ubuntu-latest + install: g++-13-multilib + address-model: 32,64 - toolset: clang compiler: clang++-3.9 - cxxstd: "03,11,14" + cxxstd: "11,14" os: ubuntu-latest container: ubuntu:18.04 install: clang-3.9 - toolset: clang compiler: clang++-4.0 - cxxstd: "03,11,14" + cxxstd: "11,14" os: ubuntu-latest container: ubuntu:18.04 install: clang-4.0 - toolset: clang compiler: clang++-5.0 - cxxstd: "03,11,14,1z" + cxxstd: "11,14,1z" os: ubuntu-latest container: ubuntu:18.04 install: clang-5.0 - toolset: clang compiler: clang++-6.0 - cxxstd: "03,11,14,17" + cxxstd: "11,14,17" os: ubuntu-20.04 install: clang-6.0 - toolset: clang compiler: clang++-7 - cxxstd: "03,11,14,17" + cxxstd: "11,14,17" os: ubuntu-20.04 install: clang-7 - toolset: clang compiler: clang++-8 - cxxstd: "03,11,14,17" + cxxstd: "11,14,17" os: ubuntu-20.04 install: clang-8 - toolset: clang compiler: clang++-9 - cxxstd: "03,11,14,17,2a" + cxxstd: "11,14,17,2a" os: ubuntu-20.04 install: clang-9 - toolset: clang compiler: clang++-10 - cxxstd: "03,11,14,17,2a" + cxxstd: "11,14,17,2a" os: ubuntu-20.04 - toolset: clang compiler: clang++-11 - cxxstd: "03,11,14,17,2a" + cxxstd: "11,14,17,2a" os: ubuntu-20.04 - toolset: clang compiler: clang++-12 - cxxstd: "03,11,14,17,20" + cxxstd: "11,14,17,20" os: ubuntu-20.04 - toolset: clang compiler: clang++-13 - cxxstd: "03,11,14,17,20,2b" - os: ubuntu-22.04 + cxxstd: "11,14,17,20,2b" + container: ubuntu:22.04 + os: ubuntu-latest install: clang-13 - toolset: clang compiler: clang++-14 - cxxstd: "03,11,14,17,20,2b" - os: ubuntu-22.04 + cxxstd: "11,14,17,20,2b" + container: ubuntu:22.04 + os: ubuntu-latest install: clang-14 - toolset: clang compiler: clang++-15 - cxxstd: "03,11,14,17,20,2b" - os: ubuntu-22.04 + cxxstd: "11,14,17,20,2b" + container: ubuntu:22.04 + os: ubuntu-latest install: clang-15 - toolset: clang - cxxstd: "03,11,14,17,2a" + compiler: clang++-16 + cxxstd: "11,14,17,20,2b" + container: ubuntu:23.04 + os: ubuntu-latest + install: clang-16 + - toolset: clang + compiler: clang++-17 + cxxstd: "11,14,17,20,2b" + container: ubuntu:23.10 + os: ubuntu-latest + install: clang-17 + - toolset: clang + cxxstd: "11,14,17,2a" os: macos-11 - toolset: clang - cxxstd: "03,11,14,17,20,2b" + cxxstd: "11,14,17,20,2b" os: macos-12 + - toolset: clang + cxxstd: "11,14,17,20,2b" + os: macos-13 runs-on: ${{matrix.os}} container: ${{matrix.container}} @@ -151,11 +175,13 @@ jobs: if: matrix.container run: | apt-get update - apt-get -y install sudo python git g++ + apt-get -y install sudo python3 git g++ - name: Install packages if: matrix.install - run: sudo apt-get -y install ${{matrix.install}} + run: | + sudo apt-get update + sudo apt-get -y install ${{matrix.install}} - name: Setup Boost run: | @@ -175,7 +201,7 @@ jobs: cd boost-root cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY git submodule update --init tools/boostdep - python tools/boostdep/depinst/depinst.py -I example --git_args "--jobs 3" $LIBRARY + python3 tools/boostdep/depinst/depinst.py -I example --git_args "--jobs 3" $LIBRARY ./bootstrap.sh ./b2 -d0 headers @@ -212,14 +238,14 @@ jobs: addrmd: 32,64 os: windows-2022 - toolset: gcc - cxxstd: "03,11,14,17,2a" + cxxstd: "11,14,17,2a" addrmd: 64 os: windows-2019 runs-on: ${{matrix.os}} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup Boost shell: cmd diff --git a/doc/reference/set_of.qbk b/doc/reference/set_of.qbk index 19a00ae..3752788 100644 --- a/doc/reference/set_of.qbk +++ b/doc/reference/set_of.qbk @@ -159,8 +159,7 @@ look at it as a whole, you will be using a set view. iterator ``[link reference_set_of_erase_iterator erase]``(iterator position); - template< class CompatibleKey > - size_type ``[link reference_set_of_erase_key erase]``(const CompatibleKey & x); + size_type ``[link reference_set_of_erase_key erase]``(const key_type & x); iterator ``[link reference_set_of_erase_iterator_iterator erase]``(iterator first, iterator last); @@ -472,10 +471,8 @@ the one that was deleted, or `end()` if no such element exists. [#reference_set_of_erase_key] - template< class CompatibleKey > - size_type erase(const CompatibleKey & x); + size_type erase(const key_type & x); -* [*Requires: ] `CompatibleKey` is a compatible key of `key_compare`. * [*Effects:] Deletes the elements with key equivalent to `x`. * [*Returns:] Number of elements deleted. * [link set_of_complexity_signature @@ -826,7 +823,7 @@ They are only provided if the other collection type is mutable template< class CompatibleKey > mapped_type & operator[](const CompatibleKey & k); -* [*Requires: ] `CompatibleKey` is a compatible key of `key_compare`. +* [*Requires: ] `CompatibleKey` is a compatible key of `key_compare`. `key_type` is constructible from `const CompatibleKey &`. * [*Effects: ] `return insert(value_type(k,mapped_type()))->second;` * [*Complexity:] O(log(n)). * [*Note:] Only provided when `set_of` is used and the other collection diff --git a/doc/reference/unordered_set_of.qbk b/doc/reference/unordered_set_of.qbk index 18e4a9e..11e6b21 100644 --- a/doc/reference/unordered_set_of.qbk +++ b/doc/reference/unordered_set_of.qbk @@ -172,8 +172,7 @@ do not exactly conform to the requirements for unordered associative containers. iterator ``[link reference_unordered_set_of_erase_iterator erase]``(iterator position); - template< class CompatibleKey > - size_type ``[link reference_unordered_set_of_erase_key erase]``(const CompatibleKey & x); + size_type ``[link reference_unordered_set_of_erase_key erase]``(const key_type & x); iterator ``[link reference_unordered_set_of_erase_iterator_iterator erase]``(iterator first, iterator last); @@ -447,8 +446,7 @@ that was deleted, or `end()` if no such element exists. [#reference_unordered_set_of_erase_key] - template< class CompatibleKey > - size_type erase(const CompatibleKey & x); + size_type erase(const key_type & x); * [*Effects:] Deletes the elements with key equivalent to `x`. * [*Returns:] Number of elements deleted. @@ -704,7 +702,7 @@ They are only provided if the other collection type is mutable template< class CompatibleKey > mapped_type & operator[](const CompatibleKey & k); -* [*Requires: ] `CompatibleKey` is a compatible key of `key_compare`. +* [*Requires: ] `CompatibleKey` is a compatible key of `key_compare`. `key_type` is constructible from `const CompatibleKey &`. * [*Effects: ] `return insert(value_type(k,mapped_type()))->second;` * [*Complexity:] If the insertion is performed O(I(n)), else: Average case O(1) (constant), worst case O(n). diff --git a/doc/release_notes.qbk b/doc/release_notes.qbk index 68baa23..96fdfc9 100644 --- a/doc/release_notes.qbk +++ b/doc/release_notes.qbk @@ -14,6 +14,10 @@ http://www.boost.org/LICENSE_1_0.txt) [section Release notes] +[heading Boost 1.85 release] + +* Fixed heterogeneous lookup for side collections ([@https://github.com/boostorg/bimap/pull/42 PR#42]). + [heading Boost 1.53 release] * Refactor map_view_iterator to improve error messages. diff --git a/include/boost/bimap/container_adaptor/detail/identity_converters.hpp b/include/boost/bimap/container_adaptor/detail/identity_converters.hpp index 4f79cfc..f99d4a8 100644 --- a/include/boost/bimap/container_adaptor/detail/identity_converters.hpp +++ b/include/boost/bimap/container_adaptor/detail/identity_converters.hpp @@ -1,6 +1,7 @@ // Boost.Bimap // // Copyright (c) 2006-2007 Matias Capeletto +// Copyright (c) 2024 Joaquin M Lopez Munoz // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -166,7 +167,7 @@ struct key_to_base_identity #ifndef BOOST_BIMAP_DOXYGEN_WILL_NOT_PROCESS_THE_FOLLOWING_LINES template< class Key > -struct key_to_base_identity< Key, Key > +struct key_to_base_identity< Key, const Key > { // As default accept any type as key in order to allow container // adaptors to work with compatible key types diff --git a/test/strong_type.hpp b/test/strong_type.hpp new file mode 100644 index 0000000..643fd8c --- /dev/null +++ b/test/strong_type.hpp @@ -0,0 +1,63 @@ +// Boost.Bimap +// +// Copyright (c) 2024 Joaquin M Lopez Munoz +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef LIBS_BIMAP_TEST_STRONG_TYPE_HPP +#define LIBS_BIMAP_TEST_STRONG_TYPE_HPP + +#if defined(_MSC_VER) +#pragma once +#endif + +#include + +// std +#include +#include + +template< class T > +struct strong +{ + template< class Q > + strong(const Q& x_):x(x_){} + + T x; +}; + +template< class T > +bool operator<(const strong& x,const strong& y) +{ + return x.x +bool operator==(const strong& x,const strong& y) +{ + return x.x==y.x; +} + +template< class T > +std::size_t hash_value(const strong& x) +{ + return boost::hash()(x.x); +} + +template< class T > +struct semistrong: strong +{ + using strong::strong; + + // semistrong is formally convertible to T but throws when + // conversion actually called + + operator const T&() const + { + throw std::runtime_error("semistrong -> T conversion called"); + } +}; + +#endif // LIBS_BIMAP_TEST_STRONG_TYPE_HPP diff --git a/test/test_bimap.hpp b/test/test_bimap.hpp index bf11b5b..a64ce4f 100644 --- a/test/test_bimap.hpp +++ b/test/test_bimap.hpp @@ -1,6 +1,7 @@ // Boost.Bimap // // Copyright (c) 2006-2007 Matias Capeletto +// Copyright (c) 2024 Joaquin M Lopez Munoz // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -189,7 +190,6 @@ void test_associative_container(Container & c, const Data & d) BOOST_TEST( c.equal_range(*da).first == c.end() ); } - template< class Container > void test_mapped_container(Container &) { @@ -253,6 +253,40 @@ void test_pair_associative_container(Container & c, const Data & d) BOOST_TEST( c.equal_range(da->first).first == c.end() ); } +template < class CompatibleKey, class Container, class Data > +void test_pair_heterogeneous_associative_container(Container & c, Data & d) +{ + c.clear(); + c.insert(d.begin(),d.end()); + + for( typename Data::const_iterator di = d.begin(), de = d.end(); + di != de; ++di ) + { + BOOST_TEST( c.find(CompatibleKey(di->first)) == c.find(di->first) ); + } + + typename Data::const_iterator da = d.begin(); + typename Data::const_iterator db = ++d.begin(); + + // erase does not support heterogeneous lookup + // as Boost.MultiIndex doesn't either + c.erase(da->first); + + BOOST_TEST( c.size() == d.size()-1 ); + + BOOST_TEST( c.count(CompatibleKey(da->first)) == 0 ); + BOOST_TEST( c.count(CompatibleKey(db->first)) == 1 ); + + BOOST_TEST( c.find(CompatibleKey(da->first)) == c.end() ); + BOOST_TEST( c.find(CompatibleKey(db->first)) == c.find(db->first) ); + + BOOST_TEST( c.equal_range(CompatibleKey(db->first)).first == + c.equal_range(db->first).first ); + + c.clear(); + + BOOST_TEST( c.equal_range(CompatibleKey(da->first)).first == c.end() ); +} template< class Container, class Data > void test_simple_ordered_associative_container_equality(Container & c, const Data & d) @@ -389,6 +423,24 @@ void test_pair_ordered_associative_container(Container & c, const Data & d) ); } +template < class CompatibleKey, class Container, class Data > +void test_pair_heterogeneous_ordered_associative_container( + Container & c, Data & d) +{ + test_pair_heterogeneous_associative_container(c,d); + + c.clear(); + c.insert(d.begin(),d.end()); + + for( typename Data::const_iterator di = d.begin(), de = d.end(); + di != de; ++di ) + { + BOOST_TEST( c.lower_bound(CompatibleKey(di->first)) == + c.lower_bound(di->first) ); + BOOST_TEST( c.upper_bound(CompatibleKey(di->first)) == + c.upper_bound(di->first) ); + } +} template< class Container, class Data > void test_pair_unordered_associative_container(Container & c, const Data & d) @@ -463,8 +515,6 @@ void test_non_unique_container(Container & c, Data & d) BOOST_TEST( c.size() == (d.size()+1) ); } - - template< class Bimap, class Data, class LeftData, class RightData > void test_basic_bimap( Bimap & b, const Data & d, diff --git a/test/test_bimap_info.cpp b/test/test_bimap_info.cpp index c6d8a82..845294e 100644 --- a/test/test_bimap_info.cpp +++ b/test/test_bimap_info.cpp @@ -1,6 +1,7 @@ // Boost.Bimap // // Copyright (c) 2006-2007 Matias Capeletto +// Copyright (c) 2024 Joaquin M Lopez Munoz // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -26,6 +27,7 @@ #include #include +#include int test_bimap_info() { @@ -116,10 +118,40 @@ int test_tagged_bimap_info() return 0; } +void test_heterogeneous_access_bimap_info() +{ + using namespace boost::bimaps; + + typedef bimap + < + set_of< int, std::less< strong > >, + unordered_set_of + < + int, boost::hash< strong >, std::equal_to< strong > + >, + with_info + > bm_type; + + bm_type bm; + bm.insert(bm_type::value_type(1,1,0)); + + BOOST_TEST( bm.left.info_at(strong(1)) == 0 ); + BOOST_TEST( bm.right.info_at(strong(1)) == 0 ); + + bm.left.info_at(strong(1))=1; + BOOST_TEST( bm.left.info_at(strong(1)) == 1 ); + BOOST_TEST( bm.right.info_at(strong(1)) == 1 ); + + bm.right.info_at(strong(1))=2; + BOOST_TEST( bm.left.info_at(strong(1)) == 2 ); + BOOST_TEST( bm.right.info_at(strong(1)) == 2 ); +} + int main() { test_bimap_info(); test_tagged_bimap_info(); + test_heterogeneous_access_bimap_info(); return boost::report_errors(); } diff --git a/test/test_bimap_operator_bracket.cpp b/test/test_bimap_operator_bracket.cpp index 06bfc63..3c70fda 100644 --- a/test/test_bimap_operator_bracket.cpp +++ b/test/test_bimap_operator_bracket.cpp @@ -1,6 +1,7 @@ // Boost.Bimap // // Copyright (c) 2006-2007 Matias Capeletto +// Copyright (c) 2024 Joaquin M Lopez Munoz // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -28,6 +29,7 @@ #include #include +#include void test_bimap_operator_bracket() { @@ -187,6 +189,44 @@ void test_bimap_operator_bracket() BOOST_TEST( b.right.at("two") == 2 ); } + // Heterogeneous access test (1) + { + typedef bimap + < + set_of > >, + list_of + > bm; + + bm b; + + b.left[1] = "0"; + b.left[semistrong(1)] = "1"; + BOOST_TEST( b.left.at(strong(1)) == "1"); + b.left.at(strong(1)) = "2"; + BOOST_TEST( b.left.at(strong(1)) == "2"); + } + + // Heterogeneous access test (2) + { + typedef bimap + < + list_of, + unordered_set_of + < + std::string, + boost::hash< strong >, + std::equal_to< strong > + > + > bm; + + bm b; + + b.right["1"]=0; + b.right[semistrong("1")] = 1; + BOOST_TEST( b.right.at(strong("1")) == 1); + b.right.at(strong("1")) = 2; + BOOST_TEST( b.right.at(strong("1")) == 2); + } } int main() diff --git a/test/test_bimap_ordered.cpp b/test/test_bimap_ordered.cpp index f6b62d0..d57b824 100644 --- a/test/test_bimap_ordered.cpp +++ b/test/test_bimap_ordered.cpp @@ -1,6 +1,7 @@ // Boost.Bimap // // Copyright (c) 2006-2007 Matias Capeletto +// Copyright (c) 2024 Joaquin M Lopez Munoz // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -31,9 +32,13 @@ #include #include +// List type specification +#include + // bimap container #include +#include #include struct left_tag {}; @@ -164,6 +169,37 @@ void test_bimap() } //-------------------------------------------------------------------- + { + typedef bimap + < + set_of< int, std::less< strong > >, + multiset_of< int, std::less< strong > >, + set_of_relation<> + + > bm_type; + + std::set< bm_type::value_type > data; + data.insert( bm_type::value_type(1,1) ); + data.insert( bm_type::value_type(2,2) ); + data.insert( bm_type::value_type(3,3) ); + data.insert( bm_type::value_type(4,4) ); + + std::map sided_data; + sided_data.emplace(1,1); + sided_data.emplace(2,2); + sided_data.emplace(3,3); + sided_data.emplace(4,4); + + bm_type bm; + + test_basic_bimap(bm,data,sided_data,sided_data); + test_associative_container(bm,data); + test_pair_heterogeneous_ordered_associative_container< strong >( + bm.left,sided_data); + test_pair_heterogeneous_ordered_associative_container< strong >( + bm.right,sided_data); + } + //-------------------------------------------------------------------- } diff --git a/test/test_bimap_unordered.cpp b/test/test_bimap_unordered.cpp index aa0120e..315893f 100644 --- a/test/test_bimap_unordered.cpp +++ b/test/test_bimap_unordered.cpp @@ -1,6 +1,7 @@ // Boost.Bimap // // Copyright (c) 2006-2007 Matias Capeletto +// Copyright (c) 2024 Joaquin M Lopez Munoz // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -34,6 +35,7 @@ // bimap container #include +#include #include struct left_tag {}; @@ -155,6 +157,43 @@ void test_bimap() } //-------------------------------------------------------------------- + { + typedef bimap + < + unordered_set_of + < + int, boost::hash< strong >, std::equal_to< strong > + >, + unordered_multiset_of< + int, boost::hash< strong >, std::equal_to< strong > + >, + unordered_set_of_relation<> + + > bm_type; + + std::set< bm_type::value_type > data; + data.insert( bm_type::value_type(1,1) ); + data.insert( bm_type::value_type(2,2) ); + data.insert( bm_type::value_type(3,3) ); + data.insert( bm_type::value_type(4,4) ); + + std::map sided_data; + sided_data.emplace(1,1); + sided_data.emplace(2,2); + sided_data.emplace(3,3); + sided_data.emplace(4,4); + + bm_type bm; + + test_basic_bimap(bm,data,sided_data,sided_data); + test_associative_container(bm,data); + test_simple_unordered_associative_container(bm,data); + test_pair_heterogeneous_associative_container< strong >( + bm.left,sided_data); + test_pair_heterogeneous_associative_container< strong >( + bm.right,sided_data); + } + //-------------------------------------------------------------------- }