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