Improve heap allocation.
diff --git a/c++/src/kj/array.c++ b/c++/src/kj/array.c++
index aec257a..f824ee6 100644
--- a/c++/src/kj/array.c++
+++ b/c++/src/kj/array.c++
@@ -22,7 +22,87 @@
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "array.h"
+#include <iostream>
namespace kj {
+ArrayDisposer::~ArrayDisposer() {}
+
+namespace internal {
+
+struct HeapArrayDisposer::ExceptionGuard {
+ byte* pos;
+ size_t elementSize;
+ size_t elementCount;
+ size_t constructedCount;
+ void (*destroyElement)(void*);
+
+ ExceptionGuard(void* ptr, size_t elementSize, size_t elementCount,
+ void (*destroyElement)(void*))
+ : pos(reinterpret_cast<byte*>(ptr) + elementSize * elementCount),
+ elementSize(elementSize), elementCount(elementCount),
+ destroyElement(destroyElement) {}
+
+ ~ExceptionGuard() {
+ if (pos != nullptr) {
+ destroyAll();
+ operator delete(pos);
+ }
+ }
+
+ void destroyAll() {
+ while (elementCount > 0) {
+ pos -= elementSize;
+ --elementCount;
+ destroyElement(pos);
+ }
+ }
+};
+
+void* HeapArrayDisposer::allocateImpl(size_t elementSize, size_t elementCount, size_t capacity,
+ void (*constructElement)(void*),
+ void (*destroyElement)(void*)) {
+ void* result = operator new(elementSize * capacity);
+
+ if (constructElement == nullptr) {
+ // Nothing to do.
+ } else if (destroyElement == nullptr) {
+ byte* pos = reinterpret_cast<byte*>(result);
+ while (elementCount > 0) {
+ constructElement(pos);
+ pos += elementSize;
+ --elementCount;
+ }
+ } else {
+ ExceptionGuard guard(result, elementSize, 0, destroyElement);
+ while (guard.elementCount < elementCount) {
+ constructElement(guard.pos);
+ guard.pos += elementSize;
+ ++guard.elementCount;
+ }
+ guard.pos = nullptr;
+ }
+
+ return result;
+}
+
+void HeapArrayDisposer::disposeImpl(
+ void* firstElement, size_t elementSize, size_t elementCount, size_t capacity,
+ void (*destroyElement)(void*)) const {
+ // Note that capacity is ignored since operator delete() doesn't care about it.
+
+ if (destroyElement == nullptr) {
+ operator delete(firstElement);
+ } else {
+ ExceptionGuard guard(firstElement, elementSize, elementCount, destroyElement);
+ guard.destroyAll();
+
+ // If an exception is thrown, we'll continue the destruction process in ExceptionGuard's
+ // destructor. If _that_ throws an exception, the program terminates according to C++ rules.
+ }
+}
+
+const HeapArrayDisposer HeapArrayDisposer::instance = HeapArrayDisposer();
+
+} // namespace internal
} // namespace kj