Split array and string stuff out of type-safety.h.
diff --git a/c++/src/capnproto/generated-header-support.h b/c++/src/capnproto/generated-header-support.h
index d8ec47b..e48bef4 100644
--- a/c++/src/capnproto/generated-header-support.h
+++ b/c++/src/capnproto/generated-header-support.h
@@ -28,6 +28,7 @@
#include "layout.h"
#include "list.h"
+#include <kj/string.h>
namespace capnproto {
diff --git a/c++/src/kj/array.c++ b/c++/src/kj/array.c++
new file mode 100644
index 0000000..aec257a
--- /dev/null
+++ b/c++/src/kj/array.c++
@@ -0,0 +1,28 @@
+// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "array.h"
+
+namespace kj {
+
+} // namespace kj
diff --git a/c++/src/kj/array.h b/c++/src/kj/array.h
new file mode 100644
index 0000000..b155cac
--- /dev/null
+++ b/c++/src/kj/array.h
@@ -0,0 +1,186 @@
+// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef KJ_ARRAY_H_
+#define KJ_ARRAY_H_
+
+#include "common.h"
+#include "memory.h"
+#include <string.h>
+
+namespace kj {
+
+// =======================================================================================
+// Array
+
+template <typename T>
+class Array {
+ // An owned array which will automatically be deleted in the destructor. Can be moved, but not
+ // copied.
+
+public:
+ inline Array(): ptr(nullptr), size_(0) {}
+ inline Array(decltype(nullptr)): ptr(nullptr), size_(0) {}
+ inline Array(Array&& other) noexcept: ptr(other.ptr), size_(other.size_) {
+ other.ptr = nullptr;
+ other.size_ = 0;
+ }
+
+ KJ_DISALLOW_COPY(Array);
+ inline ~Array() noexcept { delete[] ptr; }
+
+ inline operator ArrayPtr<T>() {
+ return ArrayPtr<T>(ptr, size_);
+ }
+ inline operator ArrayPtr<const T>() const {
+ return ArrayPtr<T>(ptr, size_);
+ }
+ inline ArrayPtr<T> asPtr() {
+ return ArrayPtr<T>(ptr, size_);
+ }
+
+ inline size_t size() const { return size_; }
+ inline T& operator[](size_t index) const {
+ KJ_INLINE_DPRECOND(index < size_, "Out-of-bounds Array access.");
+ return ptr[index];
+ }
+
+ inline T* begin() const { return ptr; }
+ inline T* end() const { return ptr + size_; }
+ inline T& front() const { return *ptr; }
+ inline T& back() const { return *(ptr + size_ - 1); }
+
+ inline ArrayPtr<T> slice(size_t start, size_t end) {
+ KJ_INLINE_DPRECOND(start <= end && end <= size_, "Out-of-bounds Array::slice().");
+ return ArrayPtr<T>(ptr + start, end - start);
+ }
+ inline ArrayPtr<const T> slice(size_t start, size_t end) const {
+ KJ_INLINE_DPRECOND(start <= end && end <= size_, "Out-of-bounds Array::slice().");
+ return ArrayPtr<const T>(ptr + start, end - start);
+ }
+
+ inline bool operator==(decltype(nullptr)) const { return size_ == 0; }
+ inline bool operator!=(decltype(nullptr)) const { return size_ != 0; }
+
+ inline Array& operator=(decltype(nullptr)) {
+ delete[] ptr;
+ ptr = nullptr;
+ size_ = 0;
+ return *this;
+ }
+
+ inline Array& operator=(Array&& other) {
+ delete[] ptr;
+ ptr = other.ptr;
+ size_ = other.size_;
+ other.ptr = nullptr;
+ other.size_ = 0;
+ return *this;
+ }
+
+private:
+ T* ptr;
+ size_t size_;
+
+ inline explicit Array(size_t size): ptr(new T[size]), size_(size) {}
+ inline Array(T* ptr, size_t size): ptr(ptr), size_(size) {}
+
+ template <typename U>
+ friend Array<U> newArray(size_t size);
+
+ template <typename U>
+ friend class ArrayBuilder;
+};
+
+template <typename T>
+inline Array<T> newArray(size_t size) {
+ return Array<T>(size);
+}
+
+// =======================================================================================
+// ArrayBuilder
+
+template <typename T>
+class ArrayBuilder {
+ // TODO(cleanup): This class doesn't work for non-primitive types because Slot is not
+ // constructable. Giving Slot a constructor/destructor means arrays of it have to be tagged
+ // so operator delete can run the destructors. If we reinterpret_cast the array to an array
+ // of T and delete it as that type, operator delete gets very upset.
+ //
+ // Perhaps we should bite the bullet and make the Array family do manual memory allocation,
+ // bypassing the rather-stupid C++ array new/delete operators which store a redundant copy of
+ // the size anyway.
+
+ union Slot {
+ T value;
+ char dummy;
+ };
+ static_assert(sizeof(Slot) == sizeof(T), "union is bigger than content?");
+
+public:
+ explicit ArrayBuilder(size_t size): ptr(new Slot[size]), pos(ptr), endPtr(ptr + size) {}
+ ~ArrayBuilder() {
+ for (Slot* p = ptr; p < pos; ++p) {
+ p->value.~T();
+ }
+ delete [] ptr;
+ }
+
+ template <typename... Params>
+ void add(Params&&... params) {
+ KJ_INLINE_DPRECOND(pos < endPtr, "Added too many elements to ArrayBuilder.");
+ new(&pos->value) T(kj::fwd<Params>(params)...);
+ ++pos;
+ }
+
+ template <typename Container>
+ void addAll(Container&& container) {
+ Slot* __restrict__ pos_ = pos;
+ auto i = container.begin();
+ auto end = container.end();
+ while (i != end) {
+ pos_++->value = *i++;
+ }
+ pos = pos_;
+ }
+
+ Array<T> finish() {
+ // We could allow partial builds if Array<T> used a deleter callback, but that would make
+ // Array<T> bigger for no benefit most of the time.
+ KJ_INLINE_DPRECOND(pos == endPtr, "ArrayBuilder::finish() called prematurely.");
+ Array<T> result(reinterpret_cast<T*>(ptr), pos - ptr);
+ ptr = nullptr;
+ pos = nullptr;
+ endPtr = nullptr;
+ return result;
+ }
+
+private:
+ Slot* ptr;
+ Slot* pos;
+ Slot* endPtr;
+};
+
+} // namespace kj
+
+#endif // KJ_ARRAY_H_
diff --git a/c++/src/kj/common.h b/c++/src/kj/common.h
index 8dd6686..7353c27 100644
--- a/c++/src/kj/common.h
+++ b/c++/src/kj/common.h
@@ -462,6 +462,63 @@
friend U* internal::readMaybe(const Maybe<U&>& maybe);
};
+
+// =======================================================================================
+// ArrayPtr
+//
+// So common that we put it in common.h rather than array.h.
+
+template <typename T>
+class ArrayPtr {
+ // A pointer to an array. Includes a size. Like any pointer, it doesn't own the target data,
+ // and passing by value only copies the pointer, not the target.
+
+public:
+ inline constexpr ArrayPtr(): ptr(nullptr), size_(0) {}
+ inline constexpr ArrayPtr(decltype(nullptr)): ptr(nullptr), size_(0) {}
+ inline constexpr ArrayPtr(T* ptr, size_t size): ptr(ptr), size_(size) {}
+ inline constexpr ArrayPtr(T* begin, T* end): ptr(begin), size_(end - begin) {}
+
+ inline operator ArrayPtr<const T>() {
+ return ArrayPtr<const T>(ptr, size_);
+ }
+
+ inline size_t size() const { return size_; }
+ inline T& operator[](size_t index) const {
+ KJ_INLINE_DPRECOND(index < size_, "Out-of-bounds ArrayPtr access.");
+ return ptr[index];
+ }
+
+ inline T* begin() const { return ptr; }
+ inline T* end() const { return ptr + size_; }
+ inline T& front() const { return *ptr; }
+ inline T& back() const { return *(ptr + size_ - 1); }
+
+ inline ArrayPtr slice(size_t start, size_t end) {
+ KJ_INLINE_DPRECOND(start <= end && end <= size_, "Out-of-bounds ArrayPtr::slice().");
+ return ArrayPtr(ptr + start, end - start);
+ }
+
+ inline bool operator==(decltype(nullptr)) { return size_ == 0; }
+ inline bool operator!=(decltype(nullptr)) { return size_ != 0; }
+
+private:
+ T* ptr;
+ size_t size_;
+};
+
+template <typename T>
+inline constexpr ArrayPtr<T> arrayPtr(T* ptr, size_t size) {
+ // Use this function to construct ArrayPtrs without writing out the type name.
+ return ArrayPtr<T>(ptr, size);
+}
+
+template <typename T>
+inline constexpr ArrayPtr<T> arrayPtr(T* begin, T* end) {
+ // Use this function to construct ArrayPtrs without writing out the type name.
+ return ArrayPtr<T>(begin, end);
+}
+
// =======================================================================================
// Upcast/downcast
diff --git a/c++/src/kj/exception.h b/c++/src/kj/exception.h
index 99907ff..333691e 100644
--- a/c++/src/kj/exception.h
+++ b/c++/src/kj/exception.h
@@ -25,7 +25,7 @@
#define KJ_EXCEPTION_H_
#include <exception>
-#include "type-safety.h"
+#include "array.h"
namespace kj {
diff --git a/c++/src/kj/io.h b/c++/src/kj/io.h
index 203d4ea..ead1190 100644
--- a/c++/src/kj/io.h
+++ b/c++/src/kj/io.h
@@ -26,7 +26,7 @@
#include <cstddef>
#include "common.h"
-#include "type-safety.h"
+#include "array.h"
namespace kj {
diff --git a/c++/src/kj/logging.c++ b/c++/src/kj/logging.c++
index f968247..fd5df37 100644
--- a/c++/src/kj/logging.c++
+++ b/c++/src/kj/logging.c++
@@ -112,11 +112,11 @@
}
{
- ArrayPtr<const char> expected = arrayPtr("expected ");
- ArrayPtr<const char> codeArray = style == LOG ? nullptr : arrayPtr(code);
- ArrayPtr<const char> sep = arrayPtr(" = ");
- ArrayPtr<const char> delim = arrayPtr("; ");
- ArrayPtr<const char> colon = arrayPtr(": ");
+ ArrayPtr<const char> expected = stringPtr("expected ");
+ ArrayPtr<const char> codeArray = style == LOG ? nullptr : stringPtr(code);
+ ArrayPtr<const char> sep = stringPtr(" = ");
+ ArrayPtr<const char> delim = stringPtr("; ");
+ ArrayPtr<const char> colon = stringPtr(": ");
if (style == ASSERTION && strcmp(code, "false") == 0) {
// Don't print "expected false", that's silly.
@@ -127,7 +127,7 @@
#if __USE_GNU
char buffer[256];
if (style == SYSCALL) {
- sysErrorArray = arrayPtr(strerror_r(errorNumber, buffer, sizeof(buffer)));
+ sysErrorArray = stringPtr(strerror_r(errorNumber, buffer, sizeof(buffer)));
}
#else
// TODO(port): Other unixes should have strerror_r but it may have a different signature.
diff --git a/c++/src/kj/memory.c++ b/c++/src/kj/memory.c++
new file mode 100644
index 0000000..bfc5f17
--- /dev/null
+++ b/c++/src/kj/memory.c++
@@ -0,0 +1,30 @@
+// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "memory.h"
+
+namespace kj {
+
+Disposer::~Disposer() {}
+
+} // namespace kj
diff --git a/c++/src/kj/memory.h b/c++/src/kj/memory.h
new file mode 100644
index 0000000..f90afa1
--- /dev/null
+++ b/c++/src/kj/memory.h
@@ -0,0 +1,143 @@
+// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef KJ_MEMORY_H_
+#define KJ_MEMORY_H_
+
+#include "common.h"
+
+namespace kj {
+
+// =======================================================================================
+
+class Disposer {
+ // Abstract interface for a thing that disposes of some other object. Often, it makes sense to
+ // decouple an object from the knowledge of how to dispose of it.
+
+protected:
+ virtual ~Disposer();
+
+public:
+ virtual void dispose(void* interiorPointer) = 0;
+ // Disposes of the object that this Disposer owns, and possibly disposes of the disposer itself.
+ //
+ // Callers must assume that the Disposer itself is no longer valid once this returns -- e.g. it
+ // might delete itself. Callers must in particular be sure not to call the Disposer again even
+ // when dispose() throws an exception.
+ //
+ // `interiorPointer` points somewhere inside of the object -- NOT necessarily at the beginning,
+ // especially in the presence of multiple inheritance. Most implementations should ignore the
+ // pointer, though a tricky memory allocator could get away with sharing one Disposer among
+ // multiple objects if it can figure out how to find the beginning of the object given an
+ // arbitrary interior pointer.
+};
+
+// =======================================================================================
+// Own<T> -- An owned pointer.
+
+template <typename T>
+class Own {
+ // A transferrable title to a T. When an Own<T> goes out of scope, the object's Disposer is
+ // called to dispose of it. An Own<T> can be efficiently passed by move, without relocating the
+ // underlying object; this transfers ownership.
+ //
+ // This is much like std::unique_ptr, except:
+ // - You cannot release(). An owned object is not necessarily allocated with new (see next
+ // point), so it would be hard to use release() correctly.
+ // - The deleter is made polymorphic by virtual call rather than by template. This is a much
+ // more powerful default -- it allows any random module to decide to use a custom allocator.
+ // This could be accomplished with unique_ptr by forcing everyone to use e.g.
+ // std::unique_ptr<T, kj::Disposer&>, but at that point we've lost basically any benefit
+ // of interoperating with std::unique_ptr anyway.
+
+public:
+ Own(const Own& other) = delete;
+ inline Own(Own&& other) noexcept
+ : disposer(other.disposer), ptr(other.ptr) { other.ptr = nullptr; }
+ template <typename U>
+ inline Own(Own<U>&& other) noexcept
+ : disposer(other.disposer), ptr(other.ptr) { other.ptr = nullptr; }
+ inline Own(T* ptr, Disposer* disposer) noexcept: disposer(disposer), ptr(ptr) {}
+
+ ~Own() noexcept { dispose(); }
+
+ inline Own& operator=(Own&& other) {
+ dispose();
+ disposer = other.disposer;
+ ptr = other.ptr;
+ other.ptr = nullptr;
+ return *this;
+ }
+
+ inline T* operator->() { return ptr; }
+ inline const T* operator->() const { return ptr; }
+ inline T& operator*() { return *ptr; }
+ inline const T& operator*() const { return *ptr; }
+ inline T* get() { return ptr; }
+ inline const T* get() const { return ptr; }
+ inline operator T*() { return ptr; }
+ inline operator const T*() const { return ptr; }
+
+private:
+ Disposer* disposer; // Only valid if ptr != nullptr.
+ T* ptr;
+
+ inline void dispose() {
+ // Make sure that if an exception is thrown, we are left with a null ptr, so we won't possibly
+ // dispose again.
+ void* ptrCopy = ptr;
+ if (ptrCopy != nullptr) {
+ ptr = nullptr;
+ disposer->dispose(ptrCopy);
+ }
+ }
+};
+
+namespace internal {
+
+template <typename T>
+class HeapValue final: public Disposer {
+public:
+ template <typename... Params>
+ inline HeapValue(Params&&... params): value(kj::fwd<Params>(params)...) {}
+
+ virtual void dispose(void*) override { delete this; }
+
+ T value;
+};
+
+} // namespace internal
+
+template <typename T, typename... Params>
+Own<T> heap(Params&&... params) {
+ // heap<T>(...) allocates a T on the heap, forwarding the parameters to its constructor. The
+ // exact heap implementation is unspecified -- for now it is operator new, but you should not
+ // assume anything.
+
+ auto result = new internal::HeapValue<T>(kj::fwd<Params>(params)...);
+ return Own<T>(&result->value, result);
+}
+
+} // namespace kj
+
+#endif // KJ_MEMORY_H_
diff --git a/c++/src/kj/string.c++ b/c++/src/kj/string.c++
new file mode 100644
index 0000000..88dcf37
--- /dev/null
+++ b/c++/src/kj/string.c++
@@ -0,0 +1,37 @@
+// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "string.h"
+
+namespace kj {
+
+String::String(const char* value): content(newArray<char>(strlen(value) + 1)) {
+ strcpy(content.begin(), value);
+}
+
+String::String(const char* value, size_t length): content(newArray<char>(length + 1)) {
+ memcpy(content.begin(), value, length);
+ content[length] = '\0';
+}
+
+} // namespace kj
diff --git a/c++/src/kj/string.h b/c++/src/kj/string.h
new file mode 100644
index 0000000..1be15a6
--- /dev/null
+++ b/c++/src/kj/string.h
@@ -0,0 +1,69 @@
+// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef KJ_STRING_H_
+#define KJ_STRING_H_
+
+#include "array.h"
+#include <string.h>
+
+namespace kj {
+
+inline ArrayPtr<const char> stringPtr(const char* text) {
+ return arrayPtr(text, strlen(text));
+}
+
+// =======================================================================================
+// String -- Just a NUL-terminated Array<char>.
+
+class String {
+public:
+ String() = default;
+ String(const char* value);
+ String(const char* value, size_t length);
+
+ inline ArrayPtr<char> asArray();
+ inline ArrayPtr<const char> asArray() const;
+ inline const char* cStr() const { return content == nullptr ? "" : content.begin(); }
+
+ inline size_t size() const { return content == nullptr ? 0 : content.size() - 1; }
+
+ inline char* begin() { return content == nullptr ? nullptr : content.begin(); }
+ inline char* end() { return content == nullptr ? nullptr : content.end() - 1; }
+ inline const char* begin() const { return content == nullptr ? nullptr : content.begin(); }
+ inline const char* end() const { return content == nullptr ? nullptr : content.end() - 1; }
+
+private:
+ Array<char> content;
+};
+
+inline ArrayPtr<char> String::asArray() {
+ return content == nullptr ? ArrayPtr<char>(nullptr) : content.slice(0, content.size() - 1);
+}
+inline ArrayPtr<const char> String::asArray() const {
+ return content == nullptr ? ArrayPtr<char>(nullptr) : content.slice(0, content.size() - 1);
+}
+
+} // namespace kj
+
+#endif // KJ_STRING_H_
diff --git a/c++/src/kj/type-safety.c++ b/c++/src/kj/type-safety.c++
index a874829..812c8bb 100644
--- a/c++/src/kj/type-safety.c++
+++ b/c++/src/kj/type-safety.c++
@@ -25,15 +25,4 @@
namespace kj {
-Disposer::~Disposer() {}
-
-String::String(const char* value): content(newArray<char>(strlen(value) + 1)) {
- strcpy(content.begin(), value);
-}
-
-String::String(const char* value, size_t length): content(newArray<char>(length + 1)) {
- memcpy(content.begin(), value, length);
- content[length] = '\0';
-}
-
} // namespace kj
diff --git a/c++/src/kj/type-safety.h b/c++/src/kj/type-safety.h
index b670c6c..effef11 100644
--- a/c++/src/kj/type-safety.h
+++ b/c++/src/kj/type-safety.h
@@ -35,349 +35,6 @@
namespace kj {
// =======================================================================================
-// Own<T> -- An owned pointer.
-
-class Disposer {
- // Abstract interface for a thing that disposes of some other object. Often, it makes sense to
- // decouple an object from the knowledge of how to dispose of it.
-
-protected:
- virtual ~Disposer();
-
-public:
- virtual void dispose(void* interiorPointer) = 0;
- // Disposes of the object that this Disposer owns, and possibly disposes of the disposer itself.
- //
- // Callers must assume that the Disposer itself is no longer valid once this returns -- e.g. it
- // might delete itself. Callers must in particular be sure not to call the Disposer again even
- // when dispose() throws an exception.
- //
- // `interiorPointer` points somewhere inside of the object -- NOT necessarily at the beginning,
- // especially in the presence of multiple inheritance. Most implementations should ignore the
- // pointer, though a tricky memory allocator could get away with sharing one Disposer among
- // multiple objects if it can figure out how to find the beginning of the object given an
- // arbitrary interior pointer.
-};
-
-template <typename T>
-class Own {
- // A transferrable title to a T. When an Own<T> goes out of scope, the object's Disposer is
- // called to dispose of it. An Own<T> can be efficiently passed by move, without relocating the
- // underlying object; this transfers ownership.
- //
- // This is much like std::unique_ptr, except:
- // - You cannot release(). An owned object is not necessarily allocated with new (see next
- // point), so it would be hard to use release() correctly.
- // - The deleter is made polymorphic by virtual call rather than by template. This is a much
- // more powerful default -- it allows any random module to decide to use a custom allocator.
- // This could be accomplished with unique_ptr by forcing everyone to use e.g.
- // std::unique_ptr<T, kj::Disposer&>, but at that point we've lost basically any benefit
- // of interoperating with std::unique_ptr anyway.
-
-public:
- Own(const Own& other) = delete;
- inline Own(Own&& other) noexcept
- : disposer(other.disposer), ptr(other.ptr) { other.ptr = nullptr; }
- template <typename U>
- inline Own(Own<U>&& other) noexcept
- : disposer(other.disposer), ptr(other.ptr) { other.ptr = nullptr; }
- inline Own(T* ptr, Disposer* disposer) noexcept: disposer(disposer), ptr(ptr) {}
-
- ~Own() noexcept { dispose(); }
-
- inline Own& operator=(Own&& other) {
- dispose();
- disposer = other.disposer;
- ptr = other.ptr;
- other.ptr = nullptr;
- return *this;
- }
-
- inline T* operator->() { return ptr; }
- inline const T* operator->() const { return ptr; }
- inline T& operator*() { return *ptr; }
- inline const T& operator*() const { return *ptr; }
- inline T* get() { return ptr; }
- inline const T* get() const { return ptr; }
- inline operator T*() { return ptr; }
- inline operator const T*() const { return ptr; }
-
-private:
- Disposer* disposer; // Only valid if ptr != nullptr.
- T* ptr;
-
- inline void dispose() {
- // Make sure that if an exception is thrown, we are left with a null ptr, so we won't possibly
- // dispose again.
- void* ptrCopy = ptr;
- if (ptrCopy != nullptr) {
- ptr = nullptr;
- disposer->dispose(ptrCopy);
- }
- }
-};
-
-namespace internal {
-
-template <typename T>
-class HeapValue final: public Disposer {
-public:
- template <typename... Params>
- inline HeapValue(Params&&... params): value(kj::fwd<Params>(params)...) {}
-
- virtual void dispose(void*) override { delete this; }
-
- T value;
-};
-
-} // namespace internal
-
-template <typename T, typename... Params>
-Own<T> heap(Params&&... params) {
- // heap<T>(...) allocates a T on the heap, forwarding the parameters to its constructor. The
- // exact heap implementation is unspecified -- for now it is operator new, but you should not
- // assume anything.
-
- auto result = new internal::HeapValue<T>(kj::fwd<Params>(params)...);
- return Own<T>(&result->value, result);
-}
-
-// =======================================================================================
-// ArrayPtr
-
-template <typename T>
-class ArrayPtr {
- // A pointer to an array. Includes a size. Like any pointer, it doesn't own the target data,
- // and passing by value only copies the pointer, not the target.
-
-public:
- inline constexpr ArrayPtr(): ptr(nullptr), size_(0) {}
- inline constexpr ArrayPtr(std::nullptr_t): ptr(nullptr), size_(0) {}
- inline constexpr ArrayPtr(T* ptr, std::size_t size): ptr(ptr), size_(size) {}
- inline constexpr ArrayPtr(T* begin, T* end): ptr(begin), size_(end - begin) {}
-
- inline operator ArrayPtr<const T>() {
- return ArrayPtr<const T>(ptr, size_);
- }
-
- inline std::size_t size() const { return size_; }
- inline T& operator[](std::size_t index) const {
- KJ_INLINE_DPRECOND(index < size_, "Out-of-bounds ArrayPtr access.");
- return ptr[index];
- }
-
- inline T* begin() const { return ptr; }
- inline T* end() const { return ptr + size_; }
- inline T& front() const { return *ptr; }
- inline T& back() const { return *(ptr + size_ - 1); }
-
- inline ArrayPtr slice(size_t start, size_t end) {
- KJ_INLINE_DPRECOND(start <= end && end <= size_, "Out-of-bounds ArrayPtr::slice().");
- return ArrayPtr(ptr + start, end - start);
- }
-
- inline bool operator==(std::nullptr_t) { return size_ == 0; }
- inline bool operator!=(std::nullptr_t) { return size_ != 0; }
-
-private:
- T* ptr;
- std::size_t size_;
-};
-
-template <typename T>
-inline constexpr ArrayPtr<T> arrayPtr(T* ptr, size_t size) {
- // Use this function to construct ArrayPtrs without writing out the type name.
- return ArrayPtr<T>(ptr, size);
-}
-
-template <typename T>
-inline constexpr ArrayPtr<T> arrayPtr(T* begin, T* end) {
- // Use this function to construct ArrayPtrs without writing out the type name.
- return ArrayPtr<T>(begin, end);
-}
-
-inline ArrayPtr<const char> arrayPtr(const char* s) {
- // Use this function to construct an ArrayPtr from a NUL-terminated string, especially a literal.
- return arrayPtr(s, strlen(s));
-}
-
-template <typename T>
-class Array {
- // An owned array which will automatically be deleted in the destructor. Can be moved, but not
- // copied.
-
-public:
- inline Array(): ptr(nullptr), size_(0) {}
- inline Array(std::nullptr_t): ptr(nullptr), size_(0) {}
- inline Array(Array&& other) noexcept: ptr(other.ptr), size_(other.size_) {
- other.ptr = nullptr;
- other.size_ = 0;
- }
-
- KJ_DISALLOW_COPY(Array);
- inline ~Array() noexcept { delete[] ptr; }
-
- inline operator ArrayPtr<T>() {
- return ArrayPtr<T>(ptr, size_);
- }
- inline operator ArrayPtr<const T>() const {
- return ArrayPtr<T>(ptr, size_);
- }
- inline ArrayPtr<T> asPtr() {
- return ArrayPtr<T>(ptr, size_);
- }
-
- inline std::size_t size() const { return size_; }
- inline T& operator[](std::size_t index) const {
- KJ_INLINE_DPRECOND(index < size_, "Out-of-bounds Array access.");
- return ptr[index];
- }
-
- inline T* begin() const { return ptr; }
- inline T* end() const { return ptr + size_; }
- inline T& front() const { return *ptr; }
- inline T& back() const { return *(ptr + size_ - 1); }
-
- inline ArrayPtr<T> slice(size_t start, size_t end) {
- KJ_INLINE_DPRECOND(start <= end && end <= size_, "Out-of-bounds Array::slice().");
- return ArrayPtr<T>(ptr + start, end - start);
- }
- inline ArrayPtr<const T> slice(size_t start, size_t end) const {
- KJ_INLINE_DPRECOND(start <= end && end <= size_, "Out-of-bounds Array::slice().");
- return ArrayPtr<const T>(ptr + start, end - start);
- }
-
- inline bool operator==(std::nullptr_t) const { return size_ == 0; }
- inline bool operator!=(std::nullptr_t) const { return size_ != 0; }
-
- inline Array& operator=(std::nullptr_t) {
- delete[] ptr;
- ptr = nullptr;
- size_ = 0;
- return *this;
- }
-
- inline Array& operator=(Array&& other) {
- delete[] ptr;
- ptr = other.ptr;
- size_ = other.size_;
- other.ptr = nullptr;
- other.size_ = 0;
- return *this;
- }
-
-private:
- T* ptr;
- size_t size_;
-
- inline explicit Array(std::size_t size): ptr(new T[size]), size_(size) {}
- inline Array(T* ptr, size_t size): ptr(ptr), size_(size) {}
-
- template <typename U>
- friend Array<U> newArray(size_t size);
-
- template <typename U>
- friend class ArrayBuilder;
-};
-
-template <typename T>
-inline Array<T> newArray(size_t size) {
- return Array<T>(size);
-}
-
-template <typename T>
-class ArrayBuilder {
- // TODO(cleanup): This class doesn't work for non-primitive types because Slot is not
- // constructable. Giving Slot a constructor/destructor means arrays of it have to be tagged
- // so operator delete can run the destructors. If we reinterpret_cast the array to an array
- // of T and delete it as that type, operator delete gets very upset.
- //
- // Perhaps we should bite the bullet and make the Array family do manual memory allocation,
- // bypassing the rather-stupid C++ array new/delete operators which store a redundant copy of
- // the size anyway.
-
- union Slot {
- T value;
- char dummy;
- };
- static_assert(sizeof(Slot) == sizeof(T), "union is bigger than content?");
-
-public:
- explicit ArrayBuilder(size_t size): ptr(new Slot[size]), pos(ptr), endPtr(ptr + size) {}
- ~ArrayBuilder() {
- for (Slot* p = ptr; p < pos; ++p) {
- p->value.~T();
- }
- delete [] ptr;
- }
-
- template <typename... Params>
- void add(Params&&... params) {
- KJ_INLINE_DPRECOND(pos < endPtr, "Added too many elements to ArrayBuilder.");
- new(&pos->value) T(kj::fwd<Params>(params)...);
- ++pos;
- }
-
- template <typename Container>
- void addAll(Container&& container) {
- Slot* __restrict__ pos_ = pos;
- auto i = container.begin();
- auto end = container.end();
- while (i != end) {
- pos_++->value = *i++;
- }
- pos = pos_;
- }
-
- Array<T> finish() {
- // We could allow partial builds if Array<T> used a deleter callback, but that would make
- // Array<T> bigger for no benefit most of the time.
- KJ_INLINE_DPRECOND(pos == endPtr, "ArrayBuilder::finish() called prematurely.");
- Array<T> result(reinterpret_cast<T*>(ptr), pos - ptr);
- ptr = nullptr;
- pos = nullptr;
- endPtr = nullptr;
- return result;
- }
-
-private:
- Slot* ptr;
- Slot* pos;
- Slot* endPtr;
-};
-
-// =======================================================================================
-// String -- Just a NUL-terminated Array<char>.
-
-class String {
-public:
- String() = default;
- String(const char* value);
- String(const char* value, size_t length);
-
- inline ArrayPtr<char> asArray();
- inline ArrayPtr<const char> asArray() const;
- inline const char* cStr() const { return content == nullptr ? "" : content.begin(); }
-
- inline size_t size() const { return content == nullptr ? 0 : content.size() - 1; }
-
- inline char* begin() { return content == nullptr ? nullptr : content.begin(); }
- inline char* end() { return content == nullptr ? nullptr : content.end() - 1; }
- inline const char* begin() const { return content == nullptr ? nullptr : content.begin(); }
- inline const char* end() const { return content == nullptr ? nullptr : content.end() - 1; }
-
-private:
- Array<char> content;
-};
-
-inline ArrayPtr<char> String::asArray() {
- return content == nullptr ? ArrayPtr<char>(nullptr) : content.slice(0, content.size() - 1);
-}
-inline ArrayPtr<const char> String::asArray() const {
- return content == nullptr ? ArrayPtr<char>(nullptr) : content.slice(0, content.size() - 1);
-}
-
-// =======================================================================================
// IDs
template <typename UnderlyingType, typename Label>
diff --git a/c++/src/kj/util.h b/c++/src/kj/util.h
index 046816f..1ca5021 100644
--- a/c++/src/kj/util.h
+++ b/c++/src/kj/util.h
@@ -27,7 +27,8 @@
#include <initializer_list>
#include <utility>
#include <type_traits>
-#include "type-safety.h"
+#include "array.h"
+#include "string.h"
#include <string.h>
namespace kj {