1 // Copyright 2013 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 #ifndef EXTENSIONS_COMMON_PERMISSIONS_BASE_SET_OPERATORS_H_ 6 #define EXTENSIONS_COMMON_PERMISSIONS_BASE_SET_OPERATORS_H_ 7 8 #include <iterator> 9 #include <map> 10 11 #include "base/memory/linked_ptr.h" 12 #include "base/template_util.h" 13 14 namespace extensions { 15 16 // Traits for template paramater of |BaseSetOperators<T>|. Specializations 17 // should define |ElementType| for the type of elements to store in the set, 18 // and |EmementIDType| for the type of element identifiers. 19 template <typename T> 20 struct BaseSetOperatorsTraits {}; 21 22 // Set operations shared by |APIPermissionSet| and |ManifestPermissionSet|. 23 // 24 // TODO(rpaquay): It would be nice to remove the need for the sub-classes and 25 // instead directly use this class where needed. 26 template <typename T> 27 class BaseSetOperators { 28 public: 29 typedef typename BaseSetOperatorsTraits<T>::ElementType ElementType; 30 typedef typename BaseSetOperatorsTraits<T>::ElementIDType ElementIDType; 31 typedef std::map<ElementIDType, linked_ptr<ElementType> > Map; 32 33 class const_iterator : 34 public std::iterator<std::input_iterator_tag, const ElementType*> { 35 public: 36 const_iterator(const typename Map::const_iterator& it) : it_(it) {} 37 const_iterator(const const_iterator& ids_it) : it_(ids_it.it_) {} 38 39 const_iterator& operator++() { 40 ++it_; 41 return *this; 42 } 43 44 const_iterator operator++(int) { 45 const_iterator tmp(it_++); 46 return tmp; 47 } 48 49 bool operator==(const const_iterator& rhs) const { 50 return it_ == rhs.it_; 51 } 52 53 bool operator!=(const const_iterator& rhs) const { 54 return it_ != rhs.it_; 55 } 56 57 const ElementType* operator*() const { 58 return it_->second.get(); 59 } 60 61 const ElementType* operator->() const { 62 return it_->second.get(); 63 } 64 65 private: 66 typename Map::const_iterator it_; 67 }; 68 69 BaseSetOperators() { 70 // Ensure |T| is convertible to us, so we can safely downcast when calling 71 // methods that must exist in |T|. 72 COMPILE_ASSERT((base::is_convertible<T*, BaseSetOperators<T>*>::value), 73 U_ptr_must_implicitly_convert_to_T_ptr); 74 } 75 76 BaseSetOperators(const T& set) { 77 this->operator=(set); 78 } 79 80 ~BaseSetOperators() {} 81 82 T& operator=(const T& rhs) { 83 return Assign(rhs); 84 } 85 86 bool operator==(const T& rhs) const { 87 return Equal(rhs); 88 } 89 90 bool operator!=(const T& rhs) const { 91 return !operator==(rhs); 92 } 93 94 T& Assign(const T& rhs) { 95 const_iterator it = rhs.begin(); 96 const const_iterator end = rhs.end(); 97 while (it != end) { 98 insert(it->Clone()); 99 ++it; 100 } 101 return *static_cast<T*>(this); 102 } 103 104 bool Equal(const T& rhs) const { 105 const_iterator it = begin(); 106 const_iterator rhs_it = rhs.begin(); 107 const_iterator it_end = end(); 108 const_iterator rhs_it_end = rhs.end(); 109 110 while (it != it_end && rhs_it != rhs_it_end) { 111 if (it->id() > rhs_it->id()) 112 return false; 113 else if (it->id() < rhs_it->id()) 114 return false; 115 else if (!it->Equal(*rhs_it)) 116 return false; 117 ++it; 118 ++rhs_it; 119 } 120 return it == it_end && rhs_it == rhs_it_end; 121 } 122 123 bool Contains(const T& rhs) const { 124 const_iterator it1 = begin(); 125 const_iterator it2 = rhs.begin(); 126 const_iterator end1 = end(); 127 const_iterator end2 = rhs.end(); 128 129 while (it1 != end1 && it2 != end2) { 130 if (it1->id() > it2->id()) { 131 return false; 132 } else if (it1->id() < it2->id()) { 133 ++it1; 134 } else { 135 if (!it1->Contains(*it2)) 136 return false; 137 ++it1; 138 ++it2; 139 } 140 } 141 142 return it2 == end2; 143 } 144 145 static void Difference(const T& set1, const T& set2, T* set3) { 146 CHECK(set3); 147 set3->clear(); 148 149 const_iterator it1 = set1.begin(); 150 const_iterator it2 = set2.begin(); 151 const const_iterator end1 = set1.end(); 152 const const_iterator end2 = set2.end(); 153 154 while (it1 != end1 && it2 != end2) { 155 if (it1->id() < it2->id()) { 156 set3->insert(it1->Clone()); 157 ++it1; 158 } else if (it1->id() > it2->id()) { 159 ++it2; 160 } else { 161 ElementType* p = it1->Diff(*it2); 162 if (p) 163 set3->insert(p); 164 ++it1; 165 ++it2; 166 } 167 } 168 169 while (it1 != end1) { 170 set3->insert(it1->Clone()); 171 ++it1; 172 } 173 } 174 175 static void Intersection(const T& set1, const T& set2, T* set3) { 176 DCHECK(set3); 177 set3->clear(); 178 179 const_iterator it1 = set1.begin(); 180 const_iterator it2 = set2.begin(); 181 const const_iterator end1 = set1.end(); 182 const const_iterator end2 = set2.end(); 183 184 while (it1 != end1 && it2 != end2) { 185 if (it1->id() < it2->id()) { 186 ++it1; 187 } else if (it1->id() > it2->id()) { 188 ++it2; 189 } else { 190 ElementType* p = it1->Intersect(*it2); 191 if (p) 192 set3->insert(p); 193 ++it1; 194 ++it2; 195 } 196 } 197 } 198 199 static void Union(const T& set1, const T& set2, T* set3) { 200 DCHECK(set3); 201 set3->clear(); 202 203 const_iterator it1 = set1.begin(); 204 const_iterator it2 = set2.begin(); 205 const const_iterator end1 = set1.end(); 206 const const_iterator end2 = set2.end(); 207 208 while (true) { 209 if (it1 == end1) { 210 while (it2 != end2) { 211 set3->insert(it2->Clone()); 212 ++it2; 213 } 214 break; 215 } 216 if (it2 == end2) { 217 while (it1 != end1) { 218 set3->insert(it1->Clone()); 219 ++it1; 220 } 221 break; 222 } 223 if (it1->id() < it2->id()) { 224 set3->insert(it1->Clone()); 225 ++it1; 226 } else if (it1->id() > it2->id()) { 227 set3->insert(it2->Clone()); 228 ++it2; 229 } else { 230 set3->insert(it1->Union(*it2)); 231 ++it1; 232 ++it2; 233 } 234 } 235 } 236 237 const_iterator begin() const { 238 return const_iterator(map().begin()); 239 } 240 241 const_iterator end() const { 242 return map().end(); 243 } 244 245 const_iterator find(ElementIDType id) const { 246 return map().find(id); 247 } 248 249 size_t count(ElementIDType id) const { 250 return map().count(id); 251 } 252 253 bool empty() const { 254 return map().empty(); 255 } 256 257 size_t erase(ElementIDType id) { 258 return map().erase(id); 259 } 260 261 // Take ownership and insert |item| into the set. 262 void insert(ElementType* item) { 263 map_[item->id()].reset(item); 264 } 265 266 size_t size() const { 267 return map().size(); 268 } 269 270 const Map& map() const { 271 return map_; 272 } 273 274 Map& map() { 275 return map_; 276 } 277 278 void clear() { 279 map_.clear(); 280 } 281 282 private: 283 Map map_; 284 }; 285 286 } // namespace extensions 287 288 #endif // EXTENSIONS_COMMON_PERMISSIONS_BASE_SET_OPERATORS_H_ 289