From 0d9840257469f0c330fd0cff00a9d731d8c08908 Mon Sep 17 00:00:00 2001 From: marehr Date: Fri, 8 Dec 2017 00:10:10 +0100 Subject: [PATCH] [FIX] travis/ubuntu16.04: gcc-7.2 bug --- .../container/concatenated_sequences.hpp | 8 +- include/seqan3/range/container/concept.hpp | 111 ++++++++++- .../container/container_concept_test.cpp | 177 +++++++++++++++++- 3 files changed, 281 insertions(+), 15 deletions(-) diff --git a/include/seqan3/range/container/concatenated_sequences.hpp b/include/seqan3/range/container/concatenated_sequences.hpp index 4ad3f9be8bf..cc65bdb8e5f 100644 --- a/include/seqan3/range/container/concatenated_sequences.hpp +++ b/include/seqan3/range/container/concatenated_sequences.hpp @@ -138,6 +138,9 @@ template , + "KNOWN BUG: inner_type = std::basic_string<> is not working " + "for the ubuntu::ppa version of gcc7, because of a faulty STL version. "); protected: //!\privatesection //!\brief Where the concatenation is stored. @@ -1319,8 +1322,3 @@ class concatenated_sequences }; } // namespace seqan3 - -#ifndef NDEBUG -static_assert(seqan3::reservable_sequence_concept>); -static_assert(seqan3::forward_range_concept>); -#endif diff --git a/include/seqan3/range/container/concept.hpp b/include/seqan3/range/container/concept.hpp index ef2566b0eff..abc1c71c920 100644 --- a/include/seqan3/range/container/concept.hpp +++ b/include/seqan3/range/container/concept.hpp @@ -42,6 +42,92 @@ #include +// remove if sequence_concept_modified_by_const_iterator_bug vanished from travis +#include + +// TODO: +// * merge sequence_concept_modified_by_const_iterator back into +// sequence_concept +// * remove is_basic_string +// * fix test cases +// * remove #include in this file +// once the ubuntu::ppa [1] of g++-7 has a newer update than +// 7.2.0-1ubuntu1~16.04 (2017-08-20) +// +// [1] https://launchpad.net/~ubuntu-toolchain-r/+archive/ubuntu/test?field.series_filter=xenial +namespace seqan3::detail +{ +//!\privatesection + +//!\brief Returns whether `basic_string_t` is of type `std::basic_string`. +//!\attention Will be deleted once seqan3::detail::sequence_concept_modified_by_const_iterator_bug is fixed. +template +struct is_basic_string : std::false_type +{}; + +//!\brief Returns whether `basic_string_t` is of type `std::basic_string`. +//!\attention Will be deleted once seqan3::detail::sequence_concept_modified_by_const_iterator_bug is fixed. +template +struct is_basic_string> : std::true_type +{}; + +//!\brief Shorthand of seqan3::detail::is_basic_string +//!\attention Will be deleted once seqan3::detail::sequence_concept_modified_by_const_iterator_bug is fixed. +template +constexpr bool is_basic_string_v = is_basic_string::value; + +static_assert(is_basic_string_v>, ""); +static_assert(is_basic_string_v, ""); +static_assert(is_basic_string_v, ""); +static_assert(!is_basic_string_v, ""); + +/*!\interface seqan3::detail::sequence_concept_modified_by_const_iterator <> + * \brief Checks whether insert and erase can be used with const_iterator + * + * \attention This will be merged back into sequence_concept once + * seqan3::detail::sequence_concept_modified_by_const_iterator_bug is fixed. + */ +//!\cond +template +concept bool sequence_concept_modified_by_const_iterator = requires (type val, type val2) +{ + { val.insert(val.cbegin(), val2.front()) } -> typename type::iterator; + { val.insert(val.cbegin(), typename type::value_type{}) } -> typename type::iterator; + { val.insert(val.cbegin(), typename type::size_type{}, typename type::value_type{})} -> typename type::iterator; + { val.insert(val.cbegin(), val2.begin(), val2.end()) } -> typename type::iterator; + requires is_basic_string_v || requires(type val) + { + // TODO this function is not defined on strings (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83328) + { val.insert(val.cbegin(), std::initializer_list{}) } -> typename type::iterator; + }; + { val.erase(val.cbegin()) } -> typename type::iterator; + { val.erase(val.cbegin(), val.cend()) } -> typename type::iterator; + + { val.insert(val.begin(), typename type::size_type{}, typename type::value_type{}) } -> typename type::iterator; + { val.insert(val.begin(), val2.begin(), val2.end()) } -> typename type::iterator; +}; +//!\endcond + +/*!\brief Workaround for a ubuntu/travis-ci exclusive bug with g++-7.2. + * + * seqan3::detail::sequence_concept_modified_by_const_iterator is + * known to work, but ubuntu::ppa (<18.04)/travis-ci has a version of g++-7.2 + * where a bug in the STL prevents this concept to be true. + * + * \attention This workaround can be removed if + * `/test/range/container/container_concept_test.cpp` is not failing on + * ubuntu::ppa (<18.04)/travis-ci anymore. \n + * Probably when the ppa version of gcc7 is newer than `7.2.0-1ubuntu1~16.04` (2017-08-20) + * \sa https://launchpad.net/~ubuntu-toolchain-r/+archive/ubuntu/test?field.series_filter=xenial + */ +template +constexpr bool sequence_concept_modified_by_const_iterator_bug + = is_basic_string_v && !sequence_concept_modified_by_const_iterator; + +//!\publicsection + +} // seqan3::detail + namespace seqan3 { @@ -127,15 +213,22 @@ concept bool sequence_concept = requires (type val, type val2) // modify container //TODO: how do you model this? -// { val.emplace(typename type::const_iterator{}, ? } -> typename type::iterator; - { val.insert(val.cbegin(), val2.front()) } -> typename type::iterator; - { val.insert(val.cbegin(), typename type::value_type{}) } -> typename type::iterator; - { val.insert(val.cbegin(), typename type::size_type{}, typename type::value_type{})} -> typename type::iterator; - { val.insert(val.cbegin(), val2.begin(), val2.end()) } -> typename type::iterator; -//TODO this fails on std::string, although it should work -// { val.insert(val.cbegin(), std::initializer_list{}) } -> typename type::iterator; - { val.erase(val.cbegin()) } -> typename type::iterator; - { val.erase(val.cbegin(), val.cend()) } -> typename type::iterator; + // { val.emplace(typename type::const_iterator{}, ? } -> typename type::iterator; + + { val.insert(val.begin(), val2.front()) } -> typename type::iterator; + { val.insert(val.begin(), typename type::value_type{}) } -> typename type::iterator; + // because of a travis bug we can't assume typename type::iterator as return type + { val.insert(val.begin(), typename type::size_type{}, typename type::value_type{}) }; + { val.insert(val.begin(), val2.begin(), val2.end()) }; + //TODO should return type::iterator on strings (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83328) + { val.insert(val.begin(), std::initializer_list{}) }; + { val.erase(val.begin()) } -> typename type::iterator; + { val.erase(val.begin(), val.end()) } -> typename type::iterator; + + // workaround a travis bug where insert/erase can't take a const iterator, e.g. cbegin() + requires detail::sequence_concept_modified_by_const_iterator_bug || + detail::sequence_concept_modified_by_const_iterator; + { val.push_back(val.front()) } -> void; { val.push_back(typename type::value_type{}) } -> void; { val.pop_back() } -> void; diff --git a/test/range/container/container_concept_test.cpp b/test/range/container/container_concept_test.cpp index 7469c693b01..ae84b860241 100644 --- a/test/range/container/container_concept_test.cpp +++ b/test/range/container/container_concept_test.cpp @@ -41,10 +41,34 @@ #include #include -#include +#include +#include using namespace seqan3; +// if detail::sequence_concept_modified_by_const_iterator_bug<> is false +// test seqan3::concatenated_sequences, otherwise +// test seqan3::concatenated_sequences> +using concatenated_sequences_string_t = seqan3::concatenated_sequences< + std::conditional_t< + detail::sequence_concept_modified_by_const_iterator_bug<>, + std::vector, + std::string + >>; + +TEST(range_concept, forward_range_concept) +{ + EXPECT_TRUE((seqan3::forward_range_concept>)); + EXPECT_TRUE((seqan3::forward_range_concept>)); + EXPECT_TRUE((seqan3::forward_range_concept>)); // `.size()` missing + EXPECT_TRUE((seqan3::forward_range_concept>)); + EXPECT_TRUE((seqan3::forward_range_concept>)); + EXPECT_TRUE((seqan3::forward_range_concept)); + + EXPECT_TRUE((seqan3::forward_range_concept)); + EXPECT_TRUE((seqan3::forward_range_concept>>)); +} + TEST(container_concept, container_concept) { EXPECT_TRUE((seqan3::container_concept>)); @@ -53,6 +77,132 @@ TEST(container_concept, container_concept) EXPECT_TRUE((seqan3::container_concept>)); EXPECT_TRUE((seqan3::container_concept>)); EXPECT_TRUE((seqan3::container_concept)); + + EXPECT_TRUE((seqan3::container_concept)); + EXPECT_TRUE((seqan3::container_concept>>)); +} + +template +void container_concept_travis_bug_test() +{ + // non const version of container_concept_const_travis_bug_test + using namespace std::string_literals; + + // example code from http://en.cppreference.com/w/cpp/string/basic_string/insert + string_t s = "xmplr"; + string_t r = ""; + typename string_t::iterator it; + + // insert(size_type index, size_type count, char ch) + r = s.insert(0, 1, 'E'); + EXPECT_EQ("Exmplr", s); + + // insert(size_type index, const char* s) + r = s.insert(2, "e"); + EXPECT_EQ("Exemplr", s); + + // insert(size_type index, string const& str) + r = s.insert(6, "a"s); + EXPECT_EQ("Exemplar", s); + + // insert(size_type index, string const& str, + // size_type index_str, size_type count) + r = s.insert(8, " is an example string."s, 0, 14); + EXPECT_EQ("Exemplar is an example", s); + + // insert(const_iterator pos, char ch) + it = s.insert(s.begin() + s.find_first_of('n') + 1, ':'); + EXPECT_EQ("Exemplar is an: example", s); + + // insert(const_iterator pos, size_type count, char ch) + //TODO should return type::iterator on strings, remove if + // sequence_concept_modified_by_const_iterator_bug is no issue anymore + // it = + s.insert(s.begin() + s.find_first_of(':') + 1, 2, '='); + EXPECT_EQ("Exemplar is an:== example", s); + + // insert(const_iterator pos, InputIt first, InputIt last) + { + string_t seq = " string"; + //TODO should return type::iterator on strings, remove if + // sequence_concept_modified_by_const_iterator_bug is no issue anymore + // it = + s.insert(s.begin() + s.find_last_of('e') + 1, + std::begin(seq), std::end(seq)); + EXPECT_EQ("Exemplar is an:== example string", s); + } + + // insert(const_iterator pos, std::initializer_list) + //TODO should return type::iterator on strings (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83328) + // it = + s.insert(s.begin() + s.find_first_of('g') + 1, { '.' }); + EXPECT_EQ("Exemplar is an:== example string.", s); +} + +template +void container_concept_const_travis_bug_test() +{ + // travis failed on this statement + // concept bool sequence_concept = requires (type val, type val2) + // ^~~~~~~~~~~~~~~~ + // /include/seqan3/range/container/concept.hpp:113:14: note: with ‘std::basic_string val’ + // /include/seqan3/range/container/concept.hpp:113:14: note: with ‘std::basic_string val2’ + // [...] + // /include/seqan3/range/container/concept.hpp:113:14: note: the required expression ‘val.erase(val.cbegin(), val.cend())’ would be ill-formed + + using namespace std::string_literals; + + static_assert(detail::sequence_concept_modified_by_const_iterator); + static_assert(!detail::sequence_concept_modified_by_const_iterator_bug && std::is_same_v); + static_assert(seqan3::container_concept); + + // example code from http://en.cppreference.com/w/cpp/string/basic_string/insert + string_t s = "xmplr"; + + // insert(size_type index, size_type count, char ch) + s.insert(0, 1, 'E'); + EXPECT_EQ("Exmplr", s); + + // insert(size_type index, const char* s) + s.insert(2, "e"); + EXPECT_EQ("Exemplr", s); + + // insert(size_type index, string const& str) + s.insert(6, "a"s); + EXPECT_EQ("Exemplar", s); + + // insert(size_type index, string const& str, + // size_type index_str, size_type count) + s.insert(8, " is an example string."s, 0, 14); + EXPECT_EQ("Exemplar is an example", s); + + // insert(const_iterator pos, char ch) + s.insert(s.cbegin() + s.find_first_of('n') + 1, ':'); + EXPECT_EQ("Exemplar is an: example", s); + + // insert(const_iterator pos, size_type count, char ch) + s.insert(s.cbegin() + s.find_first_of(':') + 1, 2, '='); + EXPECT_EQ("Exemplar is an:== example", s); + + // insert(const_iterator pos, InputIt first, InputIt last) + { + string_t seq = " string"; + s.insert(s.cbegin() + s.find_last_of('e') + 1, + std::begin(seq), std::end(seq)); + EXPECT_EQ("Exemplar is an:== example string", s); + } + + // insert(const_iterator pos, std::initializer_list) + s.insert(s.cbegin() + s.find_first_of('g') + 1, { '.' }); + EXPECT_EQ("Exemplar is an:== example string.", s); +} + +TEST(container_concept, container_concept_travis_bug) +{ + container_concept_travis_bug_test(); + + if constexpr(!detail::sequence_concept_modified_by_const_iterator_bug<>) + container_concept_const_travis_bug_test(); } TEST(container_concept, sequence_concept) @@ -63,6 +213,25 @@ TEST(container_concept, sequence_concept) EXPECT_TRUE((seqan3::sequence_concept>)); EXPECT_TRUE((seqan3::sequence_concept>)); EXPECT_TRUE((seqan3::sequence_concept)); + + EXPECT_TRUE((seqan3::sequence_concept)); + EXPECT_TRUE((seqan3::sequence_concept>>)); +} + +TEST(container_concept, sequence_concept_modified_by_const_iterator) +{ + EXPECT_FALSE((seqan3::detail::sequence_concept_modified_by_const_iterator>)); + EXPECT_TRUE((seqan3::detail::sequence_concept_modified_by_const_iterator>)); + EXPECT_FALSE((seqan3::detail::sequence_concept_modified_by_const_iterator>)); + EXPECT_TRUE((seqan3::detail::sequence_concept_modified_by_const_iterator>)); + EXPECT_TRUE((seqan3::detail::sequence_concept_modified_by_const_iterator>)); + if constexpr(!detail::sequence_concept_modified_by_const_iterator_bug<>) + { + EXPECT_TRUE((seqan3::detail::sequence_concept_modified_by_const_iterator)); + } + + EXPECT_TRUE((seqan3::detail::sequence_concept_modified_by_const_iterator)); + EXPECT_TRUE((seqan3::detail::sequence_concept_modified_by_const_iterator>>)); } TEST(container_concept, random_access_sequence_concept) @@ -73,6 +242,9 @@ TEST(container_concept, random_access_sequence_concept) EXPECT_TRUE((seqan3::random_access_sequence_concept>)); EXPECT_TRUE((seqan3::random_access_sequence_concept>)); EXPECT_TRUE((seqan3::random_access_sequence_concept)); + + EXPECT_TRUE((seqan3::random_access_sequence_concept)); + EXPECT_TRUE((seqan3::random_access_sequence_concept>>)); } TEST(container_concept, reservable_sequence_concept) @@ -83,6 +255,9 @@ TEST(container_concept, reservable_sequence_concept) EXPECT_TRUE((seqan3::reservable_sequence_concept>)); EXPECT_FALSE((seqan3::reservable_sequence_concept>)); EXPECT_TRUE((seqan3::reservable_sequence_concept)); + + EXPECT_TRUE((seqan3::reservable_sequence_concept)); + EXPECT_TRUE((seqan3::reservable_sequence_concept>>)); } /* Check the SDSL containers */