1//===-- Iterable.h ----------------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef LLDB_UTILITY_ITERABLE_H
10#define LLDB_UTILITY_ITERABLE_H
11
12#include <utility>
13
14
15namespace lldb_private {
16
17template <typename I, typename E> E map_adapter(I &iter) {
18  return iter->second;
19}
20
21template <typename I, typename E> E vector_adapter(I &iter) { return *iter; }
22
23template <typename I, typename E> E list_adapter(I &iter) { return *iter; }
24
25template <typename C, typename E, E (*A)(typename C::const_iterator &)>
26class AdaptedConstIterator {
27public:
28  typedef typename C::const_iterator BackingIterator;
29
30  // Wrapping constructor
31  AdaptedConstIterator(BackingIterator backing_iterator)
32      : m_iter(backing_iterator) {}
33
34  // Default-constructible
35  AdaptedConstIterator() : m_iter() {}
36
37  // Copy-constructible
38  AdaptedConstIterator(const AdaptedConstIterator &rhs) : m_iter(rhs.m_iter) {}
39
40  // Copy-assignable
41  AdaptedConstIterator &operator=(const AdaptedConstIterator &rhs) {
42    m_iter = rhs.m_iter;
43    return *this;
44  }
45
46  // Destructible
47  ~AdaptedConstIterator() = default;
48
49  // Comparable
50  bool operator==(const AdaptedConstIterator &rhs) {
51    return m_iter == rhs.m_iter;
52  }
53
54  bool operator!=(const AdaptedConstIterator &rhs) {
55    return m_iter != rhs.m_iter;
56  }
57
58  // Rvalue dereferenceable
59  E operator*() { return (*A)(m_iter); }
60
61  E operator->() { return (*A)(m_iter); }
62
63  // Offset dereferenceable
64  E operator[](typename BackingIterator::difference_type offset) {
65    return AdaptedConstIterator(m_iter + offset);
66  }
67
68  // Incrementable
69  AdaptedConstIterator &operator++() {
70    m_iter++;
71    return *this;
72  }
73
74  // Decrementable
75  AdaptedConstIterator &operator--() {
76    m_iter--;
77    return *this;
78  }
79
80  // Compound assignment
81  AdaptedConstIterator &
82  operator+=(typename BackingIterator::difference_type offset) {
83    m_iter += offset;
84    return *this;
85  }
86
87  AdaptedConstIterator &
88  operator-=(typename BackingIterator::difference_type offset) {
89    m_iter -= offset;
90    return *this;
91  }
92
93  // Arithmetic
94  AdaptedConstIterator
95  operator+(typename BackingIterator::difference_type offset) {
96    return AdaptedConstIterator(m_iter + offset);
97  }
98
99  AdaptedConstIterator
100  operator-(typename BackingIterator::difference_type offset) {
101    return AdaptedConstIterator(m_iter - offset);
102  }
103
104  // Comparable
105  bool operator<(AdaptedConstIterator &rhs) { return m_iter < rhs.m_iter; }
106
107  bool operator<=(AdaptedConstIterator &rhs) { return m_iter <= rhs.m_iter; }
108
109  bool operator>(AdaptedConstIterator &rhs) { return m_iter > rhs.m_iter; }
110
111  bool operator>=(AdaptedConstIterator &rhs) { return m_iter >= rhs.m_iter; }
112
113  template <typename C1, typename E1, E1 (*A1)(typename C1::const_iterator &)>
114  friend AdaptedConstIterator<C1, E1, A1>
115  operator+(typename C1::const_iterator::difference_type,
116            AdaptedConstIterator<C1, E1, A1> &);
117
118  template <typename C1, typename E1, E1 (*A1)(typename C1::const_iterator &)>
119  friend typename C1::const_iterator::difference_type
120  operator-(AdaptedConstIterator<C1, E1, A1> &,
121            AdaptedConstIterator<C1, E1, A1> &);
122
123  template <typename C1, typename E1, E1 (*A1)(typename C1::const_iterator &)>
124  friend void swap(AdaptedConstIterator<C1, E1, A1> &,
125                   AdaptedConstIterator<C1, E1, A1> &);
126
127private:
128  BackingIterator m_iter;
129};
130
131template <typename C, typename E, E (*A)(typename C::const_iterator &)>
132AdaptedConstIterator<C, E, A> operator+(
133    typename AdaptedConstIterator<C, E, A>::BackingIterator::difference_type
134        offset,
135    AdaptedConstIterator<C, E, A> &rhs) {
136  return rhs.operator+(offset);
137}
138
139template <typename C, typename E, E (*A)(typename C::const_iterator &)>
140typename AdaptedConstIterator<C, E, A>::BackingIterator::difference_type
141operator-(AdaptedConstIterator<C, E, A> &lhs,
142          AdaptedConstIterator<C, E, A> &rhs) {
143  return (lhs.m_iter - rhs.m_iter);
144}
145
146template <typename C, typename E, E (*A)(typename C::const_iterator &)>
147void swap(AdaptedConstIterator<C, E, A> &lhs,
148          AdaptedConstIterator<C, E, A> &rhs) {
149  std::swap(lhs.m_iter, rhs.m_iter);
150}
151
152template <typename C, typename E, E (*A)(typename C::const_iterator &)>
153class AdaptedIterable {
154private:
155  const C &m_container;
156
157public:
158  AdaptedIterable(const C &container) : m_container(container) {}
159
160  AdaptedConstIterator<C, E, A> begin() {
161    return AdaptedConstIterator<C, E, A>(m_container.begin());
162  }
163
164  AdaptedConstIterator<C, E, A> end() {
165    return AdaptedConstIterator<C, E, A>(m_container.end());
166  }
167};
168
169template <typename C, typename E, E (*A)(typename C::const_iterator &),
170          typename MutexType>
171class LockingAdaptedIterable : public AdaptedIterable<C, E, A> {
172public:
173  LockingAdaptedIterable(C &container, MutexType &mutex)
174      : AdaptedIterable<C, E, A>(container), m_mutex(&mutex) {
175    m_mutex->lock();
176  }
177
178  LockingAdaptedIterable(LockingAdaptedIterable &&rhs)
179      : AdaptedIterable<C, E, A>(rhs), m_mutex(rhs.m_mutex) {
180    rhs.m_mutex = nullptr;
181  }
182
183  ~LockingAdaptedIterable() {
184    if (m_mutex)
185      m_mutex->unlock();
186  }
187
188private:
189  MutexType *m_mutex = nullptr;
190
191  LockingAdaptedIterable(const LockingAdaptedIterable &) = delete;
192  LockingAdaptedIterable &operator=(const LockingAdaptedIterable &) = delete;
193};
194
195} // namespace lldb_private
196
197#endif // LLDB_UTILITY_ITERABLE_H
198