Commit e6e29122 authored by Kenton Varda's avatar Kenton Varda Committed by Kenton Varda

Better-optimize Vector and ArrayBuilder for trivial types.

parent 8f858fc4
......@@ -376,10 +376,11 @@ public:
template <typename Container>
void addAll(Container&& container) {
addAll(container.begin(), container.end());
addAll<decltype(container.begin()), !isReference<Container>()>(
container.begin(), container.end());
}
template <typename Iterator>
template <typename Iterator, bool move = false>
void addAll(Iterator start, Iterator end);
void removeLast() {
......@@ -387,6 +388,44 @@ public:
kj::dtor(*--pos);
}
void truncate(size_t size) {
KJ_IREQUIRE(size <= this->size(), "can't use truncate() to expand");
T* target = ptr + size;
if (__has_trivial_destructor(T)) {
pos = target;
} else {
while (pos > target) {
kj::dtor(*--pos);
}
}
}
void resize(size_t size) {
KJ_IREQUIRE(size <= capacity(), "can't resize past capacity");
T* target = ptr + size;
if (target > pos) {
// expand
if (__has_trivial_constructor(T)) {
pos = target;
} else {
while (pos < target) {
kj::ctor(*pos++);
}
}
} else {
// truncate
if (__has_trivial_destructor(T)) {
pos = target;
} else {
while (pos > target) {
kj::dtor(*--pos);
}
}
}
}
Array<T> finish() {
// We could safely remove this check if we assume that the disposer implementation doesn't
// need to know the original capacity, as is thes case with HeapArrayDisposer since it uses
......@@ -615,11 +654,11 @@ T* HeapArrayDisposer::allocateUninitialized(size_t count) {
return Allocate_<T, true, true>::allocate(0, count);
}
template <typename Element, typename Iterator, bool = canMemcpy<Element>()>
template <typename Element, typename Iterator, bool move, bool = canMemcpy<Element>()>
struct CopyConstructArray_;
template <typename T>
struct CopyConstructArray_<T, T*, true> {
template <typename T, bool move>
struct CopyConstructArray_<T, T*, move, true> {
static inline T* apply(T* __restrict__ pos, T* start, T* end) {
memcpy(pos, start, reinterpret_cast<byte*>(end) - reinterpret_cast<byte*>(start));
return pos + (end - start);
......@@ -627,15 +666,15 @@ struct CopyConstructArray_<T, T*, true> {
};
template <typename T>
struct CopyConstructArray_<T, const T*, true> {
struct CopyConstructArray_<T, const T*, false, true> {
static inline T* apply(T* __restrict__ pos, const T* start, const T* end) {
memcpy(pos, start, reinterpret_cast<const byte*>(end) - reinterpret_cast<const byte*>(start));
return pos + (end - start);
}
};
template <typename T, typename Iterator>
struct CopyConstructArray_<T, Iterator, true> {
template <typename T, typename Iterator, bool move>
struct CopyConstructArray_<T, Iterator, move, true> {
static inline T* apply(T* __restrict__ pos, Iterator start, Iterator end) {
// Since both the copy constructor and assignment operator are trivial, we know that assignment
// is equivalent to copy-constructing. So we can make this case somewhat easier for the
......@@ -648,7 +687,7 @@ struct CopyConstructArray_<T, Iterator, true> {
};
template <typename T, typename Iterator>
struct CopyConstructArray_<T, Iterator, false> {
struct CopyConstructArray_<T, Iterator, false, false> {
struct ExceptionGuard {
T* start;
T* pos;
......@@ -683,16 +722,48 @@ struct CopyConstructArray_<T, Iterator, false> {
};
template <typename T, typename Iterator>
inline T* copyConstructArray(T* dst, Iterator start, Iterator end) {
return CopyConstructArray_<T, Decay<Iterator>>::apply(dst, start, end);
}
struct CopyConstructArray_<T, Iterator, true, false> {
// Actually move-construct.
struct ExceptionGuard {
T* start;
T* pos;
inline explicit ExceptionGuard(T* pos): start(pos), pos(pos) {}
~ExceptionGuard() noexcept(false) {
while (pos > start) {
dtor(*--pos);
}
}
};
static T* apply(T* __restrict__ pos, Iterator start, Iterator end) {
// Verify that T can be *implicitly* constructed from the source values.
if (false) implicitCast<T>(kj::mv(*start));
if (noexcept(T(kj::mv(*start)))) {
while (start != end) {
ctor(*pos++, kj::mv(*start++));
}
return pos;
} else {
// Crap. This is complicated.
ExceptionGuard guard(pos);
while (start != end) {
ctor(*guard.pos, kj::mv(*start++));
++guard.pos;
}
guard.start = guard.pos;
return guard.pos;
}
}
};
} // namespace _ (private)
template <typename T>
template <typename Iterator>
template <typename Iterator, bool move>
void ArrayBuilder<T>::addAll(Iterator start, Iterator end) {
pos = _::copyConstructArray(pos, start, end);
pos = _::CopyConstructArray_<RemoveConst<T>, Decay<Iterator>, move>::apply(pos, start, end);
}
template <typename T>
......
......@@ -95,12 +95,7 @@ public:
inline void resize(size_t size) {
if (size > builder.capacity()) grow(size);
while (builder.size() < size) {
builder.add(T());
}
while (builder.size() > size) {
builder.removeLast();
}
builder.resize(size);
}
inline void operator=(decltype(nullptr)) {
......@@ -114,8 +109,12 @@ public:
}
inline void truncate(size_t size) {
while (builder.size() > size) {
builder.removeLast();
builder.truncate(size);
}
inline void reserve(size_t size) {
if (size > builder.capacity()) {
setCapacity(size);
}
}
......@@ -126,11 +125,11 @@ private:
setCapacity(kj::max(minCapacity, capacity() == 0 ? 4 : capacity() * 2));
}
void setCapacity(size_t newSize) {
ArrayBuilder<T> newBuilder = heapArrayBuilder<T>(newSize);
size_t moveCount = kj::min(newSize, builder.size());
for (size_t i = 0; i < moveCount; i++) {
newBuilder.add(kj::mv(builder[i]));
if (builder.size() > newSize) {
builder.truncate(newSize);
}
ArrayBuilder<T> newBuilder = heapArrayBuilder<T>(newSize);
newBuilder.addAll(kj::mv(builder));
builder = kj::mv(newBuilder);
}
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment