1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <memory>
20 #include <vector>
21 
22 #include <thrift/compiler/ast/detail/view.h>
23 
24 namespace apache {
25 namespace thrift {
26 namespace compiler {
27 
28 // The type to use to hold a list of nodes of type T.
29 template <typename T>
30 using node_list = std::vector<std::unique_ptr<T>>;
31 
32 // A view of a node_list of nodes of type T.
33 //
34 // If T is const, only provides const access to the nodes in the
35 // node_list.
36 //
37 // Like std::ranges::view, std::span and std::string_view, this class provides
38 // access to memory it does not own and must not be accessed after the
39 // associated node_list is destroyed.
40 //
41 // TODO(afuller): When c++20 can be used, switch to using
42 // std::ranges::transform_view instead.
43 template <typename T>
44 class node_list_view : public ast_detail::base_view<node_list_view<T>, T*> {
45   using base = ast_detail::base_view<node_list_view<T>, T*>;
46   using node_list_type = node_list<std::remove_cv_t<T>>;
47 
48  public:
49   using size_type = typename node_list_type::size_type;
50   using difference_type = typename node_list_type::difference_type;
51 
52   // Return by reference.
53   using value_type = std::remove_const_t<T>;
54   using pointer = T*;
55   using reference = T&;
56 
57   class iterator {
58     friend class node_list_view;
59     using itr_type = typename node_list_type::const_iterator;
iterator(itr_type itr)60     /* implicit */ constexpr iterator(itr_type itr) : itr_(std::move(itr)) {}
61 
62    public:
63     using iterator_category = typename itr_type::iterator_category;
64     using difference_type = typename itr_type::difference_type;
65     using value_type = node_list_view::value_type;
66     using pointer = node_list_view::pointer;
67     using reference = node_list_view::reference;
68 
69     reference operator*() const noexcept { return itr_->operator*(); }
70     reference operator[](difference_type n) const noexcept { return *itr_[n]; }
71 
72     iterator operator++(int) noexcept { return {itr_++}; }
73     iterator& operator++() noexcept {
74       ++itr_;
75       return *this;
76     }
77     iterator& operator+=(difference_type n) noexcept {
78       itr_ += n;
79       return *this;
80     }
81     iterator& operator-=(difference_type n) noexcept {
82       itr_ -= n;
83       return *this;
84     }
85 
86     friend iterator operator-(
87         const iterator& a, const difference_type& n) noexcept {
88       return {a.itr_ - n};
89     }
90     friend iterator operator+(
91         const iterator& a, const difference_type& n) noexcept {
92       return {a.itr_ + n};
93     }
94     friend iterator operator+(
95         const difference_type& n, const iterator& b) noexcept {
96       return {n + b.itr_};
97     }
98 
99    private:
100     itr_type itr_;
101 
102 #define __FBTHRIFT_NODE_SPAN_ITR_FWD_OP(op)                       \
103   friend auto operator op(const iterator& a, const iterator& b) { \
104     return a.itr_ op b.itr_;                                      \
105   }
106     __FBTHRIFT_NODE_SPAN_ITR_FWD_OP(-)
107     __FBTHRIFT_NODE_SPAN_ITR_FWD_OP(==)
108     __FBTHRIFT_NODE_SPAN_ITR_FWD_OP(!=)
109     __FBTHRIFT_NODE_SPAN_ITR_FWD_OP(<)
110     __FBTHRIFT_NODE_SPAN_ITR_FWD_OP(<=)
111     __FBTHRIFT_NODE_SPAN_ITR_FWD_OP(>)
112     __FBTHRIFT_NODE_SPAN_ITR_FWD_OP(>=)
113 #undef __FBTHRIFT_NODE_SPAN_ITR_FWD_OP
114   };
115   using reverse_iterator = std::reverse_iterator<iterator>;
116 
node_list_view(const node_list_type & list)117   /* implicit */ constexpr node_list_view(const node_list_type& list) noexcept
118       : list_(&list) {}
119 
120   constexpr node_list_view(const node_list_view&) noexcept = default;
121   constexpr node_list_view& operator=(const node_list_view&) noexcept = default;
122 
front()123   constexpr reference front() const { return *list_->front(); }
back()124   constexpr reference back() const { return *list_->back(); }
125   constexpr reference operator[](std::size_t pos) const { return at(pos); }
begin()126   constexpr iterator begin() const noexcept { return list_->begin(); }
end()127   constexpr iterator end() const noexcept { return list_->end(); }
size()128   constexpr std::size_t size() const noexcept { return list_->size(); }
129 
130   // Create an std::vector with the same contents as this span.
copy()131   constexpr std::vector<T*> copy() const noexcept {
132     std::vector<T*> result;
133     for (auto& ptr : *list_) {
134       result.emplace_back(ptr.get());
135     }
136     return result;
137   }
138 
139   // Provided for backwards compatibility with std::vector API.
140   using const_iterator = iterator;
141   using const_reference = reference;
142   using const_pointer = pointer;
cbegin()143   constexpr iterator cbegin() const noexcept { return list_->cbegin(); }
cend()144   constexpr iterator cend() const noexcept { return list_->cend(); }
at(std::size_t pos)145   constexpr reference at(std::size_t pos) const { return *list_->at(pos); }
146 
147  private:
148   const node_list_type* list_;
149 };
150 
151 } // namespace compiler
152 } // namespace thrift
153 } // namespace apache
154