Vcsn  2.1
Be Rational
setalpha.hh
Go to the documentation of this file.
1 #pragma once
2 
3 #include <cassert>
4 #include <initializer_list>
5 #include <stdexcept>
6 
7 #include <boost/optional.hpp>
8 
9 #include <vcsn/misc/format.hh>
10 #include <vcsn/misc/raise.hh>
11 #include <vcsn/misc/set.hh>
12 #include <vcsn/misc/stream.hh> // eat.
13 #include <vcsn/misc/symbol.hh>
14 #include <vcsn/misc/type_traits.hh>
15 
16 namespace vcsn
17 {
21  template <typename L>
22  class set_alphabet: public L
23  {
24  public:
25  using letter_t = typename L::letter_t;
26  using word_t = typename L::word_t;
27  using letters_t = std::set<letter_t, vcsn::less<L, letter_t>>;
30 
31  static symbol sname()
32  {
33  static symbol res(L::sname());
34  return res;
35  }
36 
37  static set_alphabet make(std::istream& is)
38  {
39  // name: char_letters(abc)
40  // ^^^^^^^^^^^^ ^^^
41  // letter_type gens
42  eat(is, sname());
43 
44  // The result.
45  set_alphabet res;
46 
47  // This labelset might be open: no initial letter is given, they
48  // will be discovered afterwards.
49  if (is.peek() == '(')
50  {
51  is.ignore();
52  // Previously read character, for intervals. We don't
53  // immediately add the letters: on 'a-z' we would firsts add
54  // 'a', and then ask for the interval from 'a' to 'z', which
55  // would add 'a' twice uselessly.
56  //
57  // Rather, keep the 'a' in \a prev, and flush prev when needed.
58  boost::optional<letter_t> prev;
59  while (true)
60  switch (is.peek())
61  {
62  case EOF:
63  raise(sname(), ": make: invalid end-of-file");
64  break;
65 
66  case ')':
67  eat(is, ')');
68  goto done;
69 
70  case '-':
71  if (prev == boost::none)
72  goto insert;
73  else
74  {
75  eat(is, '-');
76  res.add_range(prev.get(), L::get_letter(is));
77  prev = boost::none;
78  break;
79  }
80 
81  insert:
82  default:
83  {
84  if (prev != boost::none)
85  res.add_letter(prev.get());
86  prev = L::get_letter(is);
87  break;
88  }
89  }
90  done:
91  if (prev != boost::none)
92  res.add_letter(prev.get());
93  ;
94  }
95  else // is.peek() != '('
96  res.open_ = true;
97  return res;
98  }
99 
100  set_alphabet() = default;
101  set_alphabet(const set_alphabet&) = default;
102  set_alphabet(const std::initializer_list<letter_t>& l)
103  : alphabet_{l}
104  {}
105 
107  : alphabet_{l}
108  {}
109 
113  bool open(bool o) const
114  {
115  std::swap(o, open_);
116  return o;
117  }
118 
120  set_alphabet&
122  {
123  require(l != this->template special<letter_t>(),
124  "add_letter: the special letter is reserved: ", l);
125  alphabet_.insert(l);
126  return *this;
127  }
128 
131  template <typename Letter, typename Enable = void>
132  struct has_range: std::false_type {};
133 
134  template <typename Letter>
135  struct has_range<Letter,
136  decltype((++std::declval<Letter&>(), void()))>
137  : std::true_type
138  {};
139 
142  -> set_alphabet&
143  {
144  return add_range_<letter_t>(l1, l2);
145  }
146 
147  template <typename Letter>
148  auto add_range_(Letter l1, Letter l2)
150  {
151  for (/* empty */; L::less(l1, l2); ++l1)
152  add_letter(l1);
153  // The last letter. Do not do this in the loop, we might
154  // overflow the capacity of char. Check validity, so that 'z-a'
155  // is empty.
156  if (L::equal(l1, l2))
157  add_letter(l1);
158  return *this;
159  }
160 
161  template <typename Letter>
162  auto add_range_(Letter, Letter)
164  {
165  raise(sname(), ": does not support letter ranges");
166  }
167 
169  bool
170  has(letter_t l) const
171  {
172  if (open_)
173  {
174  // FIXME: OMG...
175  const_cast<set_alphabet&>(*this).add_letter(l);
176  return true;
177  }
178  else
180  }
181 
183  word_t
184  get_word(std::istream& i) const
185  {
186  require(!i.bad(),
187  "conv: invalid stream");
188  // Either an empty word: "\e", or a sequence of non-separators.
189  if (i.good() && i.peek() == '\\')
190  {
191  i.ignore();
192  int c = i.peek();
193  if (c == 'e')
194  {
195  i.ignore();
196  return {};
197  }
198  else
199  i.unget();
200  }
201 
202  // Stop as soon as it might be a special character (such as
203  // delimiters in polynomials, or tuple separators).
204  word_t res;
205  int c = i.peek();
206  while (i.good()
207  && (c = i.peek()) != EOF
208  && !isspace(c)
209  && c != '+'
210  && c != ','
211  && c != '|'
212  && c != '('
213  && c != ')')
214  {
215  letter_t l = L::get_letter(i, true);
216  require(has(l),
217  *this, ": invalid letter: ", str_escape(l));
218  // FIXME: in-place mul or temporary vector to build the
219  // string.
220  res = this->mul(res, l);
221  }
222  return res;
223  }
224 
225  using iterator = typename letters_t::const_iterator;
226  using const_iterator = typename letters_t::const_iterator;
227 
229  {
230  return alphabet_.begin();
231  }
232 
234  {
235  return alphabet_.end();
236  }
237 
239  {
240  return alphabet_.begin();
241  }
242 
244  {
245  return alphabet_.end();
246  }
247 
249  {
250  return alphabet_.find(l);
251  }
252 
253  std::ostream&
254  print_set(std::ostream& o, format fmt = {}) const
255  {
256  if (fmt == format::latex)
257  {
258  o << "\\{";
259  const char *sep = "";
260  for (letter_t l: alphabet_)
261  {
262  o << sep;
263  if (! this->is_letter(l))
264  o << "\\mathit{";
265  this->print(l, o, fmt);
266  if (! this->is_letter(l))
267  o << '}';
268  sep = ", ";
269  }
270  if (open_)
271  o << sep << "\\ldots";
272  o << "\\}";
273  }
274  else if (fmt == format::text)
275  {
276  o << sname() << '(';
277  for (letter_t l: alphabet_)
278  // FIXME: escape ')' and '-'.
279  this->print(l, o, fmt);
280  // Don't display openness here, as our "make()" parser is
281  // not ready for it.
282  o << ')';
283  }
284  else
285  raise(sname(), ": print_set: invalid format: ", fmt);
286  return o;
287  }
288 
290  friend set_alphabet
291  intersection(const set_alphabet& lhs, const set_alphabet& rhs)
292  {
293  return {intersection(lhs.alphabet_, rhs.alphabet_)};
294  }
295 
297  friend set_alphabet
298  get_union(const set_alphabet& lhs, const set_alphabet& rhs)
299  {
300  return {get_union(lhs.alphabet_, rhs.alphabet_)};
301  }
302 
303  private:
304  // FIXME: OMG...
306  mutable bool open_ = false;
307  };
308 }
STL namespace.
std::ostream & str_escape(std::ostream &os, const std::string &str)
Output a string, escaping special characters.
Definition: escape.cc:43
typename letters_t::const_iterator const_iterator
Definition: setalpha.hh:226
std::istringstream is
The input stream: the specification to translate.
Definition: translate.cc:372
typename L::word_t word_t
Definition: setalpha.hh:26
char eat(std::istream &is, char c)
Check lookahead character and advance.
Definition: stream.cc:37
typename L::letter_t letter_t
Definition: setalpha.hh:25
auto add_range_(Letter l1, Letter l2) -> enable_if_t< has_range< Letter >
Definition: setalpha.hh:148
typename std::enable_if< Cond, T >::type enable_if_t
Definition: type_traits.hh:16
bool open(bool o) const
Whether unknown letters should be added, or rejected.
Definition: setalpha.hh:113
friend set_alphabet get_union(const set_alphabet &lhs, const set_alphabet &rhs)
Compute the union with another alphabet.
Definition: setalpha.hh:298
A set of letters of type L.
Definition: setalpha.hh:22
set_alphabet(const letters_t &l)
Definition: setalpha.hh:106
auto add_range_(Letter, Letter) -> enable_if_t<!has_range< Letter >
Definition: setalpha.hh:162
set_alphabet()=default
const_iterator begin() const
Definition: setalpha.hh:228
set_alphabet &bool has(letter_t l) const
Whether l is a letter.
Definition: setalpha.hh:170
An input/output format.
Definition: format.hh:11
std::ostream & print(const Aut &aut, std::ostream &out, const std::string &format)
Definition: print.hh:77
static set_alphabet make(std::istream &is)
Definition: setalpha.hh:37
auto add_range(letter_t l1, letter_t l2) -> set_alphabet &
Add a range of letters, if it is accepted by the labelset.
Definition: setalpha.hh:141
void require(bool b, Args &&...args)
If b is not verified, raise an error with args as message.
Definition: raise.hh:75
letter_t value_type
The type of our values, when seen as a container.
Definition: setalpha.hh:29
friend set_alphabet intersection(const set_alphabet &lhs, const set_alphabet &rhs)
Compute the intersection with another alphabet.
Definition: setalpha.hh:291
set_alphabet & add_letter(letter_t l)
Modify this by adding l, and return *this.
Definition: setalpha.hh:121
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
const_iterator find(letter_t l) const
Definition: setalpha.hh:248
const_iterator cend() const
Definition: setalpha.hh:243
typename letters_t::const_iterator iterator
Definition: setalpha.hh:225
word_t get_word(std::istream &i) const
Extract and return the next word from i.
Definition: setalpha.hh:184
set_alphabet(const std::initializer_list< letter_t > &l)
Definition: setalpha.hh:102
std::ostream & print_set(std::ostream &o, format fmt={}) const
Definition: setalpha.hh:254
ATTRIBUTE_PURE bool has(const std::deque< T, Allocator > &s, const T &e)
Whether e is member of s.
Definition: deque.hh:13
const_iterator cbegin() const
Definition: setalpha.hh:238
std::set< letter_t, vcsn::less< L, letter_t >> letters_t
Definition: setalpha.hh:27
static symbol sname()
Definition: setalpha.hh:31
const_iterator end() const
Definition: setalpha.hh:233
Whether the genset supports the range concept: whether we can use '++' on letters.
Definition: setalpha.hh:132
letters_t alphabet_
Definition: setalpha.hh:305