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 0;
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 0;
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