15 #ifndef GTIRB_UTILITY_H
16 #define GTIRB_UTILITY_H
22 #include <boost/iterator/iterator_categories.hpp>
23 #include <boost/iterator/iterator_facade.hpp>
24 #include <boost/iterator/iterator_traits.hpp>
25 #include <boost/iterator/transform_iterator.hpp>
26 #include <boost/range/iterator_range.hpp>
30 #include <type_traits>
51 template <
typename ForwardIterator,
52 typename Compare = std::less<
53 typename std::iterator_traits<ForwardIterator>::value_type>>
54 class MergeSortedIterator
55 :
public boost::iterator_facade<
56 MergeSortedIterator<ForwardIterator, Compare>,
57 typename std::iterator_traits<ForwardIterator>::value_type,
58 boost::forward_traversal_tag,
59 typename std::iterator_traits<ForwardIterator>::reference,
60 typename std::iterator_traits<ForwardIterator>::difference_type> {
65 MergeSortedIterator() =
default;
78 template <
typename OtherForwardIterator>
80 const MergeSortedIterator<OtherForwardIterator, Compare>& MSI,
82 std::is_convertible_v<OtherForwardIterator, ForwardIterator>,
void*> =
84 : Ranges(MSI.Ranges.begin(), MSI.Ranges.end()) {}
92 template <
typename RangeIteratorRange>
93 explicit MergeSortedIterator(RangeIteratorRange RangeRange) {
94 for (
const auto& Range : RangeRange) {
95 if (
auto RBegin = Range.begin(), REnd = Range.end(); RBegin != REnd) {
96 Ranges.emplace_back(RBegin, REnd);
100 std::make_heap(Ranges.begin(), Ranges.end(), rangeGreaterThan);
110 template <
typename RangeIterator>
111 MergeSortedIterator(RangeIterator Begin, RangeIterator End)
112 : MergeSortedIterator(boost::make_iterator_range(Begin, End)) {}
115 typename std::iterator_traits<ForwardIterator>::reference
116 dereference()
const {
117 assert(!Ranges.empty() &&
"Attempt to dereference end of iterator!");
118 return *Ranges.front().first;
121 bool equal(
const MergeSortedIterator<ForwardIterator, Compare>& Other)
const {
122 return Ranges == Other.Ranges;
126 assert(!Ranges.empty() &&
"Attempt to increment end of iterator!");
130 std::pop_heap(Ranges.begin(), Ranges.end(), rangeGreaterThan);
131 ++Ranges.back().first;
132 if (Ranges.back().first == Ranges.back().second) {
135 std::push_heap(Ranges.begin(), Ranges.end(), rangeGreaterThan);
140 template <
typename OtherForwardIterator,
typename OtherCompare>
141 friend class MergeSortedIterator;
143 using RangeType = std::pair<ForwardIterator, ForwardIterator>;
148 static bool rangeGreaterThan(
const RangeType& R1,
const RangeType& R2) {
149 if (R1.first == R1.second)
152 if (R2.first == R2.second)
156 return Compare()(*R2.first, *R1.first);
162 std::vector<RangeType> Ranges;
172 template <
typename NodeType>
auto key(
const NodeType* N)
const {
173 return std::make_tuple(N->getAddress(), N->getSize(), N->getUUID());
176 template <
typename NodeType>
177 bool operator()(
const NodeType* N1,
const NodeType* N2)
const {
178 return key(N1) < key(N2);
181 template <
typename NodeType,
182 typename = std::enable_if_t<!std::is_pointer_v<NodeType>>>
183 bool operator()(
const NodeType& N1,
const NodeType& N2)
const {
184 return operator()(&N1, &N2);
188 template <
typename NodeType>
189 bool operator()(
const NodeType* N1,
const Addr& A2)
const {
190 return N1->getAddress() < A2;
194 template <
typename NodeType>
195 bool operator()(
const Addr& A1,
const NodeType* N2)
const {
196 return A1 < N2->getAddress();
203 AddressLess::operator()<CodeBlock>(
const CodeBlock* B1,
204 const CodeBlock* B2)
const;
213 AddressLess::operator()<DataBlock>(
const DataBlock* B1,
214 const DataBlock* B2)
const;
222 bool operator()(
const Node* N1,
const Node* N2)
const {
223 return operator()(*N1, *N2);
225 bool operator()(
const Node& N1,
const Node& N2)
const;
234 template <
typename T>
struct ArbitraryLess {
235 bool operator()(
const T& N1,
const T& N2)
const {
return &N1 < &N2; }
248 template <
typename T,
typename Method, Method Begin, Method End>
249 struct NodeToChildRange {
250 boost::iterator_range<decltype((std::declval<T>().*Begin)())>
251 operator()(T& N)
const {
252 return boost::make_iterator_range((N.*Begin)(), (N.*End)());
265 template <
typename T>
266 using NodeToBlockRange = NodeToChildRange<
268 std::conditional_t<std::is_const_v<T>,
271 &T::blocks_begin, &T::blocks_end>;
281 template <
typename T>
282 using NodeToCodeBlockRange = NodeToChildRange<
284 std::conditional_t<std::is_const_v<T>,
285 typename T::const_code_block_iterator (T::*)()
const,
286 typename T::code_block_iterator (T::*)()>,
287 &T::code_blocks_begin, &T::code_blocks_end>;
297 template <
typename T>
298 using NodeToDataBlockRange = NodeToChildRange<
300 std::conditional_t<std::is_const_v<T>,
301 typename T::const_data_block_iterator (T::*)()
const,
302 typename T::data_block_iterator (T::*)()>,
303 &T::data_blocks_begin, &T::data_blocks_end>;
315 template <
typename T>
316 using NodeToSymbolicExpressionRange = NodeToChildRange<
318 std::conditional_t<std::is_const_v<T>,
319 typename T::const_symbolic_expression_iterator (T::*)()
321 typename T::symbolic_expression_iterator (T::*)()>,
322 &T::symbolic_expressions_begin, &T::symbolic_expressions_end>;
332 template <
typename T>
333 using NodeToByteIntervalRange = NodeToChildRange<
335 std::conditional_t<std::is_const_v<T>,
336 typename T::const_byte_interval_iterator (T::*)()
const,
337 typename T::byte_interval_iterator (T::*)()>,
338 &T::byte_intervals_begin, &T::byte_intervals_end>;
348 template <
typename T>
349 using NodeToSymbolRange = NodeToChildRange<
351 std::conditional_t<std::is_const_v<T>,
352 typename T::const_symbol_iterator (T::*)()
const,
353 typename T::symbol_iterator (T::*)()>,
354 &T::symbols_begin, &T::symbols_end>;
364 template <
typename T>
365 using NodeToSectionRange = NodeToChildRange<
367 std::conditional_t<std::is_const_v<T>,
368 typename T::const_section_iterator (T::*)()
const,
369 typename T::section_iterator (T::*)()>,
370 &T::sections_begin, &T::sections_end>;
380 template <
typename T>
381 using NodeToProxyBlockRange = NodeToChildRange<
383 std::conditional_t<std::is_const_v<T>,
384 typename T::const_proxy_block_iterator (T::*)()
const,
385 typename T::proxy_block_iterator (T::*)()>,
386 &T::proxy_blocks_begin, &T::proxy_blocks_end>;
397 template <
typename T,
typename MethodType, MethodType Method>
401 FindNodesAt(Addr A_) : A{A_} {}
403 decltype((std::declval<T>().*Method)(Addr())) operator()(T& N)
const {
404 return (N.*Method)(A);
417 template <
typename T,
typename MethodType, MethodType Method>
struct FindNodes {
420 FindNodes(std::string X_) : X{X_} {}
422 decltype((std::declval<T>().*Method)(std::string())) operator()(T& N)
const {
423 return (N.*Method)((std::string&)X);
436 template <
typename T,
typename MethodType, MethodType Method>
437 struct FindNodesBetween {
440 FindNodesBetween(Addr Low_, Addr High_) : Low{Low_}, High{High_} {}
442 decltype((std::declval<T>().*Method)(Addr(), Addr())) operator()(T& N)
const {
443 return (N.*Method)(Low, High);
454 template <
typename T>
455 using FindBlocksIn = FindNodesAt<
457 std::conditional_t<std::is_const_v<T>,
458 typename T::const_block_subrange (T::*)(Addr)
const,
459 typename T::block_subrange (T::*)(Addr)>,
470 template <
typename T>
471 using FindBlocksAt = FindNodesAt<
473 std::conditional_t<std::is_const_v<T>,
474 typename T::const_block_range (T::*)(Addr)
const,
475 typename T::block_range (T::*)(Addr)>,
486 template <
typename T>
487 using FindBlocksBetween = FindNodesBetween<
489 std::conditional_t<std::is_const_v<T>,
490 typename T::const_block_range (T::*)(Addr, Addr)
const,
491 typename T::block_range (T::*)(Addr, Addr)>,
501 template <
typename T>
502 using FindCodeBlocksIn = FindNodesAt<
504 std::conditional_t<std::is_const_v<T>,
505 typename T::const_code_block_subrange (T::*)(Addr)
const,
506 typename T::code_block_subrange (T::*)(Addr)>,
507 &T::findCodeBlocksOn>;
517 template <
typename T>
518 using FindCodeBlocksAt = FindNodesAt<
520 std::conditional_t<std::is_const_v<T>,
521 typename T::const_code_block_range (T::*)(Addr)
const,
522 typename T::code_block_range (T::*)(Addr)>,
523 &T::findCodeBlocksAt>;
533 template <
typename T>
534 using FindCodeBlocksBetween = FindNodesBetween<
536 std::conditional_t<std::is_const_v<T>,
537 typename T::const_code_block_range (T::*)(Addr, Addr)
539 typename T::code_block_range (T::*)(Addr, Addr)>,
540 &T::findCodeBlocksAt>;
549 template <
typename T>
550 using FindDataBlocksIn = FindNodesAt<
552 std::conditional_t<std::is_const_v<T>,
553 typename T::const_data_block_subrange (T::*)(Addr)
const,
554 typename T::data_block_subrange (T::*)(Addr)>,
555 &T::findDataBlocksOn>;
565 template <
typename T>
566 using FindDataBlocksAt = FindNodesAt<
568 std::conditional_t<std::is_const_v<T>,
569 typename T::const_data_block_range (T::*)(Addr)
const,
570 typename T::data_block_range (T::*)(Addr)>,
571 &T::findDataBlocksAt>;
581 template <
typename T>
582 using FindDataBlocksBetween = FindNodesBetween<
584 std::conditional_t<std::is_const_v<T>,
585 typename T::const_data_block_range (T::*)(Addr, Addr)
587 typename T::data_block_range (T::*)(Addr, Addr)>,
588 &T::findDataBlocksAt>;
598 template <
typename T>
599 using FindSymExprsAt = FindNodesAt<
601 std::conditional_t<std::is_const_v<T>,
602 typename T::const_symbolic_expression_range (T::*)(Addr)
604 typename T::symbolic_expression_range (T::*)(Addr)>,
605 &T::findSymbolicExpressionsAt>;
615 template <
typename T>
616 using FindSymExprsBetween = FindNodesBetween<
620 typename T::const_symbolic_expression_range (T::*)(Addr, Addr)
const,
621 typename T::symbolic_expression_range (T::*)(Addr, Addr)>,
622 &T::findSymbolicExpressionsAt>;
631 template <
typename T>
632 using FindByteIntervalsIn =
636 typename T::const_byte_interval_subrange (T::*)(Addr)
const,
637 typename T::byte_interval_subrange (T::*)(Addr)>,
638 &T::findByteIntervalsOn>;
648 template <
typename T>
649 using FindByteIntervalsAt = FindNodesAt<
651 std::conditional_t<std::is_const_v<T>,
652 typename T::const_byte_interval_range (T::*)(Addr)
const,
653 typename T::byte_interval_range (T::*)(Addr)>,
654 &T::findByteIntervalsAt>;
664 template <
typename T>
665 using FindByteIntervalsBetween = FindNodesBetween<
667 std::conditional_t<std::is_const_v<T>,
668 typename T::const_byte_interval_range (T::*)(Addr, Addr)
670 typename T::byte_interval_range (T::*)(Addr, Addr)>,
671 &T::findByteIntervalsAt>;
680 template <
typename T>
681 using FindSectionsIn = FindNodesAt<
683 std::conditional_t<std::is_const_v<T>,
684 typename T::const_section_subrange (T::*)(Addr)
const,
685 typename T::section_subrange (T::*)(Addr)>,
696 template <
typename T>
697 using FindSectionsAt = FindNodesAt<
699 std::conditional_t<std::is_const_v<T>,
700 typename T::const_section_range (T::*)(Addr)
const,
701 typename T::section_range (T::*)(Addr)>,
712 template <
typename T>
713 using FindSections = FindNodes<
717 typename T::const_section_name_range (T::*)(
const std::string& X)
const,
718 typename T::section_name_range (T::*)(
const std::string& X)>,
729 template <
typename T>
730 using FindSectionsBetween = FindNodesBetween<
732 std::conditional_t<std::is_const_v<T>,
733 typename T::const_section_range (T::*)(Addr, Addr)
const,
734 typename T::section_range (T::*)(Addr, Addr)>,
741 #endif // GTIRB_UTILITY_H