summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStepan Dyatkovskiy <stpworld@narod.ru>2012-04-25 17:09:38 +0000
committerStepan Dyatkovskiy <stpworld@narod.ru>2012-04-25 17:09:38 +0000
commit76271a3366731d4c372fdebcd8d3437e6e09a61b (patch)
tree753cad255078a61246190aa77b8360ee685af238
parent50e1d84ba8efc1973137c65e0b0e048ecf8cf5d6 (diff)
First implementation of:
- FlatArrayMap. Very simple map container that uses flat array inside. - MultiImplMap. Map container interface, that has two modes, one for small amount of elements and one for big amount. - SmallMap. SmallMap is DenseMap compatible MultiImplMap. It uses FlatArrayMap for small mode, and DenseMap for big mode. Also added unittests for new classes and update for ProgrammersManual. For more details about new classes see ProgrammersManual and comments in sourcecode. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@155557 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--docs/ProgrammersManual.html81
-rw-r--r--include/llvm/ADT/FlatArrayMap.h323
-rw-r--r--include/llvm/ADT/MultiImplMap.h550
-rw-r--r--include/llvm/ADT/SmallMap.h37
-rw-r--r--unittests/ADT/SmallMapTest.cpp133
5 files changed, 1124 insertions, 0 deletions
diff --git a/docs/ProgrammersManual.html b/docs/ProgrammersManual.html
index 854f90e28b3..f81d7130a31 100644
--- a/docs/ProgrammersManual.html
+++ b/docs/ProgrammersManual.html
@@ -95,6 +95,9 @@ option</a></li>
<li><a href="#dss_stringmap">"llvm/ADT/StringMap.h"</a></li>
<li><a href="#dss_indexedmap">"llvm/ADT/IndexedMap.h"</a></li>
<li><a href="#dss_densemap">"llvm/ADT/DenseMap.h"</a></li>
+ <li><a href="#dss_multiimplmap">"llvm/ADT/MultiImplMap.h"</a></li>
+ <li><a href="#dss_flatarraymap">"llvm/ADT/FlatArrayMap.h"</a></li>
+ <li><a href="#dss_smallmap">"llvm/ADT/SmallMap.h"</a></li>
<li><a href="#dss_valuemap">"llvm/ADT/ValueMap.h"</a></li>
<li><a href="#dss_intervalmap">"llvm/ADT/IntervalMap.h"</a></li>
<li><a href="#dss_map">&lt;map&gt;</a></li>
@@ -1812,6 +1815,84 @@ a <code>Config</code> parameter to the ValueMap template.</p>
<!-- _______________________________________________________________________ -->
<h4>
+ <a name="dss_multiimplmap">"llvm/ADT/MultiImplMap.h"</a>
+</h4>
+
+<div>
+
+<p>
+MultiImplMap is map that has two modes, one for small amount of elements and
+one for big amount. User should set map implementation for both of them.
+User also should set the maximum possible number of elements for small mode.
+</p>
+
+<p>
+If user want to use MultiImplMap instead of
+<a href="#dss_densemap">DenseMap</a>, he should pass template parameter
+DenseMapCompatible = true. Note, that in this case map implementations
+should present additional DenseMap specific methods (see below):
+<code>isPointerIntoBucketsArray</code>, <code>getPointerIntoBucketsArray</code>
+and <code>FindAndConstruct</code>.
+</p>
+
+<p>
+Initially MultiImplMap uses small mode and small map implementation. It
+triggered to the big mode when the number of contained elements exceeds
+maximum possible elements for small mode.
+</p>
+
+</div>
+
+<!-- _______________________________________________________________________ -->
+<h4>
+ <a name="dss_flatarraymap">"llvm/ADT/FlatArrayMap.h"</a>
+</h4>
+
+<div>
+
+<p>
+FlatArrayMap optimized for small amount of elements. It uses flat array
+implementation inside:
+</p>
+<pre>[ key0, value0, key1, value1, ... keyN, valueN ]</pre>
+
+
+<p>
+User should pass key type, mapped type (type of value), and maximum
+number of elements.
+</p>
+
+<p>
+After maximum number of elements is reached, map declines any further
+attempts to insert new elements ("insert" method returns &#60;end(),
+false&#62;).
+</p>
+
+<p>
+FlatArrayMap has interface that is compatible with
+<a href="#dss_densemap">DenseMap</a>, so user can replace it with DenseMap
+without any code changing and vice versa.
+</p>
+
+</div>
+
+<!-- _______________________________________________________________________ -->
+<h4>
+ <a name="dss_smallmap">"llvm/ADT/SmallMap.h"</a>
+</h4>
+
+<div>
+
+<p>
+SmallMap is wrapper around <a href="#dss_multiimplmap">MultiImplMap</a>.
+It uses <a href="#dss_flatarraymap">FlatArrayMap</a> for small mode, and
+<a href="#dss_densemap">DenseMap</a> for big mode.
+</p>
+
+</div>
+
+<!-- _______________________________________________________________________ -->
+<h4>
<a name="dss_intervalmap">"llvm/ADT/IntervalMap.h"</a>
</h4>
diff --git a/include/llvm/ADT/FlatArrayMap.h b/include/llvm/ADT/FlatArrayMap.h
new file mode 100644
index 00000000000..6f920e48bc6
--- /dev/null
+++ b/include/llvm/ADT/FlatArrayMap.h
@@ -0,0 +1,323 @@
+//===- llvm/ADT/FlatArrayMap.h - 'Normally small' pointer set ----*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the FlatArrayMap class.
+// See FlatArrayMap doxygen comments for more details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FLATARRAYMAP_H_
+#define FLATARRAYMAP_H_
+
+#include <algorithm>
+#include <utility>
+#include "llvm/Support/type_traits.h"
+
+namespace llvm {
+
+ template <typename KeyTy, typename MappedTy>
+ struct FlatArrayMapTypes {
+ typedef KeyTy key_type;
+ typedef MappedTy mapped_type;
+ typedef typename std::pair<key_type, mapped_type> value_type;
+ };
+
+ template<typename KeyTy, typename MappedTy, bool IsConst = false>
+ class FlatArrayMapIterator;
+
+ //===--------------------------------------------------------------------===//
+ /// FlatArrayMap presents map container interface.
+ /// It uses flat array implementation inside:
+ /// [ <key0, value0>, <key1, value1>, ... <keyN, valueN> ]
+ /// It works fast for small amount of elements.
+ /// User should pass key type, mapped type (type of value), and maximum
+ /// number of elements.
+ /// After maximum number of elements is reached, map declines any farther
+ /// attempts to insert new elements ("insert" method returns <end(),false>).
+ ///
+ template <typename KeyTy, typename MappedTy, unsigned MaxArraySize>
+ class FlatArrayMap {
+ public:
+ typedef FlatArrayMapTypes<KeyTy, MappedTy> Types;
+
+ typedef typename Types::key_type key_type;
+ typedef typename Types::mapped_type mapped_type;
+ typedef typename Types::value_type value_type;
+
+ typedef FlatArrayMapIterator<KeyTy, MappedTy> iterator;
+ typedef FlatArrayMapIterator<KeyTy, MappedTy, true> const_iterator;
+
+ typedef FlatArrayMap<KeyTy, MappedTy, MaxArraySize> self;
+
+ private:
+
+ enum { BadIndex = ~0UL };
+
+ key_type EmptyKey;
+ mapped_type EmptyValue;
+
+ value_type Array[MaxArraySize + 1];
+ unsigned NumElements;
+
+ unsigned findFor(const KeyTy Ptr) const {
+ // Linear search for the item.
+ for (const value_type *APtr = Array, *E = Array + NumElements;
+ APtr != E; ++APtr) {
+ if (APtr->first == Ptr) {
+ return APtr - Array;
+ }
+ }
+ return BadIndex;
+ }
+
+ bool lookupFor(const KeyTy &Ptr, const value_type*& Found) const {
+ unsigned FoundIdx = findFor(Ptr);
+ if (FoundIdx != BadIndex) {
+ Found = Array + FoundIdx;
+ return true;
+ }
+ return false;
+ }
+
+ bool lookupFor(const KeyTy &Ptr, value_type*& Found) {
+ unsigned FoundIdx = findFor(Ptr);
+ if (FoundIdx != BadIndex) {
+ Found = Array + FoundIdx;
+ return true;
+ }
+ return false;
+ }
+
+
+ void copyFrom(const self &RHS) {
+ memcpy(Array, RHS.Array, sizeof(value_type) * (MaxArraySize + 1));
+ NumElements = RHS.NumElements;
+ }
+
+ void init () {
+ memset(Array + MaxArraySize, 0, sizeof(value_type));
+ NumElements = 0;
+ }
+
+ bool insertInternal(KeyTy Ptr, MappedTy Val, value_type*& Item) {
+ // Check to see if it is already in the set.
+ value_type *Found;
+ if (lookupFor(Ptr, Found)) {
+ Item = Found;
+ return false;
+ }
+ if (NumElements < MaxArraySize) {
+ unsigned Idx = NumElements++;
+ Array[Idx] = std::make_pair(Ptr, Val);
+ Item = Array + Idx;
+ return true;
+ }
+ Item = Array + MaxArraySize; // return end()
+ return false;
+ }
+
+ public:
+
+ // Constructors
+
+ FlatArrayMap() : EmptyKey(), EmptyValue() {
+ init();
+ }
+
+ FlatArrayMap(const self &that) :
+ EmptyKey(), EmptyValue() {
+ copyFrom(that);
+ }
+
+ template<typename It>
+ FlatArrayMap(It I, It E) :
+ EmptyKey(), EmptyValue() {
+ init();
+ insert(I, E);
+ }
+
+ // Size
+
+ unsigned size() const {
+ return NumElements;
+ }
+
+ bool empty() const {
+ return !NumElements;
+ }
+
+ // Iterators
+
+ iterator begin() {
+ return iterator(Array);
+ }
+ const_iterator begin() const {
+ return const_iterator(Array);
+ }
+
+ iterator end() {
+ return iterator(Array + MaxArraySize);
+ }
+ const_iterator end() const {
+ return const_iterator(Array + MaxArraySize);
+ }
+
+ // Modifiers
+
+ void clear() {
+ for (unsigned i = 0; i < NumElements; ++i) {
+ Array[i].first = EmptyKey;
+ Array[i].second = EmptyValue;
+ }
+ NumElements = 0;
+ }
+
+ // The map container is extended by inserting a single new element.
+ // The behavior is the same as the std::map::insert, except the
+ // case when maximum number of elements is reached;
+ // in this case map declines any farther attempts
+ // to insert new elements ("insert" method returns <end(),false>).
+ std::pair<iterator, bool> insert(const value_type& KV) {
+ value_type* Item;
+ bool Res = insertInternal(KV.first, KV.second, Item);
+ return std::make_pair(iterator(Item), Res);
+ }
+
+ template <typename IterT>
+ void insert(IterT I, IterT E) {
+ for (; I != E; ++I)
+ insert(*I);
+ }
+
+ void erase(key_type K) {
+ unsigned Found = findFor(K);
+ if (Found != BadIndex) {
+ value_type *APtr = Array + Found;
+ value_type *E = Array + NumElements;
+ *APtr = E[-1];
+ E[-1].first.~key_type();
+ E[-1].second.~mapped_type();
+ --NumElements;
+ }
+ }
+
+ void erase(iterator i) {
+ erase(i->first);
+ }
+
+ void swap(self& RHS) {
+ std::swap_ranges(Array, Array+MaxArraySize, RHS.Array);
+ std::swap(this->NumElements, RHS.NumElements);
+ }
+
+ // Search operations
+
+ iterator find(const key_type& K) {
+ value_type *Found;
+ if (lookupFor(K, Found))
+ return iterator(Found);
+ return end();
+ }
+
+ const_iterator find(const key_type& K) const {
+ const value_type *Found;
+ if (lookupFor(K, Found))
+ return const_iterator(Found);
+ return end();
+ }
+
+ bool count(const key_type& K) const {
+ return find(K) != end();
+ }
+
+ mapped_type &operator[](const key_type &Key) {
+ std::pair<iterator, bool> res = insert(Key, mapped_type());
+ return res.first->second;
+ }
+
+ // Other operations
+
+ self& operator=(const self& other) {
+ clear();
+ copyFrom(other);
+ return *this;
+ }
+
+ /// isPointerIntoBucketsArray - Return true if the specified pointer points
+ /// somewhere into the map's array of buckets (i.e. either to a key or
+ /// value).
+ bool isPointerIntoBucketsArray(const void *Ptr) const {
+ return Ptr >= Array && Ptr < Array + NumElements;
+ }
+
+ /// getPointerIntoBucketsArray() - Return an opaque pointer into the buckets
+ /// array.
+ const void *getPointerIntoBucketsArray() const { return Array; }
+ };
+
+ template<typename KeyTy, typename MappedTy, bool IsConst>
+ class FlatArrayMapIterator {
+
+ typedef FlatArrayMapTypes<KeyTy, MappedTy> Types;
+
+ typedef typename conditional<IsConst,
+ const typename Types::value_type,
+ typename Types::value_type>::type value_type;
+ typedef value_type *pointer;
+ typedef value_type &reference;
+
+ typedef FlatArrayMapIterator<KeyTy, MappedTy, IsConst> self;
+ typedef FlatArrayMapIterator<KeyTy, MappedTy, false> non_const_self;
+ typedef FlatArrayMapIterator<KeyTy, MappedTy, true> const_self;
+
+ friend class FlatArrayMapIterator<KeyTy, MappedTy, false>;
+ friend class FlatArrayMapIterator<KeyTy, MappedTy, true>;
+
+ pointer TheBucket;
+
+ public:
+
+ FlatArrayMapIterator() : TheBucket(0) {}
+
+ explicit FlatArrayMapIterator(pointer BP) :
+ TheBucket(BP) {}
+
+ // If IsConst is true this is a converting constructor from iterator to
+ // const_iterator and the default copy constructor is used.
+ // Otherwise this is a copy constructor for iterator.
+ FlatArrayMapIterator(const non_const_self& I)
+ : TheBucket(I.TheBucket) {}
+
+ bool operator==(const const_self &RHS) const {
+ return TheBucket->first == RHS.TheBucket->first;
+ }
+ bool operator!=(const const_self &RHS) const {
+ return TheBucket->first != RHS.TheBucket->first;
+ }
+
+ reference operator*() const {
+ return *TheBucket;
+ }
+
+ pointer operator->() const {
+ return TheBucket;
+ }
+
+ inline self& operator++() { // Preincrement
+ ++TheBucket;
+ return *this;
+ }
+
+ self operator++(int) { // Postincrement
+ FlatArrayMapIterator tmp = *this; ++*this; return tmp;
+ }
+ };
+}
+
+#endif /* FLATARRAYMAP_H_ */
diff --git a/include/llvm/ADT/MultiImplMap.h b/include/llvm/ADT/MultiImplMap.h
new file mode 100644
index 00000000000..d585de68110
--- /dev/null
+++ b/include/llvm/ADT/MultiImplMap.h
@@ -0,0 +1,550 @@
+//===- llvm/ADT/MultiImplMap.h - 'Normally small' pointer set ----*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the MultiImplMap class.
+// MultiImplMap presents map container interface.
+// It has two modes, one for small amount of elements and one for big amount.
+// User should set map implementation for both of them. User also should
+// set the maximum possible number of elements for small mode.
+// If user want to use MultiImplMap instead of DenseMap, he should pass
+// DenseMapCompatible = true. Note that in this case map implementations should
+// present additional DenseMap specific methods (see below).
+// Initially MultiImplMap uses small mode and small map implementation.
+// It triggered to the big mode when number of contained elements exceeds
+// maximum possible elements for small mode.
+//
+// Types that should be defined in nested map class:
+//
+// key_type;
+// mapped_type;
+// value_type; // std::pair<key_type, mapped_type>
+// // or std::pair<const key_type, mapped_type>
+// iterator;
+// const_iterator;
+//
+// Map implementation should provide the next interface:
+//
+// // Constructors
+// (default constructor)
+// (copy constructor)
+//
+// // Size
+// unsigned size() const;
+// bool empty() const;
+//
+// // Iterators
+// iterator begin();
+// const_iterator begin();
+// iterator end();
+// const_iterator end();
+//
+// // Modifiers
+// void clear();
+// std::pair<iterator, bool> insert(const value_type& KV);
+// template <typename IterT>
+// void insert(IterT I, IterT E);
+// void erase(key_type K);
+// void erase(iterator i);
+// void swap(MultiImplMap& rhs);
+//
+// // Search operations
+// iterator find(const key_type& K);
+// const_iterator find(const key_type& K) const;
+// bool count(const key_type& K) const;
+// mapped_type &operator[](const key_type &Key);
+//
+// // Other operations
+// self& operator=(const self& other);
+//
+// // If DenseMapCompatible == true, you also should present next methods.
+// // See DenseMap comments for more details about its behavior.
+// bool isPointerIntoBucketsArray(const void *Ptr) const;
+// const void *getPointerIntoBucketsArray() const;
+// value_type& FindAndConstruct(const key_type &Key);
+//
+// The list of methods that should be implemented in nested map iterator class:
+//
+// (conversion constructor from non-constant iterator)
+//
+// bool operator==(const const_iterator& rhs) const;
+// bool operator!=(const const_iterator& rhs) const;
+// reference operator*() const;
+// pointer operator->() const;
+// inline self& operator++();
+//
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MULTIIMPLEMENTATIONMAP_H_
+#define MULTIIMPLEMENTATIONMAP_H_
+
+
+#include <algorithm>
+#include <utility>
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/FlatArrayMap.h"
+#include "llvm/Support/type_traits.h"
+
+namespace llvm {
+
+ template<class SmallMapTy, class BigMapTy, bool IsConst = false>
+ class MultiImplMapIterator;
+
+ template<class SmallMapTy, class BigMapTy>
+ struct MultiImplMapIteratorsFactory;
+
+ template<class SmallMapTy, class BigMapTy>
+ struct MultiImplMapTypes {
+ typedef typename SmallMapTy::key_type key_type;
+ typedef typename SmallMapTy::mapped_type mapped_type;
+ typedef typename std::pair<key_type, mapped_type> value_type;
+ };
+
+ //===--------------------------------------------------------------------===//
+ /// MultiImplMap is map that has two modes, one for small amount of
+ /// elements and one for big amount.
+ /// User should set map implementation for both of them. User also should
+ /// set the maximum possible number of elements for small mode.
+ /// If user want to use MultiImplMap instead of DenseMap, he should pass
+ /// DenseMapCompatible = true.
+ /// Initially MultiImplMap uses small mode and small map implementation.
+ /// It triggered to the big mode when number of contained elements exceeds
+ /// maximum possible elements for small mode.
+ template<class SmallMapTy, class BigMapTy, unsigned MaxSmallN,
+ bool DenseMapCompatible = false,
+ class ItFactory =
+ MultiImplMapIteratorsFactory<SmallMapTy, BigMapTy> >
+ class MultiImplMap {
+
+ protected:
+ SmallMapTy SmallMap;
+ BigMapTy BigMap;
+ bool UseSmall;
+ enum { MaxSmallSize = MaxSmallN };
+
+ public:
+ typedef MultiImplMapTypes<SmallMapTy, BigMapTy> Types;
+
+ typedef typename Types::key_type key_type;
+ typedef typename Types::mapped_type mapped_type;
+ typedef typename Types::value_type value_type;
+
+ typedef typename ItFactory::iterator iterator;
+ typedef typename ItFactory::const_iterator const_iterator;
+
+ typedef std::pair<iterator, bool> ins_res;
+
+ typedef typename std::pair<typename SmallMapTy::iterator, bool>
+ small_ins_res;
+
+ typedef typename std::pair<typename BigMapTy::iterator, bool>
+ big_ins_res;
+
+ typedef MultiImplMap<SmallMapTy, BigMapTy, MaxSmallN> self;
+
+ MultiImplMap() : UseSmall(true) {}
+
+ MultiImplMap(const self& other) {
+ if (other.UseSmall) {
+ SmallMap = other.SmallMap;
+ UseSmall = true;
+ } else {
+ if (other.size() <= MaxSmallN) {
+ SmallMap.insert(other.BigMap.begin(), other.BigMap.end());
+ UseSmall = true;
+ } else {
+ BigMap = other.BigMap;
+ UseSmall = false;
+ }
+ }
+ }
+
+ // Size
+
+ unsigned size() const {
+ if (UseSmall)
+ return SmallMap.size();
+ return BigMap.size();
+ }
+
+ bool empty() const {
+ if (UseSmall)
+ return SmallMap.empty();
+ return BigMap.empty();
+ }
+
+ // Iterators
+
+ iterator begin() {
+ if (UseSmall)
+ return ItFactory::begin(SmallMap);
+ return ItFactory::begin(BigMap);
+ }
+ const_iterator begin() const {
+ if (UseSmall)
+ return ItFactory::begin(SmallMap);
+ return ItFactory::begin(BigMap);
+ }
+
+ iterator end() {
+ if (UseSmall)
+ return ItFactory::end(SmallMap);
+ return ItFactory::end(BigMap);
+ }
+ const_iterator end() const {
+ if (UseSmall)
+ return ItFactory::end(SmallMap);
+ return ItFactory::end(BigMap);
+ }
+
+ // Modifiers
+
+ void clear() {
+ if (UseSmall)
+ SmallMap.clear();
+ else
+ BigMap.clear();
+ }
+
+ std::pair<iterator, bool> insert(const value_type& KV) {
+ if (UseSmall) {
+ if (SmallMap.size() < MaxSmallSize) {
+ small_ins_res Res = SmallMap.insert(KV);
+ return std::make_pair(ItFactory::it(SmallMap, Res.first), Res.second);
+ }
+
+ // Move all to big map.
+ BigMap.insert(SmallMap.begin(), SmallMap.end());
+ SmallMap.clear();
+
+ UseSmall = false;
+ }
+ big_ins_res Res = BigMap.insert(KV);
+ return std::make_pair(ItFactory::it(BigMap, Res.first), Res.second);
+ }
+
+ template <typename OtherValTy>
+ std::pair<iterator, bool> insert(const OtherValTy& OtherKV) {
+ const value_type* KV = reinterpret_cast<const value_type*>(
+ reinterpret_cast<const void*>(OtherKV));
+ return insert(*KV);
+ }
+
+ template <typename IterT>
+ void insert(IterT I, IterT E) {
+ for (; I != E; ++I)
+ insert(*I);
+ }
+
+ void erase(key_type K) {
+ if (UseSmall)
+ SmallMap.erase(K);
+ else
+ BigMap.erase(K);
+ }
+
+ void erase(iterator i) {
+ erase(i->first);
+ }
+
+ void swap(MultiImplMap& rhs) {
+ SmallMap.swap(rhs.SmallMap);
+ BigMap.swap(rhs.BigMap);
+ std::swap(UseSmall, rhs.UseSmall);
+ }
+
+ // Search operations
+
+ iterator find(const key_type& K) {
+ if (UseSmall)
+ return ItFactory::it(SmallMap, SmallMap.find(K));
+ return ItFactory::it(BigMap, BigMap.find(K));
+ }
+
+ const_iterator find(const key_type& K) const {
+ if (UseSmall)
+ return ItFactory::const_it(SmallMap, SmallMap.find(K));
+ return ItFactory::const_it(BigMap, BigMap.find(K));
+ }
+
+ bool count(const key_type& K) const {
+ return find(K) != end();
+ }
+
+ mapped_type &operator[](const key_type &Key) {
+ ins_res res = insert(std::make_pair(Key, mapped_type()));
+ return res.first->second;
+ }
+
+ // Other operations
+
+ self& operator=(const self& other) {
+ if (other.isSmall()) {
+ SmallMap = other.SmallMap;
+ if (!UseSmall) {
+ BigMap.clear();
+ UseSmall = true;
+ }
+ return *this;
+ }
+ if (UseSmall) {
+ SmallMap.clear();
+ UseSmall = false;
+ }
+ BigMap = other.BigMap;
+ return *this;
+ }
+
+ // Utilities
+
+ bool isSmall()const {
+ return UseSmall;
+ }
+
+ SmallMapTy& getSmallMap() {
+ return SmallMap;
+ }
+
+ const SmallMapTy& getSmallMap() const {
+ return SmallMap;
+ }
+
+ BigMapTy& getBigMap() {
+ return BigMap;
+ }
+
+ const BigMapTy& getBigMap() const {
+ return BigMap;
+ }
+ };
+
+ template<class SmallMapTy, class BigMapTy, unsigned MaxSmallN>
+ class MultiImplMap<SmallMapTy, BigMapTy, MaxSmallN, true> :
+ public MultiImplMap<SmallMapTy, BigMapTy, MaxSmallN, false>
+ {
+ public:
+ typedef MultiImplMap<SmallMapTy, BigMapTy, MaxSmallN, false> ParentTy;
+ typedef typename ParentTy::Types Types;
+
+ typedef typename Types::key_type key_type;
+ typedef typename Types::mapped_type mapped_type;
+ typedef typename Types::value_type value_type;
+ typedef typename ParentTy::iterator iterator;
+
+ /// isPointerIntoBucketsArray - Return true if the specified pointer points
+ /// somewhere into the DenseMap's array of buckets (i.e. either to a key or
+ /// value).
+ bool isPointerIntoBucketsArray(const void *Ptr) const {
+ if (this->UseSmall)
+ return this->SmallMap.isPointerIntoBucketsArray(Ptr);
+ return this->BigMap.isPointerIntoBucketsArray(Ptr);
+ }
+
+ /// getPointerIntoBucketsArray() - Return an opaque pointer into the buckets
+ /// array. In conjunction with the previous method, this can be used to
+ /// determine whether an insertion caused the map to reallocate data.
+ const void *getPointerIntoBucketsArray() const {
+ if (this->UseSmall)
+ return this->SmallMap.getPointerIntoBucketsArray();
+ return this->BigMap.getPointerIntoBucketsArray();
+ }
+
+ value_type& FindAndConstruct(const key_type &Key) {
+ std::pair<iterator, bool> Res =
+ this->insert(std::make_pair(Key, mapped_type()));
+ return *Res.first;
+ }
+ };
+
+ template<class SmallMapTy, class BigMapTy, bool IsConst>
+ class MultiImplMapIterator {
+ public:
+
+ typedef MultiImplMapTypes<SmallMapTy, BigMapTy> Types;
+
+ typedef typename Types::mapped_type mapped_type;
+
+ typedef typename conditional<IsConst,
+ const typename Types::value_type,
+ typename Types::value_type>::type value_type;
+
+ typedef typename conditional<IsConst,
+ typename SmallMapTy::const_iterator,
+ typename SmallMapTy::iterator>::type
+ small_iterator;
+
+ typedef typename conditional<IsConst,
+ typename BigMapTy::const_iterator,
+ typename BigMapTy::iterator>::type
+ big_iterator;
+
+ typedef typename conditional<IsConst, const void*, void*>::type void_ptr_ty;
+
+ typedef value_type *pointer;
+ typedef value_type &reference;
+
+ typedef MultiImplMapIterator<SmallMapTy, BigMapTy, IsConst> self;
+
+ typedef MultiImplMapIterator<SmallMapTy, BigMapTy, false> non_const_self;
+ typedef MultiImplMapIterator<SmallMapTy, BigMapTy, true> const_self;
+
+ friend class MultiImplMapIterator<SmallMapTy, BigMapTy, true>;
+ friend class MultiImplMapIterator<SmallMapTy, BigMapTy, false>;
+
+ protected:
+
+ template <typename OtherValTy>
+ static value_type* toValueTypePtr(OtherValTy& ValTyRef) {
+ return reinterpret_cast<value_type*>(
+ reinterpret_cast<void_ptr_ty>(&ValTyRef));
+ }
+
+ template <typename OtherValTy>
+ static value_type& toValueTypeRef(OtherValTy& ValTyRef) {
+ return *reinterpret_cast<value_type*>(
+ reinterpret_cast<void_ptr_ty>(&ValTyRef));
+ }
+
+ small_iterator SmallIt;
+ big_iterator BigIt;
+ bool UseSmall;
+
+ public:
+
+ MultiImplMapIterator() : UseSmall(true) {}
+ MultiImplMapIterator(small_iterator It) : SmallIt(It), UseSmall(true) {}
+ MultiImplMapIterator(big_iterator It) : BigIt(It), UseSmall(false) {}
+ MultiImplMapIterator(const non_const_self& src) :
+ SmallIt(src.SmallIt), BigIt(src.BigIt), UseSmall(src.UseSmall) {}
+
+ bool operator==(const const_self& rhs) const {
+ if (UseSmall != rhs.UseSmall)
+ return false;
+ if (UseSmall)
+ return SmallIt == rhs.SmallIt;
+ return BigIt == rhs.BigIt;
+ }
+
+ bool operator!=(const const_self& rhs) const {
+ if (UseSmall != rhs.UseSmall)
+ return true;
+ if (UseSmall)
+ return SmallIt != rhs.SmallIt;
+ return BigIt != rhs.BigIt;
+ }
+
+ reference operator*() const {
+ return UseSmall ? toValueTypeRef(*SmallIt) : toValueTypeRef(*BigIt);;
+ }
+
+ pointer operator->() const {
+ return UseSmall ? toValueTypePtr(*SmallIt) : toValueTypePtr(*BigIt);
+ }
+
+ // Preincrement
+ inline self& operator++() {
+ if (UseSmall) ++SmallIt;
+ return *this;
+ }
+
+ // Postincrement
+ self operator++(int) {
+ self tmp = *this; ++*this; return tmp;
+ }
+ };
+
+ template<class SmallMapTy, class BigMapTy>
+ struct MultiImplMapIteratorsFactory {
+
+ typedef MultiImplMapIterator<SmallMapTy, BigMapTy, false> iterator;
+ typedef MultiImplMapIterator<SmallMapTy, BigMapTy, true> const_iterator;
+
+ template<class MapImpl, class ItTy>
+ static iterator it(MapImpl& impl, ItTy it) {
+ return iterator(it);
+ }
+ template<class MapImpl, class ConstItTy>
+ static const_iterator const_it(const MapImpl& impl, ConstItTy it) {
+ return const_iterator(it);
+ }
+ template<class MapImpl>
+ static iterator begin(MapImpl& impl) {
+ return iterator(impl.begin());
+ }
+ template<class MapImpl>
+ static const_iterator begin(const MapImpl& impl) {
+ return const_iterator(impl.begin());
+ }
+ template<class MapImpl>
+ static iterator end(MapImpl& impl) {
+ return iterator(impl.end());
+ }
+ template<class MapImpl>
+ static const_iterator end(const MapImpl& impl) {
+ return const_iterator(impl.end());
+ }
+ };
+
+ template<typename KeyTy, typename MappedTy, unsigned MaxArraySize,
+ typename KeyInfoT>
+ struct MultiImplMapIteratorsFactory<
+ FlatArrayMap<KeyTy, MappedTy, MaxArraySize>,
+ DenseMap<KeyTy, MappedTy, KeyInfoT> >
+ {
+
+ typedef FlatArrayMap<KeyTy, MappedTy, MaxArraySize> SmallMapTy;
+ typedef DenseMap<KeyTy, MappedTy, KeyInfoT> BigMapTy;
+
+ typedef DenseMapIterator<KeyTy, MappedTy, KeyInfoT, false>
+ iterator;
+ typedef DenseMapIterator<KeyTy, MappedTy, KeyInfoT, true>
+ const_iterator;
+
+ static iterator it(SmallMapTy& impl, typename SmallMapTy::iterator it) {
+ return iterator(&(*it), &(*impl.end()));
+ }
+ static const_iterator const_it(
+ const SmallMapTy& impl, typename SmallMapTy::const_iterator it) {
+ return const_iterator(&(*it), &(*impl.end()));
+ }
+ static iterator it(BigMapTy& impl, typename BigMapTy::iterator it) {
+ return it;
+ }
+ static const_iterator const_it(
+ const BigMapTy& impl, typename BigMapTy::const_iterator it) {
+ return it;
+ }
+ static iterator begin(SmallMapTy& impl) {
+ return it(impl, impl.begin());
+ }
+ static const_iterator begin(const SmallMapTy& impl) {
+ return it(impl, impl.begin());
+ }
+ static iterator begin(BigMapTy& impl) {
+ return impl.begin();
+ }
+ static const_iterator begin(const BigMapTy& impl) {
+ return impl.begin();
+ }
+ static iterator end(SmallMapTy& impl) {
+ return it(impl, impl.end());
+ }
+ static const_iterator end(const SmallMapTy& impl) {
+ return const_it(impl, impl.end());
+ }
+ static iterator end(BigMapTy& impl) {
+ return impl.end();
+ }
+ static const_iterator end(const BigMapTy& impl) {
+ return impl.end();
+ }
+ };
+}
+
+#endif /* MULTIIMPLEMENTATIONMAP_H_ */
diff --git a/include/llvm/ADT/SmallMap.h b/include/llvm/ADT/SmallMap.h
new file mode 100644
index 00000000000..3bfb1556ca5
--- /dev/null
+++ b/include/llvm/ADT/SmallMap.h
@@ -0,0 +1,37 @@
+//===- llvm/ADT/SmallMap.h - 'Normally small' pointer set -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the SmallMap class.
+// SmallMap is DenseMap compatible MultiImplMap.
+// It uses FlatArrayMap for small mode, and DenseMap for big mode.
+// See MultiMapImpl comments for more details on the algorithm is used.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SMALLPTRMAP_H_
+#define SMALLPTRMAP_H_
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/FlatArrayMap.h"
+#include "llvm/ADT/MultiImplMap.h"
+
+namespace llvm {
+
+ //===--------------------------------------------------------------------===//
+ /// SmallMap is wrapper around MultiImplMap. It uses FlatArrayMap for
+ /// small mode, and DenseMap for big mode.
+ template <typename KeyTy, typename MappedTy, unsigned N = 16>
+ class SmallMap : public MultiImplMap<
+ FlatArrayMap<KeyTy, MappedTy, N>,
+ DenseMap<KeyTy, MappedTy>,
+ N, true> {
+ };
+}
+
+#endif /* SMALLPTRMAP_H_ */
diff --git a/unittests/ADT/SmallMapTest.cpp b/unittests/ADT/SmallMapTest.cpp
new file mode 100644
index 00000000000..361f0126bf3
--- /dev/null
+++ b/unittests/ADT/SmallMapTest.cpp
@@ -0,0 +1,133 @@
+//===- llvm/unittest/ADT/SmallMapTest.cpp ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// SmallMap unit tests.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+#include "llvm/ADT/SmallMap.h"
+
+using namespace llvm;
+
+// SmallMap test.
+TEST(SmallMapTest, GeneralTest) {
+
+ int buf[10];
+
+ SmallMap<int *, int, 3> a;
+ SmallMap<int *, int, 3> b;
+ SmallMap<int *, int, 3>::iterator found;
+ std::pair<SmallMap<int *, int, 3>::iterator, bool> insRes;
+ SmallMap<int *, int, 3>::const_iterator foundc;
+
+ a.insert(std::make_pair(&buf[0], 0));
+ insRes = a.insert(std::make_pair(&buf[1], 1));
+ EXPECT_TRUE(insRes.second);
+
+ // Check insertion, looking up, and data editing in small mode.
+ insRes = a.insert(std::make_pair(&buf[1], 6));
+ EXPECT_FALSE(insRes.second);
+ EXPECT_EQ(insRes.first->second, 1);
+ insRes.first->second = 5;
+ found = a.find(&buf[1]);
+ EXPECT_NE(found, a.end());
+ EXPECT_EQ(found->second, 5);
+ a[&buf[1]] = 10;
+ EXPECT_EQ(found->second, 10);
+ // Check "not found" case.
+ found = a.find(&buf[8]);
+ EXPECT_EQ(found, a.end());
+
+ // Check increment for small mode.
+ found = a.begin();
+ ++found;
+ EXPECT_EQ(found->second, 10);
+
+ b.insert(std::make_pair(&buf[2], 2));
+
+ std::swap(a, b);
+ a.swap(b);
+ std::swap(a, b);
+
+ EXPECT_EQ(1U, a.size());
+ EXPECT_EQ(2U, b.size());
+ EXPECT_TRUE(a.count(&buf[2]));
+ EXPECT_TRUE(b.count(&buf[0]));
+ EXPECT_TRUE(b.count(&buf[1]));
+
+ insRes = b.insert(std::make_pair(&buf[3], 3));
+ EXPECT_TRUE(insRes.second);
+
+ // Check insertion, looking up, and data editing in big mode.
+ insRes = b.insert(std::make_pair(&buf[3], 6));
+ EXPECT_FALSE(insRes.second);
+ EXPECT_EQ(insRes.first->second, 3);
+ insRes.first->second = 7;
+ found = b.find(&buf[3]);
+ EXPECT_EQ(found->second, 7);
+ b[&buf[3]] = 14;
+ EXPECT_EQ(found->second, 14);
+ // Check constant looking up.
+ foundc = b.find(&buf[3]);
+ EXPECT_EQ(foundc->first, &buf[3]);
+ EXPECT_EQ(foundc->second, 14);
+ // Check not found case.
+ found = b.find(&buf[8]);
+ EXPECT_EQ(found, b.end());
+
+ // Check increment for big mode.
+ found = b.find(&buf[1]);
+ ++found;
+ EXPECT_EQ(found->second, 14);
+
+ std::swap(a, b);
+ a.swap(b);
+ std::swap(a, b);
+
+ EXPECT_EQ(3U, a.size());
+ EXPECT_EQ(1U, b.size());
+ EXPECT_TRUE(a.count(&buf[0]));
+ EXPECT_TRUE(a.count(&buf[1]));
+ EXPECT_TRUE(a.count(&buf[3]));
+ EXPECT_TRUE(b.count(&buf[2]));
+ EXPECT_EQ(b.find(&buf[2])->second, 2);
+
+ std::swap(a, b);
+ a.swap(b);
+ std::swap(a, b);
+
+ EXPECT_EQ(1U, a.size());
+ EXPECT_EQ(3U, b.size());
+ EXPECT_TRUE(a.count(&buf[2]));
+ EXPECT_TRUE(b.count(&buf[0]));
+ EXPECT_TRUE(b.count(&buf[1]));
+ EXPECT_TRUE(b.count(&buf[3]));
+
+ a.insert(std::make_pair(&buf[4], 4));
+ a.insert(std::make_pair(&buf[5], 5));
+ a.insert(std::make_pair(&buf[6], 6));
+
+ std::swap(b, a);
+
+ EXPECT_EQ(3U, a.size());
+ EXPECT_EQ(4U, b.size());
+ EXPECT_TRUE(b.count(&buf[2]));
+ EXPECT_TRUE(b.count(&buf[4]));
+ EXPECT_TRUE(b.count(&buf[5]));
+ EXPECT_TRUE(b.count(&buf[6]));
+ EXPECT_TRUE(a.count(&buf[0]));
+ EXPECT_TRUE(a.count(&buf[1]));
+ EXPECT_TRUE(a.count(&buf[3]));
+
+ // Check findAndConstruct
+ SmallMap<int *, int, 3>::value_type Buf7;
+ Buf7 = a.FindAndConstruct(&buf[7]);
+ EXPECT_EQ(Buf7.second, 0);
+}