//
// libsemigroups - C++ library for semigroups and monoids
// Copyright (C) 2020 James D. Mitchell
//
// 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/>.
//
// This file contains some functionality for generating elements in the free
// monoid over an alphabet with a given number of letters up to a given length
// in a lexicographic or short-lex order.
//
// SILO = Strings In Lexicographic Order
// SISLO = Strings In Short-Lex Order
// SISO = Strings In Some Order
// TODO(later):
// 1. cbegin_silo and cend_silo for rvalue references to strings
// 2. cbegin_sislo and cend_sislo for rvalue references to strings
#ifndef LIBSEMIGROUPS_SISO_HPP_
#define LIBSEMIGROUPS_SISO_HPP_
#include <cstddef>
// for size_t, ptrdiff_t, ...
#include <iterator>
// for forward_iterator_tag
#include <string>
// for string
#include <utility>
// for pair
#include "iterator.hpp" // for detail::ConstIteratorStateful
#include "wilo.hpp" // for const_wilo_iterator
#include "wislo.hpp" // for const_wislo_iterator
#include "word.hpp" // for word_to_string
namespace libsemigroups {
namespace detail {
// This is a traits class for ConstIteratorStateful in iterator.hpp
template <
typename T>
struct SisoIteratorTraits {
// state_type::first = alphabet, state_type::second = current value
using state_type = std::pair<std::string, std::string>;
using internal_iterator_type = T;
using value_type = std::string;
using reference = std::string&;
using const_reference = std::string
const&;
using difference_type = std::ptrdiff_t;
using size_type = std::size_t;
using const_pointer = std::string
const*;
using pointer = std::string*;
using iterator_category = std::forward_iterator_tag;
struct Deref {
const_reference
operator()(state_type& state,
internal_iterator_type
const& it)
const noexcept {
if (state.second.empty()) {
detail::word_to_string(state.first, *it, state.second);
}
return state.second;
}
};
struct AddressOf {
const_pointer
operator()(state_type& state,
internal_iterator_type
const& it)
const noexcept {
Deref()(state, it);
// to ensure that state.second is initialised
return &state.second;
}
};
struct PrefixIncrement {
void operator()(state_type& state,
internal_iterator_type& it)
const noexcept {
++it;
state.second.clear();
}
};
struct AddAssign {
void operator()(state_type& state,
internal_iterator_type& it,
size_t val)
const noexcept {
std::advance(it, val);
state.second.clear();
}
};
struct Swap {
void operator()(internal_iterator_type& it_this,
internal_iterator_type& it_that,
state_type& state_this,
state_type& state_that)
const noexcept {
using std::swap;
swap(it_this, it_that);
swap(state_this, state_that);
}
};
using EqualTo =
void;
using NotEqualTo =
void;
using PostfixIncrement =
void;
};
}
// namespace detail
//! No doc
using const_silo_iterator = detail::ConstIteratorStateful<
detail::SisoIteratorTraits<const_wilo_iterator>>;
static_assert(std::is_default_constructible<const_silo_iterator>::value,
"forward iterator requires default-constructible");
static_assert(std::is_copy_constructible<const_silo_iterator>::value,
"forward iterator requires copy-constructible");
static_assert(std::is_copy_assignable<const_silo_iterator>::value,
"forward iterator requires copy-assignable");
static_assert(std::is_destructible<const_silo_iterator>::value,
"forward iterator requires destructible");
//! No doc
using const_sislo_iterator = detail::ConstIteratorStateful<
detail::SisoIteratorTraits<const_wislo_iterator>>;
static_assert(std::is_default_constructible<const_sislo_iterator>::value,
"forward iterator requires default-constructible");
static_assert(std::is_copy_constructible<const_sislo_iterator>::value,
"forward iterator requires copy-constructible");
static_assert(std::is_copy_assignable<const_sislo_iterator>::value,
"forward iterator requires copy-assignable");
static_assert(std::is_destructible<const_sislo_iterator>::value,
"forward iterator requires destructible");
//! Returns a forward iterator pointing to the 3rd parameter \p first.
//!
//! If incremented, the iterator will point to the next least lexicographic
//! string after \p w over \p alphabet with length less than \p upper_bound.
//! Iterators of the type returned by this function are equal whenever they
//! are obtained by advancing the return value of any call to \c cbegin_silo
//! by the same amount, or they are both obtained by any call to
//! \c cend_silo.
//!
//! \param alphabet the alphabet
//! \param upper_bound only strings of length less than this value are
//! considered;
//! \param first the starting point for the iteration;
//! \param last the ending point for the iteration.
//!
//! \returns An iterator of type \c const_silo_iterator.
//!
//! \exceptions
//! \no_libsemigroups_except
//!
//! \note
//! The parameter \p upper_bound is required because lexicographical
//! ordering is not a well-ordering, and there might be infinitely many
//! strings between a given pair of strings.
//!
//! \warning
//! Copying iterators of this type is expensive. As a consequence, prefix
//! incrementing \c ++it the iterator \c it returned by \c cbegin_silo is
//! significantly cheaper than postfix incrementing \c it++.
//!
//! \warning
//! Iterators constructed using different parameters may not be equal, so
//! best not to loop over them.
//!
//! \sa cend_silo
//!
//! \par Example
//! \code
//! std::vector<std::string>(cbegin_silo("ba", 3, "b", "aaa"),
//! cend_silo("ba", 3, "b", "aaa"));
//! // {"b", "bb", "ba", "a", "ab", "aa"};
//! \endcode
const_silo_iterator cbegin_silo(std::string
const& alphabet,
size_t
const upper_bound,
std::string
const& first,
std::string
const& last);
//! Returns a forward iterator pointing to one after the end of the range
//! from \p first to \p last.
//!
//! The iterator returned by this is still dereferenceable and incrementable,
//! but does not point to a string in the correct range.
//!
//! \sa cbegin_silo
const_silo_iterator cend_silo(std::string
const& alphabet,
size_t
const upper_bound,
std::string
const& first,
std::string
const& last);
//! Returns a forward iterator pointing to the 2nd parameter \p first.
//!
//! If incremented, the iterator will point to the next least short-lex
//! string after \p w over \p alphabet.
//! Iterators of the type returned by this function are equal whenever they
//! are obtained by advancing the return value of any call to \c cbegin_sislo
//! by the same amount, or they are both obtained by any call to
//! \c cend_sislo.
//!
//! \param alphabet the alphabet
//! \param first the starting point for the iteration;
//! \param last the ending point for the iteration.
//!
//! \returns An iterator of type \c const_sislo_iterator.
//!
//! \exceptions
//! \no_libsemigroups_except
//!
//! \warning
//! Copying iterators of this type is expensive. As a consequence, prefix
//! incrementing \c ++it the iterator \c it returned by \c cbegin_sislo is
//! significantly cheaper than postfix incrementing \c it++.
//!
//! \warning
//! Iterators constructed using different parameters may not be equal, so
//! best not to loop over them.
//!
//! \sa cend_sislo
//!
//! \par Example
//! \code
//! std::vector<std::string>(cbegin_sislo("ba", "b", "bbb"),
//! cend_sislo("ba", "b", "bbb"));
//! // {"b", "b", "bb", "ba","ab", "aa"};
//! \endcode
const_sislo_iterator cbegin_sislo(std::string
const& alphabet,
std::string
const& first,
std::string
const& last);
//! Returns a forward iterator pointing to one after the end of the range
//! from \p first to \p last.
//!
//! The iterator returned by this is still dereferenceable and incrementable,
//! but does not point to a string in the correct range.
//!
//! \sa cbegin_sislo
const_sislo_iterator cend_sislo(std::string
const& alphabet,
std::string
const& first,
std::string
const& last);
class Sislo {
public:
Sislo() =
default;
Sislo(Sislo
const&) =
default;
Sislo(Sislo&&) =
default;
Sislo&
operator=(Sislo
const&) =
default;
Sislo&
operator=(Sislo&&) =
default;
Sislo& alphabet(std::string
const& lphbt) {
_alphabet = lphbt;
return *
this;
}
std::string
const& alphabet()
const {
return _alphabet;
}
char letter(size_t i)
const {
return _alphabet[i];
}
Sislo& first(std::string
const& first) {
_first = first;
return *
this;
}
Sislo& first(size_t min) {
_first = std::string(min, letter(0));
return *
this;
}
std::string
const& first()
const noexcept {
return _first;
}
Sislo& last(std::string
const& last) {
_last = last;
return *
this;
}
Sislo& last(size_t max) {
_last = std::string(max, letter(0));
return *
this;
}
std::string
const& last()
const noexcept {
return _last;
}
const_sislo_iterator cbegin()
const noexcept {
return cbegin_sislo(_alphabet, _first, _last);
}
const_sislo_iterator cend()
const noexcept {
return cend_sislo(_alphabet, _first, _last);
}
private:
std::string _alphabet;
std::string _first;
std::string _last;
};
}
// namespace libsemigroups
#endif // LIBSEMIGROUPS_SISO_HPP_