2011-07-18 01:40:02 +00:00
|
|
|
//===- llvm/ADT/TinyPtrVector.h - 'Normally tiny' vectors -------*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#ifndef LLVM_ADT_TINYPTRVECTOR_H
|
|
|
|
#define LLVM_ADT_TINYPTRVECTOR_H
|
|
|
|
|
2012-05-19 13:28:54 +00:00
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
2011-07-18 01:40:02 +00:00
|
|
|
#include "llvm/ADT/PointerUnion.h"
|
2012-08-01 08:40:48 +00:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
2012-05-19 13:28:54 +00:00
|
|
|
#include "llvm/Support/Compiler.h"
|
2011-07-18 01:40:02 +00:00
|
|
|
|
|
|
|
namespace llvm {
|
|
|
|
|
|
|
|
/// TinyPtrVector - This class is specialized for cases where there are
|
|
|
|
/// normally 0 or 1 element in a vector, but is general enough to go beyond that
|
|
|
|
/// when required.
|
|
|
|
///
|
|
|
|
/// NOTE: This container doesn't allow you to store a null pointer into it.
|
|
|
|
///
|
|
|
|
template <typename EltTy>
|
|
|
|
class TinyPtrVector {
|
|
|
|
public:
|
|
|
|
typedef llvm::SmallVector<EltTy, 4> VecTy;
|
Bring TinyPtrVector under test. Somehow we never picked up unit tests
for this class. These tests exercise most of the basic properties, but
the API for TinyPtrVector is very strange currently. My plan is to start
fleshing out the API to match that of SmallVector, but I wanted a test
for what is there first.
Sadly, it doesn't look reasonable to just re-use the SmallVector tests,
as this container can only ever store pointers, and much of the
SmallVector testing is to get construction and destruction right.
Just to get this basic test working, I had to add value_type to the
interface.
While here I found a subtle bug in the combination of 'erase', 'begin',
and 'end'. Both 'begin' and 'end' wanted to use a null pointer to
indicate the "end" iterator of an empty vector, regardless of whether
there is actually a vector allocated or the pointer union is null.
Everything else was fine with this except for erase. If you erase the
last element of a vector after it has held more than one element, we
return the end iterator of the underlying SmallVector which need not be
a null pointer. Instead, simply use the pointer, and poniter + size()
begin/end definitions in the tiny case, and delegate to the inner vector
whenever it is present.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@161024 91177308-0d34-0410-b5e6-96231b3b80d8
2012-07-31 02:48:31 +00:00
|
|
|
typedef typename VecTy::value_type value_type;
|
|
|
|
|
2011-07-18 01:40:02 +00:00
|
|
|
llvm::PointerUnion<EltTy, VecTy*> Val;
|
2012-07-31 04:13:57 +00:00
|
|
|
|
2011-07-18 01:40:02 +00:00
|
|
|
TinyPtrVector() {}
|
2012-07-31 09:42:24 +00:00
|
|
|
~TinyPtrVector() {
|
|
|
|
if (VecTy *V = Val.template dyn_cast<VecTy*>())
|
|
|
|
delete V;
|
|
|
|
}
|
|
|
|
|
2011-07-18 01:40:02 +00:00
|
|
|
TinyPtrVector(const TinyPtrVector &RHS) : Val(RHS.Val) {
|
|
|
|
if (VecTy *V = Val.template dyn_cast<VecTy*>())
|
|
|
|
Val = new VecTy(*V);
|
|
|
|
}
|
2012-07-31 09:42:24 +00:00
|
|
|
TinyPtrVector &operator=(const TinyPtrVector &RHS) {
|
|
|
|
if (this == &RHS)
|
|
|
|
return *this;
|
|
|
|
if (RHS.empty()) {
|
|
|
|
this->clear();
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try to squeeze into the single slot. If it won't fit, allocate a copied
|
|
|
|
// vector.
|
|
|
|
if (Val.template is<EltTy>()) {
|
|
|
|
if (RHS.size() == 1)
|
|
|
|
Val = RHS.front();
|
|
|
|
else
|
|
|
|
Val = new VecTy(*RHS.Val.template get<VecTy*>());
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we have a full vector allocated, try to re-use it.
|
|
|
|
if (RHS.Val.template is<EltTy>()) {
|
|
|
|
Val.template get<VecTy*>()->clear();
|
|
|
|
Val.template get<VecTy*>()->push_back(RHS.front());
|
|
|
|
} else {
|
|
|
|
*Val.template get<VecTy*>() = *RHS.Val.template get<VecTy*>();
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2012-11-30 11:45:22 +00:00
|
|
|
#if LLVM_HAS_RVALUE_REFERENCES
|
2012-05-19 13:28:54 +00:00
|
|
|
TinyPtrVector(TinyPtrVector &&RHS) : Val(RHS.Val) {
|
|
|
|
RHS.Val = (EltTy)0;
|
|
|
|
}
|
2012-07-31 09:42:24 +00:00
|
|
|
TinyPtrVector &operator=(TinyPtrVector &&RHS) {
|
|
|
|
if (this == &RHS)
|
|
|
|
return *this;
|
|
|
|
if (RHS.empty()) {
|
|
|
|
this->clear();
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If this vector has been allocated on the heap, re-use it if cheap. If it
|
|
|
|
// would require more copying, just delete it and we'll steal the other
|
|
|
|
// side.
|
|
|
|
if (VecTy *V = Val.template dyn_cast<VecTy*>()) {
|
|
|
|
if (RHS.Val.template is<EltTy>()) {
|
|
|
|
V->clear();
|
|
|
|
V->push_back(RHS.front());
|
|
|
|
return *this;
|
|
|
|
}
|
2011-07-18 01:40:02 +00:00
|
|
|
delete V;
|
2012-07-31 09:42:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Val = RHS.Val;
|
|
|
|
RHS.Val = (EltTy)0;
|
|
|
|
return *this;
|
2011-07-18 01:40:02 +00:00
|
|
|
}
|
2012-07-31 09:42:24 +00:00
|
|
|
#endif
|
2012-07-31 04:13:57 +00:00
|
|
|
|
2011-12-06 02:00:33 +00:00
|
|
|
// implicit conversion operator to ArrayRef.
|
|
|
|
operator ArrayRef<EltTy>() const {
|
|
|
|
if (Val.isNull())
|
|
|
|
return ArrayRef<EltTy>();
|
|
|
|
if (Val.template is<EltTy>())
|
2012-03-07 03:37:32 +00:00
|
|
|
return *Val.getAddrOfPtr1();
|
2011-12-06 02:00:33 +00:00
|
|
|
return *Val.template get<VecTy*>();
|
|
|
|
}
|
2012-07-31 04:13:57 +00:00
|
|
|
|
2011-07-18 01:40:02 +00:00
|
|
|
bool empty() const {
|
2011-07-18 16:35:57 +00:00
|
|
|
// This vector can be empty if it contains no element, or if it
|
|
|
|
// contains a pointer to an empty vector.
|
2011-07-18 01:40:02 +00:00
|
|
|
if (Val.isNull()) return true;
|
|
|
|
if (VecTy *Vec = Val.template dyn_cast<VecTy*>())
|
|
|
|
return Vec->empty();
|
|
|
|
return false;
|
|
|
|
}
|
2012-07-31 04:13:57 +00:00
|
|
|
|
2011-07-18 01:40:02 +00:00
|
|
|
unsigned size() const {
|
|
|
|
if (empty())
|
|
|
|
return 0;
|
2011-07-18 16:35:57 +00:00
|
|
|
if (Val.template is<EltTy>())
|
2011-07-18 01:40:02 +00:00
|
|
|
return 1;
|
2011-07-18 16:35:57 +00:00
|
|
|
return Val.template get<VecTy*>()->size();
|
2011-07-18 01:40:02 +00:00
|
|
|
}
|
2012-07-31 04:13:57 +00:00
|
|
|
|
2012-03-06 13:32:36 +00:00
|
|
|
typedef const EltTy *const_iterator;
|
2012-03-06 07:14:58 +00:00
|
|
|
typedef EltTy *iterator;
|
|
|
|
|
|
|
|
iterator begin() {
|
2011-07-18 01:53:11 +00:00
|
|
|
if (Val.template is<EltTy>())
|
2012-03-06 07:14:54 +00:00
|
|
|
return Val.getAddrOfPtr1();
|
2012-07-31 04:13:57 +00:00
|
|
|
|
2011-07-18 01:53:11 +00:00
|
|
|
return Val.template get<VecTy *>()->begin();
|
|
|
|
|
|
|
|
}
|
2012-03-06 07:14:58 +00:00
|
|
|
iterator end() {
|
2011-07-18 01:53:11 +00:00
|
|
|
if (Val.template is<EltTy>())
|
Bring TinyPtrVector under test. Somehow we never picked up unit tests
for this class. These tests exercise most of the basic properties, but
the API for TinyPtrVector is very strange currently. My plan is to start
fleshing out the API to match that of SmallVector, but I wanted a test
for what is there first.
Sadly, it doesn't look reasonable to just re-use the SmallVector tests,
as this container can only ever store pointers, and much of the
SmallVector testing is to get construction and destruction right.
Just to get this basic test working, I had to add value_type to the
interface.
While here I found a subtle bug in the combination of 'erase', 'begin',
and 'end'. Both 'begin' and 'end' wanted to use a null pointer to
indicate the "end" iterator of an empty vector, regardless of whether
there is actually a vector allocated or the pointer union is null.
Everything else was fine with this except for erase. If you erase the
last element of a vector after it has held more than one element, we
return the end iterator of the underlying SmallVector which need not be
a null pointer. Instead, simply use the pointer, and poniter + size()
begin/end definitions in the tiny case, and delegate to the inner vector
whenever it is present.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@161024 91177308-0d34-0410-b5e6-96231b3b80d8
2012-07-31 02:48:31 +00:00
|
|
|
return begin() + (Val.isNull() ? 0 : 1);
|
2012-07-31 04:13:57 +00:00
|
|
|
|
2011-07-18 01:53:11 +00:00
|
|
|
return Val.template get<VecTy *>()->end();
|
|
|
|
}
|
|
|
|
|
2012-03-06 07:14:58 +00:00
|
|
|
const_iterator begin() const {
|
|
|
|
return (const_iterator)const_cast<TinyPtrVector*>(this)->begin();
|
|
|
|
}
|
|
|
|
|
|
|
|
const_iterator end() const {
|
|
|
|
return (const_iterator)const_cast<TinyPtrVector*>(this)->end();
|
|
|
|
}
|
|
|
|
|
2011-07-18 01:40:02 +00:00
|
|
|
EltTy operator[](unsigned i) const {
|
|
|
|
assert(!Val.isNull() && "can't index into an empty vector");
|
|
|
|
if (EltTy V = Val.template dyn_cast<EltTy>()) {
|
|
|
|
assert(i == 0 && "tinyvector index out of range");
|
|
|
|
return V;
|
|
|
|
}
|
2012-07-31 04:13:57 +00:00
|
|
|
|
|
|
|
assert(i < Val.template get<VecTy*>()->size() &&
|
2011-07-18 01:40:02 +00:00
|
|
|
"tinyvector index out of range");
|
2011-07-18 16:35:57 +00:00
|
|
|
return (*Val.template get<VecTy*>())[i];
|
2011-07-18 01:40:02 +00:00
|
|
|
}
|
2012-07-31 04:13:57 +00:00
|
|
|
|
2011-07-18 01:40:02 +00:00
|
|
|
EltTy front() const {
|
|
|
|
assert(!empty() && "vector empty");
|
|
|
|
if (EltTy V = Val.template dyn_cast<EltTy>())
|
|
|
|
return V;
|
|
|
|
return Val.template get<VecTy*>()->front();
|
|
|
|
}
|
2012-07-31 04:13:57 +00:00
|
|
|
|
2012-05-28 01:29:59 +00:00
|
|
|
EltTy back() const {
|
|
|
|
assert(!empty() && "vector empty");
|
|
|
|
if (EltTy V = Val.template dyn_cast<EltTy>())
|
|
|
|
return V;
|
|
|
|
return Val.template get<VecTy*>()->back();
|
|
|
|
}
|
|
|
|
|
2011-07-18 01:40:02 +00:00
|
|
|
void push_back(EltTy NewVal) {
|
|
|
|
assert(NewVal != 0 && "Can't add a null value");
|
2012-07-31 04:13:57 +00:00
|
|
|
|
2011-07-18 01:40:02 +00:00
|
|
|
// If we have nothing, add something.
|
|
|
|
if (Val.isNull()) {
|
|
|
|
Val = NewVal;
|
|
|
|
return;
|
|
|
|
}
|
2012-07-31 04:13:57 +00:00
|
|
|
|
2011-07-18 01:40:02 +00:00
|
|
|
// If we have a single value, convert to a vector.
|
2011-07-18 16:35:57 +00:00
|
|
|
if (EltTy V = Val.template dyn_cast<EltTy>()) {
|
2011-07-18 01:40:02 +00:00
|
|
|
Val = new VecTy();
|
|
|
|
Val.template get<VecTy*>()->push_back(V);
|
|
|
|
}
|
2012-07-31 04:13:57 +00:00
|
|
|
|
2011-07-18 01:40:02 +00:00
|
|
|
// Add the new value, we know we have a vector.
|
|
|
|
Val.template get<VecTy*>()->push_back(NewVal);
|
|
|
|
}
|
2012-07-31 04:13:57 +00:00
|
|
|
|
2012-05-28 01:29:59 +00:00
|
|
|
void pop_back() {
|
|
|
|
// If we have a single value, convert to empty.
|
|
|
|
if (Val.template is<EltTy>())
|
|
|
|
Val = (EltTy)0;
|
|
|
|
else if (VecTy *Vec = Val.template get<VecTy*>())
|
|
|
|
Vec->pop_back();
|
|
|
|
}
|
|
|
|
|
2011-07-18 01:40:02 +00:00
|
|
|
void clear() {
|
|
|
|
// If we have a single value, convert to empty.
|
2011-07-18 01:43:58 +00:00
|
|
|
if (Val.template is<EltTy>()) {
|
2011-07-18 01:40:02 +00:00
|
|
|
Val = (EltTy)0;
|
|
|
|
} else if (VecTy *Vec = Val.template dyn_cast<VecTy*>()) {
|
|
|
|
// If we have a vector form, just clear it.
|
|
|
|
Vec->clear();
|
|
|
|
}
|
|
|
|
// Otherwise, we're already empty.
|
|
|
|
}
|
2012-03-06 07:14:58 +00:00
|
|
|
|
|
|
|
iterator erase(iterator I) {
|
2012-08-01 08:40:46 +00:00
|
|
|
assert(I >= begin() && "Iterator to erase is out of bounds.");
|
|
|
|
assert(I < end() && "Erasing at past-the-end iterator.");
|
|
|
|
|
2012-03-06 07:14:58 +00:00
|
|
|
// If we have a single value, convert to empty.
|
|
|
|
if (Val.template is<EltTy>()) {
|
|
|
|
if (I == begin())
|
|
|
|
Val = (EltTy)0;
|
|
|
|
} else if (VecTy *Vec = Val.template dyn_cast<VecTy*>()) {
|
|
|
|
// multiple items in a vector; just do the erase, there is no
|
|
|
|
// benefit to collapsing back to a pointer
|
|
|
|
return Vec->erase(I);
|
|
|
|
}
|
Bring TinyPtrVector under test. Somehow we never picked up unit tests
for this class. These tests exercise most of the basic properties, but
the API for TinyPtrVector is very strange currently. My plan is to start
fleshing out the API to match that of SmallVector, but I wanted a test
for what is there first.
Sadly, it doesn't look reasonable to just re-use the SmallVector tests,
as this container can only ever store pointers, and much of the
SmallVector testing is to get construction and destruction right.
Just to get this basic test working, I had to add value_type to the
interface.
While here I found a subtle bug in the combination of 'erase', 'begin',
and 'end'. Both 'begin' and 'end' wanted to use a null pointer to
indicate the "end" iterator of an empty vector, regardless of whether
there is actually a vector allocated or the pointer union is null.
Everything else was fine with this except for erase. If you erase the
last element of a vector after it has held more than one element, we
return the end iterator of the underlying SmallVector which need not be
a null pointer. Instead, simply use the pointer, and poniter + size()
begin/end definitions in the tiny case, and delegate to the inner vector
whenever it is present.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@161024 91177308-0d34-0410-b5e6-96231b3b80d8
2012-07-31 02:48:31 +00:00
|
|
|
return end();
|
2012-03-06 07:14:58 +00:00
|
|
|
}
|
2012-08-01 08:40:48 +00:00
|
|
|
|
|
|
|
iterator erase(iterator S, iterator E) {
|
|
|
|
assert(S >= begin() && "Range to erase is out of bounds.");
|
|
|
|
assert(S <= E && "Trying to erase invalid range.");
|
|
|
|
assert(E <= end() && "Trying to erase past the end.");
|
|
|
|
|
|
|
|
if (Val.template is<EltTy>()) {
|
|
|
|
if (S == begin() && S != E)
|
|
|
|
Val = (EltTy)0;
|
|
|
|
} else if (VecTy *Vec = Val.template dyn_cast<VecTy*>()) {
|
|
|
|
return Vec->erase(S, E);
|
|
|
|
}
|
|
|
|
return end();
|
|
|
|
}
|
|
|
|
|
|
|
|
iterator insert(iterator I, const EltTy &Elt) {
|
|
|
|
assert(I >= this->begin() && "Insertion iterator is out of bounds.");
|
|
|
|
assert(I <= this->end() && "Inserting past the end of the vector.");
|
|
|
|
if (I == end()) {
|
|
|
|
push_back(Elt);
|
|
|
|
return llvm::prior(end());
|
|
|
|
}
|
|
|
|
assert(!Val.isNull() && "Null value with non-end insert iterator.");
|
|
|
|
if (EltTy V = Val.template dyn_cast<EltTy>()) {
|
|
|
|
assert(I == begin());
|
|
|
|
Val = Elt;
|
|
|
|
push_back(V);
|
|
|
|
return begin();
|
|
|
|
}
|
|
|
|
|
|
|
|
return Val.template get<VecTy*>()->insert(I, Elt);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename ItTy>
|
|
|
|
iterator insert(iterator I, ItTy From, ItTy To) {
|
|
|
|
assert(I >= this->begin() && "Insertion iterator is out of bounds.");
|
|
|
|
assert(I <= this->end() && "Inserting past the end of the vector.");
|
|
|
|
if (From == To)
|
|
|
|
return I;
|
|
|
|
|
|
|
|
// If we have a single value, convert to a vector.
|
|
|
|
ptrdiff_t Offset = I - begin();
|
|
|
|
if (Val.isNull()) {
|
|
|
|
if (llvm::next(From) == To) {
|
|
|
|
Val = *From;
|
|
|
|
return begin();
|
|
|
|
}
|
|
|
|
|
|
|
|
Val = new VecTy();
|
|
|
|
} else if (EltTy V = Val.template dyn_cast<EltTy>()) {
|
|
|
|
Val = new VecTy();
|
|
|
|
Val.template get<VecTy*>()->push_back(V);
|
|
|
|
}
|
|
|
|
return Val.template get<VecTy*>()->insert(begin() + Offset, From, To);
|
|
|
|
}
|
2011-07-18 01:40:02 +00:00
|
|
|
};
|
|
|
|
} // end namespace llvm
|
|
|
|
|
|
|
|
#endif
|