GTIRB  v2.1.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  return operator()(*N1, *N2);
224  }
225  bool operator()(const Node& N1, const Node& N2) const;
226 };
227 
234 template <typename T> struct ArbitraryLess {
235  bool operator()(const T& N1, const T& N2) const { return &N1 < &N2; }
236 };
237 
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)());
253  }
254 };
255 
265 template <typename T>
266 using NodeToBlockRange = NodeToChildRange<
267  T,
268  std::conditional_t<std::is_const_v<T>,
269  typename T::const_block_iterator (T::*)() const,
270  typename T::block_iterator (T::*)()>,
271  &T::blocks_begin, &T::blocks_end>;
272 
281 template <typename T>
282 using NodeToCodeBlockRange = NodeToChildRange<
283  T,
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>;
288 
297 template <typename T>
298 using NodeToDataBlockRange = NodeToChildRange<
299  T,
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>;
304 
315 template <typename T>
316 using NodeToSymbolicExpressionRange = NodeToChildRange<
317  T,
318  std::conditional_t<std::is_const_v<T>,
319  typename T::const_symbolic_expression_iterator (T::*)()
320  const,
321  typename T::symbolic_expression_iterator (T::*)()>,
322  &T::symbolic_expressions_begin, &T::symbolic_expressions_end>;
323 
332 template <typename T>
333 using NodeToByteIntervalRange = NodeToChildRange<
334  T,
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>;
339 
348 template <typename T>
349 using NodeToSymbolRange = NodeToChildRange<
350  T,
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>;
355 
364 template <typename T>
365 using NodeToSectionRange = NodeToChildRange<
366  T,
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>;
371 
380 template <typename T>
381 using NodeToProxyBlockRange = NodeToChildRange<
382  T,
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>;
387 
397 template <typename T, typename MethodType, MethodType Method>
398 struct FindNodesAt {
399  Addr A;
400 
401  FindNodesAt(Addr A_) : A{A_} {}
402 
403  decltype((std::declval<T>().*Method)(Addr())) operator()(T& N) const {
404  return (N.*Method)(A);
405  }
406 };
407 
417 template <typename T, typename MethodType, MethodType Method> struct FindNodes {
418  std::string X;
419 
420  FindNodes(std::string X_) : X{X_} {}
421 
422  decltype((std::declval<T>().*Method)(std::string())) operator()(T& N) const {
423  return (N.*Method)((std::string&)X);
424  }
425 };
426 
436 template <typename T, typename MethodType, MethodType Method>
437 struct FindNodesBetween {
438  Addr Low, High;
439 
440  FindNodesBetween(Addr Low_, Addr High_) : Low{Low_}, High{High_} {}
441 
442  decltype((std::declval<T>().*Method)(Addr(), Addr())) operator()(T& N) const {
443  return (N.*Method)(Low, High);
444  }
445 };
446 
454 template <typename T>
455 using FindBlocksIn = FindNodesAt<
456  T,
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)>,
460  &T::findBlocksOn>;
461 
470 template <typename T>
471 using FindBlocksAt = FindNodesAt<
472  T,
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)>,
476  &T::findBlocksAt>;
477 
486 template <typename T>
487 using FindBlocksBetween = FindNodesBetween<
488  T,
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)>,
492  &T::findBlocksAt>;
493 
501 template <typename T>
502 using FindCodeBlocksIn = FindNodesAt<
503  T,
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>;
508 
517 template <typename T>
518 using FindCodeBlocksAt = FindNodesAt<
519  T,
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>;
524 
533 template <typename T>
534 using FindCodeBlocksBetween = FindNodesBetween<
535  T,
536  std::conditional_t<std::is_const_v<T>,
537  typename T::const_code_block_range (T::*)(Addr, Addr)
538  const,
539  typename T::code_block_range (T::*)(Addr, Addr)>,
540  &T::findCodeBlocksAt>;
541 
549 template <typename T>
550 using FindDataBlocksIn = FindNodesAt<
551  T,
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>;
556 
565 template <typename T>
566 using FindDataBlocksAt = FindNodesAt<
567  T,
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>;
572 
581 template <typename T>
582 using FindDataBlocksBetween = FindNodesBetween<
583  T,
584  std::conditional_t<std::is_const_v<T>,
585  typename T::const_data_block_range (T::*)(Addr, Addr)
586  const,
587  typename T::data_block_range (T::*)(Addr, Addr)>,
588  &T::findDataBlocksAt>;
589 
598 template <typename T>
599 using FindSymExprsAt = FindNodesAt<
600  T,
601  std::conditional_t<std::is_const_v<T>,
602  typename T::const_symbolic_expression_range (T::*)(Addr)
603  const,
604  typename T::symbolic_expression_range (T::*)(Addr)>,
605  &T::findSymbolicExpressionsAt>;
606 
615 template <typename T>
616 using FindSymExprsBetween = FindNodesBetween<
617  T,
618  std::conditional_t<
619  std::is_const_v<T>,
620  typename T::const_symbolic_expression_range (T::*)(Addr, Addr) const,
621  typename T::symbolic_expression_range (T::*)(Addr, Addr)>,
622  &T::findSymbolicExpressionsAt>;
623 
631 template <typename T>
632 using FindByteIntervalsIn =
633  FindNodesAt<T,
634  std::conditional_t<
635  std::is_const_v<T>,
636  typename T::const_byte_interval_subrange (T::*)(Addr) const,
637  typename T::byte_interval_subrange (T::*)(Addr)>,
638  &T::findByteIntervalsOn>;
639 
648 template <typename T>
649 using FindByteIntervalsAt = FindNodesAt<
650  T,
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>;
655 
664 template <typename T>
665 using FindByteIntervalsBetween = FindNodesBetween<
666  T,
667  std::conditional_t<std::is_const_v<T>,
668  typename T::const_byte_interval_range (T::*)(Addr, Addr)
669  const,
670  typename T::byte_interval_range (T::*)(Addr, Addr)>,
671  &T::findByteIntervalsAt>;
672 
680 template <typename T>
681 using FindSectionsIn = FindNodesAt<
682  T,
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)>,
686  &T::findSectionsOn>;
687 
696 template <typename T>
697 using FindSectionsAt = FindNodesAt<
698  T,
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)>,
702  &T::findSectionsAt>;
703 
712 template <typename T>
713 using FindSections = FindNodes<
714  T,
715  std::conditional_t<
716  std::is_const_v<T>,
717  typename T::const_section_name_range (T::*)(const std::string& X) const,
718  typename T::section_name_range (T::*)(const std::string& X)>,
719  &T::findSections>;
720 
729 template <typename T>
730 using FindSectionsBetween = FindNodesBetween<
731  T,
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)>,
735  &T::findSectionsAt>;
736 
738 
739 } // namespace gtirb
740 
741 #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.