Vcsn  2.1
Be Rational
genset-labelset.hh
Go to the documentation of this file.
1 #pragma once
2 
3 #include <memory>
4 #include <set>
5 
6 #include <boost/optional.hpp>
7 #include <boost/range/algorithm/for_each.hpp>
8 
9 #include <vcsn/core/kind.hh>
10 #include <vcsn/misc/raise.hh>
11 
12 namespace vcsn
13 {
14  namespace detail
15  {
18  template <typename GenSet>
20  {
21  using genset_t = GenSet;
22  using genset_ptr = std::shared_ptr<const genset_t>;
23 
24  using letter_t = typename genset_t::letter_t;
25  using word_t = typename genset_t::word_t;
26  using letters_t = typename genset_t::letters_t;
27 
29  : gs_{gs}
30  {}
31 
32  genset_labelset(const genset_t& gs = {})
33  : genset_labelset{std::make_shared<const genset_t>(gs)}
34  {}
35 
36  const genset_t& genset() const
37  {
38  return *gs_;
39  }
40 
41  static symbol sname()
42  {
43  static symbol res(genset_t::sname());
44  return res;
45  }
46 
57  template <typename Fun>
58  void
59  convs_classes_(std::istream& i, Fun fun) const
60  {
61  if (i.peek() == '^')
62  {
63  i.ignore();
64  auto alphabet = letters_t{};
65  for (auto l : this->genset())
66  alphabet.insert(l);
67  boost::for_each(set_difference(alphabet, convs_classes_(i)),
68  fun);
69  }
70  else
71  {
72  // The last letter we read, for intervals.
73  boost::optional<letter_t> prev;
74  while (i.peek() != EOF && i.peek() != ']')
75  if (i.peek() == '-')
76  {
77  require(prev != boost::none,
78  "bracket cannot begin with '-'");
79  // With string_letter's letter_t, letter_t{'-'} may
80  // fail depending on the version of Boost and of
81  // libstdc++. So rather, keep this dash.
82  auto dash = this->genset().get_letter(i);
83  // Handle ranges.
84  if (i.peek() == ']')
85  // [abc-] does not denote an interval.
86  fun(dash);
87  else
88  {
89  // [prev - l2].
90  letter_t l2 = get_letter(i);
91  // Skip prev, which was already processed.
92  for (auto i = std::next(this->genset().find(prev.get()));
93  i != this->genset().end() && *i < l2;
94  ++i)
95  fun(*i);
96  // The last letter. Do not do this in the loop,
97  // we might overflow the capacity of char.
98  // Check validity, so that 'z-a' is empty.
99  if (prev.get() < l2)
100  fun(l2);
101 
102  prev = boost::none;
103  }
104  }
105  else
106  {
107  letter_t l = get_letter(i);
108  fun(l);
109  prev = l;
110  }
111  }
112  }
113 
115  letters_t
116  convs_classes_(std::istream& i) const
117  {
118  letters_t res;
119  convs_classes_(i, [&res](letter_t l){ res.insert(l); });
120  return res;
121  }
122 
134  template <typename Fun>
135  void
136  convs_(std::istream& i, Fun fun) const
137  {
138  eat(i, '[');
139  boost::for_each(convs_classes_(i), fun);
140  eat(i, ']');
141  }
142 
144  letter_t
145  get_letter(std::istream& i, bool quoted = true) const
146  {
147  letter_t res = this->genset().get_letter(i, quoted);
148  require(this->has(res),
149  "invalid label: unexpected ", str_escape(res));
150  return res;
151  }
152 
154 # define DEFINE(Name, Attribute) \
155  template <typename... Args> \
156  Attribute \
157  auto \
158  Name(Args&&... args) const \
159  -> decltype(this->genset().Name(std::forward<Args>(args)...)) \
160  { \
161  return this->genset().Name(std::forward<Args>(args)...); \
162  }
163 
167  DEFINE(equal, ATTRIBUTE_PURE);
169  DEFINE(has, ATTRIBUTE_PURE);
170  DEFINE(is_letter, ATTRIBUTE_PURE);
171  DEFINE(less, ATTRIBUTE_PURE);
173  DEFINE(transpose, ATTRIBUTE_PURE);
175 
176 # undef DEFINE
177 
178  private:
179  genset_ptr gs_;
180  };
181  }
182 }
std::set< T, Compare, Alloc > set_difference(const std::set< T, Compare, Alloc > &set1, const std::set< T, Compare, Alloc > &set2)
The set of members of set1 that are not members of set2.
Definition: set.hh:35
std::ostream & str_escape(std::ostream &os, const std::string &str)
Output a string, escaping special characters.
Definition: escape.cc:43
letters_t convs_classes_(std::istream &i) const
Read a set of letters.
auto get_word(Args &&...args) const -> decltype(this->genset().get_word(std::forward< Args >(args)...))
This class has no modeling purpose, it only serves to factor code common to letterset, nullableset and wordset.
ATTRIBUTE_PURE auto has(Args &&...args) const -> decltype(this->genset().has(std::forward< Args >(args)...))
typename genset_t::letters_t letters_t
Functor to compare Values of ValueSets.
Definition: functional.hh:72
void convs_classes_(std::istream &i, Fun fun) const
Read and process a class of letters.
ATTRIBUTE_PURE auto equal(Args &&...args) const -> decltype(this->genset().equal(std::forward< Args >(args)...))
char eat(std::istream &is, char c)
Check lookahead character and advance.
Definition: stream.cc:37
ATTRIBUTE_PURE auto is_letter(Args &&...args) const -> decltype(this->genset().is_letter(std::forward< Args >(args)...))
std::shared_ptr< const genset_t > genset_ptr
const genset_t & genset() const
typename genset_t::word_t word_t
auto delimit(Args &&...args) const -> decltype(this->genset().delimit(std::forward< Args >(args)...))
void require(bool b, Args &&...args)
If b is not verified, raise an error with args as message.
Definition: raise.hh:75
auto begin(Args &&...args) const -> decltype(this->genset().begin(std::forward< Args >(args)...))
auto undelimit(Args &&...args) const -> decltype(this->genset().undelimit(std::forward< Args >(args)...))
symbol sname()
Definition: name.hh:67
boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::intermodule_holder > symbol
An internalized string.
Definition: symbol.hh:23
genset_labelset(const genset_ptr &gs)
auto mul(Args &&...args) const -> decltype(this->genset().mul(std::forward< Args >(args)...))
ATTRIBUTE_PURE auto transpose(Args &&...args) const -> decltype(this->genset().transpose(std::forward< Args >(args)...))
#define DEFINE(Name, Attribute)
Use the implementation from genset.
auto end(Args &&...args) const -> decltype(this->genset().end(std::forward< Args >(args)...))
letter_t get_letter(std::istream &i, bool quoted=true) const
Read one letter from i.
typename genset_t::letter_t letter_t
void convs_(std::istream &i, Fun fun) const
Read and process a class of letters.
genset_labelset(const genset_t &gs={})