#ifndef EXTENSIONS_COMMON_PERMISSIONS_BASE_SET_OPERATORS_H_
#define EXTENSIONS_COMMON_PERMISSIONS_BASE_SET_OPERATORS_H_
#include <iterator>
#include <map>
#include "base/memory/linked_ptr.h"
#include "base/template_util.h"
namespace extensions {
template <typename T>
struct BaseSetOperatorsTraits {};
template <typename T>
class BaseSetOperators {
public:
typedef typename BaseSetOperatorsTraits<T>::ElementType ElementType;
typedef typename BaseSetOperatorsTraits<T>::ElementIDType ElementIDType;
typedef std::map<ElementIDType, linked_ptr<ElementType> > Map;
class const_iterator :
public std::iterator<std::input_iterator_tag, const ElementType*> {
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() {
COMPILE_ASSERT((base::is_convertible<T*, BaseSetOperators<T>*>::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<T*>(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);
}
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_;
};
}
#endif