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 bool operator()(
const Node& N1,
const Node& N2)
const {
224 return operator()(&N1, &N2);
233 bool operator()(std::pair<uint64_t, const Node*> B1,
234 std::pair<uint64_t, const Node*> B2)
const;
243 template <
typename T>
struct ArbitraryLess {
244 bool operator()(
const T& N1,
const T& N2)
const {
return &N1 < &N2; }
257 template <
typename T,
typename Method, Method Begin, Method End>
258 struct NodeToChildRange {
259 boost::iterator_range<decltype((std::declval<T>().*Begin)())>
260 operator()(T& N)
const {
261 return boost::make_iterator_range((N.*Begin)(), (N.*End)());
274 template <
typename T>
275 using NodeToBlockRange = NodeToChildRange<
277 std::conditional_t<std::is_const_v<T>,
280 &T::blocks_begin, &T::blocks_end>;
290 template <
typename T>
291 using NodeToCodeBlockRange = NodeToChildRange<
293 std::conditional_t<std::is_const_v<T>,
294 typename T::const_code_block_iterator (T::*)()
const,
295 typename T::code_block_iterator (T::*)()>,
296 &T::code_blocks_begin, &T::code_blocks_end>;
306 template <
typename T>
307 using NodeToDataBlockRange = NodeToChildRange<
309 std::conditional_t<std::is_const_v<T>,
310 typename T::const_data_block_iterator (T::*)()
const,
311 typename T::data_block_iterator (T::*)()>,
312 &T::data_blocks_begin, &T::data_blocks_end>;
324 template <
typename T>
325 using NodeToSymbolicExpressionRange = NodeToChildRange<
327 std::conditional_t<std::is_const_v<T>,
328 typename T::const_symbolic_expression_iterator (T::*)()
330 typename T::symbolic_expression_iterator (T::*)()>,
331 &T::symbolic_expressions_begin, &T::symbolic_expressions_end>;
341 template <
typename T>
342 using NodeToByteIntervalRange = NodeToChildRange<
344 std::conditional_t<std::is_const_v<T>,
345 typename T::const_byte_interval_iterator (T::*)()
const,
346 typename T::byte_interval_iterator (T::*)()>,
347 &T::byte_intervals_begin, &T::byte_intervals_end>;
357 template <
typename T>
358 using NodeToSymbolRange = NodeToChildRange<
360 std::conditional_t<std::is_const_v<T>,
361 typename T::const_symbol_iterator (T::*)()
const,
362 typename T::symbol_iterator (T::*)()>,
363 &T::symbols_begin, &T::symbols_end>;
373 template <
typename T>
374 using NodeToSectionRange = NodeToChildRange<
376 std::conditional_t<std::is_const_v<T>,
377 typename T::const_section_iterator (T::*)()
const,
378 typename T::section_iterator (T::*)()>,
379 &T::sections_begin, &T::sections_end>;
389 template <
typename T>
390 using NodeToProxyBlockRange = NodeToChildRange<
392 std::conditional_t<std::is_const_v<T>,
393 typename T::const_proxy_block_iterator (T::*)()
const,
394 typename T::proxy_block_iterator (T::*)()>,
395 &T::proxy_blocks_begin, &T::proxy_blocks_end>;
406 template <
typename T,
typename MethodType, MethodType Method>
410 FindNodesAt(Addr A_) : A{A_} {}
412 decltype((std::declval<T>().*Method)(Addr())) operator()(T& N)
const {
413 return (N.*Method)(A);
426 template <
typename T,
typename MethodType, MethodType Method>
struct FindNodes {
429 FindNodes(std::string X_) : X{X_} {}
431 decltype((std::declval<T>().*Method)(std::string())) operator()(T& N)
const {
432 return (N.*Method)((std::string&)X);
445 template <
typename T,
typename MethodType, MethodType Method>
446 struct FindNodesBetween {
449 FindNodesBetween(Addr Low_, Addr High_) : Low{Low_}, High{High_} {}
451 decltype((std::declval<T>().*Method)(Addr(), Addr())) operator()(T& N)
const {
452 return (N.*Method)(Low, High);
463 template <
typename T>
464 using FindBlocksIn = FindNodesAt<
466 std::conditional_t<std::is_const_v<T>,
467 typename T::const_block_subrange (T::*)(Addr)
const,
468 typename T::block_subrange (T::*)(Addr)>,
479 template <
typename T>
480 using FindBlocksAt = FindNodesAt<
482 std::conditional_t<std::is_const_v<T>,
483 typename T::const_block_range (T::*)(Addr)
const,
484 typename T::block_range (T::*)(Addr)>,
495 template <
typename T>
496 using FindBlocksBetween = FindNodesBetween<
498 std::conditional_t<std::is_const_v<T>,
499 typename T::const_block_range (T::*)(Addr, Addr)
const,
500 typename T::block_range (T::*)(Addr, Addr)>,
510 template <
typename T>
511 using FindCodeBlocksIn = FindNodesAt<
513 std::conditional_t<std::is_const_v<T>,
514 typename T::const_code_block_subrange (T::*)(Addr)
const,
515 typename T::code_block_subrange (T::*)(Addr)>,
516 &T::findCodeBlocksOn>;
526 template <
typename T>
527 using FindCodeBlocksAt = FindNodesAt<
529 std::conditional_t<std::is_const_v<T>,
530 typename T::const_code_block_range (T::*)(Addr)
const,
531 typename T::code_block_range (T::*)(Addr)>,
532 &T::findCodeBlocksAt>;
542 template <
typename T>
543 using FindCodeBlocksBetween = FindNodesBetween<
545 std::conditional_t<std::is_const_v<T>,
546 typename T::const_code_block_range (T::*)(Addr, Addr)
548 typename T::code_block_range (T::*)(Addr, Addr)>,
549 &T::findCodeBlocksAt>;
558 template <
typename T>
559 using FindDataBlocksIn = FindNodesAt<
561 std::conditional_t<std::is_const_v<T>,
562 typename T::const_data_block_subrange (T::*)(Addr)
const,
563 typename T::data_block_subrange (T::*)(Addr)>,
564 &T::findDataBlocksOn>;
574 template <
typename T>
575 using FindDataBlocksAt = FindNodesAt<
577 std::conditional_t<std::is_const_v<T>,
578 typename T::const_data_block_range (T::*)(Addr)
const,
579 typename T::data_block_range (T::*)(Addr)>,
580 &T::findDataBlocksAt>;
590 template <
typename T>
591 using FindDataBlocksBetween = FindNodesBetween<
593 std::conditional_t<std::is_const_v<T>,
594 typename T::const_data_block_range (T::*)(Addr, Addr)
596 typename T::data_block_range (T::*)(Addr, Addr)>,
597 &T::findDataBlocksAt>;
607 template <
typename T>
608 using FindSymExprsAt = FindNodesAt<
610 std::conditional_t<std::is_const_v<T>,
611 typename T::const_symbolic_expression_range (T::*)(Addr)
613 typename T::symbolic_expression_range (T::*)(Addr)>,
614 &T::findSymbolicExpressionsAt>;
624 template <
typename T>
625 using FindSymExprsBetween = FindNodesBetween<
629 typename T::const_symbolic_expression_range (T::*)(Addr, Addr)
const,
630 typename T::symbolic_expression_range (T::*)(Addr, Addr)>,
631 &T::findSymbolicExpressionsAt>;
640 template <
typename T>
641 using FindByteIntervalsIn =
645 typename T::const_byte_interval_subrange (T::*)(Addr)
const,
646 typename T::byte_interval_subrange (T::*)(Addr)>,
647 &T::findByteIntervalsOn>;
657 template <
typename T>
658 using FindByteIntervalsAt = FindNodesAt<
660 std::conditional_t<std::is_const_v<T>,
661 typename T::const_byte_interval_range (T::*)(Addr)
const,
662 typename T::byte_interval_range (T::*)(Addr)>,
663 &T::findByteIntervalsAt>;
673 template <
typename T>
674 using FindByteIntervalsBetween = FindNodesBetween<
676 std::conditional_t<std::is_const_v<T>,
677 typename T::const_byte_interval_range (T::*)(Addr, Addr)
679 typename T::byte_interval_range (T::*)(Addr, Addr)>,
680 &T::findByteIntervalsAt>;
689 template <
typename T>
690 using FindSectionsIn = FindNodesAt<
692 std::conditional_t<std::is_const_v<T>,
693 typename T::const_section_subrange (T::*)(Addr)
const,
694 typename T::section_subrange (T::*)(Addr)>,
705 template <
typename T>
706 using FindSectionsAt = FindNodesAt<
708 std::conditional_t<std::is_const_v<T>,
709 typename T::const_section_range (T::*)(Addr)
const,
710 typename T::section_range (T::*)(Addr)>,
721 template <
typename T>
722 using FindSections = FindNodes<
726 typename T::const_section_name_range (T::*)(
const std::string& X)
const,
727 typename T::section_name_range (T::*)(
const std::string& X)>,
738 template <
typename T>
739 using FindSectionsBetween = FindNodesBetween<
741 std::conditional_t<std::is_const_v<T>,
742 typename T::const_section_range (T::*)(Addr, Addr)
const,
743 typename T::section_range (T::*)(Addr, Addr)>,
750 #endif // GTIRB_UTILITY_H