piranha  0.10
array_key.hpp
1 /* Copyright 2009-2017 Francesco Biscani (bluescarni@gmail.com)
2 
3 This file is part of the Piranha library.
4 
5 The Piranha library is free software; you can redistribute it and/or modify
6 it under the terms of either:
7 
8  * the GNU Lesser General Public License as published by the Free
9  Software Foundation; either version 3 of the License, or (at your
10  option) any later version.
11 
12 or
13 
14  * the GNU General Public License as published by the Free Software
15  Foundation; either version 3 of the License, or (at your option) any
16  later version.
17 
18 or both in parallel, as here.
19 
20 The Piranha library is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 for more details.
24 
25 You should have received copies of the GNU General Public License and the
26 GNU Lesser General Public License along with the Piranha library. If not,
27 see https://www.gnu.org/licenses/. */
28 
29 #ifndef PIRANHA_ARRAY_KEY_HPP
30 #define PIRANHA_ARRAY_KEY_HPP
31 
32 #include <algorithm>
33 #include <cstddef>
34 #include <functional>
35 #include <initializer_list>
36 #include <iterator>
37 #include <stdexcept>
38 #include <string>
39 #include <tuple>
40 #include <type_traits>
41 #include <utility>
42 #include <vector>
43 
44 #include <piranha/config.hpp>
45 #include <piranha/exceptions.hpp>
46 #include <piranha/math.hpp>
47 #include <piranha/safe_cast.hpp>
48 #include <piranha/small_vector.hpp>
49 #include <piranha/symbol_utils.hpp>
50 #include <piranha/type_traits.hpp>
51 
52 namespace piranha
53 {
54 
56 
85 template <typename T, typename Derived, typename S = std::integral_constant<std::size_t, 0u>>
86 class array_key
87 {
88  // NOTE: the general idea about requirements here is that these are the bare minimum
89  // to make a simple array_key suitable as key in a piranha::series. There are additional
90  // requirements which are optional and checked in the member functions.
91  PIRANHA_TT_CHECK(std::is_constructible, T, int);
92  PIRANHA_TT_CHECK(is_less_than_comparable, T);
93  PIRANHA_TT_CHECK(is_equality_comparable, T);
94  PIRANHA_TT_CHECK(is_hashable, T);
95  PIRANHA_TT_CHECK(has_is_zero, T);
96 
97 public:
109 
112  array_key() = default;
114 
117  array_key(const array_key &) = default;
119  array_key(array_key &&) = default;
120 
121 private:
122  // Enabler for constructor from init list.
123  template <typename U>
124  using init_list_enabler = enable_if_t<std::is_constructible<container_type, std::initializer_list<U>>::value, int>;
125 
126 public:
128 
138  template <typename U, init_list_enabler<U> = 0>
139  explicit array_key(std::initializer_list<U> list) : m_container(list)
140  {
141  }
143 
153  explicit array_key(const symbol_fset &args)
154  {
155  // NOTE: the back inserter transforms the assignment into a push_back() operation.
156  std::fill_n(std::back_inserter(m_container), args.size(), value_type(0));
157  }
158 
159 private:
160  // Enabler for generic ctor.
161  template <typename U>
162  using generic_ctor_enabler = enable_if_t<has_safe_cast<value_type, U>::value, int>;
163 
164 public:
166 
184  template <typename U, typename Derived2, typename S2, generic_ctor_enabler<U> = 0>
185  explicit array_key(const array_key<U, Derived2, S2> &other, const symbol_fset &args)
186  {
187  if (unlikely(other.size() != args.size())) {
188  piranha_throw(std::invalid_argument,
189  "inconsistent sizes in the generic array_key constructor: the size of the array ("
190  + std::to_string(other.size()) + ") differs from the size of the symbol set ("
191  + std::to_string(args.size()) + ")");
192  }
193  std::transform(other.begin(), other.end(), std::back_inserter(m_container),
194  [](const U &x) { return safe_cast<value_type>(x); });
195  }
198  {
199  PIRANHA_TT_CHECK(is_container_element, Derived);
200  PIRANHA_TT_CHECK(std::is_base_of, array_key, Derived);
201  }
203 
210  array_key &operator=(const array_key &other) = default;
212 
217  array_key &operator=(array_key &&other) = default;
219 
223  {
224  return m_container.begin();
225  }
227 
231  {
232  return m_container.end();
233  }
235 
239  {
240  return m_container.begin();
241  }
243 
247  {
248  return m_container.end();
249  }
251 
254  size_type size() const
255  {
256  return m_container.size();
257  }
259 
266  void resize(const size_type &new_size)
267  {
268  m_container.resize(new_size);
269  }
271 
277  {
278  return m_container[i];
279  }
281 
286  const value_type &operator[](const size_type &i) const
287  {
288  return m_container[i];
289  }
291 
296  std::size_t hash() const
297  {
298  return m_container.hash();
299  }
301 
309  {
310  m_container.push_back(std::move(x));
311  }
313 
320  void push_back(const value_type &x)
321  {
323  }
325 
332  bool operator==(const array_key &other) const
333  {
334  return m_container == other.m_container;
335  }
337 
344  bool operator!=(const array_key &other) const
345  {
346  return !operator==(other);
347  }
349 
367  void trim_identify(std::vector<char> &trim_mask, const symbol_fset &args) const
368  {
369  auto sbe = size_begin_end();
370  if (unlikely(std::get<0>(sbe) != args.size())) {
371  piranha_throw(std::invalid_argument, "invalid symbol set for trim_identify(): the size of the array ("
372  + std::to_string(std::get<0>(sbe))
373  + ") differs from the size of the reference symbol set ("
374  + std::to_string(args.size()) + ")");
375  }
376  if (unlikely(std::get<0>(sbe) != trim_mask.size())) {
377  piranha_throw(std::invalid_argument,
378  "invalid mask for trim_identify(): the size of the array (" + std::to_string(std::get<0>(sbe))
379  + ") differs from the size of the mask (" + std::to_string(trim_mask.size()) + ")");
380  }
381  for (decltype(trim_mask.size()) i = 0; std::get<1>(sbe) != std::get<2>(sbe); ++i, ++std::get<1>(sbe)) {
382  if (!math::is_zero(*std::get<1>(sbe))) {
383  // The current element of the array is nonzero, set the
384  // corresponding element in the mask to zero.
385  trim_mask[i] = 0;
386  }
387  }
388  }
390 
409  Derived trim(const std::vector<char> &trim_mask, const symbol_fset &args) const
410  {
411  auto sbe = size_begin_end();
412  if (unlikely(std::get<0>(sbe) != args.size())) {
413  piranha_throw(std::invalid_argument, "invalid arguments set for trim(): the size of the array ("
414  + std::to_string(std::get<0>(sbe))
415  + ") differs from the size of the reference symbol set ("
416  + std::to_string(args.size()) + ")");
417  }
418  if (unlikely(std::get<0>(sbe) != trim_mask.size())) {
419  piranha_throw(std::invalid_argument,
420  "invalid mask for trim(): the size of the array (" + std::to_string(std::get<0>(sbe))
421  + ") differs from the size of the mask (" + std::to_string(trim_mask.size()) + ")");
422  }
423  Derived retval;
424  for (decltype(trim_mask.size()) i = 0; std::get<1>(sbe) != std::get<2>(sbe); ++i, ++std::get<1>(sbe)) {
425  if (!trim_mask[i]) {
426  retval.push_back(*std::get<1>(sbe));
427  }
428  }
429  return retval;
430  }
431 
432 private:
433  // Enabler for addition and subtraction.
434  template <typename U>
435  using add_t = decltype(std::declval<U const &>().add(std::declval<U &>(), std::declval<U const &>()));
436  template <typename U>
437  using sub_t = decltype(std::declval<U const &>().sub(std::declval<U &>(), std::declval<U const &>()));
438  template <typename U>
439  using add_enabler = enable_if_t<is_detected<add_t, U>::value, int>;
440  template <typename U>
441  using sub_enabler = enable_if_t<is_detected<sub_t, U>::value, int>;
442 
443 public:
445 
458  template <typename U = container_type, add_enabler<U> = 0>
459  void vector_add(array_key &retval, const array_key &other) const
460  {
461  m_container.add(retval.m_container, other.m_container);
462  }
464 
477  template <typename U = container_type, sub_enabler<U> = 0>
478  void vector_sub(array_key &retval, const array_key &other) const
479  {
480  m_container.sub(retval.m_container, other.m_container);
481  }
483 
508  Derived merge_symbols(const symbol_idx_fmap<symbol_fset> &ins_map, const symbol_fset &args) const
509  {
510  Derived retval;
511  vector_key_merge_symbols(retval.m_container, m_container, ins_map, args);
512  return retval;
513  }
514 
515 protected:
518 
519 public:
521 
525  auto size_begin_end() const -> decltype(m_container.size_begin_end())
526  {
527  return m_container.size_begin_end();
528  }
530 
535  {
536  return m_container.size_begin_end();
537  }
538 };
539 }
540 
541 namespace std
542 {
543 
545 template <typename T, typename Derived, typename S>
546 struct hash<piranha::array_key<T, Derived, S>> {
548  typedef size_t result_type;
552 
558  {
559  return a.hash();
560  }
561 };
562 }
563 
564 #endif
Derived trim(const std::vector< char > &trim_mask, const symbol_fset &args) const
Trim.
Definition: array_key.hpp:409
const value_type & operator[](const size_type &i) const
Const element access.
Definition: array_key.hpp:286
Small vector class.
const_iterator begin() const
Begin const iterator.
Definition: array_key.hpp:238
void push_back(const value_type &x)
Copy-add element at the end.
iterator begin()
Mutable begin iterator.
Equality-comparable type trait.
value_type & operator[](const size_type &i)
Element access.
Definition: array_key.hpp:276
Hashable type trait.
container_type m_container
Internal container.
Definition: array_key.hpp:517
Exceptions.
auto size_begin_end() -> decltype(m_container.size_begin_end())
Get size, begin and end iterator.
Definition: array_key.hpp:534
STL namespace.
void push_back(const value_type &x)
Copy-add element at the end.
Definition: array_key.hpp:320
array_key(const symbol_fset &args)
Constructor from piranha::symbol_fset.
Definition: array_key.hpp:153
result_type operator()(const argument_type &a) const
Hash operator.
Definition: array_key.hpp:557
Type trait to detect the presence of the piranha::math::is_zero() function.
Definition: math.hpp:1049
value_type const * const_iterator
Const iterator type.
bool operator!=(const array_key &other) const
Inequality operator.
Definition: array_key.hpp:344
array_key & operator=(const array_key &other)=default
Copy assignment operator.
T value_type
Alias for T.
size_type size() const
Size.
~array_key()
Trivial destructor.
Definition: array_key.hpp:197
array_key(const array_key< U, Derived2, S2 > &other, const symbol_fset &args)
Constructor from piranha::array_key parametrized on a generic type.
Definition: array_key.hpp:185
Derived merge_symbols(const symbol_idx_fmap< symbol_fset > &ins_map, const symbol_fset &args) const
Merge symbols.
Definition: array_key.hpp:508
bool operator==(const array_key &other) const
Equality operator.
Definition: array_key.hpp:332
#define piranha_throw(exception_type,...)
Exception-throwing macro.
Definition: exceptions.hpp:118
iterator end()
Mutable end iterator.
boost::container::flat_set< std::string > symbol_fset
Flat set of symbols.
auto size_begin_end() const -> decltype(m_container.size_begin_end())
Get size, begin and end iterator (const version).
Definition: array_key.hpp:525
Array key.
Definition: array_key.hpp:86
const_iterator end() const
End const iterator.
Definition: array_key.hpp:246
value_type * iterator
Iterator type.
array_key()=default
Defaulted default constructor.
typename container_type::iterator iterator
Iterator type.
Definition: array_key.hpp:103
typename container_type::size_type size_type
Size type.
Definition: array_key.hpp:107
bool is_zero(const T &x)
Zero test.
Definition: math.hpp:133
boost::container::flat_map< symbol_idx, T > symbol_idx_fmap
Flat map of symbol indices.
void resize(const size_type &size)
Resize.
typename container_type::value_type value_type
Value type.
Definition: array_key.hpp:101
typename container_type::const_iterator const_iterator
Const iterator type.
Definition: array_key.hpp:105
Root piranha namespace.
Definition: array_key.hpp:52
void vector_sub(array_key &retval, const array_key &other) const
Vector sub.
Definition: array_key.hpp:478
Type traits.
array_key(std::initializer_list< U > list)
Constructor from initializer list.
Definition: array_key.hpp:139
Less-than-comparable type trait.
std::size_t hash() const
Hash value.
Definition: array_key.hpp:296
piranha::array_key< T, Derived, S > argument_type
Argument type.
Definition: array_key.hpp:550
void vector_add(array_key &retval, const array_key &other) const
Vector add.
Definition: array_key.hpp:459
std::size_t hash() const
Hash method.
size_type_impl size_type
A fundamental unsigned integer type representing the number of elements stored in the vector...
iterator begin()
Begin iterator.
Definition: array_key.hpp:222
void push_back(value_type &&x)
Move-add element at the end.
Definition: array_key.hpp:308
Type trait for well-behaved container elements.
size_type size() const
Size.
Definition: array_key.hpp:254
std::tuple< size_type, iterator, iterator > size_begin_end()
Size, begin and end.
void trim_identify(std::vector< char > &trim_mask, const symbol_fset &args) const
Identify symbols that can be trimmed.
Definition: array_key.hpp:367
iterator end()
End iterator.
Definition: array_key.hpp:230
void sub(small_vector &retval, const small_vector &other) const
Vector subtraction.
safe_cast_type< To, From > safe_cast(const From &x)
Safe cast.
Definition: safe_cast.hpp:219
void resize(const size_type &new_size)
Resize the internal array container.
Definition: array_key.hpp:266
void add(small_vector &retval, const small_vector &other) const
Vector addition.