piranha  0.10
km_commons.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_DETAIL_KM_COMMONS_HPP
30 #define PIRANHA_DETAIL_KM_COMMONS_HPP
31 
32 #include <algorithm>
33 #include <set>
34 #include <stdexcept>
35 #include <string>
36 #include <vector>
37 
38 #include <piranha/config.hpp>
39 #include <piranha/exceptions.hpp>
40 #include <piranha/symbol_utils.hpp>
41 #include <piranha/type_traits.hpp>
42 
43 // Common routines for use in kronecker monomial classes.
44 
45 namespace piranha
46 {
47 namespace detail
48 {
49 
50 template <typename VType, typename KaType, typename T>
51 inline VType km_unpack(const symbol_fset &args, const T &value)
52 {
53  if (unlikely(args.size() > VType::max_size)) {
54  piranha_throw(std::invalid_argument, "the size of the input arguments set (" + std::to_string(args.size())
55  + ") is larger than the maximum allowed size ("
56  + std::to_string(VType::max_size) + ")");
57  }
58  VType retval(static_cast<typename VType::size_type>(args.size()), 0);
59  piranha_assert(args.size() == retval.size());
60  KaType::decode(retval, value);
61  return retval;
62 }
63 
64 template <typename VType, typename KaType, typename T>
65 inline T km_merge_symbols(const symbol_idx_fmap<symbol_fset> &ins_map, const symbol_fset &args, const T &value)
66 {
67  if (unlikely(!ins_map.size())) {
68  // If we have nothing to insert, it means something is wrong: we should never invoke
69  // symbol merging if there's nothing to merge.
70  piranha_throw(std::invalid_argument,
71  "invalid argument(s) for symbol set merging: the insertion map cannot be empty");
72  }
73  if (unlikely(ins_map.rbegin()->first > args.size())) {
74  // The last element of the insertion map must be at most args.size(), which means that there
75  // are symbols to be appended at the end.
76  piranha_throw(std::invalid_argument,
77  "invalid argument(s) for symbol set merging: the last index of the insertion map ("
78  + std::to_string(ins_map.rbegin()->first) + ") must not be greater than the key's size ("
79  + std::to_string(args.size()) + ")");
80  }
81  const auto old_vector = km_unpack<VType, KaType>(args, value);
82  VType new_vector;
83  auto map_it = ins_map.begin();
84  const auto map_end = ins_map.end();
85  for (decltype(old_vector.size()) i = 0; i < old_vector.size(); ++i) {
86  if (map_it != map_end && map_it->first == i) {
87  // NOTE: if we move to TLS vector for unpacking, this can just
88  // become a resize (below as well).
89  std::fill_n(std::back_inserter(new_vector), map_it->second.size(), T(0));
90  ++map_it;
91  }
92  new_vector.push_back(old_vector[i]);
93  }
94  // We could still have symbols which need to be appended at the end.
95  if (map_it != map_end) {
96  std::fill_n(std::back_inserter(new_vector), map_it->second.size(), T(0));
97  piranha_assert(map_it + 1 == map_end);
98  }
99  // Return new encoded value.
100  return KaType::encode(new_vector);
101 }
102 
103 template <typename VType, typename KaType, typename T>
104 inline void km_trim_identify(std::vector<char> &candidates, const symbol_fset &args, const T &value)
105 {
106  if (unlikely(candidates.size() != args.size())) {
107  piranha_throw(std::invalid_argument, "invalid mask for trim_identify(): the size of the mask ("
108  + std::to_string(candidates.size())
109  + ") differs from the size of the reference symbol set ("
110  + std::to_string(args.size()) + ")");
111  }
112  const VType tmp = km_unpack<VType, KaType>(args, value);
113  for (decltype(tmp.size()) i = 0; i < tmp.size(); ++i) {
114  if (tmp[i] != T(0)) {
115  candidates[static_cast<decltype(candidates.size())>(i)] = 0;
116  }
117  }
118 }
119 
120 template <typename VType, typename KaType, typename T>
121 inline T km_trim(const std::vector<char> &trim_idx, const symbol_fset &args, const T &value)
122 {
123  if (unlikely(trim_idx.size() != args.size())) {
124  piranha_throw(std::invalid_argument, "invalid mask for trim(): the size of the mask ("
125  + std::to_string(trim_idx.size())
126  + ") differs from the size of the reference symbol set ("
127  + std::to_string(args.size()) + ")");
128  }
129  const VType tmp = km_unpack<VType, KaType>(args, value);
130  VType new_vector;
131  for (decltype(tmp.size()) i = 0; i < tmp.size(); ++i) {
132  if (!trim_idx[static_cast<decltype(trim_idx.size())>(i)]) {
133  new_vector.push_back(tmp[i]);
134  }
135  }
136  return KaType::encode(new_vector);
137 }
138 }
139 }
140 
141 #endif
Exceptions.
#define piranha_throw(exception_type,...)
Exception-throwing macro.
Definition: exceptions.hpp:118
boost::container::flat_set< std::string > symbol_fset
Flat set of symbols.
Root piranha namespace.
Definition: array_key.hpp:52
Type traits.