/src/brpc/src/butil/stl_util.h
Line | Count | Source |
1 | | // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 | | // Use of this source code is governed by a BSD-style license that can be |
3 | | // found in the LICENSE file. |
4 | | |
5 | | // Derived from google3/util/gtl/stl_util.h |
6 | | |
7 | | #ifndef BUTIL_STL_UTIL_H_ |
8 | | #define BUTIL_STL_UTIL_H_ |
9 | | |
10 | | #include <algorithm> |
11 | | #include <functional> |
12 | | #include <iterator> |
13 | | #include <string> |
14 | | #include <vector> |
15 | | |
16 | | #include "butil/logging.h" |
17 | | |
18 | | namespace butil { |
19 | | |
20 | | // Clears internal memory of an STL object. |
21 | | // STL clear()/reserve(0) does not always free internal memory allocated |
22 | | // This function uses swap/destructor to ensure the internal memory is freed. |
23 | | template<class T> |
24 | | void STLClearObject(T* obj) { |
25 | | T tmp; |
26 | | tmp.swap(*obj); |
27 | | // Sometimes "T tmp" allocates objects with memory (arena implementation?). |
28 | | // Hence using additional reserve(0) even if it doesn't always work. |
29 | | obj->reserve(0); |
30 | | } |
31 | | |
32 | | // For a range within a container of pointers, calls delete (non-array version) |
33 | | // on these pointers. |
34 | | // NOTE: for these three functions, we could just implement a DeleteObject |
35 | | // functor and then call for_each() on the range and functor, but this |
36 | | // requires us to pull in all of algorithm.h, which seems expensive. |
37 | | // For hash_[multi]set, it is important that this deletes behind the iterator |
38 | | // because the hash_set may call the hash function on the iterator when it is |
39 | | // advanced, which could result in the hash function trying to deference a |
40 | | // stale pointer. |
41 | | template <class ForwardIterator> |
42 | | void STLDeleteContainerPointers(ForwardIterator begin, ForwardIterator end) { |
43 | | while (begin != end) { |
44 | | ForwardIterator temp = begin; |
45 | | ++begin; |
46 | | delete *temp; |
47 | | } |
48 | | } |
49 | | |
50 | | // For a range within a container of pairs, calls delete (non-array version) on |
51 | | // BOTH items in the pairs. |
52 | | // NOTE: Like STLDeleteContainerPointers, it is important that this deletes |
53 | | // behind the iterator because if both the key and value are deleted, the |
54 | | // container may call the hash function on the iterator when it is advanced, |
55 | | // which could result in the hash function trying to dereference a stale |
56 | | // pointer. |
57 | | template <class ForwardIterator> |
58 | | void STLDeleteContainerPairPointers(ForwardIterator begin, |
59 | | ForwardIterator end) { |
60 | | while (begin != end) { |
61 | | ForwardIterator temp = begin; |
62 | | ++begin; |
63 | | delete temp->first; |
64 | | delete temp->second; |
65 | | } |
66 | | } |
67 | | |
68 | | // For a range within a container of pairs, calls delete (non-array version) on |
69 | | // the FIRST item in the pairs. |
70 | | // NOTE: Like STLDeleteContainerPointers, deleting behind the iterator. |
71 | | template <class ForwardIterator> |
72 | | void STLDeleteContainerPairFirstPointers(ForwardIterator begin, |
73 | | ForwardIterator end) { |
74 | | while (begin != end) { |
75 | | ForwardIterator temp = begin; |
76 | | ++begin; |
77 | | delete temp->first; |
78 | | } |
79 | | } |
80 | | |
81 | | // For a range within a container of pairs, calls delete. |
82 | | // NOTE: Like STLDeleteContainerPointers, deleting behind the iterator. |
83 | | // Deleting the value does not always invalidate the iterator, but it may |
84 | | // do so if the key is a pointer into the value object. |
85 | | template <class ForwardIterator> |
86 | | void STLDeleteContainerPairSecondPointers(ForwardIterator begin, |
87 | | ForwardIterator end) { |
88 | | while (begin != end) { |
89 | | ForwardIterator temp = begin; |
90 | | ++begin; |
91 | | delete temp->second; |
92 | | } |
93 | | } |
94 | | |
95 | | // To treat a possibly-empty vector as an array, use these functions. |
96 | | // If you know the array will never be empty, you can use &*v.begin() |
97 | | // directly, but that is undefined behaviour if |v| is empty. |
98 | | template<typename T> |
99 | | inline T* vector_as_array(std::vector<T>* v) { |
100 | | return v->empty() ? NULL : &*v->begin(); |
101 | | } |
102 | | |
103 | | template<typename T> |
104 | | inline const T* vector_as_array(const std::vector<T>* v) { |
105 | | return v->empty() ? NULL : &*v->begin(); |
106 | | } |
107 | | |
108 | | // Return a mutable char* pointing to a string's internal buffer, |
109 | | // which may not be null-terminated. Writing through this pointer will |
110 | | // modify the string. |
111 | | // |
112 | | // string_as_array(&str)[i] is valid for 0 <= i < str.size() until the |
113 | | // next call to a string method that invalidates iterators. |
114 | | // |
115 | | // As of 2006-04, there is no standard-blessed way of getting a |
116 | | // mutable reference to a string's internal buffer. However, issue 530 |
117 | | // (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530) |
118 | | // proposes this as the method. According to Matt Austern, this should |
119 | | // already work on all current implementations. |
120 | 0 | inline char* string_as_array(std::string* str) { |
121 | 0 | // DO NOT USE const_cast<char*>(str->data()) |
122 | 0 | return str->empty() ? NULL : &*str->begin(); |
123 | 0 | } |
124 | | |
125 | | // The following functions are useful for cleaning up STL containers whose |
126 | | // elements point to allocated memory. |
127 | | |
128 | | // STLDeleteElements() deletes all the elements in an STL container and clears |
129 | | // the container. This function is suitable for use with a vector, set, |
130 | | // hash_set, or any other STL container which defines sensible begin(), end(), |
131 | | // and clear() methods. |
132 | | // |
133 | | // If container is NULL, this function is a no-op. |
134 | | // |
135 | | // As an alternative to calling STLDeleteElements() directly, consider |
136 | | // STLElementDeleter (defined below), which ensures that your container's |
137 | | // elements are deleted when the STLElementDeleter goes out of scope. |
138 | | template <class T> |
139 | | void STLDeleteElements(T* container) { |
140 | | if (!container) |
141 | | return; |
142 | | STLDeleteContainerPointers(container->begin(), container->end()); |
143 | | container->clear(); |
144 | | } |
145 | | |
146 | | // Given an STL container consisting of (key, value) pairs, STLDeleteValues |
147 | | // deletes all the "value" components and clears the container. Does nothing |
148 | | // in the case it's given a NULL pointer. |
149 | | template <class T> |
150 | | void STLDeleteValues(T* container) { |
151 | | if (!container) |
152 | | return; |
153 | | for (typename T::iterator i(container->begin()); i != container->end(); ++i) |
154 | | delete i->second; |
155 | | container->clear(); |
156 | | } |
157 | | |
158 | | |
159 | | // The following classes provide a convenient way to delete all elements or |
160 | | // values from STL containers when they goes out of scope. This greatly |
161 | | // simplifies code that creates temporary objects and has multiple return |
162 | | // statements. Example: |
163 | | // |
164 | | // vector<MyProto *> tmp_proto; |
165 | | // STLElementDeleter<vector<MyProto *> > d(&tmp_proto); |
166 | | // if (...) return false; |
167 | | // ... |
168 | | // return success; |
169 | | |
170 | | // Given a pointer to an STL container this class will delete all the element |
171 | | // pointers when it goes out of scope. |
172 | | template<class T> |
173 | | class STLElementDeleter { |
174 | | public: |
175 | | STLElementDeleter(T* container) : container_(container) {} |
176 | | ~STLElementDeleter() { STLDeleteElements(container_); } |
177 | | |
178 | | private: |
179 | | T* container_; |
180 | | }; |
181 | | |
182 | | // Given a pointer to an STL container this class will delete all the value |
183 | | // pointers when it goes out of scope. |
184 | | template<class T> |
185 | | class STLValueDeleter { |
186 | | public: |
187 | | STLValueDeleter(T* container) : container_(container) {} |
188 | | ~STLValueDeleter() { STLDeleteValues(container_); } |
189 | | |
190 | | private: |
191 | | T* container_; |
192 | | }; |
193 | | |
194 | | // Test to see if a set, map, hash_set or hash_map contains a particular key. |
195 | | // Returns true if the key is in the collection. |
196 | | template <typename Collection, typename Key> |
197 | 0 | bool ContainsKey(const Collection& collection, const Key& key) { |
198 | 0 | return collection.find(key) != collection.end(); |
199 | 0 | } |
200 | | |
201 | | // Returns true if the container is sorted. |
202 | | template <typename Container> |
203 | | bool STLIsSorted(const Container& cont) { |
204 | | // Note: Use reverse iterator on container to ensure we only require |
205 | | // value_type to implement operator<. |
206 | | return std::adjacent_find(cont.rbegin(), cont.rend(), |
207 | | std::less<typename Container::value_type>()) |
208 | | == cont.rend(); |
209 | | } |
210 | | |
211 | | // Returns a new ResultType containing the difference of two sorted containers. |
212 | | template <typename ResultType, typename Arg1, typename Arg2> |
213 | | ResultType STLSetDifference(const Arg1& a1, const Arg2& a2) { |
214 | | DCHECK(STLIsSorted(a1)); |
215 | | DCHECK(STLIsSorted(a2)); |
216 | | ResultType difference; |
217 | | std::set_difference(a1.begin(), a1.end(), |
218 | | a2.begin(), a2.end(), |
219 | | std::inserter(difference, difference.end())); |
220 | | return difference; |
221 | | } |
222 | | |
223 | | // Returns a new ResultType containing the union of two sorted containers. |
224 | | template <typename ResultType, typename Arg1, typename Arg2> |
225 | | ResultType STLSetUnion(const Arg1& a1, const Arg2& a2) { |
226 | | DCHECK(STLIsSorted(a1)); |
227 | | DCHECK(STLIsSorted(a2)); |
228 | | ResultType result; |
229 | | std::set_union(a1.begin(), a1.end(), |
230 | | a2.begin(), a2.end(), |
231 | | std::inserter(result, result.end())); |
232 | | return result; |
233 | | } |
234 | | |
235 | | // Returns a new ResultType containing the intersection of two sorted |
236 | | // containers. |
237 | | template <typename ResultType, typename Arg1, typename Arg2> |
238 | | ResultType STLSetIntersection(const Arg1& a1, const Arg2& a2) { |
239 | | DCHECK(STLIsSorted(a1)); |
240 | | DCHECK(STLIsSorted(a2)); |
241 | | ResultType result; |
242 | | std::set_intersection(a1.begin(), a1.end(), |
243 | | a2.begin(), a2.end(), |
244 | | std::inserter(result, result.end())); |
245 | | return result; |
246 | | } |
247 | | |
248 | | // Returns true if the sorted container |a1| contains all elements of the sorted |
249 | | // container |a2|. |
250 | | template <typename Arg1, typename Arg2> |
251 | | bool STLIncludes(const Arg1& a1, const Arg2& a2) { |
252 | | DCHECK(STLIsSorted(a1)); |
253 | | DCHECK(STLIsSorted(a2)); |
254 | | return std::includes(a1.begin(), a1.end(), |
255 | | a2.begin(), a2.end()); |
256 | | } |
257 | | |
258 | | } // namespace butil |
259 | | |
260 | | #endif // BUTIL_STL_UTIL_H_ |