1 /* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15
16 // This file provides utility functions for use with STL map-like data
17 // structures, such as std::map and hash_map. Some functions will also work with
18 // sets, such as ContainsKey().
19
20 #ifndef TENSORFLOW_LIB_GTL_MAP_UTIL_H_
21 #define TENSORFLOW_LIB_GTL_MAP_UTIL_H_
22
23 #include <stddef.h>
24
25 #include <iterator>
26 #include <memory>
27 #include <string>
28 #include <utility>
29
30 #include "tensorflow/core/lib/gtl/subtle/map_traits.h"
31
32 namespace tensorflow {
33 namespace gtl {
34
35 // Returns a pointer to the const value associated with the given key if it
36 // exists, or NULL otherwise.
37 template <class Collection>
FindOrNull(const Collection & collection,const typename Collection::value_type::first_type & key)38 const typename Collection::value_type::second_type* FindOrNull(
39 const Collection& collection,
40 const typename Collection::value_type::first_type& key) {
41 typename Collection::const_iterator it = collection.find(key);
42 if (it == collection.end()) {
43 return nullptr;
44 }
45 return &it->second;
46 }
47
48 // Same as above but returns a pointer to the non-const value.
49 template <class Collection>
FindOrNull(Collection & collection,const typename Collection::value_type::first_type & key)50 typename Collection::value_type::second_type* FindOrNull(
51 Collection& collection, // NOLINT
52 const typename Collection::value_type::first_type& key) {
53 typename Collection::iterator it = collection.find(key);
54 if (it == collection.end()) {
55 return nullptr;
56 }
57 return &it->second;
58 }
59
60 // Returns the pointer value associated with the given key. If none is found,
61 // NULL is returned. The function is designed to be used with a map of keys to
62 // pointers.
63 //
64 // This function does not distinguish between a missing key and a key mapped
65 // to a NULL value.
66 template <class Collection>
FindPtrOrNull(const Collection & collection,const typename Collection::value_type::first_type & key)67 typename Collection::value_type::second_type FindPtrOrNull(
68 const Collection& collection,
69 const typename Collection::value_type::first_type& key) {
70 typename Collection::const_iterator it = collection.find(key);
71 if (it == collection.end()) {
72 return typename Collection::value_type::second_type();
73 }
74 return it->second;
75 }
76
77 // Returns a const reference to the value associated with the given key if it
78 // exists, otherwise returns a const reference to the provided default value.
79 //
80 // WARNING: If a temporary object is passed as the default "value,"
81 // this function will return a reference to that temporary object,
82 // which will be destroyed at the end of the statement. A common
83 // example: if you have a map with string values, and you pass a char*
84 // as the default "value," either use the returned value immediately
85 // or store it in a string (not string&).
86 template <class Collection>
FindWithDefault(const Collection & collection,const typename Collection::value_type::first_type & key,const typename Collection::value_type::second_type & value)87 const typename Collection::value_type::second_type& FindWithDefault(
88 const Collection& collection,
89 const typename Collection::value_type::first_type& key,
90 const typename Collection::value_type::second_type& value) {
91 typename Collection::const_iterator it = collection.find(key);
92 if (it == collection.end()) {
93 return value;
94 }
95 return it->second;
96 }
97
98 // Inserts the given key-value pair into the collection. Returns true if and
99 // only if the key from the given pair didn't previously exist. Otherwise, the
100 // value in the map is replaced with the value from the given pair.
101 template <class Collection>
InsertOrUpdate(Collection * const collection,const typename Collection::value_type & vt)102 bool InsertOrUpdate(Collection* const collection,
103 const typename Collection::value_type& vt) {
104 std::pair<typename Collection::iterator, bool> ret = collection->insert(vt);
105 if (!ret.second) {
106 // update
107 ret.first->second = vt.second;
108 return false;
109 }
110 return true;
111 }
112
113 // Same as above, except that the key and value are passed separately.
114 template <class Collection>
InsertOrUpdate(Collection * const collection,const typename Collection::value_type::first_type & key,const typename Collection::value_type::second_type & value)115 bool InsertOrUpdate(Collection* const collection,
116 const typename Collection::value_type::first_type& key,
117 const typename Collection::value_type::second_type& value) {
118 return InsertOrUpdate(collection,
119 typename Collection::value_type(key, value));
120 }
121
122 // Inserts the given key and value into the given collection if and only if the
123 // given key did NOT already exist in the collection. If the key previously
124 // existed in the collection, the value is not changed. Returns true if the
125 // key-value pair was inserted; returns false if the key was already present.
126 template <class Collection>
InsertIfNotPresent(Collection * const collection,const typename Collection::value_type & vt)127 bool InsertIfNotPresent(Collection* const collection,
128 const typename Collection::value_type& vt) {
129 return collection->insert(vt).second;
130 }
131
132 // Same as above except the key and value are passed separately.
133 template <class Collection>
InsertIfNotPresent(Collection * const collection,const typename Collection::value_type::first_type & key,const typename Collection::value_type::second_type & value)134 bool InsertIfNotPresent(
135 Collection* const collection,
136 const typename Collection::value_type::first_type& key,
137 const typename Collection::value_type::second_type& value) {
138 return InsertIfNotPresent(collection,
139 typename Collection::value_type(key, value));
140 }
141
142 // Looks up a given key and value pair in a collection and inserts the key-value
143 // pair if it's not already present. Returns a reference to the value associated
144 // with the key.
145 template <class Collection>
LookupOrInsert(Collection * const collection,const typename Collection::value_type & vt)146 typename Collection::value_type::second_type& LookupOrInsert(
147 Collection* const collection, const typename Collection::value_type& vt) {
148 return collection->insert(vt).first->second;
149 }
150
151 // Same as above except the key-value are passed separately.
152 template <class Collection>
LookupOrInsert(Collection * const collection,const typename Collection::value_type::first_type & key,const typename Collection::value_type::second_type & value)153 typename Collection::value_type::second_type& LookupOrInsert(
154 Collection* const collection,
155 const typename Collection::value_type::first_type& key,
156 const typename Collection::value_type::second_type& value) {
157 return LookupOrInsert(collection,
158 typename Collection::value_type(key, value));
159 }
160
161 // Saves the reverse mapping into reverse. Returns true if values could all be
162 // inserted.
163 template <typename M, typename ReverseM>
ReverseMap(const M & m,ReverseM * reverse)164 bool ReverseMap(const M& m, ReverseM* reverse) {
165 bool all_unique = true;
166 for (const auto& kv : m) {
167 if (!InsertOrUpdate(reverse, kv.second, kv.first)) {
168 all_unique = false;
169 }
170 }
171 return all_unique;
172 }
173
174 // Like ReverseMap above, but returns its output m. Return type has to
175 // be specified explicitly. Example:
176 // M::M(...) : m_(...), r_(ReverseMap<decltype(r_)>(m_)) {}
177 template <typename ReverseM, typename M>
ReverseMap(const M & m)178 ReverseM ReverseMap(const M& m) {
179 typename std::remove_const<ReverseM>::type reverse;
180 ReverseMap(m, &reverse);
181 return reverse;
182 }
183
184 // Erases the m item identified by the given key, and returns the value
185 // associated with that key. It is assumed that the value (i.e., the
186 // mapped_type) is a pointer. Returns null if the key was not found in the
187 // m.
188 //
189 // Examples:
190 // std::map<string, MyType*> my_map;
191 //
192 // One line cleanup:
193 // delete EraseKeyReturnValuePtr(&my_map, "abc");
194 //
195 // Use returned value:
196 // std::unique_ptr<MyType> value_ptr(
197 // EraseKeyReturnValuePtr(&my_map, "abc"));
198 // if (value_ptr.get())
199 // value_ptr->DoSomething();
200 //
201 template <typename Collection>
EraseKeyReturnValuePtr(Collection * collection,const typename Collection::value_type::first_type & key)202 typename Collection::value_type::second_type EraseKeyReturnValuePtr(
203 Collection* collection,
204 const typename Collection::value_type::first_type& key) {
205 auto it = collection->find(key);
206 if (it == collection->end()) return nullptr;
207 auto v = gtl::subtle::GetMapped(*it);
208 collection->erase(it);
209 return v;
210 }
211
212 } // namespace gtl
213 } // namespace tensorflow
214
215 #endif // TENSORFLOW_LIB_GTL_MAP_UTIL_H_
216