// libsemigroups - C++ library for semigroups and monoids
// Copyright (C) 2021 James D. Mitchell + Maria Tsalakou
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/ >.
//
// TODO(later)
// - Write tests for maximum_common_suffix
#include "catch.hpp" // for REQUIRE, REQUIRE_NOTHROW, REQUIRE_THROWS_AS
#include "test-main.hpp" // for LIBSEMIGROUPS_TEST_CASE
#include <cstddef> // for size_t
#include <cstdint> // for int64_t, uint64_t
#include <iterator> // for distance, advance, operator!=
#include <string> // for string
#include <string> // for basic_string, operator==
#include <type_traits> // for move
#include "libsemigroups/string-view.hpp" // for MultiStringView, StringView...
namespace libsemigroups {
using detail::MultiStringView;
struct LibsemigroupsException; // forward decl
LIBSEMIGROUPS_TEST_CASE("MultiStringView" ,
"000" ,
"catch all" ,
"[quick][multistringview]" ) {
// REQUIRE(sizeof(detail::MultiStringView) == 32);
// REQUIRE(sizeof(uint64_t) == 8);
std::string s = "abcdefghijkl" ;
detail::MultiStringView msv(s.cbegin(), s.cbegin() + 3);
REQUIRE(msv.size() == 3);
msv.append(s.cbegin(), s.cend());
REQUIRE(msv.size() == s.size() + 3);
REQUIRE(msv.cbegin() != msv.cbegin() + 3);
REQUIRE(*msv.cbegin() == *(msv.cbegin() + 3));
REQUIRE(msv.cbegin() + 1 != msv.cbegin() + 4);
REQUIRE(*(msv.cbegin() + 1) == *(msv.cbegin() + 4));
REQUIRE(msv.cbegin() + 2 != msv.cbegin() + 5);
REQUIRE(*(msv.cbegin() + 2) == *(msv.cbegin() + 5));
REQUIRE((msv.cbegin() + 3) != (msv.cbegin() + 6));
REQUIRE(*(msv.cbegin() + 3) != *(msv.cbegin() + 6));
REQUIRE(std::string(msv) == "abcabcdefghijkl" );
REQUIRE(((msv.cbegin() + 3) - msv.cbegin()) == 3);
REQUIRE((msv.cbegin() - (msv.cbegin() + 3)) == -3);
REQUIRE(static_cast <size_t>(msv.cend() - msv.cbegin()) == msv.size());
REQUIRE(msv.cbegin() - msv.cend() == -static_cast <int64_t>(msv.size()));
REQUIRE(msv.cbegin() + msv.size() == msv.cend());
std::string t = "" ;
for (auto it = msv.cbegin(); it != msv.cend(); ++it) {
t += *it;
}
REQUIRE(t == "abcabcdefghijkl" );
REQUIRE(msv.number_of_views() == 2);
REQUIRE(msv == msv);
REQUIRE(msv.cbegin()[10] == 'h' );
detail::MultiStringView msv2(s.cbegin(), s.cbegin() + 3);
msv2.append(s.cbegin(), s.cbegin() + 3);
msv2.append(s.cbegin() + 3, s.cend());
REQUIRE(msv == msv);
REQUIRE(msv == msv2);
REQUIRE(msv2 == msv);
msv2.append(s.cbegin(), s.cbegin() + 3);
REQUIRE(msv2 != msv);
REQUIRE(msv != msv2);
REQUIRE(msv < msv2);
REQUIRE(msv <= msv2);
REQUIRE(msv2 >= msv);
REQUIRE(msv2 > msv);
t = "" ;
for (auto it = msv2.crbegin(); it != msv2.crend(); ++it) {
t += *it;
}
REQUIRE(t == "cbalkjihgfedcbacba" );
REQUIRE(msv2.number_of_views() == 3);
msv2.append(s.cbegin() + 1, s.cbegin() + 1);
REQUIRE(msv2.number_of_views() == 3);
detail::MultiStringView msv3;
REQUIRE(msv3.empty());
REQUIRE(std::string(msv3) == "" );
msv += msv2;
REQUIRE(std::string(msv) == "abcabcdefghijklabcabcdefghijklabc" );
REQUIRE(msv.number_of_views() == 5);
auto it1 = msv.cbegin();
auto it2 = msv.cbegin();
std::advance(it1, 6);
std::advance(it2, 15);
REQUIRE(it2 - it1 == 9);
auto it3 = (msv.cbegin() + 6);
REQUIRE(it3 == it1);
it3 = (msv.cbegin() + 6);
std::advance(it3, 9);
REQUIRE(*it3 == 'a' );
REQUIRE(it3 - msv.cbegin() == 15);
REQUIRE(it3 == (msv.cbegin() + 15));
REQUIRE((msv.cbegin() + 15) - (msv.cbegin() + 6) == 9);
t = "" ;
for (auto it = msv.cbegin() + 6; it != msv.cbegin() + 15; ++it) {
t += *it;
}
REQUIRE(t == "defghijkl" );
REQUIRE(msv3.number_of_views() == 0);
msv3.append(msv.cbegin() + 6, msv.cbegin() + 15);
REQUIRE(std::string(msv3) == "defghijkl" );
msv3.clear();
REQUIRE(msv3.empty());
msv3.append(msv.cbegin() + 6, msv.cbegin() + 16);
REQUIRE(std::string(msv3) == "defghijkla" );
}
LIBSEMIGROUPS_TEST_CASE("MultiStringView" ,
"001" ,
"is_prefix" ,
"[quick][multistringview]" ) {
using detail::MultiStringView;
std::string s = "abcdefghijkl" ;
MultiStringView m1(s.cbegin(), s.cend() - 4);
REQUIRE(std::string(m1) == "abcdefgh" );
REQUIRE(m1.number_of_views() == 1);
m1.append(s.begin(), s.cend());
REQUIRE(std::string(m1) == "abcdefghabcdefghijkl" );
REQUIRE(m1.number_of_views() == 2);
m1.append(s.begin(), s.cend());
REQUIRE(m1.number_of_views() == 3);
REQUIRE(std::string(m1) == "abcdefghabcdefghijklabcdefghijkl" );
m1.append(s.begin(), s.cend());
REQUIRE(m1.number_of_views() == 4);
MultiStringView m2(s.cbegin(), s.cend() - 4);
m2.append(s.begin(), s.cend());
REQUIRE(detail::is_prefix(m1, m2));
}
LIBSEMIGROUPS_TEST_CASE("MultiStringView" ,
"002" ,
"erase" ,
"[quick][multistringview]" ) {
std::string s = "abcdefghijkl" ;
MultiStringView m(s.cbegin(), s.cend() - 4);
m.append(s.begin(), s.cend());
m.append(s.begin(), s.cend());
m.append(s.begin(), s.cend());
REQUIRE(std::string(m) == "abcdefghabcdefghijklabcdefghijklabcdefghijkl" );
// Both string_type::iterators in the same range not at the beginning or
// end.
m.erase(m.cbegin() + 1, m.cbegin() + 2);
REQUIRE(std::string(m) == "acdefghabcdefghijklabcdefghijklabcdefghijkl" );
m.erase(m.cbegin(), m.cbegin() + 3);
REQUIRE(std::string(m) == "efghabcdefghijklabcdefghijklabcdefghijkl" );
m.erase(m.cbegin() + 1, m.cbegin() + 4);
REQUIRE(std::string(m) == "eabcdefghijklabcdefghijklabcdefghijkl" );
m.erase(m.cbegin() + 5, m.cend());
REQUIRE(std::string(m) == "eabcd" );
REQUIRE(m.size() == 5);
m.erase(m.cend(), m.cbegin());
REQUIRE(m.size() == 5);
}
LIBSEMIGROUPS_TEST_CASE("MultiStringView" ,
"003" ,
"iterators" ,
"[quick][multistringview]" ) {
std::string s = "abcdefghijkl" ;
MultiStringView m(s.cbegin(), s.cend() - 4);
m.append(s.begin(), s.cend());
m.append(s.begin(), s.cend());
m.append(s.begin(), s.cend());
auto it = m.cbegin();
it += 0;
REQUIRE(it == m.cbegin());
REQUIRE(m.cbegin() == it);
it += 3;
REQUIRE(it > m.cbegin());
REQUIRE(it - m.cbegin() == 3);
MultiStringView mm;
REQUIRE(mm.empty());
REQUIRE(mm.cbegin() == mm.cend());
}
LIBSEMIGROUPS_TEST_CASE("MultiStringView" ,
"004" ,
"constructors (long)" ,
"[quick][multistringview]" ) {
std::string s = "abcdefghijkl" ;
MultiStringView m(s.cbegin(), s.cend() - 4);
m.append(s.begin(), s.cend());
m.append(s.begin(), s.cend());
m.append(s.begin(), s.cend());
REQUIRE(!m.empty());
MultiStringView mm(m);
REQUIRE(m == mm);
MultiStringView mmm(std::move(mm));
REQUIRE(m == mmm);
m.erase(m.cbegin() + 1, m.cbegin() + 4);
REQUIRE(std::string(m) == "aefghabcdefghijklabcdefghijklabcdefghijkl" );
mm = m;
REQUIRE(mm == m);
REQUIRE(mm != mmm);
mmm = std::move(mm);
REQUIRE(mmm == m);
REQUIRE(m.size() == 41);
REQUIRE(std::distance(m.cbegin() + 4, m.cend()) == 37);
REQUIRE((m.cend() - 11) - (m.cbegin() + 4) == 26);
MultiStringView mmmm(m.cbegin() + 4, m.cend() - 11);
REQUIRE(std::string(m) == "aefghabcdefghijklabcdefghijklabcdefghijkl" );
REQUIRE(std::string(mmmm) == "habcdefghijklabcdefghijkla" );
REQUIRE(mmmm == MultiStringView("habcdefghijklabcdefghijkla" ));
REQUIRE(!mmmm.empty());
}
LIBSEMIGROUPS_TEST_CASE("MultiStringView" ,
"005" ,
"constructors (short)" ,
"[quick][multistringview]" ) {
std::string s = "abcdefghijkl" ;
MultiStringView m(s.cbegin(), s.cend() - 4);
m.append(s.begin(), s.cend());
MultiStringView mm(m);
REQUIRE(m == mm);
MultiStringView mmm(std::move(mm));
REQUIRE(m == mmm);
m.erase(m.cbegin() + 1, m.cbegin() + 4);
REQUIRE(std::string(m) == "aefghabcdefghijkl" );
mm = m;
REQUIRE(mm == m);
REQUIRE(mm != mmm);
mmm = std::move(mm);
REQUIRE(mmm == m);
REQUIRE(m.size() == 17);
MultiStringView mmmm(m.cbegin() + 4, m.cend() - 11);
REQUIRE(std::string(m) == "aefghabcdefghijkl" );
REQUIRE(std::string(mmmm) == "ha" );
REQUIRE(mmmm == MultiStringView("ha" ));
}
LIBSEMIGROUPS_TEST_CASE("MultiStringView" ,
"006" ,
"copy assignment (short assigned to long)" ,
"[quick][multistringview]" ) {
std::string s = "abcdefghijkl" ;
MultiStringView m(s.cbegin(), s.cend() - 4);
m.append(s.begin(), s.cend());
REQUIRE(m.size() == 20);
MultiStringView mm(s.cbegin(), s.cend() - 4);
mm.append(s.begin(), s.cend());
mm.append(s.begin(), s.cend());
REQUIRE(mm.size() == 32);
mm = m;
REQUIRE(mm.size() == 20);
REQUIRE(mm == m);
REQUIRE(mm.number_of_views() == 2);
REQUIRE(std::string(mm) == std::string(m));
REQUIRE(std::string(mm) == "abcdefghabcdefghijkl" );
}
LIBSEMIGROUPS_TEST_CASE("MultiStringView" ,
"007" ,
"copy assignment (short assigned to short)" ,
"[quick][multistringview]" ) {
std::string s = "abcdefghijkl" ;
MultiStringView m(s.cbegin(), s.cend() - 4);
m.append(s.begin(), s.cend());
REQUIRE(m.size() == 20);
MultiStringView mm(s.cbegin(), s.cend() - 4);
mm.append(s.begin(), s.cend() - 1);
REQUIRE(mm.size() == 19);
REQUIRE(m != mm);
mm = m;
REQUIRE(mm.size() == 20);
REQUIRE(mm == m);
REQUIRE(mm.number_of_views() == 2);
REQUIRE(std::string(mm) == std::string(m));
REQUIRE(std::string(mm) == "abcdefghabcdefghijkl" );
}
LIBSEMIGROUPS_TEST_CASE("MultiStringView" ,
"008" ,
"move assignment (short assigned to long)" ,
"[quick][multistringview]" ) {
std::string s = "abcdefghijkl" ;
MultiStringView m(s.cbegin(), s.cend() - 4);
m.append(s.begin(), s.cend());
REQUIRE(m.size() == 20);
MultiStringView mm(s.cbegin(), s.cend() - 4);
mm.append(s.begin(), s.cend());
mm.append(s.begin(), s.cend());
REQUIRE(mm.size() == 32);
mm = std::move(m);
REQUIRE(mm.size() == 20);
REQUIRE(mm == m);
REQUIRE(mm.number_of_views() == 2);
REQUIRE(std::string(mm) == std::string(m));
REQUIRE(std::string(mm) == "abcdefghabcdefghijkl" );
}
LIBSEMIGROUPS_TEST_CASE("MultiStringView" ,
"009" ,
"move assignment (short assigned to short)" ,
"[quick][multistringview]" ) {
std::string s = "abcdefghijkl" ;
MultiStringView m(s.cbegin(), s.cend() - 4);
m.append(s.begin(), s.cend());
REQUIRE(m.size() == 20);
MultiStringView mm(s.cbegin(), s.cend() - 4);
mm.append(s.begin(), s.cend() - 1);
REQUIRE(mm.size() == 19);
REQUIRE(m != mm);
mm = std::move(m);
REQUIRE(mm.size() == 20);
REQUIRE(mm == m);
REQUIRE(mm.number_of_views() == 2);
REQUIRE(std::string(mm) == std::string(m));
REQUIRE(std::string(mm) == "abcdefghabcdefghijkl" );
}
LIBSEMIGROUPS_TEST_CASE("MultiStringView" ,
"010" ,
"code coverage" ,
"[quick][stringview]" ) {
std::string s = "abcdefghijkl" ;
detail::StringViewContainer m;
m.emplace_back(s.cbegin() + 1, s.cbegin() + 5);
m.emplace_back(s.cbegin() + 2, s.cbegin() + 6);
REQUIRE(m.size(0) == 4);
REQUIRE(m.size(1) == 4);
REQUIRE(m.number_of_views() == 2);
auto foo = [](detail::StringViewContainer const & mm) { return mm.size(1); };
REQUIRE(foo(m) == 4);
m.pop_back();
REQUIRE(m.number_of_views() == 1);
m.pop_back();
REQUIRE(m.number_of_views() == 0);
REQUIRE(m.size() == 0);
REQUIRE(m.empty());
m.pop_back(); // does nothing
REQUIRE(m.number_of_views() == 0);
REQUIRE(m.size() == 0);
REQUIRE(m.empty());
m.insert(0, detail::StringView(s.cbegin(), s.cend()));
REQUIRE(m.number_of_views() == 1);
REQUIRE(m.size() == 12);
m.insert(0, detail::StringView(s.cend() - 2, s.cend()));
REQUIRE(m.number_of_views() == 2);
REQUIRE(m.size(0) == 2);
REQUIRE(m.size(1) == 12);
REQUIRE(m.size() == 14);
m.erase(0, 1);
REQUIRE(m.number_of_views() == 1);
REQUIRE(m.size() == 12);
m.insert(1, detail::StringView(s.cend() - 2, s.cend()));
REQUIRE(m.number_of_views() == 2);
REQUIRE(m.size(1) == 2);
REQUIRE(m.size(0) == 12);
m.erase(0, 2);
REQUIRE(m.empty());
m.erase(0, 2); // does nothing
REQUIRE(m.empty());
m.emplace_back(s.cbegin() + 1, s.cbegin() + 6);
m.emplace_back(s.cbegin() + 2, s.cbegin() + 6);
REQUIRE(m.size(0) == 5);
REQUIRE(m.size(1) == 4);
REQUIRE(m.size() == 9);
REQUIRE(m.number_of_views() == 2);
m.erase(1, 2);
REQUIRE(m.size(0) == 5);
REQUIRE(m.size() == 5);
REQUIRE(m.number_of_views() == 1);
m.erase(0, 1);
REQUIRE(m.size() == 0);
REQUIRE(m.number_of_views() == 0);
REQUIRE(m.empty());
m.emplace_back(s.cbegin() + 1, s.cbegin() + 6);
m.emplace_back(s.cbegin() + 2, s.cbegin() + 6);
m.emplace_back(s.cbegin() + 2, s.cbegin() + 6);
m.emplace_back(s.cbegin() + 2, s.cbegin() + 6);
REQUIRE(!m.empty());
REQUIRE(m.size() == 17);
m.pop_back();
REQUIRE(m.size() == 13);
m.clear();
REQUIRE(m.empty());
}
LIBSEMIGROUPS_TEST_CASE("MultiStringView" ,
"011" ,
"pop_front" ,
"[quick][multistringview]" ) {
std::string s = "abcdefghijkl" ;
MultiStringView m(s.cbegin(), s.begin() + 4);
m.append(s.begin() + 1, s.begin() + 3);
REQUIRE(m.number_of_views() == 2);
REQUIRE(m.size() == 6);
REQUIRE(std::string(m) == "abcdbc" );
REQUIRE(m.pop_front() == 'a' );
REQUIRE(std::string(m) == "bcdbc" );
REQUIRE(m.number_of_views() == 2);
REQUIRE(m.pop_front() == 'b' );
REQUIRE(std::string(m) == "cdbc" );
REQUIRE(m.number_of_views() == 2);
REQUIRE(m.pop_front() == 'c' );
REQUIRE(std::string(m) == "dbc" );
REQUIRE(m.number_of_views() == 2);
REQUIRE(m.pop_front() == 'd' );
REQUIRE(std::string(m) == "bc" );
REQUIRE(m.number_of_views() == 1);
REQUIRE(m.pop_front() == 'b' );
REQUIRE(std::string(m) == "c" );
REQUIRE(m.number_of_views() == 1);
REQUIRE(m.pop_front() == 'c' );
REQUIRE(std::string(m) == "" );
REQUIRE(m.number_of_views() == 0);
REQUIRE_THROWS_AS(m.pop_front(), LibsemigroupsException);
}
LIBSEMIGROUPS_TEST_CASE("MultiStringView" ,
"012" ,
"append" ,
"[quick][multistringview]" ) {
std::string s = "abcdefghijkl" ;
MultiStringView m(s.cbegin() + 3, s.begin() + 6);
REQUIRE(std::string(m) == "def" );
m.append(m.cbegin(), m.cbegin() + 1);
REQUIRE(std::string(m) == "defd" );
m.append(m.cbegin(), m.cend());
REQUIRE(std::string(m) == "defddefd" );
m.append(m.cbegin() + 3, m.cbegin() + 5);
REQUIRE(std::string(m) == "defddefddd" );
REQUIRE(m.size() == 10);
m.append(m.cbegin(), m.cend());
REQUIRE(m.size() == 20);
// Check the case when we append an interval adjacent to the end of the
// current view
m.clear();
REQUIRE(m.number_of_views() == 0);
m.append(s.cbegin(), s.cbegin() + 5);
REQUIRE(m.number_of_views() == 1);
m.append(s.cbegin() + 5, s.cend());
REQUIRE(m.number_of_views() == 1);
}
LIBSEMIGROUPS_TEST_CASE("MultiStringView" ,
"013" ,
"operators" ,
"[quick][multistringview]" ) {
std::string s = "abcdefghijkl" ;
MultiStringView m(s.cbegin() + 3, s.begin() + 6);
m.append(m.cbegin(), m.cbegin() + 1);
m.append(m.cbegin(), m.cend());
m.append(m.cbegin() + 3, m.cbegin() + 5);
REQUIRE(std::string(m) == "defddefddd" );
REQUIRE(m[0] == 'd' );
REQUIRE(m[1] == 'e' );
REQUIRE(m[2] == 'f' );
REQUIRE(m[3] == 'd' );
REQUIRE(m[4] == 'd' );
REQUIRE(m[5] == 'e' );
REQUIRE(m[6] == 'f' );
REQUIRE(m[7] == 'd' );
REQUIRE(m[8] == 'd' );
REQUIRE(m[9] == 'd' );
MultiStringView mm(s);
REQUIRE(std::string(mm + m) == "abcdefghijkldefddefddd" );
}
LIBSEMIGROUPS_TEST_CASE("MultiStringView" ,
"014" ,
"maximum_common_suffix" ,
"[quick][multistringview]" ) {
std::string s = "abcdefghijkl" ;
MultiStringView m(s.cbegin() + 3, s.begin() + 6);
m.append(m.cbegin(), m.cbegin() + 1);
m.append(m.cbegin(), m.cend());
m.append(m.cbegin() + 3, m.cbegin() + 5);
REQUIRE(std::string(m) == "defddefddd" );
MultiStringView mm = m + m;
REQUIRE(maximum_common_suffix(mm, m) == m);
}
LIBSEMIGROUPS_TEST_CASE("MultiStringView" ,
"015" ,
"deep tests" ,
"[quick][multistringview]" ) {
std::string s = "bcdabcd" ;
MultiStringView m(s.cbegin(), s.begin() + 2);
m.append(s.cbegin() + 2, s.end());
MultiStringView ww(m.cbegin(), m.cbegin() + 2);
REQUIRE(ww.size() == 2);
}
} // namespace libsemigroups
quality 95%
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet)
¤
*© Formatika GbR, Deutschland