/* * Ceph - scalable distributed file system * * Copyright (C) 2015 Red Hat, Inc * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_COMPACT_MAP_H #define CEPH_COMPACT_MAP_H #include "buffer.h" #include "encoding.h" #include #include #include "include/encoding.h" template class compact_map_base { protected: std::unique_ptr map; void alloc_internal() { if (!map) map.reset(new Map); } void free_internal() { map.reset(); } template class const_iterator_base { const compact_map_base *map; It it; const_iterator_base() : map(0) { } const_iterator_base(const compact_map_base* m) : map(m) { } const_iterator_base(const compact_map_base *m, const It& i) : map(m), it(i) { } friend class compact_map_base; friend class iterator_base; public: const_iterator_base(const const_iterator_base& o) { map = o.map; it = o.it; } bool operator==(const const_iterator_base& o) const { return (map == o.map) && (!map->map || it == o.it); } bool operator!=(const const_iterator_base& o) const { return !(*this == o);; } const_iterator_base& operator=(const const_iterator_base& o) { map = o.map; it = o.it; return *this; } const_iterator_base& operator++() { ++it; return *this; } const_iterator_base& operator--() { --it; return *this; } const std::pair& operator*() { return *it; } const std::pair* operator->() { return it.operator->(); } }; template class iterator_base { private: const compact_map_base* map; It it; iterator_base() : map(0) { } iterator_base(compact_map_base* m) : map(m) { } iterator_base(compact_map_base* m, const It& i) : map(m), it(i) { } friend class compact_map_base; public: iterator_base(const iterator_base& o) { map = o.map; it = o.it; } bool operator==(const iterator_base& o) const { return (map == o.map) && (!map->map || it == o.it); } bool operator!=(const iterator_base& o) const { return !(*this == o);; } iterator_base& operator=(const iterator_base& o) { map = o.map; it = o.it; return *this; } iterator_base& operator++() { ++it; return *this; } iterator_base operator++(int) { iterator_base tmp = *this; ++it; return tmp; } iterator_base& operator--() { --it; return *this; } std::pair& operator*() { return *it; } std::pair* operator->() { return it.operator->(); } operator const_iterator_base() const { return const_iterator_base(map, it); } }; public: class iterator : public iterator_base { public: iterator() { } iterator(const iterator_base& o) : iterator_base(o) { } iterator(compact_map_base* m) : iterator_base(m) { } iterator(compact_map_base* m, const typename Map::iterator& i) : iterator_base(m, i) { } }; class const_iterator : public const_iterator_base { public: const_iterator() { } const_iterator(const iterator_base& o) : const_iterator_base(o) { } const_iterator(const compact_map_base* m) : const_iterator_base(m) { } const_iterator(const compact_map_base* m, const typename Map::const_iterator& i) : const_iterator_base(m, i) { } }; class reverse_iterator : public iterator_base { public: reverse_iterator() { } reverse_iterator(const iterator_base& o) : iterator_base(o) { } reverse_iterator(compact_map_base* m) : iterator_base(m) { } reverse_iterator(compact_map_base* m, const typename Map::reverse_iterator& i) : iterator_base(m, i) { } }; class const_reverse_iterator : public const_iterator_base { public: const_reverse_iterator() { } const_reverse_iterator(const iterator_base& o) : iterator_base(o) { } const_reverse_iterator(const compact_map_base* m) : const_iterator_base(m) { } const_reverse_iterator(const compact_map_base* m, const typename Map::const_reverse_iterator& i) : const_iterator_base(m, i) { } }; compact_map_base(const compact_map_base& o) { if (o.map) { alloc_internal(); *map = *o.map; } } compact_map_base() {} ~compact_map_base() {} bool empty() const { return !map || map->empty(); } size_t size() const { return map ? map->size() : 0; } bool operator==(const compact_map_base& o) const { return (empty() && o.empty()) || (map && o.map && *map == *o.map); } bool operator!=(const compact_map_base& o) const { return !(*this == o); } size_t count (const Key& k) const { return map ? map->count(k) : 0; } iterator erase (iterator p) { if (map) { ceph_assert(this == p.map); auto it = map->erase(p.it); if (map->empty()) { free_internal(); return iterator(this); } else { return iterator(this, it); } } else { return iterator(this); } } size_t erase (const Key& k) { if (!map) return 0; size_t r = map->erase(k); if (map->empty()) free_internal(); return r; } void clear() { free_internal(); } void swap(compact_map_base& o) { map.swap(o.map); } compact_map_base& operator=(const compact_map_base& o) { if (o.map) { alloc_internal(); *map = *o.map; } else free_internal(); return *this; } iterator insert(const std::pair& val) { alloc_internal(); return iterator(this, map->insert(val)); } template std::pair emplace ( Args&&... args ) { alloc_internal(); auto em = map->emplace(std::forward(args)...); return std::pair(iterator(this, em.first), em.second); } iterator begin() { if (!map) return iterator(this); return iterator(this, map->begin()); } iterator end() { if (!map) return iterator(this); return iterator(this, map->end()); } reverse_iterator rbegin() { if (!map) return reverse_iterator(this); return reverse_iterator(this, map->rbegin()); } reverse_iterator rend() { if (!map) return reverse_iterator(this); return reverse_iterator(this, map->rend()); } iterator find(const Key& k) { if (!map) return iterator(this); return iterator(this, map->find(k)); } iterator lower_bound(const Key& k) { if (!map) return iterator(this); return iterator(this, map->lower_bound(k)); } iterator upper_bound(const Key& k) { if (!map) return iterator(this); return iterator(this, map->upper_bound(k)); } const_iterator begin() const { if (!map) return const_iterator(this); return const_iterator(this, map->begin()); } const_iterator end() const { if (!map) return const_iterator(this); return const_iterator(this, map->end()); } const_reverse_iterator rbegin() const { if (!map) return const_reverse_iterator(this); return const_reverse_iterator(this, map->rbegin()); } const_reverse_iterator rend() const { if (!map) return const_reverse_iterator(this); return const_reverse_iterator(this, map->rend()); } const_iterator find(const Key& k) const { if (!map) return const_iterator(this); return const_iterator(this, map->find(k)); } const_iterator lower_bound(const Key& k) const { if (!map) return const_iterator(this); return const_iterator(this, map->lower_bound(k)); } const_iterator upper_bound(const Key& k) const { if (!map) return const_iterator(this); return const_iterator(this, map->upper_bound(k)); } void encode(ceph::buffer::list &bl) const { using ceph::encode; if (map) encode(*map, bl); else encode((uint32_t)0, bl); } void encode(ceph::buffer::list &bl, uint64_t features) const { using ceph::encode; if (map) encode(*map, bl, features); else encode((uint32_t)0, bl); } void decode(ceph::buffer::list::const_iterator& p) { using ceph::decode; using ceph::decode_nohead; uint32_t n; decode(n, p); if (n > 0) { alloc_internal(); decode_nohead(n, *map, p); } else free_internal(); } }; template inline void encode(const compact_map_base& m, ceph::buffer::list& bl) { m.encode(bl); } template inline void encode(const compact_map_base& m, ceph::buffer::list& bl, uint64_t features) { m.encode(bl, features); } template inline void decode(compact_map_base& m, ceph::buffer::list::const_iterator& p) { m.decode(p); } template , class Alloc = std::allocator< std::pair > > class compact_map : public compact_map_base > { public: T& operator[](const Key& k) { this->alloc_internal(); return (*(this->map))[k]; } }; template , class Alloc = std::allocator< std::pair > > inline std::ostream& operator<<(std::ostream& out, const compact_map& m) { out << "{"; bool first = true; for (const auto &p : m) { if (!first) out << ","; out << p.first << "=" << p.second; first = false; } out << "}"; return out; } template , class Alloc = std::allocator< std::pair > > class compact_multimap : public compact_map_base > { }; template , class Alloc = std::allocator< std::pair > > inline std::ostream& operator<<(std::ostream& out, const compact_multimap& m) { out << "{{"; bool first = true; for (const auto &p : m) { if (!first) out << ","; out << p.first << "=" << p.second; first = false; } out << "}}"; return out; } #endif