// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef EXTENSIONS_COMMON_PERMISSIONS_BASE_SET_OPERATORS_H_ #define EXTENSIONS_COMMON_PERMISSIONS_BASE_SET_OPERATORS_H_ #include #include #include #include "base/memory/linked_ptr.h" namespace extensions { // Traits for template paramater of |BaseSetOperators|. Specializations // should define |ElementType| for the type of elements to store in the set, // and |EmementIDType| for the type of element identifiers. template struct BaseSetOperatorsTraits {}; // Set operations shared by |APIPermissionSet| and |ManifestPermissionSet|. // // TODO(rpaquay): It would be nice to remove the need for the sub-classes and // instead directly use this class where needed. template class BaseSetOperators { public: typedef typename BaseSetOperatorsTraits::ElementType ElementType; typedef typename BaseSetOperatorsTraits::ElementIDType ElementIDType; typedef std::map > Map; class const_iterator : public std::iterator { public: const_iterator(const typename Map::const_iterator& it) : it_(it) {} const_iterator(const const_iterator& ids_it) : it_(ids_it.it_) {} const_iterator& operator++() { ++it_; return *this; } const_iterator operator++(int) { const_iterator tmp(it_++); return tmp; } bool operator==(const const_iterator& rhs) const { return it_ == rhs.it_; } bool operator!=(const const_iterator& rhs) const { return it_ != rhs.it_; } const ElementType* operator*() const { return it_->second.get(); } const ElementType* operator->() const { return it_->second.get(); } private: typename Map::const_iterator it_; }; BaseSetOperators() { // Ensure |T| is convertible to us, so we can safely downcast when calling // methods that must exist in |T|. static_assert(std::is_convertible*>::value, "U ptr must implicitly convert to T ptr"); } BaseSetOperators(const T& set) { this->operator=(set); } ~BaseSetOperators() {} T& operator=(const T& rhs) { return Assign(rhs); } bool operator==(const T& rhs) const { return Equal(rhs); } bool operator!=(const T& rhs) const { return !operator==(rhs); } T& Assign(const T& rhs) { const_iterator it = rhs.begin(); const const_iterator end = rhs.end(); while (it != end) { insert(it->Clone()); ++it; } return *static_cast(this); } bool Equal(const T& rhs) const { const_iterator it = begin(); const_iterator rhs_it = rhs.begin(); const_iterator it_end = end(); const_iterator rhs_it_end = rhs.end(); while (it != it_end && rhs_it != rhs_it_end) { if (it->id() > rhs_it->id()) return false; else if (it->id() < rhs_it->id()) return false; else if (!it->Equal(*rhs_it)) return false; ++it; ++rhs_it; } return it == it_end && rhs_it == rhs_it_end; } bool Contains(const T& rhs) const { const_iterator it1 = begin(); const_iterator it2 = rhs.begin(); const_iterator end1 = end(); const_iterator end2 = rhs.end(); while (it1 != end1 && it2 != end2) { if (it1->id() > it2->id()) { return false; } else if (it1->id() < it2->id()) { ++it1; } else { if (!it1->Contains(*it2)) return false; ++it1; ++it2; } } return it2 == end2; } static void Difference(const T& set1, const T& set2, T* set3) { CHECK(set3); set3->clear(); const_iterator it1 = set1.begin(); const_iterator it2 = set2.begin(); const const_iterator end1 = set1.end(); const const_iterator end2 = set2.end(); while (it1 != end1 && it2 != end2) { if (it1->id() < it2->id()) { set3->insert(it1->Clone()); ++it1; } else if (it1->id() > it2->id()) { ++it2; } else { ElementType* p = it1->Diff(*it2); if (p) set3->insert(p); ++it1; ++it2; } } while (it1 != end1) { set3->insert(it1->Clone()); ++it1; } } static void Intersection(const T& set1, const T& set2, T* set3) { DCHECK(set3); set3->clear(); const_iterator it1 = set1.begin(); const_iterator it2 = set2.begin(); const const_iterator end1 = set1.end(); const const_iterator end2 = set2.end(); while (it1 != end1 && it2 != end2) { if (it1->id() < it2->id()) { ++it1; } else if (it1->id() > it2->id()) { ++it2; } else { ElementType* p = it1->Intersect(*it2); if (p) set3->insert(p); ++it1; ++it2; } } } static void Union(const T& set1, const T& set2, T* set3) { DCHECK(set3); set3->clear(); const_iterator it1 = set1.begin(); const_iterator it2 = set2.begin(); const const_iterator end1 = set1.end(); const const_iterator end2 = set2.end(); while (true) { if (it1 == end1) { while (it2 != end2) { set3->insert(it2->Clone()); ++it2; } break; } if (it2 == end2) { while (it1 != end1) { set3->insert(it1->Clone()); ++it1; } break; } if (it1->id() < it2->id()) { set3->insert(it1->Clone()); ++it1; } else if (it1->id() > it2->id()) { set3->insert(it2->Clone()); ++it2; } else { set3->insert(it1->Union(*it2)); ++it1; ++it2; } } } const_iterator begin() const { return const_iterator(map().begin()); } const_iterator end() const { return map().end(); } const_iterator find(ElementIDType id) const { return map().find(id); } size_t count(ElementIDType id) const { return map().count(id); } bool empty() const { return map().empty(); } size_t erase(ElementIDType id) { return map().erase(id); } // Take ownership and insert |item| into the set. void insert(ElementType* item) { map_[item->id()].reset(item); } size_t size() const { return map().size(); } const Map& map() const { return map_; } Map& map() { return map_; } void clear() { map_.clear(); } private: Map map_; }; } // namespace extensions #endif // EXTENSIONS_COMMON_PERMISSIONS_BASE_SET_OPERATORS_H_