29 #ifndef PIRANHA_SYMBOL_UTILS_HPP 30 #define PIRANHA_SYMBOL_UTILS_HPP 38 #include <type_traits> 42 #include <boost/container/container_fwd.hpp> 43 #include <boost/container/flat_map.hpp> 44 #include <boost/container/flat_set.hpp> 45 #include <boost/iterator/filter_iterator.hpp> 46 #include <boost/iterator/transform_iterator.hpp> 47 #include <boost/iterator/zip_iterator.hpp> 48 #include <boost/tuple/tuple.hpp> 50 #include <piranha/config.hpp> 52 #include <piranha/safe_cast.hpp> 68 using symbol_fmap = boost::container::flat_map<std::string, T>;
94 template <
typename Vector>
98 using value_type =
typename Vector::value_type;
99 if (unlikely(v.size() != orig_args.size())) {
101 piranha_throw(std::invalid_argument,
"invalid argument(s) for symbol set merging: the size of the original " 103 + std::to_string(orig_args.size())
104 +
") must be equal to the key's size (" + std::to_string(v.size())
107 if (unlikely(!ins_map.size())) {
111 "invalid argument(s) for symbol set merging: the insertion map cannot be empty");
113 if (unlikely(ins_map.rbegin()->first > v.size())) {
117 "invalid argument(s) for symbol set merging: the last index of the insertion map (" 118 + std::to_string(ins_map.rbegin()->first) +
") must not be greater than the key's size (" 119 + std::to_string(v.size()) +
")");
122 piranha_assert(retval.size() == 0u);
123 auto map_it = ins_map.begin();
124 const auto map_end = ins_map.end();
125 for (decltype(v.size()) i = 0; i < v.size(); ++i) {
126 if (map_it != map_end && map_it->first == i) {
130 std::fill_n(std::back_inserter(retval), map_it->second.size(), value_type(0));
133 retval.push_back(v[i]);
136 if (map_it != map_end) {
137 std::fill_n(std::back_inserter(retval), map_it->second.size(), value_type(0));
138 piranha_assert(map_it + 1 == map_end);
169 inline std::tuple<symbol_fset, symbol_idx_fmap<symbol_fset>, symbol_idx_fmap<symbol_fset>>
173 PIRANHA_MAYBE_TLS std::vector<std::string> v_cache;
174 using v_cache_size_t = decltype(v_cache.size());
177 if (unlikely(s2.size() > std::numeric_limits<v_cache_size_t>::max()
178 || s1.size() > std::numeric_limits<v_cache_size_t>::max() - s2.size())) {
180 "overflow in the computation of the size of the union of two symbol sets of sizes " 181 + std::to_string(s1.size()) +
" and " + std::to_string(s2.size()));
183 const auto max_size =
static_cast<v_cache_size_t
>(
static_cast<v_cache_size_t
>(s1.size()) + s2.size());
184 if (v_cache.size() < max_size) {
186 v_cache.resize(max_size);
189 const auto u_end = std::set_union(s1.begin(), s1.end(), s2.begin(), s2.end(), v_cache.begin());
191 symbol_fset u_set{boost::container::ordered_unique_range_t{}, v_cache.begin(), u_end};
192 auto compute_map = [&u_set](
const symbol_fset &s) {
201 retval.reserve(
static_cast<decltype(retval.size())
>(s.size() + 1u));
202 auto u_it = u_set.cbegin();
203 for (decltype(s.size()) i = 0; i < s.size(); ++i, ++u_it) {
204 piranha_assert(u_it != u_set.end());
205 const auto &cur_sym = *s.nth(i);
206 if (*u_it < cur_sym) {
207 const auto new_it = retval.emplace_hint(retval.end(), i,
symbol_fset{*u_it});
208 for (++u_it; *u_it < cur_sym; ++u_it) {
209 piranha_assert(u_it != u_set.end());
210 new_it->second.insert(new_it->second.end(), *u_it);
212 piranha_assert(*u_it == cur_sym);
216 if (u_it != u_set.cend()) {
217 const auto new_it = retval.emplace_hint(retval.end(), s.size(),
symbol_fset{*u_it});
218 for (++u_it; u_it != u_set.cend(); ++u_it) {
219 new_it->second.insert(new_it->second.end(), *u_it);
224 return std::make_tuple(std::move(u_set), compute_map(s1), compute_map(s2));
239 return ref.index_of(ref.find(name));
242 inline namespace impl
246 struct mask_ss_filter {
247 template <
typename Tuple>
248 bool operator()(
const Tuple &t)
const 253 return t.template get<0>() ==
char(0);
258 struct mask_ss_transform {
259 template <
typename Tuple>
260 const std::string &operator()(
const Tuple &t)
const 264 return t.template get<1>();
289 if (unlikely(s.size() != mask.size())) {
292 "invalid argument(s) for symbol set trimming: the size of the original symbol set (" 293 + std::to_string(s.size()) +
") differs from the size of trimming mask (" 294 + std::to_string(mask.size()) +
")");
297 auto zip_begin = boost::make_zip_iterator(boost::make_tuple(mask.begin(), s.begin()));
298 auto zip_end = boost::make_zip_iterator(boost::make_tuple(mask.end(), s.end()));
301 auto filter_begin = boost::make_filter_iterator(mask_ss_filter{}, zip_begin, zip_end);
302 auto filter_end = boost::make_filter_iterator(mask_ss_filter{}, zip_end, zip_end);
305 auto trans_begin = boost::make_transform_iterator(filter_begin, mask_ss_transform{});
306 auto trans_end = boost::make_transform_iterator(filter_end, mask_ss_transform{});
309 return symbol_fset{boost::container::ordered_unique_range_t{}, trans_begin, trans_end};
331 using it_diff_t = decltype(s1.end() - s1.begin());
332 using it_udiff_t = std::make_unsigned<it_diff_t>::type;
335 if (unlikely(s1.size() >
static_cast<it_udiff_t
>(std::numeric_limits<it_diff_t>::max()))) {
338 "overflow in the determination of the indices of the intersection of two symbol_fset: the size of one of " 340 + std::to_string(s1.size())
341 +
") is larger than the maximum value representable by the difference type of symbol_fset's iterators (" 342 + std::to_string(std::numeric_limits<it_diff_t>::max()) +
")");
345 PIRANHA_MAYBE_TLS std::vector<symbol_idx> vidx;
348 const auto max_size = std::min(s1.size(), s2.size());
350 if (vidx.size() < max_size) {
351 vidx.resize(
safe_cast<decltype(vidx.size())>(max_size));
353 auto vidx_it = vidx.begin();
354 const auto s1_it_b = s1.begin(), s1_it_f = s1.end();
355 auto s1_it = s1_it_b;
356 for (
const auto &sym : s2) {
359 s1_it = std::lower_bound(s1_it, s1_it_f, sym);
360 if (s1_it == s1_it_f) {
374 piranha_assert(vidx_it != vidx.end());
375 *(vidx_it++) = safe_cast<symbol_idx>(static_cast<it_udiff_t>(s1_it - s1_it_b));
383 assert(std::is_sorted(vidx.begin(), vidx_it));
384 return symbol_idx_fset{boost::container::ordered_unique_range_t{}, vidx.begin(), vidx_it};
387 inline namespace impl
391 template <
typename T>
392 using has_sm_intersect_idx
393 = conjunction<std::is_default_constructible<T>, std::is_copy_assignable<T>, std::is_copy_constructible<T>>;
395 template <
typename T>
396 using sm_intersect_idx_enabler = enable_if_t<has_sm_intersect_idx<T>::value,
int>;
424 template <
typename T, sm_
intersect_
idx_enabler<T> = 0>
430 using it_diff_t = decltype(s.end() - s.begin());
431 using it_udiff_t = std::make_unsigned<it_diff_t>::type;
434 if (unlikely(s.size() >
static_cast<it_udiff_t
>(std::numeric_limits<it_diff_t>::max()))) {
437 "overflow in the determination of the indices of the intersection of a symbol_fset and a symbol_fmap: the " 439 + std::to_string(s.size())
440 +
") is larger than the maximum value representable by the difference type of symbol_fset's iterators (" 441 + std::to_string(std::numeric_limits<it_diff_t>::max()) +
")");
444 PIRANHA_MAYBE_TLS std::vector<std::pair<symbol_idx, T>> vidx;
448 = std::min<
typename std::common_type<decltype(s.size()), decltype(m.size())>::type>(s.size(), m.size());
450 if (vidx.size() < max_size) {
451 vidx.resize(
safe_cast<decltype(vidx.size())>(max_size));
453 auto vidx_it = vidx.begin();
454 const auto s_it_b = s.begin(), s_it_f = s.end();
456 for (
const auto &p : m) {
457 const auto &sym = p.first;
460 s_it = std::lower_bound(s_it, s_it_f, sym);
461 if (s_it == s_it_f) {
475 piranha_assert(vidx_it != vidx.end());
478 vidx_it->second = p.second;
487 return symbol_idx_fmap<T>{boost::container::ordered_unique_range_t{}, vidx.begin(), vidx_it};
symbol_idx_fset ss_intersect_idx(const symbol_fset &s1, const symbol_fset &s2)
Find the indices of the intersection of two symbol_fset.
boost::container::flat_map< std::string, T > symbol_fmap
Flat map of symbols.
std::tuple< symbol_fset, symbol_idx_fmap< symbol_fset >, symbol_idx_fmap< symbol_fset > > ss_merge(const symbol_fset &s1, const symbol_fset &s2)
Merge two symbol_fset.
#define piranha_throw(exception_type,...)
Exception-throwing macro.
boost::container::flat_set< std::string > symbol_fset
Flat set of symbols.
symbol_idx_fmap< T > sm_intersect_idx(const symbol_fset &s, const symbol_fmap< T > &m)
Find the indices of the intersection of a symbol_fset and a symbol_fmap.
symbol_fset::size_type symbol_idx
Symbol index.
symbol_idx ss_index_of(const symbol_fset &ref, const std::string &name)
Identify the index of a symbol in a symbol_fset.
symbol_fset ss_trim(const symbol_fset &s, const std::vector< char > &mask)
Trim a symbol_fset.
boost::container::flat_map< symbol_idx, T > symbol_idx_fmap
Flat map of symbol indices.
boost::container::flat_set< symbol_idx > symbol_idx_fset
Flat set of symbol indices.
safe_cast_type< To, From > safe_cast(const From &x)
Safe cast.