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: ...@@ -376,10 +376,11 @@ public:
template <typename Container> template <typename Container>
void addAll(Container&& 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 addAll(Iterator start, Iterator end);
void removeLast() { void removeLast() {
...@@ -387,6 +388,44 @@ public: ...@@ -387,6 +388,44 @@ public:
kj::dtor(*--pos); 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() { Array<T> finish() {
// We could safely remove this check if we assume that the disposer implementation doesn't // 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 // 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) { ...@@ -615,11 +654,11 @@ T* HeapArrayDisposer::allocateUninitialized(size_t count) {
return Allocate_<T, true, true>::allocate(0, 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_; struct CopyConstructArray_;
template <typename T> template <typename T, bool move>
struct CopyConstructArray_<T, T*, true> { struct CopyConstructArray_<T, T*, move, true> {
static inline T* apply(T* __restrict__ pos, T* start, T* end) { static inline T* apply(T* __restrict__ pos, T* start, T* end) {
memcpy(pos, start, reinterpret_cast<byte*>(end) - reinterpret_cast<byte*>(start)); memcpy(pos, start, reinterpret_cast<byte*>(end) - reinterpret_cast<byte*>(start));
return pos + (end - start); return pos + (end - start);
...@@ -627,15 +666,15 @@ struct CopyConstructArray_<T, T*, true> { ...@@ -627,15 +666,15 @@ struct CopyConstructArray_<T, T*, true> {
}; };
template <typename T> 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) { 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)); memcpy(pos, start, reinterpret_cast<const byte*>(end) - reinterpret_cast<const byte*>(start));
return pos + (end - start); return pos + (end - start);
} }
}; };
template <typename T, typename Iterator> template <typename T, typename Iterator, bool move>
struct CopyConstructArray_<T, Iterator, true> { struct CopyConstructArray_<T, Iterator, move, true> {
static inline T* apply(T* __restrict__ pos, Iterator start, Iterator end) { 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 // 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 // is equivalent to copy-constructing. So we can make this case somewhat easier for the
...@@ -648,7 +687,7 @@ struct CopyConstructArray_<T, Iterator, true> { ...@@ -648,7 +687,7 @@ struct CopyConstructArray_<T, Iterator, true> {
}; };
template <typename T, typename Iterator> template <typename T, typename Iterator>
struct CopyConstructArray_<T, Iterator, false> { struct CopyConstructArray_<T, Iterator, false, false> {
struct ExceptionGuard { struct ExceptionGuard {
T* start; T* start;
T* pos; T* pos;
...@@ -683,16 +722,48 @@ struct CopyConstructArray_<T, Iterator, false> { ...@@ -683,16 +722,48 @@ struct CopyConstructArray_<T, Iterator, false> {
}; };
template <typename T, typename Iterator> template <typename T, typename Iterator>
inline T* copyConstructArray(T* dst, Iterator start, Iterator end) { struct CopyConstructArray_<T, Iterator, true, false> {
return CopyConstructArray_<T, Decay<Iterator>>::apply(dst, start, end); // 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) } // namespace _ (private)
template <typename T> template <typename T>
template <typename Iterator> template <typename Iterator, bool move>
void ArrayBuilder<T>::addAll(Iterator start, Iterator end) { 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> template <typename T>
......
...@@ -95,12 +95,7 @@ public: ...@@ -95,12 +95,7 @@ public:
inline void resize(size_t size) { inline void resize(size_t size) {
if (size > builder.capacity()) grow(size); if (size > builder.capacity()) grow(size);
while (builder.size() < size) { builder.resize(size);
builder.add(T());
}
while (builder.size() > size) {
builder.removeLast();
}
} }
inline void operator=(decltype(nullptr)) { inline void operator=(decltype(nullptr)) {
...@@ -114,8 +109,12 @@ public: ...@@ -114,8 +109,12 @@ public:
} }
inline void truncate(size_t size) { inline void truncate(size_t size) {
while (builder.size() > size) { builder.truncate(size);
builder.removeLast(); }
inline void reserve(size_t size) {
if (size > builder.capacity()) {
setCapacity(size);
} }
} }
...@@ -126,11 +125,11 @@ private: ...@@ -126,11 +125,11 @@ private:
setCapacity(kj::max(minCapacity, capacity() == 0 ? 4 : capacity() * 2)); setCapacity(kj::max(minCapacity, capacity() == 0 ? 4 : capacity() * 2));
} }
void setCapacity(size_t newSize) { void setCapacity(size_t newSize) {
ArrayBuilder<T> newBuilder = heapArrayBuilder<T>(newSize); if (builder.size() > newSize) {
size_t moveCount = kj::min(newSize, builder.size()); builder.truncate(newSize);
for (size_t i = 0; i < moveCount; i++) {
newBuilder.add(kj::mv(builder[i]));
} }
ArrayBuilder<T> newBuilder = heapArrayBuilder<T>(newSize);
newBuilder.addAll(kj::mv(builder));
builder = kj::mv(newBuilder); 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