GTIRB  v2.2.0
GrammaTech Intermediate Representation for Binaries: C++ API
Utility.hpp
Go to the documentation of this file.
1 //===- Utility.hpp ----------------------------------------------*- C++ -*-===//
2 //
3 // Copyright (C) 2021 GrammaTech, Inc.
4 //
5 // This code is licensed under the MIT license. See the LICENSE file in the
6 // project root for license terms.
7 //
8 // This project is sponsored by the Office of Naval Research, One Liberty
9 // Center, 875 N. Randolph Street, Arlington, VA 22203 under contract #
10 // N68335-17-C-0700. The content of the information does not necessarily
11 // reflect the position or policy of the Government and no official
12 // endorsement should be inferred.
13 //
14 //===----------------------------------------------------------------------===//
15 #ifndef GTIRB_UTILITY_H
16 #define GTIRB_UTILITY_H
17 
18 #include <gtirb/Addr.hpp>
19 #include <gtirb/Export.hpp>
20 #include <gtirb/Node.hpp>
21 #include <algorithm>
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>
27 #include <functional>
28 #include <iterator>
29 #include <optional>
30 #include <type_traits>
31 #include <vector>
32 
33 namespace gtirb {
34 
36 
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> {
61 public:
65  MergeSortedIterator() = default;
66 
78  template <typename OtherForwardIterator>
79  MergeSortedIterator(
80  const MergeSortedIterator<OtherForwardIterator, Compare>& MSI,
81  std::enable_if_t<
82  std::is_convertible_v<OtherForwardIterator, ForwardIterator>, void*> =
83  0)
84  : Ranges(MSI.Ranges.begin(), MSI.Ranges.end()) {}
85 
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);
97  }
98  }
99  // Establish the heap invariant for Ranges.
100  std::make_heap(Ranges.begin(), Ranges.end(), rangeGreaterThan);
101  }
102 
110  template <typename RangeIterator>
111  MergeSortedIterator(RangeIterator Begin, RangeIterator End)
112  : MergeSortedIterator(boost::make_iterator_range(Begin, End)) {}
113 
114  // Beginning of functions for iterator facade compatibility.
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;
119  }
120 
121  bool equal(const MergeSortedIterator<ForwardIterator, Compare>& Other) const {
122  return Ranges == Other.Ranges;
123  }
124 
125  void increment() {
126  assert(!Ranges.empty() && "Attempt to increment end of iterator!");
127  // After incrementing the first range, it may no longer have the lowest
128  // first element. Removing the range, then re-inserting it ensures that the
129  // heap invariant is maintained.
130  std::pop_heap(Ranges.begin(), Ranges.end(), rangeGreaterThan);
131  ++Ranges.back().first;
132  if (Ranges.back().first == Ranges.back().second) {
133  Ranges.pop_back();
134  } else {
135  std::push_heap(Ranges.begin(), Ranges.end(), rangeGreaterThan);
136  }
137  }
138  // End of functions for iterator facade compatibility.
139 private:
140  template <typename OtherForwardIterator, typename OtherCompare>
141  friend class MergeSortedIterator;
142 
143  using RangeType = std::pair<ForwardIterator, ForwardIterator>;
144 
145  // Compares two ranges according to the relationship of their first elements
146  // given by \c Compare. Empty ranges are treated as being greater than any
147  // non-empty range.
148  static bool rangeGreaterThan(const RangeType& R1, const RangeType& R2) {
149  if (R1.first == R1.second)
150  // An empty R1 is greater than every R2.
151  return true;
152  if (R2.first == R2.second)
153  // Any R1 is less than an empty R2.
154  return false;
155  // Flip the comparison to implement "greater-than".
156  return Compare()(*R2.first, *R1.first);
157  }
158 
159  // Ranges is a heap ordered by \c rangeGreaterThan. This ensures that the
160  // range with the lowest first element (according to \c Compare) is always at
161  // the front.
162  std::vector<RangeType> Ranges;
163 };
164 
171 struct GTIRB_EXPORT_API AddressLess {
172  template <typename NodeType> auto key(const NodeType* N) const {
173  return std::make_tuple(N->getAddress(), N->getSize(), N->getUUID());
174  }
175 
176  template <typename NodeType>
177  bool operator()(const NodeType* N1, const NodeType* N2) const {
178  return key(N1) < key(N2);
179  }
180 
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);
185  }
186 
188  template <typename NodeType>
189  bool operator()(const NodeType* N1, const Addr& A2) const {
190  return N1->getAddress() < A2;
191  }
192 
194  template <typename NodeType>
195  bool operator()(const Addr& A1, const NodeType* N2) const {
196  return A1 < N2->getAddress();
197  }
198 };
199 
201 template <>
202 GTIRB_EXPORT_API bool
203 AddressLess::operator()<CodeBlock>(const CodeBlock* B1,
204  const CodeBlock* B2) const;
205 
211 template <>
212 GTIRB_EXPORT_API bool
213 AddressLess::operator()<DataBlock>(const DataBlock* B1,
214  const DataBlock* B2) const;
215 
221 struct GTIRB_EXPORT_API BlockAddressLess {
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);
225  }
226 };
227 
232 struct GTIRB_EXPORT_API BlockOffsetPairLess {
233  bool operator()(std::pair<uint64_t, const Node*> B1,
234  std::pair<uint64_t, const Node*> B2) const;
235 };
236 
243 template <typename T> struct ArbitraryLess {
244  bool operator()(const T& N1, const T& N2) const { return &N1 < &N2; }
245 };
246 
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)());
262  }
263 };
264 
274 template <typename T>
275 using NodeToBlockRange = NodeToChildRange<
276  T,
277  std::conditional_t<std::is_const_v<T>,
278  typename T::const_block_iterator (T::*)() const,
279  typename T::block_iterator (T::*)()>,
280  &T::blocks_begin, &T::blocks_end>;
281 
290 template <typename T>
291 using NodeToCodeBlockRange = NodeToChildRange<
292  T,
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>;
297 
306 template <typename T>
307 using NodeToDataBlockRange = NodeToChildRange<
308  T,
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>;
313 
324 template <typename T>
325 using NodeToSymbolicExpressionRange = NodeToChildRange<
326  T,
327  std::conditional_t<std::is_const_v<T>,
328  typename T::const_symbolic_expression_iterator (T::*)()
329  const,
330  typename T::symbolic_expression_iterator (T::*)()>,
331  &T::symbolic_expressions_begin, &T::symbolic_expressions_end>;
332 
341 template <typename T>
342 using NodeToByteIntervalRange = NodeToChildRange<
343  T,
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>;
348 
357 template <typename T>
358 using NodeToSymbolRange = NodeToChildRange<
359  T,
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>;
364 
373 template <typename T>
374 using NodeToSectionRange = NodeToChildRange<
375  T,
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>;
380 
389 template <typename T>
390 using NodeToProxyBlockRange = NodeToChildRange<
391  T,
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>;
396 
406 template <typename T, typename MethodType, MethodType Method>
407 struct FindNodesAt {
408  Addr A;
409 
410  FindNodesAt(Addr A_) : A{A_} {}
411 
412  decltype((std::declval<T>().*Method)(Addr())) operator()(T& N) const {
413  return (N.*Method)(A);
414  }
415 };
416 
426 template <typename T, typename MethodType, MethodType Method> struct FindNodes {
427  std::string X;
428 
429  FindNodes(std::string X_) : X{X_} {}
430 
431  decltype((std::declval<T>().*Method)(std::string())) operator()(T& N) const {
432  return (N.*Method)((std::string&)X);
433  }
434 };
435 
445 template <typename T, typename MethodType, MethodType Method>
446 struct FindNodesBetween {
447  Addr Low, High;
448 
449  FindNodesBetween(Addr Low_, Addr High_) : Low{Low_}, High{High_} {}
450 
451  decltype((std::declval<T>().*Method)(Addr(), Addr())) operator()(T& N) const {
452  return (N.*Method)(Low, High);
453  }
454 };
455 
463 template <typename T>
464 using FindBlocksIn = FindNodesAt<
465  T,
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)>,
469  &T::findBlocksOn>;
470 
479 template <typename T>
480 using FindBlocksAt = FindNodesAt<
481  T,
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)>,
485  &T::findBlocksAt>;
486 
495 template <typename T>
496 using FindBlocksBetween = FindNodesBetween<
497  T,
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)>,
501  &T::findBlocksAt>;
502 
510 template <typename T>
511 using FindCodeBlocksIn = FindNodesAt<
512  T,
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>;
517 
526 template <typename T>
527 using FindCodeBlocksAt = FindNodesAt<
528  T,
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>;
533 
542 template <typename T>
543 using FindCodeBlocksBetween = FindNodesBetween<
544  T,
545  std::conditional_t<std::is_const_v<T>,
546  typename T::const_code_block_range (T::*)(Addr, Addr)
547  const,
548  typename T::code_block_range (T::*)(Addr, Addr)>,
549  &T::findCodeBlocksAt>;
550 
558 template <typename T>
559 using FindDataBlocksIn = FindNodesAt<
560  T,
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>;
565 
574 template <typename T>
575 using FindDataBlocksAt = FindNodesAt<
576  T,
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>;
581 
590 template <typename T>
591 using FindDataBlocksBetween = FindNodesBetween<
592  T,
593  std::conditional_t<std::is_const_v<T>,
594  typename T::const_data_block_range (T::*)(Addr, Addr)
595  const,
596  typename T::data_block_range (T::*)(Addr, Addr)>,
597  &T::findDataBlocksAt>;
598 
607 template <typename T>
608 using FindSymExprsAt = FindNodesAt<
609  T,
610  std::conditional_t<std::is_const_v<T>,
611  typename T::const_symbolic_expression_range (T::*)(Addr)
612  const,
613  typename T::symbolic_expression_range (T::*)(Addr)>,
614  &T::findSymbolicExpressionsAt>;
615 
624 template <typename T>
625 using FindSymExprsBetween = FindNodesBetween<
626  T,
627  std::conditional_t<
628  std::is_const_v<T>,
629  typename T::const_symbolic_expression_range (T::*)(Addr, Addr) const,
630  typename T::symbolic_expression_range (T::*)(Addr, Addr)>,
631  &T::findSymbolicExpressionsAt>;
632 
640 template <typename T>
641 using FindByteIntervalsIn =
642  FindNodesAt<T,
643  std::conditional_t<
644  std::is_const_v<T>,
645  typename T::const_byte_interval_subrange (T::*)(Addr) const,
646  typename T::byte_interval_subrange (T::*)(Addr)>,
647  &T::findByteIntervalsOn>;
648 
657 template <typename T>
658 using FindByteIntervalsAt = FindNodesAt<
659  T,
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>;
664 
673 template <typename T>
674 using FindByteIntervalsBetween = FindNodesBetween<
675  T,
676  std::conditional_t<std::is_const_v<T>,
677  typename T::const_byte_interval_range (T::*)(Addr, Addr)
678  const,
679  typename T::byte_interval_range (T::*)(Addr, Addr)>,
680  &T::findByteIntervalsAt>;
681 
689 template <typename T>
690 using FindSectionsIn = FindNodesAt<
691  T,
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)>,
695  &T::findSectionsOn>;
696 
705 template <typename T>
706 using FindSectionsAt = FindNodesAt<
707  T,
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)>,
711  &T::findSectionsAt>;
712 
721 template <typename T>
722 using FindSections = FindNodes<
723  T,
724  std::conditional_t<
725  std::is_const_v<T>,
726  typename T::const_section_name_range (T::*)(const std::string& X) const,
727  typename T::section_name_range (T::*)(const std::string& X)>,
728  &T::findSections>;
729 
738 template <typename T>
739 using FindSectionsBetween = FindNodesBetween<
740  T,
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)>,
744  &T::findSectionsAt>;
745 
747 
748 } // namespace gtirb
749 
750 #endif // GTIRB_UTILITY_H
gtirb::const_block_iterator
cfg_node_cast_iter< const CodeBlock > const_block_iterator
Constant iterator over blocks (Block).
Definition: CFG.hpp:198
Node.hpp
Class gtirb::Node.
GTIRB_EXPORT_API
#define GTIRB_EXPORT_API
This macro controls the visibility of exported symbols (i.e. classes) in shared libraries....
Definition: Export.hpp:52
gtirb
Main namespace for the GTIRB API.
Definition: Addr.hpp:28
Export.hpp
gtirb::block_iterator
cfg_node_cast_iter< CodeBlock > block_iterator
Iterator over blocks (Block).
Definition: CFG.hpp:194
Addr.hpp
Class gtirb::Addr and related functions.