mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-08-21 08:14:00 +08:00
bring over phonelibs minus frida-gum and qsml
This commit is contained in:
@@ -0,0 +1,213 @@
|
||||
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef KJ_ARENA_H_
|
||||
#define KJ_ARENA_H_
|
||||
|
||||
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include "memory.h"
|
||||
#include "array.h"
|
||||
#include "string.h"
|
||||
|
||||
namespace kj {
|
||||
|
||||
class Arena {
|
||||
// A class which allows several objects to be allocated in contiguous chunks of memory, then
|
||||
// frees them all at once.
|
||||
//
|
||||
// Allocating from the same Arena in multiple threads concurrently is NOT safe, because making
|
||||
// it safe would require atomic operations that would slow down allocation even when
|
||||
// single-threaded. If you need to use arena allocation in a multithreaded context, consider
|
||||
// allocating thread-local arenas.
|
||||
|
||||
public:
|
||||
explicit Arena(size_t chunkSizeHint = 1024);
|
||||
// Create an Arena. `chunkSizeHint` hints at where to start when allocating chunks, but is only
|
||||
// a hint -- the Arena will, for example, allocate progressively larger chunks as time goes on,
|
||||
// in order to reduce overall allocation overhead.
|
||||
|
||||
explicit Arena(ArrayPtr<byte> scratch);
|
||||
// Allocates from the given scratch space first, only resorting to the heap when it runs out.
|
||||
|
||||
KJ_DISALLOW_COPY(Arena);
|
||||
~Arena() noexcept(false);
|
||||
|
||||
template <typename T, typename... Params>
|
||||
T& allocate(Params&&... params);
|
||||
template <typename T>
|
||||
ArrayPtr<T> allocateArray(size_t size);
|
||||
// Allocate an object or array of type T. If T has a non-trivial destructor, that destructor
|
||||
// will be run during the Arena's destructor. Such destructors are run in opposite order of
|
||||
// allocation. Note that these methods must maintain a list of destructors to call, which has
|
||||
// overhead, but this overhead only applies if T has a non-trivial destructor.
|
||||
|
||||
template <typename T, typename... Params>
|
||||
Own<T> allocateOwn(Params&&... params);
|
||||
template <typename T>
|
||||
Array<T> allocateOwnArray(size_t size);
|
||||
template <typename T>
|
||||
ArrayBuilder<T> allocateOwnArrayBuilder(size_t capacity);
|
||||
// Allocate an object or array of type T. Destructors are executed when the returned Own<T>
|
||||
// or Array<T> goes out-of-scope, which must happen before the Arena is destroyed. This variant
|
||||
// is useful when you need to control when the destructor is called. This variant also avoids
|
||||
// the need for the Arena itself to keep track of destructors to call later, which may make it
|
||||
// slightly more efficient.
|
||||
|
||||
template <typename T>
|
||||
inline T& copy(T&& value) { return allocate<Decay<T>>(kj::fwd<T>(value)); }
|
||||
// Allocate a copy of the given value in the arena. This is just a shortcut for calling the
|
||||
// type's copy (or move) constructor.
|
||||
|
||||
StringPtr copyString(StringPtr content);
|
||||
// Make a copy of the given string inside the arena, and return a pointer to the copy.
|
||||
|
||||
private:
|
||||
struct ChunkHeader {
|
||||
ChunkHeader* next;
|
||||
byte* pos; // first unallocated byte in this chunk
|
||||
byte* end; // end of this chunk
|
||||
};
|
||||
struct ObjectHeader {
|
||||
void (*destructor)(void*);
|
||||
ObjectHeader* next;
|
||||
};
|
||||
|
||||
size_t nextChunkSize;
|
||||
ChunkHeader* chunkList = nullptr;
|
||||
ObjectHeader* objectList = nullptr;
|
||||
|
||||
ChunkHeader* currentChunk = nullptr;
|
||||
|
||||
void cleanup();
|
||||
// Run all destructors, leaving the above pointers null. If a destructor throws, the State is
|
||||
// left in a consistent state, such that if cleanup() is called again, it will pick up where
|
||||
// it left off.
|
||||
|
||||
void* allocateBytes(size_t amount, uint alignment, bool hasDisposer);
|
||||
// Allocate the given number of bytes. `hasDisposer` must be true if `setDisposer()` may be
|
||||
// called on this pointer later.
|
||||
|
||||
void* allocateBytesInternal(size_t amount, uint alignment);
|
||||
// Try to allocate the given number of bytes without taking a lock. Fails if and only if there
|
||||
// is no space left in the current chunk.
|
||||
|
||||
void setDestructor(void* ptr, void (*destructor)(void*));
|
||||
// Schedule the given destructor to be executed when the Arena is destroyed. `ptr` must be a
|
||||
// pointer previously returned by an `allocateBytes()` call for which `hasDisposer` was true.
|
||||
|
||||
template <typename T>
|
||||
static void destroyArray(void* pointer) {
|
||||
size_t elementCount = *reinterpret_cast<size_t*>(pointer);
|
||||
constexpr size_t prefixSize = kj::max(alignof(T), sizeof(size_t));
|
||||
DestructorOnlyArrayDisposer::instance.disposeImpl(
|
||||
reinterpret_cast<byte*>(pointer) + prefixSize,
|
||||
sizeof(T), elementCount, elementCount, &destroyObject<T>);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void destroyObject(void* pointer) {
|
||||
dtor(*reinterpret_cast<T*>(pointer));
|
||||
}
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
// Inline implementation details
|
||||
|
||||
template <typename T, typename... Params>
|
||||
T& Arena::allocate(Params&&... params) {
|
||||
T& result = *reinterpret_cast<T*>(allocateBytes(
|
||||
sizeof(T), alignof(T), !__has_trivial_destructor(T)));
|
||||
if (!__has_trivial_constructor(T) || sizeof...(Params) > 0) {
|
||||
ctor(result, kj::fwd<Params>(params)...);
|
||||
}
|
||||
if (!__has_trivial_destructor(T)) {
|
||||
setDestructor(&result, &destroyObject<T>);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ArrayPtr<T> Arena::allocateArray(size_t size) {
|
||||
if (__has_trivial_destructor(T)) {
|
||||
ArrayPtr<T> result =
|
||||
arrayPtr(reinterpret_cast<T*>(allocateBytes(
|
||||
sizeof(T) * size, alignof(T), false)), size);
|
||||
if (!__has_trivial_constructor(T)) {
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
ctor(result[i]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
// Allocate with a 64-bit prefix in which we store the array size.
|
||||
constexpr size_t prefixSize = kj::max(alignof(T), sizeof(size_t));
|
||||
void* base = allocateBytes(sizeof(T) * size + prefixSize, alignof(T), true);
|
||||
size_t& tag = *reinterpret_cast<size_t*>(base);
|
||||
ArrayPtr<T> result =
|
||||
arrayPtr(reinterpret_cast<T*>(reinterpret_cast<byte*>(base) + prefixSize), size);
|
||||
setDestructor(base, &destroyArray<T>);
|
||||
|
||||
if (__has_trivial_constructor(T)) {
|
||||
tag = size;
|
||||
} else {
|
||||
// In case of constructor exceptions, we need the tag to end up storing the number of objects
|
||||
// that were successfully constructed, so that they'll be properly destroyed.
|
||||
tag = 0;
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
ctor(result[i]);
|
||||
tag = i + 1;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename... Params>
|
||||
Own<T> Arena::allocateOwn(Params&&... params) {
|
||||
T& result = *reinterpret_cast<T*>(allocateBytes(sizeof(T), alignof(T), false));
|
||||
if (!__has_trivial_constructor(T) || sizeof...(Params) > 0) {
|
||||
ctor(result, kj::fwd<Params>(params)...);
|
||||
}
|
||||
return Own<T>(&result, DestructorOnlyDisposer<T>::instance);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Array<T> Arena::allocateOwnArray(size_t size) {
|
||||
ArrayBuilder<T> result = allocateOwnArrayBuilder<T>(size);
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
result.add();
|
||||
}
|
||||
return result.finish();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ArrayBuilder<T> Arena::allocateOwnArrayBuilder(size_t capacity) {
|
||||
return ArrayBuilder<T>(
|
||||
reinterpret_cast<T*>(allocateBytes(sizeof(T) * capacity, alignof(T), false)),
|
||||
capacity, DestructorOnlyArrayDisposer::instance);
|
||||
}
|
||||
|
||||
} // namespace kj
|
||||
|
||||
#endif // KJ_ARENA_H_
|
||||
@@ -0,0 +1,813 @@
|
||||
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef KJ_ARRAY_H_
|
||||
#define KJ_ARRAY_H_
|
||||
|
||||
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
#include <string.h>
|
||||
#include <initializer_list>
|
||||
|
||||
namespace kj {
|
||||
|
||||
// =======================================================================================
|
||||
// ArrayDisposer -- Implementation details.
|
||||
|
||||
class ArrayDisposer {
|
||||
// Much like Disposer from memory.h.
|
||||
|
||||
protected:
|
||||
// Do not declare a destructor, as doing so will force a global initializer for
|
||||
// HeapArrayDisposer::instance.
|
||||
|
||||
virtual void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount,
|
||||
size_t capacity, void (*destroyElement)(void*)) const = 0;
|
||||
// Disposes of the array. `destroyElement` invokes the destructor of each element, or is nullptr
|
||||
// if the elements have trivial destructors. `capacity` is the amount of space that was
|
||||
// allocated while `elementCount` is the number of elements that were actually constructed;
|
||||
// these are always the same number for Array<T> but may be different when using ArrayBuilder<T>.
|
||||
|
||||
public:
|
||||
|
||||
template <typename T>
|
||||
void dispose(T* firstElement, size_t elementCount, size_t capacity) const;
|
||||
// Helper wrapper around disposeImpl().
|
||||
//
|
||||
// Callers must not call dispose() on the same array twice, even if the first call throws
|
||||
// an exception.
|
||||
|
||||
private:
|
||||
template <typename T, bool hasTrivialDestructor = __has_trivial_destructor(T)>
|
||||
struct Dispose_;
|
||||
};
|
||||
|
||||
class ExceptionSafeArrayUtil {
|
||||
// Utility class that assists in constructing or destroying elements of an array, where the
|
||||
// constructor or destructor could throw exceptions. In case of an exception,
|
||||
// ExceptionSafeArrayUtil's destructor will call destructors on all elements that have been
|
||||
// constructed but not destroyed. Remember that destructors that throw exceptions are required
|
||||
// to use UnwindDetector to detect unwind and avoid exceptions in this case. Therefore, no more
|
||||
// than one exception will be thrown (and the program will not terminate).
|
||||
|
||||
public:
|
||||
inline ExceptionSafeArrayUtil(void* ptr, size_t elementSize, size_t constructedElementCount,
|
||||
void (*destroyElement)(void*))
|
||||
: pos(reinterpret_cast<byte*>(ptr) + elementSize * constructedElementCount),
|
||||
elementSize(elementSize), constructedElementCount(constructedElementCount),
|
||||
destroyElement(destroyElement) {}
|
||||
KJ_DISALLOW_COPY(ExceptionSafeArrayUtil);
|
||||
|
||||
inline ~ExceptionSafeArrayUtil() noexcept(false) {
|
||||
if (constructedElementCount > 0) destroyAll();
|
||||
}
|
||||
|
||||
void construct(size_t count, void (*constructElement)(void*));
|
||||
// Construct the given number of elements.
|
||||
|
||||
void destroyAll();
|
||||
// Destroy all elements. Call this immediately before ExceptionSafeArrayUtil goes out-of-scope
|
||||
// to ensure that one element throwing an exception does not prevent the others from being
|
||||
// destroyed.
|
||||
|
||||
void release() { constructedElementCount = 0; }
|
||||
// Prevent ExceptionSafeArrayUtil's destructor from destroying the constructed elements.
|
||||
// Call this after you've successfully finished constructing.
|
||||
|
||||
private:
|
||||
byte* pos;
|
||||
size_t elementSize;
|
||||
size_t constructedElementCount;
|
||||
void (*destroyElement)(void*);
|
||||
};
|
||||
|
||||
class DestructorOnlyArrayDisposer: public ArrayDisposer {
|
||||
public:
|
||||
static const DestructorOnlyArrayDisposer instance;
|
||||
|
||||
void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount,
|
||||
size_t capacity, void (*destroyElement)(void*)) const override;
|
||||
};
|
||||
|
||||
class NullArrayDisposer: public ArrayDisposer {
|
||||
// An ArrayDisposer that does nothing. Can be used to construct a fake Arrays that doesn't
|
||||
// actually own its content.
|
||||
|
||||
public:
|
||||
static const NullArrayDisposer instance;
|
||||
|
||||
void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount,
|
||||
size_t capacity, void (*destroyElement)(void*)) const override;
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
// Array
|
||||
|
||||
template <typename T>
|
||||
class Array {
|
||||
// An owned array which will automatically be disposed of (using an ArrayDisposer) in the
|
||||
// destructor. Can be moved, but not copied. Much like Own<T>, but for arrays rather than
|
||||
// single objects.
|
||||
|
||||
public:
|
||||
inline Array(): ptr(nullptr), size_(0), disposer(nullptr) {}
|
||||
inline Array(decltype(nullptr)): ptr(nullptr), size_(0), disposer(nullptr) {}
|
||||
inline Array(Array&& other) noexcept
|
||||
: ptr(other.ptr), size_(other.size_), disposer(other.disposer) {
|
||||
other.ptr = nullptr;
|
||||
other.size_ = 0;
|
||||
}
|
||||
inline Array(Array<RemoveConstOrDisable<T>>&& other) noexcept
|
||||
: ptr(other.ptr), size_(other.size_), disposer(other.disposer) {
|
||||
other.ptr = nullptr;
|
||||
other.size_ = 0;
|
||||
}
|
||||
inline Array(T* firstElement, size_t size, const ArrayDisposer& disposer)
|
||||
: ptr(firstElement), size_(size), disposer(&disposer) {}
|
||||
|
||||
KJ_DISALLOW_COPY(Array);
|
||||
inline ~Array() noexcept { dispose(); }
|
||||
|
||||
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 ArrayPtr<const T> asPtr() const {
|
||||
return ArrayPtr<T>(ptr, size_);
|
||||
}
|
||||
|
||||
inline size_t size() const { return size_; }
|
||||
inline T& operator[](size_t index) const {
|
||||
KJ_IREQUIRE(index < size_, "Out-of-bounds Array access.");
|
||||
return ptr[index];
|
||||
}
|
||||
|
||||
inline const T* begin() const { return ptr; }
|
||||
inline const T* end() const { return ptr + size_; }
|
||||
inline const T& front() const { return *ptr; }
|
||||
inline const T& back() const { return *(ptr + size_ - 1); }
|
||||
inline T* begin() { return ptr; }
|
||||
inline T* end() { return ptr + size_; }
|
||||
inline T& front() { return *ptr; }
|
||||
inline T& back() { return *(ptr + size_ - 1); }
|
||||
|
||||
inline ArrayPtr<T> slice(size_t start, size_t end) {
|
||||
KJ_IREQUIRE(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_IREQUIRE(start <= end && end <= size_, "Out-of-bounds Array::slice().");
|
||||
return ArrayPtr<const T>(ptr + start, end - start);
|
||||
}
|
||||
|
||||
inline ArrayPtr<const byte> asBytes() const { return asPtr().asBytes(); }
|
||||
inline ArrayPtr<PropagateConst<T, byte>> asBytes() { return asPtr().asBytes(); }
|
||||
inline ArrayPtr<const char> asChars() const { return asPtr().asChars(); }
|
||||
inline ArrayPtr<PropagateConst<T, char>> asChars() { return asPtr().asChars(); }
|
||||
|
||||
inline Array<PropagateConst<T, byte>> releaseAsBytes() {
|
||||
// Like asBytes() but transfers ownership.
|
||||
static_assert(sizeof(T) == sizeof(byte),
|
||||
"releaseAsBytes() only possible on arrays with byte-size elements (e.g. chars).");
|
||||
Array<PropagateConst<T, byte>> result(
|
||||
reinterpret_cast<PropagateConst<T, byte>*>(ptr), size_, *disposer);
|
||||
ptr = nullptr;
|
||||
size_ = 0;
|
||||
return result;
|
||||
}
|
||||
inline Array<PropagateConst<T, char>> releaseAsChars() {
|
||||
// Like asChars() but transfers ownership.
|
||||
static_assert(sizeof(T) == sizeof(PropagateConst<T, char>),
|
||||
"releaseAsChars() only possible on arrays with char-size elements (e.g. bytes).");
|
||||
Array<PropagateConst<T, char>> result(
|
||||
reinterpret_cast<PropagateConst<T, char>*>(ptr), size_, *disposer);
|
||||
ptr = nullptr;
|
||||
size_ = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bool operator==(decltype(nullptr)) const { return size_ == 0; }
|
||||
inline bool operator!=(decltype(nullptr)) const { return size_ != 0; }
|
||||
|
||||
inline Array& operator=(decltype(nullptr)) {
|
||||
dispose();
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Array& operator=(Array&& other) {
|
||||
dispose();
|
||||
ptr = other.ptr;
|
||||
size_ = other.size_;
|
||||
disposer = other.disposer;
|
||||
other.ptr = nullptr;
|
||||
other.size_ = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
T* ptr;
|
||||
size_t size_;
|
||||
const ArrayDisposer* disposer;
|
||||
|
||||
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.
|
||||
T* ptrCopy = ptr;
|
||||
size_t sizeCopy = size_;
|
||||
if (ptrCopy != nullptr) {
|
||||
ptr = nullptr;
|
||||
size_ = 0;
|
||||
disposer->dispose(ptrCopy, sizeCopy, sizeCopy);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
friend class Array;
|
||||
};
|
||||
|
||||
static_assert(!canMemcpy<Array<char>>(), "canMemcpy<>() is broken");
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
class HeapArrayDisposer final: public ArrayDisposer {
|
||||
public:
|
||||
template <typename T>
|
||||
static T* allocate(size_t count);
|
||||
template <typename T>
|
||||
static T* allocateUninitialized(size_t count);
|
||||
|
||||
static const HeapArrayDisposer instance;
|
||||
|
||||
private:
|
||||
static void* allocateImpl(size_t elementSize, size_t elementCount, size_t capacity,
|
||||
void (*constructElement)(void*), void (*destroyElement)(void*));
|
||||
// Allocates and constructs the array. Both function pointers are null if the constructor is
|
||||
// trivial, otherwise destroyElement is null if the constructor doesn't throw.
|
||||
|
||||
virtual void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount,
|
||||
size_t capacity, void (*destroyElement)(void*)) const override;
|
||||
|
||||
template <typename T, bool hasTrivialConstructor = __has_trivial_constructor(T),
|
||||
bool hasNothrowConstructor = __has_nothrow_constructor(T)>
|
||||
struct Allocate_;
|
||||
};
|
||||
|
||||
} // namespace _ (private)
|
||||
|
||||
template <typename T>
|
||||
inline Array<T> heapArray(size_t size) {
|
||||
// Much like `heap<T>()` from memory.h, allocates a new array on the heap.
|
||||
|
||||
return Array<T>(_::HeapArrayDisposer::allocate<T>(size), size,
|
||||
_::HeapArrayDisposer::instance);
|
||||
}
|
||||
|
||||
template <typename T> Array<T> heapArray(const T* content, size_t size);
|
||||
template <typename T> Array<T> heapArray(ArrayPtr<T> content);
|
||||
template <typename T> Array<T> heapArray(ArrayPtr<const T> content);
|
||||
template <typename T, typename Iterator> Array<T> heapArray(Iterator begin, Iterator end);
|
||||
template <typename T> Array<T> heapArray(std::initializer_list<T> init);
|
||||
// Allocate a heap array containing a copy of the given content.
|
||||
|
||||
template <typename T, typename Container>
|
||||
Array<T> heapArrayFromIterable(Container&& a) { return heapArray<T>(a.begin(), a.end()); }
|
||||
template <typename T>
|
||||
Array<T> heapArrayFromIterable(Array<T>&& a) { return mv(a); }
|
||||
|
||||
// =======================================================================================
|
||||
// ArrayBuilder
|
||||
|
||||
template <typename T>
|
||||
class ArrayBuilder {
|
||||
// Class which lets you build an Array<T> specifying the exact constructor arguments for each
|
||||
// element, rather than starting by default-constructing them.
|
||||
|
||||
public:
|
||||
ArrayBuilder(): ptr(nullptr), pos(nullptr), endPtr(nullptr) {}
|
||||
ArrayBuilder(decltype(nullptr)): ptr(nullptr), pos(nullptr), endPtr(nullptr) {}
|
||||
explicit ArrayBuilder(RemoveConst<T>* firstElement, size_t capacity,
|
||||
const ArrayDisposer& disposer)
|
||||
: ptr(firstElement), pos(firstElement), endPtr(firstElement + capacity),
|
||||
disposer(&disposer) {}
|
||||
ArrayBuilder(ArrayBuilder&& other)
|
||||
: ptr(other.ptr), pos(other.pos), endPtr(other.endPtr), disposer(other.disposer) {
|
||||
other.ptr = nullptr;
|
||||
other.pos = nullptr;
|
||||
other.endPtr = nullptr;
|
||||
}
|
||||
KJ_DISALLOW_COPY(ArrayBuilder);
|
||||
inline ~ArrayBuilder() noexcept(false) { dispose(); }
|
||||
|
||||
inline operator ArrayPtr<T>() {
|
||||
return arrayPtr(ptr, pos);
|
||||
}
|
||||
inline operator ArrayPtr<const T>() const {
|
||||
return arrayPtr(ptr, pos);
|
||||
}
|
||||
inline ArrayPtr<T> asPtr() {
|
||||
return arrayPtr(ptr, pos);
|
||||
}
|
||||
inline ArrayPtr<const T> asPtr() const {
|
||||
return arrayPtr(ptr, pos);
|
||||
}
|
||||
|
||||
inline size_t size() const { return pos - ptr; }
|
||||
inline size_t capacity() const { return endPtr - ptr; }
|
||||
inline T& operator[](size_t index) const {
|
||||
KJ_IREQUIRE(index < implicitCast<size_t>(pos - ptr), "Out-of-bounds Array access.");
|
||||
return ptr[index];
|
||||
}
|
||||
|
||||
inline const T* begin() const { return ptr; }
|
||||
inline const T* end() const { return pos; }
|
||||
inline const T& front() const { return *ptr; }
|
||||
inline const T& back() const { return *(pos - 1); }
|
||||
inline T* begin() { return ptr; }
|
||||
inline T* end() { return pos; }
|
||||
inline T& front() { return *ptr; }
|
||||
inline T& back() { return *(pos - 1); }
|
||||
|
||||
ArrayBuilder& operator=(ArrayBuilder&& other) {
|
||||
dispose();
|
||||
ptr = other.ptr;
|
||||
pos = other.pos;
|
||||
endPtr = other.endPtr;
|
||||
disposer = other.disposer;
|
||||
other.ptr = nullptr;
|
||||
other.pos = nullptr;
|
||||
other.endPtr = nullptr;
|
||||
return *this;
|
||||
}
|
||||
ArrayBuilder& operator=(decltype(nullptr)) {
|
||||
dispose();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename... Params>
|
||||
T& add(Params&&... params) {
|
||||
KJ_IREQUIRE(pos < endPtr, "Added too many elements to ArrayBuilder.");
|
||||
ctor(*pos, kj::fwd<Params>(params)...);
|
||||
return *pos++;
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
void addAll(Container&& container) {
|
||||
addAll<decltype(container.begin()), !isReference<Container>()>(
|
||||
container.begin(), container.end());
|
||||
}
|
||||
|
||||
template <typename Iterator, bool move = false>
|
||||
void addAll(Iterator start, Iterator end);
|
||||
|
||||
void removeLast() {
|
||||
KJ_IREQUIRE(pos > ptr, "No elements present to remove.");
|
||||
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
|
||||
// operator new() or if we created a custom disposer for ArrayBuilder which stores the capacity
|
||||
// in a prefix. But that would make it hard to write cleverer heap allocators, and anyway this
|
||||
// check might catch bugs. Probably people should use Vector if they want to build arrays
|
||||
// without knowing the final size in advance.
|
||||
KJ_IREQUIRE(pos == endPtr, "ArrayBuilder::finish() called prematurely.");
|
||||
Array<T> result(reinterpret_cast<T*>(ptr), pos - ptr, *disposer);
|
||||
ptr = nullptr;
|
||||
pos = nullptr;
|
||||
endPtr = nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bool isFull() const {
|
||||
return pos == endPtr;
|
||||
}
|
||||
|
||||
private:
|
||||
T* ptr;
|
||||
RemoveConst<T>* pos;
|
||||
T* endPtr;
|
||||
const ArrayDisposer* disposer;
|
||||
|
||||
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.
|
||||
T* ptrCopy = ptr;
|
||||
T* posCopy = pos;
|
||||
T* endCopy = endPtr;
|
||||
if (ptrCopy != nullptr) {
|
||||
ptr = nullptr;
|
||||
pos = nullptr;
|
||||
endPtr = nullptr;
|
||||
disposer->dispose(ptrCopy, posCopy - ptrCopy, endCopy - ptrCopy);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline ArrayBuilder<T> heapArrayBuilder(size_t size) {
|
||||
// Like `heapArray<T>()` but does not default-construct the elements. You must construct them
|
||||
// manually by calling `add()`.
|
||||
|
||||
return ArrayBuilder<T>(_::HeapArrayDisposer::allocateUninitialized<RemoveConst<T>>(size),
|
||||
size, _::HeapArrayDisposer::instance);
|
||||
}
|
||||
|
||||
// =======================================================================================
|
||||
// Inline Arrays
|
||||
|
||||
template <typename T, size_t fixedSize>
|
||||
class FixedArray {
|
||||
// A fixed-width array whose storage is allocated inline rather than on the heap.
|
||||
|
||||
public:
|
||||
inline size_t size() const { return fixedSize; }
|
||||
inline T* begin() { return content; }
|
||||
inline T* end() { return content + fixedSize; }
|
||||
inline const T* begin() const { return content; }
|
||||
inline const T* end() const { return content + fixedSize; }
|
||||
|
||||
inline operator ArrayPtr<T>() {
|
||||
return arrayPtr(content, fixedSize);
|
||||
}
|
||||
inline operator ArrayPtr<const T>() const {
|
||||
return arrayPtr(content, fixedSize);
|
||||
}
|
||||
|
||||
inline T& operator[](size_t index) { return content[index]; }
|
||||
inline const T& operator[](size_t index) const { return content[index]; }
|
||||
|
||||
private:
|
||||
T content[fixedSize];
|
||||
};
|
||||
|
||||
template <typename T, size_t fixedSize>
|
||||
class CappedArray {
|
||||
// Like `FixedArray` but can be dynamically resized as long as the size does not exceed the limit
|
||||
// specified by the template parameter.
|
||||
//
|
||||
// TODO(someday): Don't construct elements past currentSize?
|
||||
|
||||
public:
|
||||
inline KJ_CONSTEXPR() CappedArray(): currentSize(fixedSize) {}
|
||||
inline explicit constexpr CappedArray(size_t s): currentSize(s) {}
|
||||
|
||||
inline size_t size() const { return currentSize; }
|
||||
inline void setSize(size_t s) { KJ_IREQUIRE(s <= fixedSize); currentSize = s; }
|
||||
inline T* begin() { return content; }
|
||||
inline T* end() { return content + currentSize; }
|
||||
inline const T* begin() const { return content; }
|
||||
inline const T* end() const { return content + currentSize; }
|
||||
|
||||
inline operator ArrayPtr<T>() {
|
||||
return arrayPtr(content, currentSize);
|
||||
}
|
||||
inline operator ArrayPtr<const T>() const {
|
||||
return arrayPtr(content, currentSize);
|
||||
}
|
||||
|
||||
inline T& operator[](size_t index) { return content[index]; }
|
||||
inline const T& operator[](size_t index) const { return content[index]; }
|
||||
|
||||
private:
|
||||
size_t currentSize;
|
||||
T content[fixedSize];
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
// KJ_MAP
|
||||
|
||||
#define KJ_MAP(elementName, array) \
|
||||
::kj::_::Mapper<KJ_DECLTYPE_REF(array)>(array) * \
|
||||
[&](typename ::kj::_::Mapper<KJ_DECLTYPE_REF(array)>::Element elementName)
|
||||
// Applies some function to every element of an array, returning an Array of the results, with
|
||||
// nice syntax. Example:
|
||||
//
|
||||
// StringPtr foo = "abcd";
|
||||
// Array<char> bar = KJ_MAP(c, foo) -> char { return c + 1; };
|
||||
// KJ_ASSERT(str(bar) == "bcde");
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
template <typename T>
|
||||
struct Mapper {
|
||||
T array;
|
||||
Mapper(T&& array): array(kj::fwd<T>(array)) {}
|
||||
template <typename Func>
|
||||
auto operator*(Func&& func) -> Array<decltype(func(*array.begin()))> {
|
||||
auto builder = heapArrayBuilder<decltype(func(*array.begin()))>(array.size());
|
||||
for (auto iter = array.begin(); iter != array.end(); ++iter) {
|
||||
builder.add(func(*iter));
|
||||
}
|
||||
return builder.finish();
|
||||
}
|
||||
typedef decltype(*kj::instance<T>().begin()) Element;
|
||||
};
|
||||
|
||||
template <typename T, size_t s>
|
||||
struct Mapper<T(&)[s]> {
|
||||
T* array;
|
||||
Mapper(T* array): array(array) {}
|
||||
template <typename Func>
|
||||
auto operator*(Func&& func) -> Array<decltype(func(*array))> {
|
||||
auto builder = heapArrayBuilder<decltype(func(*array))>(s);
|
||||
for (size_t i = 0; i < s; i++) {
|
||||
builder.add(func(array[i]));
|
||||
}
|
||||
return builder.finish();
|
||||
}
|
||||
typedef decltype(*array)& Element;
|
||||
};
|
||||
|
||||
} // namespace _ (private)
|
||||
|
||||
// =======================================================================================
|
||||
// Inline implementation details
|
||||
|
||||
template <typename T>
|
||||
struct ArrayDisposer::Dispose_<T, true> {
|
||||
static void dispose(T* firstElement, size_t elementCount, size_t capacity,
|
||||
const ArrayDisposer& disposer) {
|
||||
disposer.disposeImpl(const_cast<RemoveConst<T>*>(firstElement),
|
||||
sizeof(T), elementCount, capacity, nullptr);
|
||||
}
|
||||
};
|
||||
template <typename T>
|
||||
struct ArrayDisposer::Dispose_<T, false> {
|
||||
static void destruct(void* ptr) {
|
||||
kj::dtor(*reinterpret_cast<T*>(ptr));
|
||||
}
|
||||
|
||||
static void dispose(T* firstElement, size_t elementCount, size_t capacity,
|
||||
const ArrayDisposer& disposer) {
|
||||
disposer.disposeImpl(firstElement, sizeof(T), elementCount, capacity, &destruct);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void ArrayDisposer::dispose(T* firstElement, size_t elementCount, size_t capacity) const {
|
||||
Dispose_<T>::dispose(firstElement, elementCount, capacity, *this);
|
||||
}
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
template <typename T>
|
||||
struct HeapArrayDisposer::Allocate_<T, true, true> {
|
||||
static T* allocate(size_t elementCount, size_t capacity) {
|
||||
return reinterpret_cast<T*>(allocateImpl(
|
||||
sizeof(T), elementCount, capacity, nullptr, nullptr));
|
||||
}
|
||||
};
|
||||
template <typename T>
|
||||
struct HeapArrayDisposer::Allocate_<T, false, true> {
|
||||
static void construct(void* ptr) {
|
||||
kj::ctor(*reinterpret_cast<T*>(ptr));
|
||||
}
|
||||
static T* allocate(size_t elementCount, size_t capacity) {
|
||||
return reinterpret_cast<T*>(allocateImpl(
|
||||
sizeof(T), elementCount, capacity, &construct, nullptr));
|
||||
}
|
||||
};
|
||||
template <typename T>
|
||||
struct HeapArrayDisposer::Allocate_<T, false, false> {
|
||||
static void construct(void* ptr) {
|
||||
kj::ctor(*reinterpret_cast<T*>(ptr));
|
||||
}
|
||||
static void destruct(void* ptr) {
|
||||
kj::dtor(*reinterpret_cast<T*>(ptr));
|
||||
}
|
||||
static T* allocate(size_t elementCount, size_t capacity) {
|
||||
return reinterpret_cast<T*>(allocateImpl(
|
||||
sizeof(T), elementCount, capacity, &construct, &destruct));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
T* HeapArrayDisposer::allocate(size_t count) {
|
||||
return Allocate_<T>::allocate(count, count);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* HeapArrayDisposer::allocateUninitialized(size_t count) {
|
||||
return Allocate_<T, true, true>::allocate(0, count);
|
||||
}
|
||||
|
||||
template <typename Element, typename Iterator, bool move, bool = canMemcpy<Element>()>
|
||||
struct CopyConstructArray_;
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
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, 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
|
||||
// compiler to optimize.
|
||||
while (start != end) {
|
||||
*pos++ = *start++;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Iterator>
|
||||
struct CopyConstructArray_<T, Iterator, false, false> {
|
||||
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>(*start);
|
||||
|
||||
if (noexcept(T(*start))) {
|
||||
while (start != end) {
|
||||
ctor(*pos++, *start++);
|
||||
}
|
||||
return pos;
|
||||
} else {
|
||||
// Crap. This is complicated.
|
||||
ExceptionGuard guard(pos);
|
||||
while (start != end) {
|
||||
ctor(*guard.pos, *start++);
|
||||
++guard.pos;
|
||||
}
|
||||
guard.start = guard.pos;
|
||||
return guard.pos;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Iterator>
|
||||
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, bool move>
|
||||
void ArrayBuilder<T>::addAll(Iterator start, Iterator end) {
|
||||
pos = _::CopyConstructArray_<RemoveConst<T>, Decay<Iterator>, move>::apply(pos, start, end);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Array<T> heapArray(const T* content, size_t size) {
|
||||
ArrayBuilder<T> builder = heapArrayBuilder<T>(size);
|
||||
builder.addAll(content, content + size);
|
||||
return builder.finish();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Array<T> heapArray(T* content, size_t size) {
|
||||
ArrayBuilder<T> builder = heapArrayBuilder<T>(size);
|
||||
builder.addAll(content, content + size);
|
||||
return builder.finish();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Array<T> heapArray(ArrayPtr<T> content) {
|
||||
ArrayBuilder<T> builder = heapArrayBuilder<T>(content.size());
|
||||
builder.addAll(content);
|
||||
return builder.finish();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Array<T> heapArray(ArrayPtr<const T> content) {
|
||||
ArrayBuilder<T> builder = heapArrayBuilder<T>(content.size());
|
||||
builder.addAll(content);
|
||||
return builder.finish();
|
||||
}
|
||||
|
||||
template <typename T, typename Iterator> Array<T>
|
||||
heapArray(Iterator begin, Iterator end) {
|
||||
ArrayBuilder<T> builder = heapArrayBuilder<T>(end - begin);
|
||||
builder.addAll(begin, end);
|
||||
return builder.finish();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Array<T> heapArray(std::initializer_list<T> init) {
|
||||
return heapArray<T>(init.begin(), init.end());
|
||||
}
|
||||
|
||||
} // namespace kj
|
||||
|
||||
#endif // KJ_ARRAY_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,561 @@
|
||||
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef KJ_ASYNC_IO_H_
|
||||
#define KJ_ASYNC_IO_H_
|
||||
|
||||
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include "async.h"
|
||||
#include "function.h"
|
||||
#include "thread.h"
|
||||
#include "time.h"
|
||||
|
||||
struct sockaddr;
|
||||
|
||||
namespace kj {
|
||||
|
||||
#if _WIN32
|
||||
class Win32EventPort;
|
||||
#else
|
||||
class UnixEventPort;
|
||||
#endif
|
||||
|
||||
class NetworkAddress;
|
||||
class AsyncOutputStream;
|
||||
|
||||
// =======================================================================================
|
||||
// Streaming I/O
|
||||
|
||||
class AsyncInputStream {
|
||||
// Asynchronous equivalent of InputStream (from io.h).
|
||||
|
||||
public:
|
||||
virtual Promise<size_t> read(void* buffer, size_t minBytes, size_t maxBytes);
|
||||
virtual Promise<size_t> tryRead(void* buffer, size_t minBytes, size_t maxBytes) = 0;
|
||||
|
||||
Promise<void> read(void* buffer, size_t bytes);
|
||||
|
||||
virtual Maybe<uint64_t> tryGetLength();
|
||||
// Get the remaining number of bytes that will be produced by this stream, if known.
|
||||
//
|
||||
// This is used e.g. to fill in the Content-Length header of an HTTP message. If unknown, the
|
||||
// HTTP implementation may need to fall back to Transfer-Encoding: chunked.
|
||||
//
|
||||
// The default implementation always returns null.
|
||||
|
||||
virtual Promise<uint64_t> pumpTo(
|
||||
AsyncOutputStream& output, uint64_t amount = kj::maxValue);
|
||||
// Read `amount` bytes from this stream (or to EOF) and write them to `output`, returning the
|
||||
// total bytes actually pumped (which is only less than `amount` if EOF was reached).
|
||||
//
|
||||
// Override this if your stream type knows how to pump itself to certain kinds of output
|
||||
// streams more efficiently than via the naive approach. You can use
|
||||
// kj::dynamicDowncastIfAvailable() to test for stream types you recognize, and if none match,
|
||||
// delegate to the default implementation.
|
||||
//
|
||||
// The default implementation first tries calling output.tryPumpFrom(), but if that fails, it
|
||||
// performs a naive pump by allocating a buffer and reading to it / writing from it in a loop.
|
||||
|
||||
Promise<Array<byte>> readAllBytes();
|
||||
Promise<String> readAllText();
|
||||
// Read until EOF and return as one big byte array or string.
|
||||
};
|
||||
|
||||
class AsyncOutputStream {
|
||||
// Asynchronous equivalent of OutputStream (from io.h).
|
||||
|
||||
public:
|
||||
virtual Promise<void> write(const void* buffer, size_t size) KJ_WARN_UNUSED_RESULT = 0;
|
||||
virtual Promise<void> write(ArrayPtr<const ArrayPtr<const byte>> pieces)
|
||||
KJ_WARN_UNUSED_RESULT = 0;
|
||||
|
||||
virtual Maybe<Promise<uint64_t>> tryPumpFrom(
|
||||
AsyncInputStream& input, uint64_t amount = kj::maxValue);
|
||||
// Implements double-dispatch for AsyncInputStream::pumpTo().
|
||||
//
|
||||
// This method should only be called from within an implementation of pumpTo().
|
||||
//
|
||||
// This method examines the type of `input` to find optimized ways to pump data from it to this
|
||||
// output stream. If it finds one, it performs the pump. Otherwise, it returns null.
|
||||
//
|
||||
// The default implementation always returns null.
|
||||
};
|
||||
|
||||
class AsyncIoStream: public AsyncInputStream, public AsyncOutputStream {
|
||||
// A combination input and output stream.
|
||||
|
||||
public:
|
||||
virtual void shutdownWrite() = 0;
|
||||
// Cleanly shut down just the write end of the stream, while keeping the read end open.
|
||||
|
||||
virtual void abortRead() {}
|
||||
// Similar to shutdownWrite, but this will shut down the read end of the stream, and should only
|
||||
// be called when an error has occurred.
|
||||
|
||||
virtual void getsockopt(int level, int option, void* value, uint* length);
|
||||
virtual void setsockopt(int level, int option, const void* value, uint length);
|
||||
// Corresponds to getsockopt() and setsockopt() syscalls. Will throw an "unimplemented" exception
|
||||
// if the stream is not a socket or the option is not appropriate for the socket type. The
|
||||
// default implementations always throw "unimplemented".
|
||||
|
||||
virtual void getsockname(struct sockaddr* addr, uint* length);
|
||||
virtual void getpeername(struct sockaddr* addr, uint* length);
|
||||
// Corresponds to getsockname() and getpeername() syscalls. Will throw an "unimplemented"
|
||||
// exception if the stream is not a socket. The default implementations always throw
|
||||
// "unimplemented".
|
||||
//
|
||||
// Note that we don't provide methods that return NetworkAddress because it usually wouldn't
|
||||
// be useful. You can't connect() to or listen() on these addresses, obviously, because they are
|
||||
// ephemeral addresses for a single connection.
|
||||
};
|
||||
|
||||
struct OneWayPipe {
|
||||
// A data pipe with an input end and an output end. (Typically backed by pipe() system call.)
|
||||
|
||||
Own<AsyncInputStream> in;
|
||||
Own<AsyncOutputStream> out;
|
||||
};
|
||||
|
||||
struct TwoWayPipe {
|
||||
// A data pipe that supports sending in both directions. Each end's output sends data to the
|
||||
// other end's input. (Typically backed by socketpair() system call.)
|
||||
|
||||
Own<AsyncIoStream> ends[2];
|
||||
};
|
||||
|
||||
class ConnectionReceiver {
|
||||
// Represents a server socket listening on a port.
|
||||
|
||||
public:
|
||||
virtual Promise<Own<AsyncIoStream>> accept() = 0;
|
||||
// Accept the next incoming connection.
|
||||
|
||||
virtual uint getPort() = 0;
|
||||
// Gets the port number, if applicable (i.e. if listening on IP). This is useful if you didn't
|
||||
// specify a port when constructing the NetworkAddress -- one will have been assigned
|
||||
// automatically.
|
||||
|
||||
virtual void getsockopt(int level, int option, void* value, uint* length);
|
||||
virtual void setsockopt(int level, int option, const void* value, uint length);
|
||||
// Same as the methods of AsyncIoStream.
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
// Datagram I/O
|
||||
|
||||
class AncillaryMessage {
|
||||
// Represents an ancillary message (aka control message) received using the recvmsg() system
|
||||
// call (or equivalent). Most apps will not use this.
|
||||
|
||||
public:
|
||||
inline AncillaryMessage(int level, int type, ArrayPtr<const byte> data);
|
||||
AncillaryMessage() = default;
|
||||
|
||||
inline int getLevel() const;
|
||||
// Originating protocol / socket level.
|
||||
|
||||
inline int getType() const;
|
||||
// Protocol-specific message type.
|
||||
|
||||
template <typename T>
|
||||
inline Maybe<const T&> as();
|
||||
// Interpret the ancillary message as the given struct type. Most ancillary messages are some
|
||||
// sort of struct, so this is a convenient way to access it. Returns nullptr if the message
|
||||
// is smaller than the struct -- this can happen if the message was truncated due to
|
||||
// insufficient ancillary buffer space.
|
||||
|
||||
template <typename T>
|
||||
inline ArrayPtr<const T> asArray();
|
||||
// Interpret the ancillary message as an array of items. If the message size does not evenly
|
||||
// divide into elements of type T, the remainder is discarded -- this can happen if the message
|
||||
// was truncated due to insufficient ancillary buffer space.
|
||||
|
||||
private:
|
||||
int level;
|
||||
int type;
|
||||
ArrayPtr<const byte> data;
|
||||
// Message data. In most cases you should use `as()` or `asArray()`.
|
||||
};
|
||||
|
||||
class DatagramReceiver {
|
||||
// Class encapsulating the recvmsg() system call. You must specify the DatagramReceiver's
|
||||
// capacity in advance; if a received packet is larger than the capacity, it will be truncated.
|
||||
|
||||
public:
|
||||
virtual Promise<void> receive() = 0;
|
||||
// Receive a new message, overwriting this object's content.
|
||||
//
|
||||
// receive() may reuse the same buffers for content and ancillary data with each call.
|
||||
|
||||
template <typename T>
|
||||
struct MaybeTruncated {
|
||||
T value;
|
||||
|
||||
bool isTruncated;
|
||||
// True if the Receiver's capacity was insufficient to receive the value and therefore the
|
||||
// value is truncated.
|
||||
};
|
||||
|
||||
virtual MaybeTruncated<ArrayPtr<const byte>> getContent() = 0;
|
||||
// Get the content of the datagram.
|
||||
|
||||
virtual MaybeTruncated<ArrayPtr<const AncillaryMessage>> getAncillary() = 0;
|
||||
// Ancilarry messages received with the datagram. See the recvmsg() system call and the cmsghdr
|
||||
// struct. Most apps don't need this.
|
||||
//
|
||||
// If the returned value is truncated, then the last message in the array may itself be
|
||||
// truncated, meaning its as<T>() method will return nullptr or its asArray<T>() method will
|
||||
// return fewer elements than expected. Truncation can also mean that additional messages were
|
||||
// available but discarded.
|
||||
|
||||
virtual NetworkAddress& getSource() = 0;
|
||||
// Get the datagram sender's address.
|
||||
|
||||
struct Capacity {
|
||||
size_t content = 8192;
|
||||
// How much space to allocate for the datagram content. If a datagram is received that is
|
||||
// larger than this, it will be truncated, with no way to recover the tail.
|
||||
|
||||
size_t ancillary = 0;
|
||||
// How much space to allocate for ancillary messages. As with content, if the ancillary data
|
||||
// is larger than this, it will be truncated.
|
||||
};
|
||||
};
|
||||
|
||||
class DatagramPort {
|
||||
public:
|
||||
virtual Promise<size_t> send(const void* buffer, size_t size, NetworkAddress& destination) = 0;
|
||||
virtual Promise<size_t> send(ArrayPtr<const ArrayPtr<const byte>> pieces,
|
||||
NetworkAddress& destination) = 0;
|
||||
|
||||
virtual Own<DatagramReceiver> makeReceiver(
|
||||
DatagramReceiver::Capacity capacity = DatagramReceiver::Capacity()) = 0;
|
||||
// Create a new `Receiver` that can be used to receive datagrams. `capacity` specifies how much
|
||||
// space to allocate for the received message. The `DatagramPort` must outlive the `Receiver`.
|
||||
|
||||
virtual uint getPort() = 0;
|
||||
// Gets the port number, if applicable (i.e. if listening on IP). This is useful if you didn't
|
||||
// specify a port when constructing the NetworkAddress -- one will have been assigned
|
||||
// automatically.
|
||||
|
||||
virtual void getsockopt(int level, int option, void* value, uint* length);
|
||||
virtual void setsockopt(int level, int option, const void* value, uint length);
|
||||
// Same as the methods of AsyncIoStream.
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
// Networks
|
||||
|
||||
class NetworkAddress {
|
||||
// Represents a remote address to which the application can connect.
|
||||
|
||||
public:
|
||||
virtual Promise<Own<AsyncIoStream>> connect() = 0;
|
||||
// Make a new connection to this address.
|
||||
//
|
||||
// The address must not be a wildcard ("*"). If it is an IP address, it must have a port number.
|
||||
|
||||
virtual Own<ConnectionReceiver> listen() = 0;
|
||||
// Listen for incoming connections on this address.
|
||||
//
|
||||
// The address must be local.
|
||||
|
||||
virtual Own<DatagramPort> bindDatagramPort();
|
||||
// Open this address as a datagram (e.g. UDP) port.
|
||||
//
|
||||
// The address must be local.
|
||||
|
||||
virtual Own<NetworkAddress> clone() = 0;
|
||||
// Returns an equivalent copy of this NetworkAddress.
|
||||
|
||||
virtual String toString() = 0;
|
||||
// Produce a human-readable string which hopefully can be passed to Network::parseAddress()
|
||||
// to reproduce this address, although whether or not that works of course depends on the Network
|
||||
// implementation. This should be called only to display the address to human users, who will
|
||||
// hopefully know what they are able to do with it.
|
||||
};
|
||||
|
||||
class Network {
|
||||
// Factory for NetworkAddress instances, representing the network services offered by the
|
||||
// operating system.
|
||||
//
|
||||
// This interface typically represents broad authority, and well-designed code should limit its
|
||||
// use to high-level startup code and user interaction. Low-level APIs should accept
|
||||
// NetworkAddress instances directly and work from there, if at all possible.
|
||||
|
||||
public:
|
||||
virtual Promise<Own<NetworkAddress>> parseAddress(StringPtr addr, uint portHint = 0) = 0;
|
||||
// Construct a network address from a user-provided string. The format of the address
|
||||
// strings is not specified at the API level, and application code should make no assumptions
|
||||
// about them. These strings should always be provided by humans, and said humans will know
|
||||
// what format to use in their particular context.
|
||||
//
|
||||
// `portHint`, if provided, specifies the "standard" IP port number for the application-level
|
||||
// service in play. If the address turns out to be an IP address (v4 or v6), and it lacks a
|
||||
// port number, this port will be used. If `addr` lacks a port number *and* `portHint` is
|
||||
// omitted, then the returned address will only support listen() and bindDatagramPort()
|
||||
// (not connect()), and an unused port will be chosen each time one of those methods is called.
|
||||
|
||||
virtual Own<NetworkAddress> getSockaddr(const void* sockaddr, uint len) = 0;
|
||||
// Construct a network address from a legacy struct sockaddr.
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
// I/O Provider
|
||||
|
||||
class AsyncIoProvider {
|
||||
// Class which constructs asynchronous wrappers around the operating system's I/O facilities.
|
||||
//
|
||||
// Generally, the implementation of this interface must integrate closely with a particular
|
||||
// `EventLoop` implementation. Typically, the EventLoop implementation itself will provide
|
||||
// an AsyncIoProvider.
|
||||
|
||||
public:
|
||||
virtual OneWayPipe newOneWayPipe() = 0;
|
||||
// Creates an input/output stream pair representing the ends of a one-way pipe (e.g. created with
|
||||
// the pipe(2) system call).
|
||||
|
||||
virtual TwoWayPipe newTwoWayPipe() = 0;
|
||||
// Creates two AsyncIoStreams representing the two ends of a two-way pipe (e.g. created with
|
||||
// socketpair(2) system call). Data written to one end can be read from the other.
|
||||
|
||||
virtual Network& getNetwork() = 0;
|
||||
// Creates a new `Network` instance representing the networks exposed by the operating system.
|
||||
//
|
||||
// DO NOT CALL THIS except at the highest levels of your code, ideally in the main() function. If
|
||||
// you call this from low-level code, then you are preventing higher-level code from injecting an
|
||||
// alternative implementation. Instead, if your code needs to use network functionality, it
|
||||
// should ask for a `Network` as a constructor or method parameter, so that higher-level code can
|
||||
// chose what implementation to use. The system network is essentially a singleton. See:
|
||||
// http://www.object-oriented-security.org/lets-argue/singletons
|
||||
//
|
||||
// Code that uses the system network should not make any assumptions about what kinds of
|
||||
// addresses it will parse, as this could differ across platforms. String addresses should come
|
||||
// strictly from the user, who will know how to write them correctly for their system.
|
||||
//
|
||||
// With that said, KJ currently supports the following string address formats:
|
||||
// - IPv4: "1.2.3.4", "1.2.3.4:80"
|
||||
// - IPv6: "1234:5678::abcd", "[1234:5678::abcd]:80"
|
||||
// - Local IP wildcard (covers both v4 and v6): "*", "*:80"
|
||||
// - Symbolic names: "example.com", "example.com:80", "example.com:http", "1.2.3.4:http"
|
||||
// - Unix domain: "unix:/path/to/socket"
|
||||
|
||||
struct PipeThread {
|
||||
// A combination of a thread and a two-way pipe that communicates with that thread.
|
||||
//
|
||||
// The fields are intentionally ordered so that the pipe will be destroyed (and therefore
|
||||
// disconnected) before the thread is destroyed (and therefore joined). Thus if the thread
|
||||
// arranges to exit when it detects disconnect, destruction should be clean.
|
||||
|
||||
Own<Thread> thread;
|
||||
Own<AsyncIoStream> pipe;
|
||||
};
|
||||
|
||||
virtual PipeThread newPipeThread(
|
||||
Function<void(AsyncIoProvider&, AsyncIoStream&, WaitScope&)> startFunc) = 0;
|
||||
// Create a new thread and set up a two-way pipe (socketpair) which can be used to communicate
|
||||
// with it. One end of the pipe is passed to the thread's start function and the other end of
|
||||
// the pipe is returned. The new thread also gets its own `AsyncIoProvider` instance and will
|
||||
// already have an active `EventLoop` when `startFunc` is called.
|
||||
//
|
||||
// TODO(someday): I'm not entirely comfortable with this interface. It seems to be doing too
|
||||
// much at once but I'm not sure how to cleanly break it down.
|
||||
|
||||
virtual Timer& getTimer() = 0;
|
||||
// Returns a `Timer` based on real time. Time does not pass while event handlers are running --
|
||||
// it only updates when the event loop polls for system events. This means that calling `now()`
|
||||
// on this timer does not require a system call.
|
||||
//
|
||||
// This timer is not affected by changes to the system date. It is unspecified whether the timer
|
||||
// continues to count while the system is suspended.
|
||||
};
|
||||
|
||||
class LowLevelAsyncIoProvider {
|
||||
// Similar to `AsyncIoProvider`, but represents a lower-level interface that may differ on
|
||||
// different operating systems. You should prefer to use `AsyncIoProvider` over this interface
|
||||
// whenever possible, as `AsyncIoProvider` is portable and friendlier to dependency-injection.
|
||||
//
|
||||
// On Unix, this interface can be used to import native file descriptors into the async framework.
|
||||
// Different implementations of this interface might work on top of different event handling
|
||||
// primitives, such as poll vs. epoll vs. kqueue vs. some higher-level event library.
|
||||
//
|
||||
// On Windows, this interface can be used to import native HANDLEs into the async framework.
|
||||
// Different implementations of this interface might work on top of different event handling
|
||||
// primitives, such as I/O completion ports vs. completion routines.
|
||||
//
|
||||
// TODO(port): Actually implement Windows support.
|
||||
|
||||
public:
|
||||
// ---------------------------------------------------------------------------
|
||||
// Unix-specific stuff
|
||||
|
||||
enum Flags {
|
||||
// Flags controlling how to wrap a file descriptor.
|
||||
|
||||
TAKE_OWNERSHIP = 1 << 0,
|
||||
// The returned object should own the file descriptor, automatically closing it when destroyed.
|
||||
// The close-on-exec flag will be set on the descriptor if it is not already.
|
||||
//
|
||||
// If this flag is not used, then the file descriptor is not automatically closed and the
|
||||
// close-on-exec flag is not modified.
|
||||
|
||||
#if !_WIN32
|
||||
ALREADY_CLOEXEC = 1 << 1,
|
||||
// Indicates that the close-on-exec flag is known already to be set, so need not be set again.
|
||||
// Only relevant when combined with TAKE_OWNERSHIP.
|
||||
//
|
||||
// On Linux, all system calls which yield new file descriptors have flags or variants which
|
||||
// set the close-on-exec flag immediately. Unfortunately, other OS's do not.
|
||||
|
||||
ALREADY_NONBLOCK = 1 << 2
|
||||
// Indicates that the file descriptor is known already to be in non-blocking mode, so the flag
|
||||
// need not be set again. Otherwise, all wrap*Fd() methods will enable non-blocking mode
|
||||
// automatically.
|
||||
//
|
||||
// On Linux, all system calls which yield new file descriptors have flags or variants which
|
||||
// enable non-blocking mode immediately. Unfortunately, other OS's do not.
|
||||
#endif
|
||||
};
|
||||
|
||||
#if _WIN32
|
||||
typedef uintptr_t Fd;
|
||||
// On Windows, the `fd` parameter to each of these methods must be a SOCKET, and must have the
|
||||
// flag WSA_FLAG_OVERLAPPED (which socket() uses by default, but WSASocket() wants you to specify
|
||||
// explicitly).
|
||||
#else
|
||||
typedef int Fd;
|
||||
// On Unix, any arbitrary file descriptor is supported.
|
||||
#endif
|
||||
|
||||
virtual Own<AsyncInputStream> wrapInputFd(Fd fd, uint flags = 0) = 0;
|
||||
// Create an AsyncInputStream wrapping a file descriptor.
|
||||
//
|
||||
// `flags` is a bitwise-OR of the values of the `Flags` enum.
|
||||
|
||||
virtual Own<AsyncOutputStream> wrapOutputFd(Fd fd, uint flags = 0) = 0;
|
||||
// Create an AsyncOutputStream wrapping a file descriptor.
|
||||
//
|
||||
// `flags` is a bitwise-OR of the values of the `Flags` enum.
|
||||
|
||||
virtual Own<AsyncIoStream> wrapSocketFd(Fd fd, uint flags = 0) = 0;
|
||||
// Create an AsyncIoStream wrapping a socket file descriptor.
|
||||
//
|
||||
// `flags` is a bitwise-OR of the values of the `Flags` enum.
|
||||
|
||||
virtual Promise<Own<AsyncIoStream>> wrapConnectingSocketFd(
|
||||
Fd fd, const struct sockaddr* addr, uint addrlen, uint flags = 0) = 0;
|
||||
// Create an AsyncIoStream wrapping a socket and initiate a connection to the given address.
|
||||
// The returned promise does not resolve until connection has completed.
|
||||
//
|
||||
// `flags` is a bitwise-OR of the values of the `Flags` enum.
|
||||
|
||||
virtual Own<ConnectionReceiver> wrapListenSocketFd(Fd fd, uint flags = 0) = 0;
|
||||
// Create an AsyncIoStream wrapping a listen socket file descriptor. This socket should already
|
||||
// have had `bind()` and `listen()` called on it, so it's ready for `accept()`.
|
||||
//
|
||||
// `flags` is a bitwise-OR of the values of the `Flags` enum.
|
||||
|
||||
virtual Own<DatagramPort> wrapDatagramSocketFd(Fd fd, uint flags = 0);
|
||||
|
||||
virtual Timer& getTimer() = 0;
|
||||
// Returns a `Timer` based on real time. Time does not pass while event handlers are running --
|
||||
// it only updates when the event loop polls for system events. This means that calling `now()`
|
||||
// on this timer does not require a system call.
|
||||
//
|
||||
// This timer is not affected by changes to the system date. It is unspecified whether the timer
|
||||
// continues to count while the system is suspended.
|
||||
};
|
||||
|
||||
Own<AsyncIoProvider> newAsyncIoProvider(LowLevelAsyncIoProvider& lowLevel);
|
||||
// Make a new AsyncIoProvider wrapping a `LowLevelAsyncIoProvider`.
|
||||
|
||||
struct AsyncIoContext {
|
||||
Own<LowLevelAsyncIoProvider> lowLevelProvider;
|
||||
Own<AsyncIoProvider> provider;
|
||||
WaitScope& waitScope;
|
||||
|
||||
#if _WIN32
|
||||
Win32EventPort& win32EventPort;
|
||||
#else
|
||||
UnixEventPort& unixEventPort;
|
||||
// TEMPORARY: Direct access to underlying UnixEventPort, mainly for waiting on signals. This
|
||||
// field will go away at some point when we have a chance to improve these interfaces.
|
||||
#endif
|
||||
};
|
||||
|
||||
AsyncIoContext setupAsyncIo();
|
||||
// Convenience method which sets up the current thread with everything it needs to do async I/O.
|
||||
// The returned objects contain an `EventLoop` which is wrapping an appropriate `EventPort` for
|
||||
// doing I/O on the host system, so everything is ready for the thread to start making async calls
|
||||
// and waiting on promises.
|
||||
//
|
||||
// You would typically call this in your main() loop or in the start function of a thread.
|
||||
// Example:
|
||||
//
|
||||
// int main() {
|
||||
// auto ioContext = kj::setupAsyncIo();
|
||||
//
|
||||
// // Now we can call an async function.
|
||||
// Promise<String> textPromise = getHttp(*ioContext.provider, "http://example.com");
|
||||
//
|
||||
// // And we can wait for the promise to complete. Note that you can only use `wait()`
|
||||
// // from the top level, not from inside a promise callback.
|
||||
// String text = textPromise.wait(ioContext.waitScope);
|
||||
// print(text);
|
||||
// return 0;
|
||||
// }
|
||||
//
|
||||
// WARNING: An AsyncIoContext can only be used in the thread and process that created it. In
|
||||
// particular, note that after a fork(), an AsyncIoContext created in the parent process will
|
||||
// not work correctly in the child, even if the parent ceases to use its copy. In particular
|
||||
// note that this means that server processes which daemonize themselves at startup must wait
|
||||
// until after daemonization to create an AsyncIoContext.
|
||||
|
||||
// =======================================================================================
|
||||
// inline implementation details
|
||||
|
||||
inline AncillaryMessage::AncillaryMessage(
|
||||
int level, int type, ArrayPtr<const byte> data)
|
||||
: level(level), type(type), data(data) {}
|
||||
|
||||
inline int AncillaryMessage::getLevel() const { return level; }
|
||||
inline int AncillaryMessage::getType() const { return type; }
|
||||
|
||||
template <typename T>
|
||||
inline Maybe<const T&> AncillaryMessage::as() {
|
||||
if (data.size() >= sizeof(T)) {
|
||||
return *reinterpret_cast<const T*>(data.begin());
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline ArrayPtr<const T> AncillaryMessage::asArray() {
|
||||
return arrayPtr(reinterpret_cast<const T*>(data.begin()), data.size() / sizeof(T));
|
||||
}
|
||||
|
||||
} // namespace kj
|
||||
|
||||
#endif // KJ_ASYNC_IO_H_
|
||||
@@ -0,0 +1,218 @@
|
||||
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// This file contains a bunch of internal declarations that must appear before async.h can start.
|
||||
// We don't define these directly in async.h because it makes the file hard to read.
|
||||
|
||||
#ifndef KJ_ASYNC_PRELUDE_H_
|
||||
#define KJ_ASYNC_PRELUDE_H_
|
||||
|
||||
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include "exception.h"
|
||||
#include "tuple.h"
|
||||
|
||||
namespace kj {
|
||||
|
||||
class EventLoop;
|
||||
template <typename T>
|
||||
class Promise;
|
||||
class WaitScope;
|
||||
|
||||
template <typename T>
|
||||
Promise<Array<T>> joinPromises(Array<Promise<T>>&& promises);
|
||||
Promise<void> joinPromises(Array<Promise<void>>&& promises);
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
template <typename T> struct JoinPromises_ { typedef T Type; };
|
||||
template <typename T> struct JoinPromises_<Promise<T>> { typedef T Type; };
|
||||
|
||||
template <typename T>
|
||||
using JoinPromises = typename JoinPromises_<T>::Type;
|
||||
// If T is Promise<U>, resolves to U, otherwise resolves to T.
|
||||
//
|
||||
// TODO(cleanup): Rename to avoid confusion with joinPromises() call which is completely
|
||||
// unrelated.
|
||||
|
||||
class PropagateException {
|
||||
// A functor which accepts a kj::Exception as a parameter and returns a broken promise of
|
||||
// arbitrary type which simply propagates the exception.
|
||||
public:
|
||||
class Bottom {
|
||||
public:
|
||||
Bottom(Exception&& exception): exception(kj::mv(exception)) {}
|
||||
|
||||
Exception asException() { return kj::mv(exception); }
|
||||
|
||||
private:
|
||||
Exception exception;
|
||||
};
|
||||
|
||||
Bottom operator()(Exception&& e) {
|
||||
return Bottom(kj::mv(e));
|
||||
}
|
||||
Bottom operator()(const Exception& e) {
|
||||
return Bottom(kj::cp(e));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Func, typename T>
|
||||
struct ReturnType_ { typedef decltype(instance<Func>()(instance<T>())) Type; };
|
||||
template <typename Func>
|
||||
struct ReturnType_<Func, void> { typedef decltype(instance<Func>()()) Type; };
|
||||
|
||||
template <typename Func, typename T>
|
||||
using ReturnType = typename ReturnType_<Func, T>::Type;
|
||||
// The return type of functor Func given a parameter of type T, with the special exception that if
|
||||
// T is void, this is the return type of Func called with no arguments.
|
||||
|
||||
template <typename T> struct SplitTuplePromise_ { typedef Promise<T> Type; };
|
||||
template <typename... T>
|
||||
struct SplitTuplePromise_<kj::_::Tuple<T...>> {
|
||||
typedef kj::Tuple<Promise<JoinPromises<T>>...> Type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using SplitTuplePromise = typename SplitTuplePromise_<T>::Type;
|
||||
// T -> Promise<T>
|
||||
// Tuple<T> -> Tuple<Promise<T>>
|
||||
|
||||
struct Void {};
|
||||
// Application code should NOT refer to this! See `kj::READY_NOW` instead.
|
||||
|
||||
template <typename T> struct FixVoid_ { typedef T Type; };
|
||||
template <> struct FixVoid_<void> { typedef Void Type; };
|
||||
template <typename T> using FixVoid = typename FixVoid_<T>::Type;
|
||||
// FixVoid<T> is just T unless T is void in which case it is _::Void (an empty struct).
|
||||
|
||||
template <typename T> struct UnfixVoid_ { typedef T Type; };
|
||||
template <> struct UnfixVoid_<Void> { typedef void Type; };
|
||||
template <typename T> using UnfixVoid = typename UnfixVoid_<T>::Type;
|
||||
// UnfixVoid is the opposite of FixVoid.
|
||||
|
||||
template <typename In, typename Out>
|
||||
struct MaybeVoidCaller {
|
||||
// Calls the function converting a Void input to an empty parameter list and a void return
|
||||
// value to a Void output.
|
||||
|
||||
template <typename Func>
|
||||
static inline Out apply(Func& func, In&& in) {
|
||||
return func(kj::mv(in));
|
||||
}
|
||||
};
|
||||
template <typename In, typename Out>
|
||||
struct MaybeVoidCaller<In&, Out> {
|
||||
template <typename Func>
|
||||
static inline Out apply(Func& func, In& in) {
|
||||
return func(in);
|
||||
}
|
||||
};
|
||||
template <typename Out>
|
||||
struct MaybeVoidCaller<Void, Out> {
|
||||
template <typename Func>
|
||||
static inline Out apply(Func& func, Void&& in) {
|
||||
return func();
|
||||
}
|
||||
};
|
||||
template <typename In>
|
||||
struct MaybeVoidCaller<In, Void> {
|
||||
template <typename Func>
|
||||
static inline Void apply(Func& func, In&& in) {
|
||||
func(kj::mv(in));
|
||||
return Void();
|
||||
}
|
||||
};
|
||||
template <typename In>
|
||||
struct MaybeVoidCaller<In&, Void> {
|
||||
template <typename Func>
|
||||
static inline Void apply(Func& func, In& in) {
|
||||
func(in);
|
||||
return Void();
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct MaybeVoidCaller<Void, Void> {
|
||||
template <typename Func>
|
||||
static inline Void apply(Func& func, Void&& in) {
|
||||
func();
|
||||
return Void();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline T&& returnMaybeVoid(T&& t) {
|
||||
return kj::fwd<T>(t);
|
||||
}
|
||||
inline void returnMaybeVoid(Void&& v) {}
|
||||
|
||||
class ExceptionOrValue;
|
||||
class PromiseNode;
|
||||
class ChainPromiseNode;
|
||||
template <typename T>
|
||||
class ForkHub;
|
||||
|
||||
class TaskSetImpl;
|
||||
|
||||
class Event;
|
||||
|
||||
class PromiseBase {
|
||||
public:
|
||||
kj::String trace();
|
||||
// Dump debug info about this promise.
|
||||
|
||||
private:
|
||||
Own<PromiseNode> node;
|
||||
|
||||
PromiseBase() = default;
|
||||
PromiseBase(Own<PromiseNode>&& node): node(kj::mv(node)) {}
|
||||
|
||||
friend class kj::EventLoop;
|
||||
friend class ChainPromiseNode;
|
||||
template <typename>
|
||||
friend class kj::Promise;
|
||||
friend class TaskSetImpl;
|
||||
template <typename U>
|
||||
friend Promise<Array<U>> kj::joinPromises(Array<Promise<U>>&& promises);
|
||||
friend Promise<void> kj::joinPromises(Array<Promise<void>>&& promises);
|
||||
};
|
||||
|
||||
void detach(kj::Promise<void>&& promise);
|
||||
void waitImpl(Own<_::PromiseNode>&& node, _::ExceptionOrValue& result, WaitScope& waitScope);
|
||||
Promise<void> yield();
|
||||
Own<PromiseNode> neverDone();
|
||||
|
||||
class NeverDone {
|
||||
public:
|
||||
template <typename T>
|
||||
operator Promise<T>() const {
|
||||
return Promise<T>(false, neverDone());
|
||||
}
|
||||
|
||||
KJ_NORETURN(void wait(WaitScope& waitScope) const);
|
||||
};
|
||||
|
||||
} // namespace _ (private)
|
||||
} // namespace kj
|
||||
|
||||
#endif // KJ_ASYNC_PRELUDE_H_
|
||||
@@ -0,0 +1,274 @@
|
||||
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef KJ_ASYNC_UNIX_H_
|
||||
#define KJ_ASYNC_UNIX_H_
|
||||
|
||||
#if _WIN32
|
||||
#error "This file is Unix-specific. On Windows, include async-win32.h instead."
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include "async.h"
|
||||
#include "time.h"
|
||||
#include "vector.h"
|
||||
#include "io.h"
|
||||
#include <signal.h>
|
||||
|
||||
#if __linux__ && !__BIONIC__ && !defined(KJ_USE_EPOLL)
|
||||
// Default to epoll on Linux, except on Bionic (Android) which doesn't have signalfd.h.
|
||||
#define KJ_USE_EPOLL 1
|
||||
#endif
|
||||
|
||||
namespace kj {
|
||||
|
||||
class UnixEventPort: public EventPort {
|
||||
// An EventPort implementation which can wait for events on file descriptors as well as signals.
|
||||
// This API only makes sense on Unix.
|
||||
//
|
||||
// The implementation uses `poll()` or possibly a platform-specific API (e.g. epoll, kqueue).
|
||||
// To also wait on signals without race conditions, the implementation may block signals until
|
||||
// just before `poll()` while using a signal handler which `siglongjmp()`s back to just before
|
||||
// the signal was unblocked, or it may use a nicer platform-specific API like signalfd.
|
||||
//
|
||||
// The implementation reserves a signal for internal use. By default, it uses SIGUSR1. If you
|
||||
// need to use SIGUSR1 for something else, you must offer a different signal by calling
|
||||
// setReservedSignal() at startup.
|
||||
//
|
||||
// WARNING: A UnixEventPort can only be used in the thread and process that created it. In
|
||||
// particular, note that after a fork(), a UnixEventPort created in the parent process will
|
||||
// not work correctly in the child, even if the parent ceases to use its copy. In particular
|
||||
// note that this means that server processes which daemonize themselves at startup must wait
|
||||
// until after daemonization to create a UnixEventPort.
|
||||
|
||||
public:
|
||||
UnixEventPort();
|
||||
~UnixEventPort() noexcept(false);
|
||||
|
||||
class FdObserver;
|
||||
// Class that watches an fd for readability or writability. See definition below.
|
||||
|
||||
Promise<siginfo_t> onSignal(int signum);
|
||||
// When the given signal is delivered to this thread, return the corresponding siginfo_t.
|
||||
// The signal must have been captured using `captureSignal()`.
|
||||
//
|
||||
// If `onSignal()` has not been called, the signal will remain blocked in this thread.
|
||||
// Therefore, a signal which arrives before `onSignal()` was called will not be "missed" -- the
|
||||
// next call to 'onSignal()' will receive it. Also, you can control which thread receives a
|
||||
// process-wide signal by only calling `onSignal()` on that thread's event loop.
|
||||
//
|
||||
// The result of waiting on the same signal twice at once is undefined.
|
||||
|
||||
static void captureSignal(int signum);
|
||||
// Arranges for the given signal to be captured and handled via UnixEventPort, so that you may
|
||||
// then pass it to `onSignal()`. This method is static because it registers a signal handler
|
||||
// which applies process-wide. If any other threads exist in the process when `captureSignal()`
|
||||
// is called, you *must* set the signal mask in those threads to block this signal, otherwise
|
||||
// terrible things will happen if the signal happens to be delivered to those threads. If at
|
||||
// all possible, call `captureSignal()` *before* creating threads, so that threads you create in
|
||||
// the future will inherit the proper signal mask.
|
||||
//
|
||||
// To un-capture a signal, simply install a different signal handler and then un-block it from
|
||||
// the signal mask.
|
||||
|
||||
static void setReservedSignal(int signum);
|
||||
// Sets the signal number which `UnixEventPort` reserves for internal use. If your application
|
||||
// needs to use SIGUSR1, call this at startup (before any calls to `captureSignal()` and before
|
||||
// constructing an `UnixEventPort`) to offer a different signal.
|
||||
|
||||
Timer& getTimer() { return timerImpl; }
|
||||
|
||||
// implements EventPort ------------------------------------------------------
|
||||
bool wait() override;
|
||||
bool poll() override;
|
||||
void wake() const override;
|
||||
|
||||
private:
|
||||
struct TimerSet; // Defined in source file to avoid STL include.
|
||||
class TimerPromiseAdapter;
|
||||
class SignalPromiseAdapter;
|
||||
|
||||
TimerImpl timerImpl;
|
||||
|
||||
SignalPromiseAdapter* signalHead = nullptr;
|
||||
SignalPromiseAdapter** signalTail = &signalHead;
|
||||
|
||||
TimePoint readClock();
|
||||
void gotSignal(const siginfo_t& siginfo);
|
||||
|
||||
friend class TimerPromiseAdapter;
|
||||
|
||||
#if KJ_USE_EPOLL
|
||||
AutoCloseFd epollFd;
|
||||
AutoCloseFd signalFd;
|
||||
AutoCloseFd eventFd; // Used for cross-thread wakeups.
|
||||
|
||||
sigset_t signalFdSigset;
|
||||
// Signal mask as currently set on the signalFd. Tracked so we can detect whether or not it
|
||||
// needs updating.
|
||||
|
||||
bool doEpollWait(int timeout);
|
||||
|
||||
#else
|
||||
class PollContext;
|
||||
|
||||
FdObserver* observersHead = nullptr;
|
||||
FdObserver** observersTail = &observersHead;
|
||||
|
||||
unsigned long long threadId; // actually pthread_t
|
||||
#endif
|
||||
};
|
||||
|
||||
class UnixEventPort::FdObserver {
|
||||
// Object which watches a file descriptor to determine when it is readable or writable.
|
||||
//
|
||||
// For listen sockets, "readable" means that there is a connection to accept(). For everything
|
||||
// else, it means that read() (or recv()) will return data.
|
||||
//
|
||||
// The presence of out-of-band data should NOT fire this event. However, the event may
|
||||
// occasionally fire spuriously (when there is actually no data to read), and one thing that can
|
||||
// cause such spurious events is the arrival of OOB data on certain platforms whose event
|
||||
// interfaces fail to distinguish between regular and OOB data (e.g. Mac OSX).
|
||||
//
|
||||
// WARNING: The exact behavior of this class differs across systems, since event interfaces
|
||||
// vary wildly. Be sure to read the documentation carefully and avoid depending on unspecified
|
||||
// behavior. If at all possible, use the higher-level AsyncInputStream interface instead.
|
||||
|
||||
public:
|
||||
enum Flags {
|
||||
OBSERVE_READ = 1,
|
||||
OBSERVE_WRITE = 2,
|
||||
OBSERVE_URGENT = 4,
|
||||
OBSERVE_READ_WRITE = OBSERVE_READ | OBSERVE_WRITE
|
||||
};
|
||||
|
||||
FdObserver(UnixEventPort& eventPort, int fd, uint flags);
|
||||
// Begin watching the given file descriptor for readability. Only one ReadObserver may exist
|
||||
// for a given file descriptor at a time.
|
||||
|
||||
~FdObserver() noexcept(false);
|
||||
|
||||
KJ_DISALLOW_COPY(FdObserver);
|
||||
|
||||
Promise<void> whenBecomesReadable();
|
||||
// Resolves the next time the file descriptor transitions from having no data to read to having
|
||||
// some data to read.
|
||||
//
|
||||
// KJ uses "edge-triggered" event notification whenever possible. As a result, it is an error
|
||||
// to call this method when there is already data in the read buffer which has been there since
|
||||
// prior to the last turn of the event loop or prior to creation FdWatcher. In this case, it is
|
||||
// unspecified whether the promise will ever resolve -- it depends on the underlying event
|
||||
// mechanism being used.
|
||||
//
|
||||
// In order to avoid this problem, make sure that you only call `whenBecomesReadable()`
|
||||
// only at times when you know the buffer is empty. You know this for sure when one of the
|
||||
// following happens:
|
||||
// * read() or recv() fails with EAGAIN or EWOULDBLOCK. (You MUST have non-blocking mode
|
||||
// enabled on the fd!)
|
||||
// * The file descriptor is a regular byte-oriented object (like a socket or pipe),
|
||||
// read() or recv() returns fewer than the number of bytes requested, and `atEndHint()`
|
||||
// returns false. This can only happen if the buffer is empty but EOF is not reached. (Note,
|
||||
// though, that for record-oriented file descriptors like Linux's inotify interface, this
|
||||
// rule does not hold, because it could simply be that the next record did not fit into the
|
||||
// space available.)
|
||||
//
|
||||
// It is an error to call `whenBecomesReadable()` again when the promise returned previously
|
||||
// has not yet resolved. If you do this, the previous promise may throw an exception.
|
||||
|
||||
inline Maybe<bool> atEndHint() { return atEnd; }
|
||||
// Returns true if the event system has indicated that EOF has been received. There may still
|
||||
// be data in the read buffer, but once that is gone, there's nothing left.
|
||||
//
|
||||
// Returns false if the event system has indicated that EOF had NOT been received as of the
|
||||
// last turn of the event loop.
|
||||
//
|
||||
// Returns nullptr if the event system does not know whether EOF has been reached. In this
|
||||
// case, the only way to know for sure is to call read() or recv() and check if it returns
|
||||
// zero.
|
||||
//
|
||||
// This hint may be useful as an optimization to avoid an unnecessary system call.
|
||||
|
||||
Promise<void> whenBecomesWritable();
|
||||
// Resolves the next time the file descriptor transitions from having no space available in the
|
||||
// write buffer to having some space available.
|
||||
//
|
||||
// KJ uses "edge-triggered" event notification whenever possible. As a result, it is an error
|
||||
// to call this method when there is already space in the write buffer which has been there
|
||||
// since prior to the last turn of the event loop or prior to creation FdWatcher. In this case,
|
||||
// it is unspecified whether the promise will ever resolve -- it depends on the underlying
|
||||
// event mechanism being used.
|
||||
//
|
||||
// In order to avoid this problem, make sure that you only call `whenBecomesWritable()`
|
||||
// only at times when you know the buffer is full. You know this for sure when one of the
|
||||
// following happens:
|
||||
// * write() or send() fails with EAGAIN or EWOULDBLOCK. (You MUST have non-blocking mode
|
||||
// enabled on the fd!)
|
||||
// * write() or send() succeeds but accepts fewer than the number of bytes provided. This can
|
||||
// only happen if the buffer is full.
|
||||
//
|
||||
// It is an error to call `whenBecomesWritable()` again when the promise returned previously
|
||||
// has not yet resolved. If you do this, the previous promise may throw an exception.
|
||||
|
||||
Promise<void> whenUrgentDataAvailable();
|
||||
// Resolves the next time the file descriptor's read buffer contains "urgent" data.
|
||||
//
|
||||
// The conditions for availability of urgent data are specific to the file descriptor's
|
||||
// underlying implementation.
|
||||
//
|
||||
// It is an error to call `whenUrgentDataAvailable()` again when the promise returned previously
|
||||
// has not yet resolved. If you do this, the previous promise may throw an exception.
|
||||
//
|
||||
// WARNING: This has some known weird behavior on macOS. See
|
||||
// https://github.com/sandstorm-io/capnproto/issues/374.
|
||||
|
||||
private:
|
||||
UnixEventPort& eventPort;
|
||||
int fd;
|
||||
uint flags;
|
||||
|
||||
kj::Maybe<Own<PromiseFulfiller<void>>> readFulfiller;
|
||||
kj::Maybe<Own<PromiseFulfiller<void>>> writeFulfiller;
|
||||
kj::Maybe<Own<PromiseFulfiller<void>>> urgentFulfiller;
|
||||
// Replaced each time `whenBecomesReadable()` or `whenBecomesWritable()` is called. Reverted to
|
||||
// null every time an event is fired.
|
||||
|
||||
Maybe<bool> atEnd;
|
||||
|
||||
void fire(short events);
|
||||
|
||||
#if !KJ_USE_EPOLL
|
||||
FdObserver* next;
|
||||
FdObserver** prev;
|
||||
// Linked list of observers which currently have a non-null readFulfiller or writeFulfiller.
|
||||
// If `prev` is null then the observer is not currently in the list.
|
||||
|
||||
short getEventMask();
|
||||
#endif
|
||||
|
||||
friend class UnixEventPort;
|
||||
};
|
||||
|
||||
} // namespace kj
|
||||
|
||||
#endif // KJ_ASYNC_UNIX_H_
|
||||
@@ -0,0 +1,234 @@
|
||||
// Copyright (c) 2016 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef KJ_ASYNC_WIN32_H_
|
||||
#define KJ_ASYNC_WIN32_H_
|
||||
|
||||
#if !_WIN32
|
||||
#error "This file is Windows-specific. On Unix, include async-unix.h instead."
|
||||
#endif
|
||||
|
||||
#include "async.h"
|
||||
#include "time.h"
|
||||
#include "io.h"
|
||||
#include <atomic>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Include windows.h as lean as possible. (If you need more of the Windows API for your app,
|
||||
// #include windows.h yourself before including this header.)
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#define NOSERVICE 1
|
||||
#define NOMCX 1
|
||||
#define NOIME 1
|
||||
#include <windows.h>
|
||||
#include "windows-sanity.h"
|
||||
|
||||
namespace kj {
|
||||
|
||||
class Win32EventPort: public EventPort {
|
||||
// Abstract base interface for EventPorts that can listen on Win32 event types. Due to the
|
||||
// absurd complexity of the Win32 API, it's not possible to standardize on a single
|
||||
// implementation of EventPort. In particular, there is no way for a single thread to use I/O
|
||||
// completion ports (the most efficient way of handling I/O) while at the same time waiting for
|
||||
// signalable handles or UI messages.
|
||||
//
|
||||
// Note that UI messages are not supported at all by this interface because the message queue
|
||||
// is implemented by user32.dll and we want libkj to depend only on kernel32.dll. A separate
|
||||
// compat library could provide a Win32EventPort implementation that works with the UI message
|
||||
// queue.
|
||||
|
||||
public:
|
||||
// ---------------------------------------------------------------------------
|
||||
// overlapped I/O
|
||||
|
||||
struct IoResult {
|
||||
DWORD errorCode;
|
||||
DWORD bytesTransferred;
|
||||
};
|
||||
|
||||
class IoOperation {
|
||||
public:
|
||||
virtual LPOVERLAPPED getOverlapped() = 0;
|
||||
// Gets the OVERLAPPED structure to pass to the Win32 I/O call. Do NOT modify it; just pass it
|
||||
// on.
|
||||
|
||||
virtual Promise<IoResult> onComplete() = 0;
|
||||
// After making the Win32 call, if the return value indicates that the operation was
|
||||
// successfully queued (i.e. the completion event will definitely occur), call this to wait
|
||||
// for completion.
|
||||
//
|
||||
// You MUST call this if the operation was successfully queued, and you MUST NOT call this
|
||||
// otherwise. If the Win32 call failed (without queuing any operation or event) then you should
|
||||
// simply drop the IoOperation object.
|
||||
//
|
||||
// Dropping the returned Promise cancels the operation via Win32's CancelIoEx(). The destructor
|
||||
// will wait for the cancellation to complete, such that after dropping the proimse it is safe
|
||||
// to free the buffer that the operation was reading from / writing to.
|
||||
//
|
||||
// You may safely drop the `IoOperation` while still waiting for this promise. You may not,
|
||||
// however, drop the `IoObserver`.
|
||||
};
|
||||
|
||||
class IoObserver {
|
||||
public:
|
||||
virtual Own<IoOperation> newOperation(uint64_t offset) = 0;
|
||||
// Begin an I/O operation. For file operations, `offset` is the offset within the file at
|
||||
// which the operation will start. For stream operations, `offset` is ignored.
|
||||
};
|
||||
|
||||
virtual Own<IoObserver> observeIo(HANDLE handle) = 0;
|
||||
// Given a handle which supports overlapped I/O, arrange to receive I/O completion events via
|
||||
// this EventPort.
|
||||
//
|
||||
// Different Win32EventPort implementations may handle this in different ways, such as by using
|
||||
// completion routines (APCs) or by using I/O completion ports. The caller should not assume
|
||||
// any particular technique.
|
||||
//
|
||||
// WARNING: It is only safe to call observeIo() on a particular handle once during its lifetime.
|
||||
// You cannot observe the same handle from multiple Win32EventPorts, even if not at the same
|
||||
// time. This is because the Win32 API provides no way to disassociate a handle from an I/O
|
||||
// completion port once it is associated.
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// signalable handles
|
||||
//
|
||||
// Warning: Due to limitations in the Win32 API, implementations of EventPort may be forced to
|
||||
// spawn additional threads to wait for signaled objects. This is necessary if the EventPort
|
||||
// implementation is based on I/O completion ports, or if you need to wait on more than 64
|
||||
// handles at once.
|
||||
|
||||
class SignalObserver {
|
||||
public:
|
||||
virtual Promise<void> onSignaled() = 0;
|
||||
// Returns a promise that completes the next time the handle enters the signaled state.
|
||||
//
|
||||
// Depending on the type of handle, the handle may automatically be reset to a non-signaled
|
||||
// state before the promise resolves. The underlying implementaiton uses WaitForSingleObject()
|
||||
// or an equivalent wait call, so check the documentation for that to understand the semantics.
|
||||
//
|
||||
// If the handle is a mutex and it is abandoned without being unlocked, the promise breaks with
|
||||
// an exception.
|
||||
|
||||
virtual Promise<bool> onSignaledOrAbandoned() = 0;
|
||||
// Like onSingaled(), but instead of throwing when a mutex is abandoned, resolves to `true`.
|
||||
// Resolves to `false` for non-abandoned signals.
|
||||
};
|
||||
|
||||
virtual Own<SignalObserver> observeSignalState(HANDLE handle) = 0;
|
||||
// Given a handle that supports waiting for it to become "signaled" via WaitForSingleObject(),
|
||||
// return an object that can wait for this state using the EventPort.
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// APCs
|
||||
|
||||
virtual void allowApc() = 0;
|
||||
// If this is ever called, the Win32EventPort will switch modes so that APCs can be scheduled
|
||||
// on the thread, e.g. through the Win32 QueueUserAPC() call. In the future, this may be enabled
|
||||
// by default. However, as of this writing, Wine does not support the necessary
|
||||
// GetQueuedCompletionStatusEx() call, thus allowApc() breaks Wine support. (Tested on Wine
|
||||
// 1.8.7.)
|
||||
//
|
||||
// If the event port implementation can't support APCs for some reason, this throws.
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// time
|
||||
|
||||
virtual Timer& getTimer() = 0;
|
||||
};
|
||||
|
||||
class Win32WaitObjectThreadPool {
|
||||
// Helper class that implements Win32EventPort::observeSignalState() by spawning additional
|
||||
// threads as needed to perform the actual waiting.
|
||||
//
|
||||
// This class is intended to be used to assist in building Win32EventPort implementations.
|
||||
|
||||
public:
|
||||
Win32WaitObjectThreadPool(uint mainThreadCount = 0);
|
||||
// `mainThreadCount` indicates the number of objects the main thread is able to listen on
|
||||
// directly. Typically this would be zero (e.g. if the main thread watches an I/O completion
|
||||
// port) or MAXIMUM_WAIT_OBJECTS (e.g. if the main thread is a UI thread but can use
|
||||
// MsgWaitForMultipleObjectsEx() to wait on some handles at the same time as messages).
|
||||
|
||||
Own<Win32EventPort::SignalObserver> observeSignalState(HANDLE handle);
|
||||
// Implemetns Win32EventPort::observeSignalState().
|
||||
|
||||
uint prepareMainThreadWait(HANDLE* handles[]);
|
||||
// Call immediately before invoking WaitForMultipleObjects() or similar in the main thread.
|
||||
// Fills in `handles` with the handle pointers to wait on, and returns the number of handles
|
||||
// in this array. (The array should be allocated to be at least the size passed to the
|
||||
// constructor).
|
||||
//
|
||||
// There's no need to call this if `mainThreadCount` as passed to the constructor was zero.
|
||||
|
||||
bool finishedMainThreadWait(DWORD returnCode);
|
||||
// Call immediately after invoking WaitForMultipleObjects() or similar in the main thread,
|
||||
// passing the value returend by that call. Returns true if the event indicated by `returnCode`
|
||||
// has been handled (i.e. it was WAIT_OBJECT_n or WAIT_ABANDONED_n where n is in-range for the
|
||||
// last call to prepareMainThreadWait()).
|
||||
};
|
||||
|
||||
class Win32IocpEventPort final: public Win32EventPort {
|
||||
// An EventPort implementation which uses Windows I/O completion ports to listen for events.
|
||||
//
|
||||
// With this implementation, observeSignalState() requires spawning a separate thread.
|
||||
|
||||
public:
|
||||
Win32IocpEventPort();
|
||||
~Win32IocpEventPort() noexcept(false);
|
||||
|
||||
// implements EventPort ------------------------------------------------------
|
||||
bool wait() override;
|
||||
bool poll() override;
|
||||
void wake() const override;
|
||||
|
||||
// implements Win32IocpEventPort ---------------------------------------------
|
||||
Own<IoObserver> observeIo(HANDLE handle) override;
|
||||
Own<SignalObserver> observeSignalState(HANDLE handle) override;
|
||||
Timer& getTimer() override { return timerImpl; }
|
||||
void allowApc() override { isAllowApc = true; }
|
||||
|
||||
private:
|
||||
class IoPromiseAdapter;
|
||||
class IoOperationImpl;
|
||||
class IoObserverImpl;
|
||||
|
||||
AutoCloseHandle iocp;
|
||||
AutoCloseHandle thread;
|
||||
Win32WaitObjectThreadPool waitThreads;
|
||||
TimerImpl timerImpl;
|
||||
mutable std::atomic<bool> sentWake {false};
|
||||
bool isAllowApc = false;
|
||||
|
||||
static TimePoint readClock();
|
||||
|
||||
void waitIocp(DWORD timeoutMs);
|
||||
// Wait on the I/O completion port for up to timeoutMs and pump events. Does not advance the
|
||||
// timer; caller must do that.
|
||||
|
||||
bool receivedWake();
|
||||
|
||||
static AutoCloseHandle newIocpHandle();
|
||||
static AutoCloseHandle openCurrentThread();
|
||||
};
|
||||
|
||||
} // namespace kj
|
||||
|
||||
#endif // KJ_ASYNC_WIN32_H_
|
||||
@@ -0,0 +1,682 @@
|
||||
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef KJ_ASYNC_H_
|
||||
#define KJ_ASYNC_H_
|
||||
|
||||
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include "async-prelude.h"
|
||||
#include "exception.h"
|
||||
#include "refcount.h"
|
||||
|
||||
namespace kj {
|
||||
|
||||
class EventLoop;
|
||||
class WaitScope;
|
||||
|
||||
template <typename T>
|
||||
class Promise;
|
||||
template <typename T>
|
||||
class ForkedPromise;
|
||||
template <typename T>
|
||||
class PromiseFulfiller;
|
||||
template <typename T>
|
||||
struct PromiseFulfillerPair;
|
||||
|
||||
template <typename Func, typename T>
|
||||
using PromiseForResult = Promise<_::JoinPromises<_::ReturnType<Func, T>>>;
|
||||
// Evaluates to the type of Promise for the result of calling functor type Func with parameter type
|
||||
// T. If T is void, then the promise is for the result of calling Func with no arguments. If
|
||||
// Func itself returns a promise, the promises are joined, so you never get Promise<Promise<T>>.
|
||||
|
||||
// =======================================================================================
|
||||
// Promises
|
||||
|
||||
template <typename T>
|
||||
class Promise: protected _::PromiseBase {
|
||||
// The basic primitive of asynchronous computation in KJ. Similar to "futures", but designed
|
||||
// specifically for event loop concurrency. Similar to E promises and JavaScript Promises/A.
|
||||
//
|
||||
// A Promise represents a promise to produce a value of type T some time in the future. Once
|
||||
// that value has been produced, the promise is "fulfilled". Alternatively, a promise can be
|
||||
// "broken", with an Exception describing what went wrong. You may implicitly convert a value of
|
||||
// type T to an already-fulfilled Promise<T>. You may implicitly convert the constant
|
||||
// `kj::READY_NOW` to an already-fulfilled Promise<void>. You may also implicitly convert a
|
||||
// `kj::Exception` to an already-broken promise of any type.
|
||||
//
|
||||
// Promises are linear types -- they are moveable but not copyable. If a Promise is destroyed
|
||||
// or goes out of scope (without being moved elsewhere), any ongoing asynchronous operations
|
||||
// meant to fulfill the promise will be canceled if possible. All methods of `Promise` (unless
|
||||
// otherwise noted) actually consume the promise in the sense of move semantics. (Arguably they
|
||||
// should be rvalue-qualified, but at the time this interface was created compilers didn't widely
|
||||
// support that yet and anyway it would be pretty ugly typing kj::mv(promise).whatever().) If
|
||||
// you want to use one Promise in two different places, you must fork it with `fork()`.
|
||||
//
|
||||
// To use the result of a Promise, you must call `then()` and supply a callback function to
|
||||
// call with the result. `then()` returns another promise, for the result of the callback.
|
||||
// Any time that this would result in Promise<Promise<T>>, the promises are collapsed into a
|
||||
// simple Promise<T> that first waits for the outer promise, then the inner. Example:
|
||||
//
|
||||
// // Open a remote file, read the content, and then count the
|
||||
// // number of lines of text.
|
||||
// // Note that none of the calls here block. `file`, `content`
|
||||
// // and `lineCount` are all initialized immediately before any
|
||||
// // asynchronous operations occur. The lambda callbacks are
|
||||
// // called later.
|
||||
// Promise<Own<File>> file = openFtp("ftp://host/foo/bar");
|
||||
// Promise<String> content = file.then(
|
||||
// [](Own<File> file) -> Promise<String> {
|
||||
// return file.readAll();
|
||||
// });
|
||||
// Promise<int> lineCount = content.then(
|
||||
// [](String text) -> int {
|
||||
// uint count = 0;
|
||||
// for (char c: text) count += (c == '\n');
|
||||
// return count;
|
||||
// });
|
||||
//
|
||||
// For `then()` to work, the current thread must have an active `EventLoop`. Each callback
|
||||
// is scheduled to execute in that loop. Since `then()` schedules callbacks only on the current
|
||||
// thread's event loop, you do not need to worry about two callbacks running at the same time.
|
||||
// You will need to set up at least one `EventLoop` at the top level of your program before you
|
||||
// can use promises.
|
||||
//
|
||||
// To adapt a non-Promise-based asynchronous API to promises, use `newAdaptedPromise()`.
|
||||
//
|
||||
// Systems using promises should consider supporting the concept of "pipelining". Pipelining
|
||||
// means allowing a caller to start issuing method calls against a promised object before the
|
||||
// promise has actually been fulfilled. This is particularly useful if the promise is for a
|
||||
// remote object living across a network, as this can avoid round trips when chaining a series
|
||||
// of calls. It is suggested that any class T which supports pipelining implement a subclass of
|
||||
// Promise<T> which adds "eventual send" methods -- methods which, when called, say "please
|
||||
// invoke the corresponding method on the promised value once it is available". These methods
|
||||
// should in turn return promises for the eventual results of said invocations. Cap'n Proto,
|
||||
// for example, implements the type `RemotePromise` which supports pipelining RPC requests -- see
|
||||
// `capnp/capability.h`.
|
||||
//
|
||||
// KJ Promises are based on E promises:
|
||||
// http://wiki.erights.org/wiki/Walnut/Distributed_Computing#Promises
|
||||
//
|
||||
// KJ Promises are also inspired in part by the evolving standards for JavaScript/ECMAScript
|
||||
// promises, which are themselves influenced by E promises:
|
||||
// http://promisesaplus.com/
|
||||
// https://github.com/domenic/promises-unwrapping
|
||||
|
||||
public:
|
||||
Promise(_::FixVoid<T> value);
|
||||
// Construct an already-fulfilled Promise from a value of type T. For non-void promises, the
|
||||
// parameter type is simply T. So, e.g., in a function that returns `Promise<int>`, you can
|
||||
// say `return 123;` to return a promise that is already fulfilled to 123.
|
||||
//
|
||||
// For void promises, use `kj::READY_NOW` as the value, e.g. `return kj::READY_NOW`.
|
||||
|
||||
Promise(kj::Exception&& e);
|
||||
// Construct an already-broken Promise.
|
||||
|
||||
inline Promise(decltype(nullptr)) {}
|
||||
|
||||
template <typename Func, typename ErrorFunc = _::PropagateException>
|
||||
PromiseForResult<Func, T> then(Func&& func, ErrorFunc&& errorHandler = _::PropagateException())
|
||||
KJ_WARN_UNUSED_RESULT;
|
||||
// Register a continuation function to be executed when the promise completes. The continuation
|
||||
// (`func`) takes the promised value (an rvalue of type `T`) as its parameter. The continuation
|
||||
// may return a new value; `then()` itself returns a promise for the continuation's eventual
|
||||
// result. If the continuation itself returns a `Promise<U>`, then `then()` shall also return
|
||||
// a `Promise<U>` which first waits for the original promise, then executes the continuation,
|
||||
// then waits for the inner promise (i.e. it automatically "unwraps" the promise).
|
||||
//
|
||||
// In all cases, `then()` returns immediately. The continuation is executed later. The
|
||||
// continuation is always executed on the same EventLoop (and, therefore, the same thread) which
|
||||
// called `then()`, therefore no synchronization is necessary on state shared by the continuation
|
||||
// and the surrounding scope. If no EventLoop is running on the current thread, `then()` throws
|
||||
// an exception.
|
||||
//
|
||||
// You may also specify an error handler continuation as the second parameter. `errorHandler`
|
||||
// must be a functor taking a parameter of type `kj::Exception&&`. It must return the same
|
||||
// type as `func` returns (except when `func` returns `Promise<U>`, in which case `errorHandler`
|
||||
// may return either `Promise<U>` or just `U`). The default error handler simply propagates the
|
||||
// exception to the returned promise.
|
||||
//
|
||||
// Either `func` or `errorHandler` may, of course, throw an exception, in which case the promise
|
||||
// is broken. When compiled with -fno-exceptions, the framework will still detect when a
|
||||
// recoverable exception was thrown inside of a continuation and will consider the promise
|
||||
// broken even though a (presumably garbage) result was returned.
|
||||
//
|
||||
// If the returned promise is destroyed before the callback runs, the callback will be canceled
|
||||
// (it will never run).
|
||||
//
|
||||
// Note that `then()` -- like all other Promise methods -- consumes the promise on which it is
|
||||
// called, in the sense of move semantics. After returning, the original promise is no longer
|
||||
// valid, but `then()` returns a new promise.
|
||||
//
|
||||
// *Advanced implementation tips:* Most users will never need to worry about the below, but
|
||||
// it is good to be aware of.
|
||||
//
|
||||
// As an optimization, if the callback function `func` does _not_ return another promise, then
|
||||
// execution of `func` itself may be delayed until its result is known to be needed. The
|
||||
// expectation here is that `func` is just doing some transformation on the results, not
|
||||
// scheduling any other actions, therefore the system doesn't need to be proactive about
|
||||
// evaluating it. This way, a chain of trivial then() transformations can be executed all at
|
||||
// once without repeatedly re-scheduling through the event loop. Use the `eagerlyEvaluate()`
|
||||
// method to suppress this behavior.
|
||||
//
|
||||
// On the other hand, if `func` _does_ return another promise, then the system evaluates `func`
|
||||
// as soon as possible, because the promise it returns might be for a newly-scheduled
|
||||
// long-running asynchronous task.
|
||||
//
|
||||
// As another optimization, when a callback function registered with `then()` is actually
|
||||
// scheduled, it is scheduled to occur immediately, preempting other work in the event queue.
|
||||
// This allows a long chain of `then`s to execute all at once, improving cache locality by
|
||||
// clustering operations on the same data. However, this implies that starvation can occur
|
||||
// if a chain of `then()`s takes a very long time to execute without ever stopping to wait for
|
||||
// actual I/O. To solve this, use `kj::evalLater()` to yield control; this way, all other events
|
||||
// in the queue will get a chance to run before your callback is executed.
|
||||
|
||||
Promise<void> ignoreResult() KJ_WARN_UNUSED_RESULT { return then([](T&&) {}); }
|
||||
// Convenience method to convert the promise to a void promise by ignoring the return value.
|
||||
//
|
||||
// You must still wait on the returned promise if you want the task to execute.
|
||||
|
||||
template <typename ErrorFunc>
|
||||
Promise<T> catch_(ErrorFunc&& errorHandler) KJ_WARN_UNUSED_RESULT;
|
||||
// Equivalent to `.then(identityFunc, errorHandler)`, where `identifyFunc` is a function that
|
||||
// just returns its input.
|
||||
|
||||
T wait(WaitScope& waitScope);
|
||||
// Run the event loop until the promise is fulfilled, then return its result. If the promise
|
||||
// is rejected, throw an exception.
|
||||
//
|
||||
// wait() is primarily useful at the top level of a program -- typically, within the function
|
||||
// that allocated the EventLoop. For example, a program that performs one or two RPCs and then
|
||||
// exits would likely use wait() in its main() function to wait on each RPC. On the other hand,
|
||||
// server-side code generally cannot use wait(), because it has to be able to accept multiple
|
||||
// requests at once.
|
||||
//
|
||||
// If the promise is rejected, `wait()` throws an exception. If the program was compiled without
|
||||
// exceptions (-fno-exceptions), this will usually abort. In this case you really should first
|
||||
// use `then()` to set an appropriate handler for the exception case, so that the promise you
|
||||
// actually wait on never throws.
|
||||
//
|
||||
// `waitScope` is an object proving that the caller is in a scope where wait() is allowed. By
|
||||
// convention, any function which might call wait(), or which might call another function which
|
||||
// might call wait(), must take `WaitScope&` as one of its parameters. This is needed for two
|
||||
// reasons:
|
||||
// * `wait()` is not allowed during an event callback, because event callbacks are themselves
|
||||
// called during some other `wait()`, and such recursive `wait()`s would only be able to
|
||||
// complete in LIFO order, which might mean that the outer `wait()` ends up waiting longer
|
||||
// than it is supposed to. To prevent this, a `WaitScope` cannot be constructed or used during
|
||||
// an event callback.
|
||||
// * Since `wait()` runs the event loop, unrelated event callbacks may execute before `wait()`
|
||||
// returns. This means that anyone calling `wait()` must be reentrant -- state may change
|
||||
// around them in arbitrary ways. Therefore, callers really need to know if a function they
|
||||
// are calling might wait(), and the `WaitScope&` parameter makes this clear.
|
||||
//
|
||||
// TODO(someday): Implement fibers, and let them call wait() even when they are handling an
|
||||
// event.
|
||||
|
||||
ForkedPromise<T> fork() KJ_WARN_UNUSED_RESULT;
|
||||
// Forks the promise, so that multiple different clients can independently wait on the result.
|
||||
// `T` must be copy-constructable for this to work. Or, in the special case where `T` is
|
||||
// `Own<U>`, `U` must have a method `Own<U> addRef()` which returns a new reference to the same
|
||||
// (or an equivalent) object (probably implemented via reference counting).
|
||||
|
||||
_::SplitTuplePromise<T> split();
|
||||
// Split a promise for a tuple into a tuple of promises.
|
||||
//
|
||||
// E.g. if you have `Promise<kj::Tuple<T, U>>`, `split()` returns
|
||||
// `kj::Tuple<Promise<T>, Promise<U>>`.
|
||||
|
||||
Promise<T> exclusiveJoin(Promise<T>&& other) KJ_WARN_UNUSED_RESULT;
|
||||
// Return a new promise that resolves when either the original promise resolves or `other`
|
||||
// resolves (whichever comes first). The promise that didn't resolve first is canceled.
|
||||
|
||||
// TODO(someday): inclusiveJoin(), or perhaps just join(), which waits for both completions
|
||||
// and produces a tuple?
|
||||
|
||||
template <typename... Attachments>
|
||||
Promise<T> attach(Attachments&&... attachments) KJ_WARN_UNUSED_RESULT;
|
||||
// "Attaches" one or more movable objects (often, Own<T>s) to the promise, such that they will
|
||||
// be destroyed when the promise resolves. This is useful when a promise's callback contains
|
||||
// pointers into some object and you want to make sure the object still exists when the callback
|
||||
// runs -- after calling then(), use attach() to add necessary objects to the result.
|
||||
|
||||
template <typename ErrorFunc>
|
||||
Promise<T> eagerlyEvaluate(ErrorFunc&& errorHandler) KJ_WARN_UNUSED_RESULT;
|
||||
Promise<T> eagerlyEvaluate(decltype(nullptr)) KJ_WARN_UNUSED_RESULT;
|
||||
// Force eager evaluation of this promise. Use this if you are going to hold on to the promise
|
||||
// for awhile without consuming the result, but you want to make sure that the system actually
|
||||
// processes it.
|
||||
//
|
||||
// `errorHandler` is a function that takes `kj::Exception&&`, like the second parameter to
|
||||
// `then()`, except that it must return void. We make you specify this because otherwise it's
|
||||
// easy to forget to handle errors in a promise that you never use. You may specify nullptr for
|
||||
// the error handler if you are sure that ignoring errors is fine, or if you know that you'll
|
||||
// eventually wait on the promise somewhere.
|
||||
|
||||
template <typename ErrorFunc>
|
||||
void detach(ErrorFunc&& errorHandler);
|
||||
// Allows the promise to continue running in the background until it completes or the
|
||||
// `EventLoop` is destroyed. Be careful when using this: since you can no longer cancel this
|
||||
// promise, you need to make sure that the promise owns all the objects it touches or make sure
|
||||
// those objects outlive the EventLoop.
|
||||
//
|
||||
// `errorHandler` is a function that takes `kj::Exception&&`, like the second parameter to
|
||||
// `then()`, except that it must return void.
|
||||
//
|
||||
// This function exists mainly to implement the Cap'n Proto requirement that RPC calls cannot be
|
||||
// canceled unless the callee explicitly permits it.
|
||||
|
||||
kj::String trace();
|
||||
// Returns a dump of debug info about this promise. Not for production use. Requires RTTI.
|
||||
// This method does NOT consume the promise as other methods do.
|
||||
|
||||
private:
|
||||
Promise(bool, Own<_::PromiseNode>&& node): PromiseBase(kj::mv(node)) {}
|
||||
// Second parameter prevent ambiguity with immediate-value constructor.
|
||||
|
||||
template <typename>
|
||||
friend class Promise;
|
||||
friend class EventLoop;
|
||||
template <typename U, typename Adapter, typename... Params>
|
||||
friend Promise<U> newAdaptedPromise(Params&&... adapterConstructorParams);
|
||||
template <typename U>
|
||||
friend PromiseFulfillerPair<U> newPromiseAndFulfiller();
|
||||
template <typename>
|
||||
friend class _::ForkHub;
|
||||
friend class _::TaskSetImpl;
|
||||
friend Promise<void> _::yield();
|
||||
friend class _::NeverDone;
|
||||
template <typename U>
|
||||
friend Promise<Array<U>> joinPromises(Array<Promise<U>>&& promises);
|
||||
friend Promise<void> joinPromises(Array<Promise<void>>&& promises);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ForkedPromise {
|
||||
// The result of `Promise::fork()` and `EventLoop::fork()`. Allows branches to be created.
|
||||
// Like `Promise<T>`, this is a pass-by-move type.
|
||||
|
||||
public:
|
||||
inline ForkedPromise(decltype(nullptr)) {}
|
||||
|
||||
Promise<T> addBranch();
|
||||
// Add a new branch to the fork. The branch is equivalent to the original promise.
|
||||
|
||||
private:
|
||||
Own<_::ForkHub<_::FixVoid<T>>> hub;
|
||||
|
||||
inline ForkedPromise(bool, Own<_::ForkHub<_::FixVoid<T>>>&& hub): hub(kj::mv(hub)) {}
|
||||
|
||||
friend class Promise<T>;
|
||||
friend class EventLoop;
|
||||
};
|
||||
|
||||
constexpr _::Void READY_NOW = _::Void();
|
||||
// Use this when you need a Promise<void> that is already fulfilled -- this value can be implicitly
|
||||
// cast to `Promise<void>`.
|
||||
|
||||
constexpr _::NeverDone NEVER_DONE = _::NeverDone();
|
||||
// The opposite of `READY_NOW`, return this when the promise should never resolve. This can be
|
||||
// implicitly converted to any promise type. You may also call `NEVER_DONE.wait()` to wait
|
||||
// forever (useful for servers).
|
||||
|
||||
template <typename Func>
|
||||
PromiseForResult<Func, void> evalLater(Func&& func) KJ_WARN_UNUSED_RESULT;
|
||||
// Schedule for the given zero-parameter function to be executed in the event loop at some
|
||||
// point in the near future. Returns a Promise for its result -- or, if `func()` itself returns
|
||||
// a promise, `evalLater()` returns a Promise for the result of resolving that promise.
|
||||
//
|
||||
// Example usage:
|
||||
// Promise<int> x = evalLater([]() { return 123; });
|
||||
//
|
||||
// The above is exactly equivalent to:
|
||||
// Promise<int> x = Promise<void>(READY_NOW).then([]() { return 123; });
|
||||
//
|
||||
// If the returned promise is destroyed before the callback runs, the callback will be canceled
|
||||
// (never called).
|
||||
//
|
||||
// If you schedule several evaluations with `evalLater` during the same callback, they are
|
||||
// guaranteed to be executed in order.
|
||||
|
||||
template <typename Func>
|
||||
PromiseForResult<Func, void> evalNow(Func&& func) KJ_WARN_UNUSED_RESULT;
|
||||
// Run `func()` and return a promise for its result. `func()` executes before `evalNow()` returns.
|
||||
// If `func()` throws an exception, the exception is caught and wrapped in a promise -- this is the
|
||||
// main reason why `evalNow()` is useful.
|
||||
|
||||
template <typename T>
|
||||
Promise<Array<T>> joinPromises(Array<Promise<T>>&& promises);
|
||||
// Join an array of promises into a promise for an array.
|
||||
|
||||
// =======================================================================================
|
||||
// Hack for creating a lambda that holds an owned pointer.
|
||||
|
||||
template <typename Func, typename MovedParam>
|
||||
class CaptureByMove {
|
||||
public:
|
||||
inline CaptureByMove(Func&& func, MovedParam&& param)
|
||||
: func(kj::mv(func)), param(kj::mv(param)) {}
|
||||
|
||||
template <typename... Params>
|
||||
inline auto operator()(Params&&... params)
|
||||
-> decltype(kj::instance<Func>()(kj::instance<MovedParam&&>(), kj::fwd<Params>(params)...)) {
|
||||
return func(kj::mv(param), kj::fwd<Params>(params)...);
|
||||
}
|
||||
|
||||
private:
|
||||
Func func;
|
||||
MovedParam param;
|
||||
};
|
||||
|
||||
template <typename Func, typename MovedParam>
|
||||
inline CaptureByMove<Func, Decay<MovedParam>> mvCapture(MovedParam&& param, Func&& func) {
|
||||
// Hack to create a "lambda" which captures a variable by moving it rather than copying or
|
||||
// referencing. C++14 generalized captures should make this obsolete, but for now in C++11 this
|
||||
// is commonly needed for Promise continuations that own their state. Example usage:
|
||||
//
|
||||
// Own<Foo> ptr = makeFoo();
|
||||
// Promise<int> promise = callRpc();
|
||||
// promise.then(mvCapture(ptr, [](Own<Foo>&& ptr, int result) {
|
||||
// return ptr->finish(result);
|
||||
// }));
|
||||
|
||||
return CaptureByMove<Func, Decay<MovedParam>>(kj::fwd<Func>(func), kj::mv(param));
|
||||
}
|
||||
|
||||
// =======================================================================================
|
||||
// Advanced promise construction
|
||||
|
||||
template <typename T>
|
||||
class PromiseFulfiller {
|
||||
// A callback which can be used to fulfill a promise. Only the first call to fulfill() or
|
||||
// reject() matters; subsequent calls are ignored.
|
||||
|
||||
public:
|
||||
virtual void fulfill(T&& value) = 0;
|
||||
// Fulfill the promise with the given value.
|
||||
|
||||
virtual void reject(Exception&& exception) = 0;
|
||||
// Reject the promise with an error.
|
||||
|
||||
virtual bool isWaiting() = 0;
|
||||
// Returns true if the promise is still unfulfilled and someone is potentially waiting for it.
|
||||
// Returns false if fulfill()/reject() has already been called *or* if the promise to be
|
||||
// fulfilled has been discarded and therefore the result will never be used anyway.
|
||||
|
||||
template <typename Func>
|
||||
bool rejectIfThrows(Func&& func);
|
||||
// Call the function (with no arguments) and return true. If an exception is thrown, call
|
||||
// `fulfiller.reject()` and then return false. When compiled with exceptions disabled,
|
||||
// non-fatal exceptions are still detected and handled correctly.
|
||||
};
|
||||
|
||||
template <>
|
||||
class PromiseFulfiller<void> {
|
||||
// Specialization of PromiseFulfiller for void promises. See PromiseFulfiller<T>.
|
||||
|
||||
public:
|
||||
virtual void fulfill(_::Void&& value = _::Void()) = 0;
|
||||
// Call with zero parameters. The parameter is a dummy that only exists so that subclasses don't
|
||||
// have to specialize for <void>.
|
||||
|
||||
virtual void reject(Exception&& exception) = 0;
|
||||
virtual bool isWaiting() = 0;
|
||||
|
||||
template <typename Func>
|
||||
bool rejectIfThrows(Func&& func);
|
||||
};
|
||||
|
||||
template <typename T, typename Adapter, typename... Params>
|
||||
Promise<T> newAdaptedPromise(Params&&... adapterConstructorParams);
|
||||
// Creates a new promise which owns an instance of `Adapter` which encapsulates the operation
|
||||
// that will eventually fulfill the promise. This is primarily useful for adapting non-KJ
|
||||
// asynchronous APIs to use promises.
|
||||
//
|
||||
// An instance of `Adapter` will be allocated and owned by the returned `Promise`. A
|
||||
// `PromiseFulfiller<T>&` will be passed as the first parameter to the adapter's constructor,
|
||||
// and `adapterConstructorParams` will be forwarded as the subsequent parameters. The adapter
|
||||
// is expected to perform some asynchronous operation and call the `PromiseFulfiller<T>` once
|
||||
// it is finished.
|
||||
//
|
||||
// The adapter is destroyed when its owning Promise is destroyed. This may occur before the
|
||||
// Promise has been fulfilled. In this case, the adapter's destructor should cancel the
|
||||
// asynchronous operation. Once the adapter is destroyed, the fulfillment callback cannot be
|
||||
// called.
|
||||
//
|
||||
// An adapter implementation should be carefully written to ensure that it cannot accidentally
|
||||
// be left unfulfilled permanently because of an exception. Consider making liberal use of
|
||||
// `PromiseFulfiller<T>::rejectIfThrows()`.
|
||||
|
||||
template <typename T>
|
||||
struct PromiseFulfillerPair {
|
||||
Promise<_::JoinPromises<T>> promise;
|
||||
Own<PromiseFulfiller<T>> fulfiller;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
PromiseFulfillerPair<T> newPromiseAndFulfiller();
|
||||
// Construct a Promise and a separate PromiseFulfiller which can be used to fulfill the promise.
|
||||
// If the PromiseFulfiller is destroyed before either of its methods are called, the Promise is
|
||||
// implicitly rejected.
|
||||
//
|
||||
// Although this function is easier to use than `newAdaptedPromise()`, it has the serious drawback
|
||||
// that there is no way to handle cancellation (i.e. detect when the Promise is discarded).
|
||||
//
|
||||
// You can arrange to fulfill a promise with another promise by using a promise type for T. E.g.
|
||||
// `newPromiseAndFulfiller<Promise<U>>()` will produce a promise of type `Promise<U>` but the
|
||||
// fulfiller will be of type `PromiseFulfiller<Promise<U>>`. Thus you pass a `Promise<U>` to the
|
||||
// `fulfill()` callback, and the promises are chained.
|
||||
|
||||
// =======================================================================================
|
||||
// TaskSet
|
||||
|
||||
class TaskSet {
|
||||
// Holds a collection of Promise<void>s and ensures that each executes to completion. Memory
|
||||
// associated with each promise is automatically freed when the promise completes. Destroying
|
||||
// the TaskSet itself automatically cancels all unfinished promises.
|
||||
//
|
||||
// This is useful for "daemon" objects that perform background tasks which aren't intended to
|
||||
// fulfill any particular external promise, but which may need to be canceled (and thus can't
|
||||
// use `Promise::detach()`). The daemon object holds a TaskSet to collect these tasks it is
|
||||
// working on. This way, if the daemon itself is destroyed, the TaskSet is detroyed as well,
|
||||
// and everything the daemon is doing is canceled.
|
||||
|
||||
public:
|
||||
class ErrorHandler {
|
||||
public:
|
||||
virtual void taskFailed(kj::Exception&& exception) = 0;
|
||||
};
|
||||
|
||||
TaskSet(ErrorHandler& errorHandler);
|
||||
// `loop` will be used to wait on promises. `errorHandler` will be executed any time a task
|
||||
// throws an exception, and will execute within the given EventLoop.
|
||||
|
||||
~TaskSet() noexcept(false);
|
||||
|
||||
void add(Promise<void>&& promise);
|
||||
|
||||
kj::String trace();
|
||||
// Return debug info about all promises currently in the TaskSet.
|
||||
|
||||
private:
|
||||
Own<_::TaskSetImpl> impl;
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
// The EventLoop class
|
||||
|
||||
class EventPort {
|
||||
// Interfaces between an `EventLoop` and events originating from outside of the loop's thread.
|
||||
// All such events come in through the `EventPort` implementation.
|
||||
//
|
||||
// An `EventPort` implementation may interface with low-level operating system APIs and/or other
|
||||
// threads. You can also write an `EventPort` which wraps some other (non-KJ) event loop
|
||||
// framework, allowing the two to coexist in a single thread.
|
||||
|
||||
public:
|
||||
virtual bool wait() = 0;
|
||||
// Wait for an external event to arrive, sleeping if necessary. Once at least one event has
|
||||
// arrived, queue it to the event loop (e.g. by fulfilling a promise) and return.
|
||||
//
|
||||
// This is called during `Promise::wait()` whenever the event queue becomes empty, in order to
|
||||
// wait for new events to populate the queue.
|
||||
//
|
||||
// It is safe to return even if nothing has actually been queued, so long as calling `wait()` in
|
||||
// a loop will eventually sleep. (That is to say, false positives are fine.)
|
||||
//
|
||||
// Returns true if wake() has been called from another thread. (Precisely, returns true if
|
||||
// no previous call to wait `wait()` nor `poll()` has returned true since `wake()` was last
|
||||
// called.)
|
||||
|
||||
virtual bool poll() = 0;
|
||||
// Check if any external events have arrived, but do not sleep. If any events have arrived,
|
||||
// add them to the event queue (e.g. by fulfilling promises) before returning.
|
||||
//
|
||||
// This may be called during `Promise::wait()` when the EventLoop has been executing for a while
|
||||
// without a break but is still non-empty.
|
||||
//
|
||||
// Returns true if wake() has been called from another thread. (Precisely, returns true if
|
||||
// no previous call to wait `wait()` nor `poll()` has returned true since `wake()` was last
|
||||
// called.)
|
||||
|
||||
virtual void setRunnable(bool runnable);
|
||||
// Called to notify the `EventPort` when the `EventLoop` has work to do; specifically when it
|
||||
// transitions from empty -> runnable or runnable -> empty. This is typically useful when
|
||||
// integrating with an external event loop; if the loop is currently runnable then you should
|
||||
// arrange to call run() on it soon. The default implementation does nothing.
|
||||
|
||||
virtual void wake() const;
|
||||
// Wake up the EventPort's thread from another thread.
|
||||
//
|
||||
// Unlike all other methods on this interface, `wake()` may be called from another thread, hence
|
||||
// it is `const`.
|
||||
//
|
||||
// Technically speaking, `wake()` causes the target thread to cease sleeping and not to sleep
|
||||
// again until `wait()` or `poll()` has returned true at least once.
|
||||
//
|
||||
// The default implementation throws an UNIMPLEMENTED exception.
|
||||
};
|
||||
|
||||
class EventLoop {
|
||||
// Represents a queue of events being executed in a loop. Most code won't interact with
|
||||
// EventLoop directly, but instead use `Promise`s to interact with it indirectly. See the
|
||||
// documentation for `Promise`.
|
||||
//
|
||||
// Each thread can have at most one current EventLoop. To make an `EventLoop` current for
|
||||
// the thread, create a `WaitScope`. Async APIs require that the thread has a current EventLoop,
|
||||
// or they will throw exceptions. APIs that use `Promise::wait()` additionally must explicitly
|
||||
// be passed a reference to the `WaitScope` to make the caller aware that they might block.
|
||||
//
|
||||
// Generally, you will want to construct an `EventLoop` at the top level of your program, e.g.
|
||||
// in the main() function, or in the start function of a thread. You can then use it to
|
||||
// construct some promises and wait on the result. Example:
|
||||
//
|
||||
// int main() {
|
||||
// // `loop` becomes the official EventLoop for the thread.
|
||||
// MyEventPort eventPort;
|
||||
// EventLoop loop(eventPort);
|
||||
//
|
||||
// // Now we can call an async function.
|
||||
// Promise<String> textPromise = getHttp("http://example.com");
|
||||
//
|
||||
// // And we can wait for the promise to complete. Note that you can only use `wait()`
|
||||
// // from the top level, not from inside a promise callback.
|
||||
// String text = textPromise.wait();
|
||||
// print(text);
|
||||
// return 0;
|
||||
// }
|
||||
//
|
||||
// Most applications that do I/O will prefer to use `setupAsyncIo()` from `async-io.h` rather
|
||||
// than allocate an `EventLoop` directly.
|
||||
|
||||
public:
|
||||
EventLoop();
|
||||
// Construct an `EventLoop` which does not receive external events at all.
|
||||
|
||||
explicit EventLoop(EventPort& port);
|
||||
// Construct an `EventLoop` which receives external events through the given `EventPort`.
|
||||
|
||||
~EventLoop() noexcept(false);
|
||||
|
||||
void run(uint maxTurnCount = maxValue);
|
||||
// Run the event loop for `maxTurnCount` turns or until there is nothing left to be done,
|
||||
// whichever comes first. This never calls the `EventPort`'s `sleep()` or `poll()`. It will
|
||||
// call the `EventPort`'s `setRunnable(false)` if the queue becomes empty.
|
||||
|
||||
bool isRunnable();
|
||||
// Returns true if run() would currently do anything, or false if the queue is empty.
|
||||
|
||||
private:
|
||||
EventPort& port;
|
||||
|
||||
bool running = false;
|
||||
// True while looping -- wait() is then not allowed.
|
||||
|
||||
bool lastRunnableState = false;
|
||||
// What did we last pass to port.setRunnable()?
|
||||
|
||||
_::Event* head = nullptr;
|
||||
_::Event** tail = &head;
|
||||
_::Event** depthFirstInsertPoint = &head;
|
||||
|
||||
Own<_::TaskSetImpl> daemons;
|
||||
|
||||
bool turn();
|
||||
void setRunnable(bool runnable);
|
||||
void enterScope();
|
||||
void leaveScope();
|
||||
|
||||
friend void _::detach(kj::Promise<void>&& promise);
|
||||
friend void _::waitImpl(Own<_::PromiseNode>&& node, _::ExceptionOrValue& result,
|
||||
WaitScope& waitScope);
|
||||
friend class _::Event;
|
||||
friend class WaitScope;
|
||||
};
|
||||
|
||||
class WaitScope {
|
||||
// Represents a scope in which asynchronous programming can occur. A `WaitScope` should usually
|
||||
// be allocated on the stack and serves two purposes:
|
||||
// * While the `WaitScope` exists, its `EventLoop` is registered as the current loop for the
|
||||
// thread. Most operations dealing with `Promise` (including all of its methods) do not work
|
||||
// unless the thread has a current `EventLoop`.
|
||||
// * `WaitScope` may be passed to `Promise::wait()` to synchronously wait for a particular
|
||||
// promise to complete. See `Promise::wait()` for an extended discussion.
|
||||
|
||||
public:
|
||||
inline explicit WaitScope(EventLoop& loop): loop(loop) { loop.enterScope(); }
|
||||
inline ~WaitScope() { loop.leaveScope(); }
|
||||
KJ_DISALLOW_COPY(WaitScope);
|
||||
|
||||
private:
|
||||
EventLoop& loop;
|
||||
friend class EventLoop;
|
||||
friend void _::waitImpl(Own<_::PromiseNode>&& node, _::ExceptionOrValue& result,
|
||||
WaitScope& waitScope);
|
||||
};
|
||||
|
||||
} // namespace kj
|
||||
|
||||
#include "async-inl.h"
|
||||
|
||||
#endif // KJ_ASYNC_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,122 @@
|
||||
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef KJ_COMPAT_GTEST_H_
|
||||
#define KJ_COMPAT_GTEST_H_
|
||||
// This file defines compatibility macros converting Google Test tests into KJ tests.
|
||||
//
|
||||
// This is only intended to cover the most common functionality. Many tests will likely need
|
||||
// additional tweaks. For instance:
|
||||
// - Using operator<< to print information on failure is not supported. Instead, switch to
|
||||
// KJ_ASSERT/KJ_EXPECT and pass in stuff to print as additional parameters.
|
||||
// - Test fixtures are not supported. Allocate your "test fixture" on the stack instead. Do setup
|
||||
// in the constructor, teardown in the destructor.
|
||||
|
||||
#include "../test.h"
|
||||
|
||||
namespace kj {
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
template <typename T>
|
||||
T abs(T value) { return value < 0 ? -value : value; }
|
||||
|
||||
inline bool floatAlmostEqual(float a, float b) {
|
||||
return a == b || abs(a - b) < (abs(a) + abs(b)) * 1e-5;
|
||||
}
|
||||
|
||||
inline bool doubleAlmostEqual(double a, double b) {
|
||||
return a == b || abs(a - b) < (abs(a) + abs(b)) * 1e-12;
|
||||
}
|
||||
|
||||
} // namespace _ (private)
|
||||
|
||||
#define EXPECT_FALSE(x) KJ_EXPECT(!(x))
|
||||
#define EXPECT_TRUE(x) KJ_EXPECT(x)
|
||||
#define EXPECT_EQ(x, y) KJ_EXPECT((x) == (y), x, y)
|
||||
#define EXPECT_NE(x, y) KJ_EXPECT((x) != (y), x, y)
|
||||
#define EXPECT_LE(x, y) KJ_EXPECT((x) <= (y), x, y)
|
||||
#define EXPECT_GE(x, y) KJ_EXPECT((x) >= (y), x, y)
|
||||
#define EXPECT_LT(x, y) KJ_EXPECT((x) < (y), x, y)
|
||||
#define EXPECT_GT(x, y) KJ_EXPECT((x) > (y), x, y)
|
||||
#define EXPECT_STREQ(x, y) KJ_EXPECT(::strcmp(x, y) == 0, x, y)
|
||||
#define EXPECT_FLOAT_EQ(x, y) KJ_EXPECT(::kj::_::floatAlmostEqual(y, x), y, x);
|
||||
#define EXPECT_DOUBLE_EQ(x, y) KJ_EXPECT(::kj::_::doubleAlmostEqual(y, x), y, x);
|
||||
|
||||
#define ASSERT_FALSE(x) KJ_ASSERT(!(x))
|
||||
#define ASSERT_TRUE(x) KJ_ASSERT(x)
|
||||
#define ASSERT_EQ(x, y) KJ_ASSERT((x) == (y), x, y)
|
||||
#define ASSERT_NE(x, y) KJ_ASSERT((x) != (y), x, y)
|
||||
#define ASSERT_LE(x, y) KJ_ASSERT((x) <= (y), x, y)
|
||||
#define ASSERT_GE(x, y) KJ_ASSERT((x) >= (y), x, y)
|
||||
#define ASSERT_LT(x, y) KJ_ASSERT((x) < (y), x, y)
|
||||
#define ASSERT_GT(x, y) KJ_ASSERT((x) > (y), x, y)
|
||||
#define ASSERT_STREQ(x, y) KJ_ASSERT(::strcmp(x, y) == 0, x, y)
|
||||
#define ASSERT_FLOAT_EQ(x, y) KJ_ASSERT(::kj::_::floatAlmostEqual(y, x), y, x);
|
||||
#define ASSERT_DOUBLE_EQ(x, y) KJ_ASSERT(::kj::_::doubleAlmostEqual(y, x), y, x);
|
||||
|
||||
class AddFailureAdapter {
|
||||
public:
|
||||
AddFailureAdapter(const char* file, int line): file(file), line(line) {}
|
||||
|
||||
~AddFailureAdapter() {
|
||||
if (!handled) {
|
||||
_::Debug::log(file, line, LogSeverity::ERROR, "expectation failed");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void operator<<(T&& info) {
|
||||
handled = true;
|
||||
_::Debug::log(file, line, LogSeverity::ERROR, "\"expectation failed\", info",
|
||||
"expectation failed", kj::fwd<T>(info));
|
||||
}
|
||||
|
||||
private:
|
||||
bool handled = false;
|
||||
const char* file;
|
||||
int line;
|
||||
};
|
||||
|
||||
#define ADD_FAILURE() ::kj::AddFailureAdapter(__FILE__, __LINE__)
|
||||
|
||||
#if KJ_NO_EXCEPTIONS
|
||||
#define EXPECT_ANY_THROW(code) \
|
||||
KJ_EXPECT(::kj::_::expectFatalThrow(nullptr, nullptr, [&]() { code; }))
|
||||
#else
|
||||
#define EXPECT_ANY_THROW(code) \
|
||||
KJ_EXPECT(::kj::runCatchingExceptions([&]() { code; }) != nullptr)
|
||||
#endif
|
||||
|
||||
#define EXPECT_NONFATAL_FAILURE(code) \
|
||||
EXPECT_TRUE(kj::runCatchingExceptions([&]() { code; }) != nullptr);
|
||||
|
||||
#ifdef KJ_DEBUG
|
||||
#define EXPECT_DEBUG_ANY_THROW EXPECT_ANY_THROW
|
||||
#else
|
||||
#define EXPECT_DEBUG_ANY_THROW(EXP)
|
||||
#endif
|
||||
|
||||
#define TEST(x, y) KJ_TEST("legacy test: " #x "/" #y)
|
||||
|
||||
} // namespace kj
|
||||
|
||||
#endif // KJ_COMPAT_GTEST_H_
|
||||
@@ -0,0 +1,636 @@
|
||||
// Copyright (c) 2017 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef KJ_COMPAT_HTTP_H_
|
||||
#define KJ_COMPAT_HTTP_H_
|
||||
// The KJ HTTP client/server library.
|
||||
//
|
||||
// This is a simple library which can be used to implement an HTTP client or server. Properties
|
||||
// of this library include:
|
||||
// - Uses KJ async framework.
|
||||
// - Agnostic to transport layer -- you can provide your own.
|
||||
// - Header parsing is zero-copy -- it results in strings that point directly into the buffer
|
||||
// received off the wire.
|
||||
// - Application code which reads and writes headers refers to headers by symbolic names, not by
|
||||
// string literals, with lookups being array-index-based, not map-based. To make this possible,
|
||||
// the application announces what headers it cares about in advance, in order to assign numeric
|
||||
// values to them.
|
||||
// - Methods are identified by an enum.
|
||||
|
||||
#include <kj/string.h>
|
||||
#include <kj/vector.h>
|
||||
#include <kj/memory.h>
|
||||
#include <kj/one-of.h>
|
||||
#include <kj/async-io.h>
|
||||
|
||||
namespace kj {
|
||||
|
||||
#define KJ_HTTP_FOR_EACH_METHOD(MACRO) \
|
||||
MACRO(GET) \
|
||||
MACRO(HEAD) \
|
||||
MACRO(POST) \
|
||||
MACRO(PUT) \
|
||||
MACRO(DELETE) \
|
||||
MACRO(PATCH) \
|
||||
MACRO(PURGE) \
|
||||
MACRO(OPTIONS) \
|
||||
MACRO(TRACE) \
|
||||
/* standard methods */ \
|
||||
/* */ \
|
||||
/* (CONNECT is intentionally omitted since it is handled specially in HttpHandler) */ \
|
||||
\
|
||||
MACRO(COPY) \
|
||||
MACRO(LOCK) \
|
||||
MACRO(MKCOL) \
|
||||
MACRO(MOVE) \
|
||||
MACRO(PROPFIND) \
|
||||
MACRO(PROPPATCH) \
|
||||
MACRO(SEARCH) \
|
||||
MACRO(UNLOCK) \
|
||||
/* WebDAV */ \
|
||||
\
|
||||
MACRO(REPORT) \
|
||||
MACRO(MKACTIVITY) \
|
||||
MACRO(CHECKOUT) \
|
||||
MACRO(MERGE) \
|
||||
/* Subversion */ \
|
||||
\
|
||||
MACRO(MSEARCH) \
|
||||
MACRO(NOTIFY) \
|
||||
MACRO(SUBSCRIBE) \
|
||||
MACRO(UNSUBSCRIBE)
|
||||
/* UPnP */
|
||||
|
||||
#define KJ_HTTP_FOR_EACH_CONNECTION_HEADER(MACRO) \
|
||||
MACRO(connection, "Connection") \
|
||||
MACRO(contentLength, "Content-Length") \
|
||||
MACRO(keepAlive, "Keep-Alive") \
|
||||
MACRO(te, "TE") \
|
||||
MACRO(trailer, "Trailer") \
|
||||
MACRO(transferEncoding, "Transfer-Encoding") \
|
||||
MACRO(upgrade, "Upgrade")
|
||||
|
||||
enum class HttpMethod {
|
||||
// Enum of known HTTP methods.
|
||||
//
|
||||
// We use an enum rather than a string to allow for faster parsing and switching and to reduce
|
||||
// ambiguity.
|
||||
|
||||
#define DECLARE_METHOD(id) id,
|
||||
KJ_HTTP_FOR_EACH_METHOD(DECLARE_METHOD)
|
||||
#undef DECLARE_METHOD
|
||||
};
|
||||
|
||||
kj::StringPtr KJ_STRINGIFY(HttpMethod method);
|
||||
kj::Maybe<HttpMethod> tryParseHttpMethod(kj::StringPtr name);
|
||||
|
||||
class HttpHeaderTable;
|
||||
|
||||
class HttpHeaderId {
|
||||
// Identifies an HTTP header by numeric ID that indexes into an HttpHeaderTable.
|
||||
//
|
||||
// The KJ HTTP API prefers that headers be identified by these IDs for a few reasons:
|
||||
// - Integer lookups are much more efficient than string lookups.
|
||||
// - Case-insensitivity is awkward to deal with when const strings are being passed to the lookup
|
||||
// method.
|
||||
// - Writing out strings less often means fewer typos.
|
||||
//
|
||||
// See HttpHeaderTable for usage hints.
|
||||
|
||||
public:
|
||||
HttpHeaderId() = default;
|
||||
|
||||
inline bool operator==(const HttpHeaderId& other) const { return id == other.id; }
|
||||
inline bool operator!=(const HttpHeaderId& other) const { return id != other.id; }
|
||||
inline bool operator< (const HttpHeaderId& other) const { return id < other.id; }
|
||||
inline bool operator> (const HttpHeaderId& other) const { return id > other.id; }
|
||||
inline bool operator<=(const HttpHeaderId& other) const { return id <= other.id; }
|
||||
inline bool operator>=(const HttpHeaderId& other) const { return id >= other.id; }
|
||||
|
||||
inline size_t hashCode() const { return id; }
|
||||
|
||||
kj::StringPtr toString() const;
|
||||
|
||||
void requireFrom(HttpHeaderTable& table) const;
|
||||
// In debug mode, throws an exception if the HttpHeaderId is not from the given table.
|
||||
//
|
||||
// In opt mode, no-op.
|
||||
|
||||
#define KJ_HTTP_FOR_EACH_BUILTIN_HEADER(MACRO) \
|
||||
MACRO(HOST, "Host") \
|
||||
MACRO(DATE, "Date") \
|
||||
MACRO(LOCATION, "Location") \
|
||||
MACRO(CONTENT_TYPE, "Content-Type")
|
||||
// For convenience, these very-common headers are valid for all HttpHeaderTables. You can refer
|
||||
// to them like:
|
||||
//
|
||||
// HttpHeaderId::HOST
|
||||
//
|
||||
// TODO(0.7): Fill this out with more common headers.
|
||||
|
||||
#define DECLARE_HEADER(id, name) \
|
||||
static const HttpHeaderId id;
|
||||
// Declare a constant for each builtin header, e.g.: HttpHeaderId::CONNECTION
|
||||
|
||||
KJ_HTTP_FOR_EACH_BUILTIN_HEADER(DECLARE_HEADER);
|
||||
#undef DECLARE_HEADER
|
||||
|
||||
private:
|
||||
HttpHeaderTable* table;
|
||||
uint id;
|
||||
|
||||
inline explicit constexpr HttpHeaderId(HttpHeaderTable* table, uint id): table(table), id(id) {}
|
||||
friend class HttpHeaderTable;
|
||||
friend class HttpHeaders;
|
||||
};
|
||||
|
||||
class HttpHeaderTable {
|
||||
// Construct an HttpHeaderTable to declare which headers you'll be interested in later on, and
|
||||
// to manufacture IDs for them.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Build a header table with the headers we are interested in.
|
||||
// kj::HttpHeaderTable::Builder builder;
|
||||
// const HttpHeaderId accept = builder.add("Accept");
|
||||
// const HttpHeaderId contentType = builder.add("Content-Type");
|
||||
// kj::HttpHeaderTable table(kj::mv(builder));
|
||||
//
|
||||
// // Create an HTTP client.
|
||||
// auto client = kj::newHttpClient(table, network);
|
||||
//
|
||||
// // Get http://example.com.
|
||||
// HttpHeaders headers(table);
|
||||
// headers.set(accept, "text/html");
|
||||
// auto response = client->send(kj::HttpMethod::GET, "http://example.com", headers)
|
||||
// .wait(waitScope);
|
||||
// auto msg = kj::str("Response content type: ", response.headers.get(contentType));
|
||||
|
||||
struct IdsByNameMap;
|
||||
|
||||
public:
|
||||
HttpHeaderTable();
|
||||
// Constructs a table that only contains the builtin headers.
|
||||
|
||||
class Builder {
|
||||
public:
|
||||
Builder();
|
||||
HttpHeaderId add(kj::StringPtr name);
|
||||
Own<HttpHeaderTable> build();
|
||||
|
||||
HttpHeaderTable& getFutureTable();
|
||||
// Get the still-unbuilt header table. You cannot actually use it until build() has been
|
||||
// called.
|
||||
//
|
||||
// This method exists to help when building a shared header table -- the Builder may be passed
|
||||
// to several components, each of which will register the headers they need and get a reference
|
||||
// to the future table.
|
||||
|
||||
private:
|
||||
kj::Own<HttpHeaderTable> table;
|
||||
};
|
||||
|
||||
KJ_DISALLOW_COPY(HttpHeaderTable); // Can't copy because HttpHeaderId points to the table.
|
||||
~HttpHeaderTable() noexcept(false);
|
||||
|
||||
uint idCount();
|
||||
// Return the number of IDs in the table.
|
||||
|
||||
kj::Maybe<HttpHeaderId> stringToId(kj::StringPtr name);
|
||||
// Try to find an ID for the given name. The matching is case-insensitive, per the HTTP spec.
|
||||
//
|
||||
// Note: if `name` contains characters that aren't allowed in HTTP header names, this may return
|
||||
// a bogus value rather than null, due to optimizations used in case-insensitive matching.
|
||||
|
||||
kj::StringPtr idToString(HttpHeaderId id);
|
||||
// Get the canonical string name for the given ID.
|
||||
|
||||
private:
|
||||
kj::Vector<kj::StringPtr> namesById;
|
||||
kj::Own<IdsByNameMap> idsByName;
|
||||
};
|
||||
|
||||
class HttpHeaders {
|
||||
// Represents a set of HTTP headers.
|
||||
//
|
||||
// This class guards against basic HTTP header injection attacks: Trying to set a header name or
|
||||
// value containing a newline, carriage return, or other invalid character will throw an
|
||||
// exception.
|
||||
|
||||
public:
|
||||
explicit HttpHeaders(HttpHeaderTable& table);
|
||||
|
||||
KJ_DISALLOW_COPY(HttpHeaders);
|
||||
HttpHeaders(HttpHeaders&&) = default;
|
||||
HttpHeaders& operator=(HttpHeaders&&) = default;
|
||||
|
||||
void clear();
|
||||
// Clears all contents, as if the object was freshly-allocated. However, calling this rather
|
||||
// than actually re-allocating the object may avoid re-allocation of internal objects.
|
||||
|
||||
HttpHeaders clone() const;
|
||||
// Creates a deep clone of the HttpHeaders. The returned object owns all strings it references.
|
||||
|
||||
HttpHeaders cloneShallow() const;
|
||||
// Creates a shallow clone of the HttpHeaders. The returned object references the same strings
|
||||
// as the original, owning none of them.
|
||||
|
||||
kj::Maybe<kj::StringPtr> get(HttpHeaderId id) const;
|
||||
// Read a header.
|
||||
|
||||
template <typename Func>
|
||||
void forEach(Func&& func) const;
|
||||
// Calls `func(name, value)` for each header in the set -- including headers that aren't mapped
|
||||
// to IDs in the header table. Both inputs are of type kj::StringPtr.
|
||||
|
||||
void set(HttpHeaderId id, kj::StringPtr value);
|
||||
void set(HttpHeaderId id, kj::String&& value);
|
||||
// Sets a header value, overwriting the existing value.
|
||||
//
|
||||
// The String&& version is equivalent to calling the other version followed by takeOwnership().
|
||||
//
|
||||
// WARNING: It is the caller's responsibility to ensure that `value` remains valid until the
|
||||
// HttpHeaders object is destroyed. This allows string literals to be passed without making a
|
||||
// copy, but complicates the use of dynamic values. Hint: Consider using `takeOwnership()`.
|
||||
|
||||
void add(kj::StringPtr name, kj::StringPtr value);
|
||||
void add(kj::StringPtr name, kj::String&& value);
|
||||
void add(kj::String&& name, kj::String&& value);
|
||||
// Append a header. `name` will be looked up in the header table, but if it's not mapped, the
|
||||
// header will be added to the list of unmapped headers.
|
||||
//
|
||||
// The String&& versions are equivalent to calling the other version followed by takeOwnership().
|
||||
//
|
||||
// WARNING: It is the caller's responsibility to ensure that `name` and `value` remain valid
|
||||
// until the HttpHeaders object is destroyed. This allows string literals to be passed without
|
||||
// making a copy, but complicates the use of dynamic values. Hint: Consider using
|
||||
// `takeOwnership()`.
|
||||
|
||||
void unset(HttpHeaderId id);
|
||||
// Removes a header.
|
||||
//
|
||||
// It's not possible to remove a header by string name because non-indexed headers would take
|
||||
// O(n) time to remove. Instead, construct a new HttpHeaders object and copy contents.
|
||||
|
||||
void takeOwnership(kj::String&& string);
|
||||
void takeOwnership(kj::Array<char>&& chars);
|
||||
void takeOwnership(HttpHeaders&& otherHeaders);
|
||||
// Takes overship of a string so that it lives until the HttpHeaders object is destroyed. Useful
|
||||
// when you've passed a dynamic value to set() or add() or parse*().
|
||||
|
||||
struct ConnectionHeaders {
|
||||
// These headers govern details of the specific HTTP connection or framing of the content.
|
||||
// Hence, they are managed internally within the HTTP library, and never appear in an
|
||||
// HttpHeaders structure.
|
||||
|
||||
#define DECLARE_HEADER(id, name) \
|
||||
kj::StringPtr id;
|
||||
KJ_HTTP_FOR_EACH_CONNECTION_HEADER(DECLARE_HEADER)
|
||||
#undef DECLARE_HEADER
|
||||
};
|
||||
|
||||
struct Request {
|
||||
HttpMethod method;
|
||||
kj::StringPtr url;
|
||||
ConnectionHeaders connectionHeaders;
|
||||
};
|
||||
struct Response {
|
||||
uint statusCode;
|
||||
kj::StringPtr statusText;
|
||||
ConnectionHeaders connectionHeaders;
|
||||
};
|
||||
|
||||
kj::Maybe<Request> tryParseRequest(kj::ArrayPtr<char> content);
|
||||
kj::Maybe<Response> tryParseResponse(kj::ArrayPtr<char> content);
|
||||
// Parse an HTTP header blob and add all the headers to this object.
|
||||
//
|
||||
// `content` should be all text from the start of the request to the first occurrance of two
|
||||
// newlines in a row -- including the first of these two newlines, but excluding the second.
|
||||
//
|
||||
// The parse is performed with zero copies: The callee clobbers `content` with '\0' characters
|
||||
// to split it into a bunch of shorter strings. The caller must keep `content` valid until the
|
||||
// `HttpHeaders` is destroyed, or pass it to `takeOwnership()`.
|
||||
|
||||
kj::String serializeRequest(HttpMethod method, kj::StringPtr url,
|
||||
const ConnectionHeaders& connectionHeaders) const;
|
||||
kj::String serializeResponse(uint statusCode, kj::StringPtr statusText,
|
||||
const ConnectionHeaders& connectionHeaders) const;
|
||||
// Serialize the headers as a complete request or response blob. The blob uses '\r\n' newlines
|
||||
// and includes the double-newline to indicate the end of the headers.
|
||||
|
||||
kj::String toString() const;
|
||||
|
||||
private:
|
||||
HttpHeaderTable* table;
|
||||
|
||||
kj::Array<kj::StringPtr> indexedHeaders;
|
||||
// Size is always table->idCount().
|
||||
|
||||
struct Header {
|
||||
kj::StringPtr name;
|
||||
kj::StringPtr value;
|
||||
};
|
||||
kj::Vector<Header> unindexedHeaders;
|
||||
|
||||
kj::Vector<kj::Array<char>> ownedStrings;
|
||||
|
||||
kj::Maybe<uint> addNoCheck(kj::StringPtr name, kj::StringPtr value);
|
||||
|
||||
kj::StringPtr cloneToOwn(kj::StringPtr str);
|
||||
|
||||
kj::String serialize(kj::ArrayPtr<const char> word1,
|
||||
kj::ArrayPtr<const char> word2,
|
||||
kj::ArrayPtr<const char> word3,
|
||||
const ConnectionHeaders& connectionHeaders) const;
|
||||
|
||||
bool parseHeaders(char* ptr, char* end, ConnectionHeaders& connectionHeaders);
|
||||
|
||||
// TODO(perf): Arguably we should store a map, but header sets are never very long
|
||||
// TODO(perf): We could optimize for common headers by storing them directly as fields. We could
|
||||
// also add direct accessors for those headers.
|
||||
};
|
||||
|
||||
class WebSocket {
|
||||
public:
|
||||
WebSocket(kj::Own<kj::AsyncIoStream> stream);
|
||||
// Create a WebSocket wrapping the given I/O stream.
|
||||
|
||||
kj::Promise<void> send(kj::ArrayPtr<const byte> message);
|
||||
kj::Promise<void> send(kj::ArrayPtr<const char> message);
|
||||
};
|
||||
|
||||
class HttpClient {
|
||||
// Interface to the client end of an HTTP connection.
|
||||
//
|
||||
// There are two kinds of clients:
|
||||
// * Host clients are used when talking to a specific host. The `url` specified in a request
|
||||
// is actually just a path. (A `Host` header is still required in all requests.)
|
||||
// * Proxy clients are used when the target could be any arbitrary host on the internet.
|
||||
// The `url` specified in a request is a full URL including protocol and hostname.
|
||||
|
||||
public:
|
||||
struct Response {
|
||||
uint statusCode;
|
||||
kj::StringPtr statusText;
|
||||
const HttpHeaders* headers;
|
||||
kj::Own<kj::AsyncInputStream> body;
|
||||
// `statusText` and `headers` remain valid until `body` is dropped.
|
||||
};
|
||||
|
||||
struct Request {
|
||||
kj::Own<kj::AsyncOutputStream> body;
|
||||
// Write the request entity body to this stream, then drop it when done.
|
||||
//
|
||||
// May be null for GET and HEAD requests (which have no body) and requests that have
|
||||
// Content-Length: 0.
|
||||
|
||||
kj::Promise<Response> response;
|
||||
// Promise for the eventual respnose.
|
||||
};
|
||||
|
||||
virtual Request request(HttpMethod method, kj::StringPtr url, const HttpHeaders& headers,
|
||||
kj::Maybe<uint64_t> expectedBodySize = nullptr) = 0;
|
||||
// Perform an HTTP request.
|
||||
//
|
||||
// `url` may be a full URL (with protocol and host) or it may be only the path part of the URL,
|
||||
// depending on whether the client is a proxy client or a host client.
|
||||
//
|
||||
// `url` and `headers` need only remain valid until `request()` returns (they can be
|
||||
// stack-allocated).
|
||||
//
|
||||
// `expectedBodySize`, if provided, must be exactly the number of bytes that will be written to
|
||||
// the body. This will trigger use of the `Content-Length` connection header. Otherwise,
|
||||
// `Transfer-Encoding: chunked` will be used.
|
||||
|
||||
struct WebSocketResponse {
|
||||
uint statusCode;
|
||||
kj::StringPtr statusText;
|
||||
const HttpHeaders* headers;
|
||||
kj::OneOf<kj::Own<kj::AsyncInputStream>, kj::Own<WebSocket>> upstreamOrBody;
|
||||
// `statusText` and `headers` remain valid until `upstreamOrBody` is dropped.
|
||||
};
|
||||
virtual kj::Promise<WebSocketResponse> openWebSocket(
|
||||
kj::StringPtr url, const HttpHeaders& headers, kj::Own<WebSocket> downstream);
|
||||
// Tries to open a WebSocket. Default implementation calls send() and never returns a WebSocket.
|
||||
//
|
||||
// `url` and `headers` are invalidated when the returned promise resolves.
|
||||
|
||||
virtual kj::Promise<kj::Own<kj::AsyncIoStream>> connect(kj::String host);
|
||||
// Handles CONNECT requests. Only relevant for proxy clients. Default implementation throws
|
||||
// UNIMPLEMENTED.
|
||||
};
|
||||
|
||||
class HttpService {
|
||||
// Interface which HTTP services should implement.
|
||||
//
|
||||
// This interface is functionally equivalent to HttpClient, but is intended for applications to
|
||||
// implement rather than call. The ergonomics and performance of the method signatures are
|
||||
// optimized for the serving end.
|
||||
//
|
||||
// As with clients, there are two kinds of services:
|
||||
// * Host services are used when talking to a specific host. The `url` specified in a request
|
||||
// is actually just a path. (A `Host` header is still required in all requests, and the service
|
||||
// may in fact serve multiple origins via this header.)
|
||||
// * Proxy services are used when the target could be any arbitrary host on the internet, i.e. to
|
||||
// implement an HTTP proxy. The `url` specified in a request is a full URL including protocol
|
||||
// and hostname.
|
||||
|
||||
public:
|
||||
class Response {
|
||||
public:
|
||||
virtual kj::Own<kj::AsyncOutputStream> send(
|
||||
uint statusCode, kj::StringPtr statusText, const HttpHeaders& headers,
|
||||
kj::Maybe<uint64_t> expectedBodySize = nullptr) = 0;
|
||||
// Begin the response.
|
||||
//
|
||||
// `statusText` and `headers` need only remain valid until send() returns (they can be
|
||||
// stack-allocated).
|
||||
};
|
||||
|
||||
virtual kj::Promise<void> request(
|
||||
HttpMethod method, kj::StringPtr url, const HttpHeaders& headers,
|
||||
kj::AsyncInputStream& requestBody, Response& response) = 0;
|
||||
// Perform an HTTP request.
|
||||
//
|
||||
// `url` may be a full URL (with protocol and host) or it may be only the path part of the URL,
|
||||
// depending on whether the service is a proxy service or a host service.
|
||||
//
|
||||
// `url` and `headers` are invalidated on the first read from `requestBody` or when the returned
|
||||
// promise resolves, whichever comes first.
|
||||
|
||||
class WebSocketResponse: public Response {
|
||||
public:
|
||||
kj::Own<WebSocket> startWebSocket(
|
||||
uint statusCode, kj::StringPtr statusText, const HttpHeaders& headers,
|
||||
WebSocket& upstream);
|
||||
// Begin the response.
|
||||
//
|
||||
// `statusText` and `headers` need only remain valid until startWebSocket() returns (they can
|
||||
// be stack-allocated).
|
||||
};
|
||||
|
||||
virtual kj::Promise<void> openWebSocket(
|
||||
kj::StringPtr url, const HttpHeaders& headers, WebSocketResponse& response);
|
||||
// Tries to open a WebSocket. Default implementation calls request() and never returns a
|
||||
// WebSocket.
|
||||
//
|
||||
// `url` and `headers` are invalidated when the returned promise resolves.
|
||||
|
||||
virtual kj::Promise<kj::Own<kj::AsyncIoStream>> connect(kj::String host);
|
||||
// Handles CONNECT requests. Only relevant for proxy services. Default implementation throws
|
||||
// UNIMPLEMENTED.
|
||||
};
|
||||
|
||||
kj::Own<HttpClient> newHttpClient(HttpHeaderTable& responseHeaderTable, kj::Network& network,
|
||||
kj::Maybe<kj::Network&> tlsNetwork = nullptr);
|
||||
// Creates a proxy HttpClient that connects to hosts over the given network.
|
||||
//
|
||||
// `responseHeaderTable` is used when parsing HTTP responses. Requests can use any header table.
|
||||
//
|
||||
// `tlsNetwork` is required to support HTTPS destination URLs. Otherwise, only HTTP URLs can be
|
||||
// fetched.
|
||||
|
||||
kj::Own<HttpClient> newHttpClient(HttpHeaderTable& responseHeaderTable, kj::AsyncIoStream& stream);
|
||||
// Creates an HttpClient that speaks over the given pre-established connection. The client may
|
||||
// be used as a proxy client or a host client depending on whether the peer is operating as
|
||||
// a proxy.
|
||||
//
|
||||
// Note that since this client has only one stream to work with, it will try to pipeline all
|
||||
// requests on this stream. If one request or response has an I/O failure, all subsequent requests
|
||||
// fail as well. If the destination server chooses to close the connection after a response,
|
||||
// subsequent requests will fail. If a response takes a long time, it blocks subsequent responses.
|
||||
// If a WebSocket is opened successfully, all subsequent requests fail.
|
||||
|
||||
kj::Own<HttpClient> newHttpClient(HttpService& service);
|
||||
kj::Own<HttpService> newHttpService(HttpClient& client);
|
||||
// Adapts an HttpClient to an HttpService and vice versa.
|
||||
|
||||
struct HttpServerSettings {
|
||||
kj::Duration headerTimeout = 15 * kj::SECONDS;
|
||||
// After initial connection open, or after receiving the first byte of a pipelined request,
|
||||
// the client must send the complete request within this time.
|
||||
|
||||
kj::Duration pipelineTimeout = 5 * kj::SECONDS;
|
||||
// After one request/response completes, we'll wait up to this long for a pipelined request to
|
||||
// arrive.
|
||||
};
|
||||
|
||||
class HttpServer: private kj::TaskSet::ErrorHandler {
|
||||
// Class which listens for requests on ports or connections and sends them to an HttpService.
|
||||
|
||||
public:
|
||||
typedef HttpServerSettings Settings;
|
||||
|
||||
HttpServer(kj::Timer& timer, HttpHeaderTable& requestHeaderTable, HttpService& service,
|
||||
Settings settings = Settings());
|
||||
// Set up an HttpServer that directs incoming connections to the given service. The service
|
||||
// may be a host service or a proxy service depending on whether you are intending to implement
|
||||
// an HTTP server or an HTTP proxy.
|
||||
|
||||
kj::Promise<void> drain();
|
||||
// Stop accepting new connections or new requests on existing connections. Finish any requests
|
||||
// that are already executing, then close the connections. Returns once no more requests are
|
||||
// in-flight.
|
||||
|
||||
kj::Promise<void> listenHttp(kj::ConnectionReceiver& port);
|
||||
// Accepts HTTP connections on the given port and directs them to the handler.
|
||||
//
|
||||
// The returned promise never completes normally. It may throw if port.accept() throws. Dropping
|
||||
// the returned promise will cause the server to stop listening on the port, but already-open
|
||||
// connections will continue to be served. Destroy the whole HttpServer to cancel all I/O.
|
||||
|
||||
kj::Promise<void> listenHttp(kj::Own<kj::AsyncIoStream> connection);
|
||||
// Reads HTTP requests from the given connection and directs them to the handler. A successful
|
||||
// completion of the promise indicates that all requests received on the connection resulted in
|
||||
// a complete response, and the client closed the connection gracefully or drain() was called.
|
||||
// The promise throws if an unparseable request is received or if some I/O error occurs. Dropping
|
||||
// the returned promise will cancel all I/O on the connection and cancel any in-flight requests.
|
||||
|
||||
private:
|
||||
class Connection;
|
||||
|
||||
kj::Timer& timer;
|
||||
HttpHeaderTable& requestHeaderTable;
|
||||
HttpService& service;
|
||||
Settings settings;
|
||||
|
||||
bool draining = false;
|
||||
kj::ForkedPromise<void> onDrain;
|
||||
kj::Own<kj::PromiseFulfiller<void>> drainFulfiller;
|
||||
|
||||
uint connectionCount = 0;
|
||||
kj::Maybe<kj::Own<kj::PromiseFulfiller<void>>> zeroConnectionsFulfiller;
|
||||
|
||||
kj::TaskSet tasks;
|
||||
|
||||
HttpServer(kj::Timer& timer, HttpHeaderTable& requestHeaderTable, HttpService& service,
|
||||
Settings settings, kj::PromiseFulfillerPair<void> paf);
|
||||
|
||||
kj::Promise<void> listenLoop(kj::ConnectionReceiver& port);
|
||||
|
||||
void taskFailed(kj::Exception&& exception) override;
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
// inline implementation
|
||||
|
||||
inline void HttpHeaderId::requireFrom(HttpHeaderTable& table) const {
|
||||
KJ_IREQUIRE(this->table == nullptr || this->table == &table,
|
||||
"the provided HttpHeaderId is from the wrong HttpHeaderTable");
|
||||
}
|
||||
|
||||
inline kj::Own<HttpHeaderTable> HttpHeaderTable::Builder::build() { return kj::mv(table); }
|
||||
inline HttpHeaderTable& HttpHeaderTable::Builder::getFutureTable() { return *table; }
|
||||
|
||||
inline uint HttpHeaderTable::idCount() { return namesById.size(); }
|
||||
|
||||
inline kj::StringPtr HttpHeaderTable::idToString(HttpHeaderId id) {
|
||||
id.requireFrom(*this);
|
||||
return namesById[id.id];
|
||||
}
|
||||
|
||||
inline kj::Maybe<kj::StringPtr> HttpHeaders::get(HttpHeaderId id) const {
|
||||
id.requireFrom(*table);
|
||||
auto result = indexedHeaders[id.id];
|
||||
return result == nullptr ? kj::Maybe<kj::StringPtr>(nullptr) : result;
|
||||
}
|
||||
|
||||
inline void HttpHeaders::unset(HttpHeaderId id) {
|
||||
id.requireFrom(*table);
|
||||
indexedHeaders[id.id] = nullptr;
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
inline void HttpHeaders::forEach(Func&& func) const {
|
||||
for (auto i: kj::indices(indexedHeaders)) {
|
||||
if (indexedHeaders[i] != nullptr) {
|
||||
func(table->idToString(HttpHeaderId(table, i)), indexedHeaders[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& header: unindexedHeaders) {
|
||||
func(header.name, header.value);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace kj
|
||||
|
||||
#endif // KJ_COMPAT_HTTP_H_
|
||||
@@ -0,0 +1,555 @@
|
||||
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// This file declares convenient macros for debug logging and error handling. The macros make
|
||||
// it excessively easy to extract useful context information from code. Example:
|
||||
//
|
||||
// KJ_ASSERT(a == b, a, b, "a and b must be the same.");
|
||||
//
|
||||
// On failure, this will throw an exception whose description looks like:
|
||||
//
|
||||
// myfile.c++:43: bug in code: expected a == b; a = 14; b = 72; a and b must be the same.
|
||||
//
|
||||
// As you can see, all arguments after the first provide additional context.
|
||||
//
|
||||
// The macros available are:
|
||||
//
|
||||
// * `KJ_LOG(severity, ...)`: Just writes a log message, to stderr by default (but you can
|
||||
// intercept messages by implementing an ExceptionCallback). `severity` is `INFO`, `WARNING`,
|
||||
// `ERROR`, or `FATAL`. By default, `INFO` logs are not written, but for command-line apps the
|
||||
// user should be able to pass a flag like `--verbose` to enable them. Other log levels are
|
||||
// enabled by default. Log messages -- like exceptions -- can be intercepted by registering an
|
||||
// ExceptionCallback.
|
||||
//
|
||||
// * `KJ_DBG(...)`: Like `KJ_LOG`, but intended specifically for temporary log lines added while
|
||||
// debugging a particular problem. Calls to `KJ_DBG` should always be deleted before committing
|
||||
// code. It is suggested that you set up a pre-commit hook that checks for this.
|
||||
//
|
||||
// * `KJ_ASSERT(condition, ...)`: Throws an exception if `condition` is false, or aborts if
|
||||
// exceptions are disabled. This macro should be used to check for bugs in the surrounding code
|
||||
// and its dependencies, but NOT to check for invalid input. The macro may be followed by a
|
||||
// brace-delimited code block; if so, the block will be executed in the case where the assertion
|
||||
// fails, before throwing the exception. If control jumps out of the block (e.g. with "break",
|
||||
// "return", or "goto"), then the error is considered "recoverable" -- in this case, if
|
||||
// exceptions are disabled, execution will continue normally rather than aborting (but if
|
||||
// exceptions are enabled, an exception will still be thrown on exiting the block). A "break"
|
||||
// statement in particular will jump to the code immediately after the block (it does not break
|
||||
// any surrounding loop or switch). Example:
|
||||
//
|
||||
// KJ_ASSERT(value >= 0, "Value cannot be negative.", value) {
|
||||
// // Assertion failed. Set value to zero to "recover".
|
||||
// value = 0;
|
||||
// // Don't abort if exceptions are disabled. Continue normally.
|
||||
// // (Still throw an exception if they are enabled, though.)
|
||||
// break;
|
||||
// }
|
||||
// // When exceptions are disabled, we'll get here even if the assertion fails.
|
||||
// // Otherwise, we get here only if the assertion passes.
|
||||
//
|
||||
// * `KJ_REQUIRE(condition, ...)`: Like `KJ_ASSERT` but used to check preconditions -- e.g. to
|
||||
// validate parameters passed from a caller. A failure indicates that the caller is buggy.
|
||||
//
|
||||
// * `KJ_SYSCALL(code, ...)`: Executes `code` assuming it makes a system call. A negative result
|
||||
// is considered an error, with error code reported via `errno`. EINTR is handled by retrying.
|
||||
// Other errors are handled by throwing an exception. If you need to examine the return code,
|
||||
// assign it to a variable like so:
|
||||
//
|
||||
// int fd;
|
||||
// KJ_SYSCALL(fd = open(filename, O_RDONLY), filename);
|
||||
//
|
||||
// `KJ_SYSCALL` can be followed by a recovery block, just like `KJ_ASSERT`.
|
||||
//
|
||||
// * `KJ_NONBLOCKING_SYSCALL(code, ...)`: Like KJ_SYSCALL, but will not throw an exception on
|
||||
// EAGAIN/EWOULDBLOCK. The calling code should check the syscall's return value to see if it
|
||||
// indicates an error; in this case, it can assume the error was EAGAIN because any other error
|
||||
// would have caused an exception to be thrown.
|
||||
//
|
||||
// * `KJ_CONTEXT(...)`: Notes additional contextual information relevant to any exceptions thrown
|
||||
// from within the current scope. That is, until control exits the block in which KJ_CONTEXT()
|
||||
// is used, if any exception is generated, it will contain the given information in its context
|
||||
// chain. This is helpful because it can otherwise be very difficult to come up with error
|
||||
// messages that make sense within low-level helper code. Note that the parameters to
|
||||
// KJ_CONTEXT() are only evaluated if an exception is thrown. This implies that any variables
|
||||
// used must remain valid until the end of the scope.
|
||||
//
|
||||
// Notes:
|
||||
// * Do not write expressions with side-effects in the message content part of the macro, as the
|
||||
// message will not necessarily be evaluated.
|
||||
// * For every macro `FOO` above except `LOG`, there is also a `FAIL_FOO` macro used to report
|
||||
// failures that already happened. For the macros that check a boolean condition, `FAIL_FOO`
|
||||
// omits the first parameter and behaves like it was `false`. `FAIL_SYSCALL` and
|
||||
// `FAIL_RECOVERABLE_SYSCALL` take a string and an OS error number as the first two parameters.
|
||||
// The string should be the name of the failed system call.
|
||||
// * For every macro `FOO` above, there is a `DFOO` version (or `RECOVERABLE_DFOO`) which is only
|
||||
// executed in debug mode, i.e. when KJ_DEBUG is defined. KJ_DEBUG is defined automatically
|
||||
// by common.h when compiling without optimization (unless NDEBUG is defined), but you can also
|
||||
// define it explicitly (e.g. -DKJ_DEBUG). Generally, production builds should NOT use KJ_DEBUG
|
||||
// as it may enable expensive checks that are unlikely to fail.
|
||||
|
||||
#ifndef KJ_DEBUG_H_
|
||||
#define KJ_DEBUG_H_
|
||||
|
||||
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include "string.h"
|
||||
#include "exception.h"
|
||||
|
||||
#ifdef ERROR
|
||||
// This is problematic because windows.h #defines ERROR, which we use in an enum here.
|
||||
#error "Make sure to to undefine ERROR (or just #include <kj/windows-sanity.h>) before this file"
|
||||
#endif
|
||||
|
||||
namespace kj {
|
||||
|
||||
#if _MSC_VER
|
||||
// MSVC does __VA_ARGS__ differently from GCC:
|
||||
// - A trailing comma before an empty __VA_ARGS__ is removed automatically, whereas GCC wants
|
||||
// you to request this behavior with "##__VA_ARGS__".
|
||||
// - If __VA_ARGS__ is passed directly as an argument to another macro, it will be treated as a
|
||||
// *single* argument rather than an argument list. This can be worked around by wrapping the
|
||||
// outer macro call in KJ_EXPAND(), which appraently forces __VA_ARGS__ to be expanded before
|
||||
// the macro is evaluated. I don't understand the C preprocessor.
|
||||
// - Using "#__VA_ARGS__" to stringify __VA_ARGS__ expands to zero tokens when __VA_ARGS__ is
|
||||
// empty, rather than expanding to an empty string literal. We can work around by concatenating
|
||||
// with an empty string literal.
|
||||
|
||||
#define KJ_EXPAND(X) X
|
||||
|
||||
#define KJ_LOG(severity, ...) \
|
||||
if (!::kj::_::Debug::shouldLog(::kj::LogSeverity::severity)) {} else \
|
||||
::kj::_::Debug::log(__FILE__, __LINE__, ::kj::LogSeverity::severity, \
|
||||
"" #__VA_ARGS__, __VA_ARGS__)
|
||||
|
||||
#define KJ_DBG(...) KJ_EXPAND(KJ_LOG(DBG, __VA_ARGS__))
|
||||
|
||||
#define KJ_REQUIRE(cond, ...) \
|
||||
if (KJ_LIKELY(cond)) {} else \
|
||||
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \
|
||||
#cond, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
|
||||
|
||||
#define KJ_FAIL_REQUIRE(...) \
|
||||
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \
|
||||
nullptr, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
|
||||
|
||||
#define KJ_SYSCALL(call, ...) \
|
||||
if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, false)) {} else \
|
||||
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
|
||||
_kjSyscallResult.getErrorNumber(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
|
||||
|
||||
#define KJ_NONBLOCKING_SYSCALL(call, ...) \
|
||||
if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, true)) {} else \
|
||||
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
|
||||
_kjSyscallResult.getErrorNumber(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
|
||||
|
||||
#define KJ_FAIL_SYSCALL(code, errorNumber, ...) \
|
||||
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
|
||||
errorNumber, code, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
|
||||
|
||||
#if _WIN32
|
||||
|
||||
#define KJ_WIN32(call, ...) \
|
||||
if (::kj::_::Debug::isWin32Success(call)) {} else \
|
||||
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
|
||||
::kj::_::Debug::getWin32Error(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
|
||||
|
||||
#define KJ_WINSOCK(call, ...) \
|
||||
if ((call) != SOCKET_ERROR) {} else \
|
||||
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
|
||||
::kj::_::Debug::getWin32Error(), #call, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
|
||||
|
||||
#define KJ_FAIL_WIN32(code, errorNumber, ...) \
|
||||
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
|
||||
::kj::_::Debug::Win32Error(errorNumber), code, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
|
||||
|
||||
#endif
|
||||
|
||||
#define KJ_UNIMPLEMENTED(...) \
|
||||
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::UNIMPLEMENTED, \
|
||||
nullptr, "" #__VA_ARGS__, __VA_ARGS__);; f.fatal())
|
||||
|
||||
// TODO(msvc): MSVC mis-deduces `ContextImpl<decltype(func)>` as `ContextImpl<int>` in some edge
|
||||
// cases, such as inside nested lambdas inside member functions. Wrapping the type in
|
||||
// `decltype(instance<...>())` helps it deduce the context function's type correctly.
|
||||
#define KJ_CONTEXT(...) \
|
||||
auto KJ_UNIQUE_NAME(_kjContextFunc) = [&]() -> ::kj::_::Debug::Context::Value { \
|
||||
return ::kj::_::Debug::Context::Value(__FILE__, __LINE__, \
|
||||
::kj::_::Debug::makeDescription("" #__VA_ARGS__, __VA_ARGS__)); \
|
||||
}; \
|
||||
decltype(::kj::instance<::kj::_::Debug::ContextImpl<decltype(KJ_UNIQUE_NAME(_kjContextFunc))>>()) \
|
||||
KJ_UNIQUE_NAME(_kjContext)(KJ_UNIQUE_NAME(_kjContextFunc))
|
||||
|
||||
#define KJ_REQUIRE_NONNULL(value, ...) \
|
||||
(*[&] { \
|
||||
auto _kj_result = ::kj::_::readMaybe(value); \
|
||||
if (KJ_UNLIKELY(!_kj_result)) { \
|
||||
::kj::_::Debug::Fault(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \
|
||||
#value " != nullptr", "" #__VA_ARGS__, __VA_ARGS__).fatal(); \
|
||||
} \
|
||||
return _kj_result; \
|
||||
}())
|
||||
|
||||
#define KJ_EXCEPTION(type, ...) \
|
||||
::kj::Exception(::kj::Exception::Type::type, __FILE__, __LINE__, \
|
||||
::kj::_::Debug::makeDescription("" #__VA_ARGS__, __VA_ARGS__))
|
||||
|
||||
#else
|
||||
|
||||
#define KJ_LOG(severity, ...) \
|
||||
if (!::kj::_::Debug::shouldLog(::kj::LogSeverity::severity)) {} else \
|
||||
::kj::_::Debug::log(__FILE__, __LINE__, ::kj::LogSeverity::severity, \
|
||||
#__VA_ARGS__, ##__VA_ARGS__)
|
||||
|
||||
#define KJ_DBG(...) KJ_LOG(DBG, ##__VA_ARGS__)
|
||||
|
||||
#define KJ_REQUIRE(cond, ...) \
|
||||
if (KJ_LIKELY(cond)) {} else \
|
||||
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \
|
||||
#cond, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
|
||||
|
||||
#define KJ_FAIL_REQUIRE(...) \
|
||||
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \
|
||||
nullptr, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
|
||||
|
||||
#define KJ_SYSCALL(call, ...) \
|
||||
if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, false)) {} else \
|
||||
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
|
||||
_kjSyscallResult.getErrorNumber(), #call, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
|
||||
|
||||
#define KJ_NONBLOCKING_SYSCALL(call, ...) \
|
||||
if (auto _kjSyscallResult = ::kj::_::Debug::syscall([&](){return (call);}, true)) {} else \
|
||||
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
|
||||
_kjSyscallResult.getErrorNumber(), #call, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
|
||||
|
||||
#define KJ_FAIL_SYSCALL(code, errorNumber, ...) \
|
||||
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
|
||||
errorNumber, code, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
|
||||
|
||||
#if _WIN32
|
||||
|
||||
#define KJ_WIN32(call, ...) \
|
||||
if (::kj::_::Debug::isWin32Success(call)) {} else \
|
||||
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
|
||||
::kj::_::Debug::getWin32Error(), #call, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
|
||||
|
||||
#define KJ_WINSOCK(call, ...) \
|
||||
if ((call) != SOCKET_ERROR) {} else \
|
||||
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
|
||||
::kj::_::Debug::getWin32Error(), #call, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
|
||||
|
||||
#define KJ_FAIL_WIN32(code, errorNumber, ...) \
|
||||
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, \
|
||||
::kj::_::Debug::Win32Error(errorNumber), code, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
|
||||
|
||||
#endif
|
||||
|
||||
#define KJ_UNIMPLEMENTED(...) \
|
||||
for (::kj::_::Debug::Fault f(__FILE__, __LINE__, ::kj::Exception::Type::UNIMPLEMENTED, \
|
||||
nullptr, #__VA_ARGS__, ##__VA_ARGS__);; f.fatal())
|
||||
|
||||
#define KJ_CONTEXT(...) \
|
||||
auto KJ_UNIQUE_NAME(_kjContextFunc) = [&]() -> ::kj::_::Debug::Context::Value { \
|
||||
return ::kj::_::Debug::Context::Value(__FILE__, __LINE__, \
|
||||
::kj::_::Debug::makeDescription(#__VA_ARGS__, ##__VA_ARGS__)); \
|
||||
}; \
|
||||
::kj::_::Debug::ContextImpl<decltype(KJ_UNIQUE_NAME(_kjContextFunc))> \
|
||||
KJ_UNIQUE_NAME(_kjContext)(KJ_UNIQUE_NAME(_kjContextFunc))
|
||||
|
||||
#define KJ_REQUIRE_NONNULL(value, ...) \
|
||||
(*({ \
|
||||
auto _kj_result = ::kj::_::readMaybe(value); \
|
||||
if (KJ_UNLIKELY(!_kj_result)) { \
|
||||
::kj::_::Debug::Fault(__FILE__, __LINE__, ::kj::Exception::Type::FAILED, \
|
||||
#value " != nullptr", #__VA_ARGS__, ##__VA_ARGS__).fatal(); \
|
||||
} \
|
||||
kj::mv(_kj_result); \
|
||||
}))
|
||||
|
||||
#define KJ_EXCEPTION(type, ...) \
|
||||
::kj::Exception(::kj::Exception::Type::type, __FILE__, __LINE__, \
|
||||
::kj::_::Debug::makeDescription(#__VA_ARGS__, ##__VA_ARGS__))
|
||||
|
||||
#endif
|
||||
|
||||
#define KJ_SYSCALL_HANDLE_ERRORS(call) \
|
||||
if (int _kjSyscallError = ::kj::_::Debug::syscallError([&](){return (call);}, false)) \
|
||||
switch (int error = _kjSyscallError)
|
||||
// Like KJ_SYSCALL, but doesn't throw. Instead, the block after the macro is a switch block on the
|
||||
// error. Additionally, the int value `error` is defined within the block. So you can do:
|
||||
//
|
||||
// KJ_SYSCALL_HANDLE_ERRORS(foo()) {
|
||||
// case ENOENT:
|
||||
// handleNoSuchFile();
|
||||
// break;
|
||||
// case EEXIST:
|
||||
// handleExists();
|
||||
// break;
|
||||
// default:
|
||||
// KJ_FAIL_SYSCALL("foo()", error);
|
||||
// } else {
|
||||
// handleSuccessCase();
|
||||
// }
|
||||
|
||||
#define KJ_ASSERT KJ_REQUIRE
|
||||
#define KJ_FAIL_ASSERT KJ_FAIL_REQUIRE
|
||||
#define KJ_ASSERT_NONNULL KJ_REQUIRE_NONNULL
|
||||
// Use "ASSERT" in place of "REQUIRE" when the problem is local to the immediate surrounding code.
|
||||
// That is, if the assert ever fails, it indicates that the immediate surrounding code is broken.
|
||||
|
||||
#ifdef KJ_DEBUG
|
||||
#define KJ_DLOG KJ_LOG
|
||||
#define KJ_DASSERT KJ_ASSERT
|
||||
#define KJ_DREQUIRE KJ_REQUIRE
|
||||
#else
|
||||
#define KJ_DLOG(...) do {} while (false)
|
||||
#define KJ_DASSERT(...) do {} while (false)
|
||||
#define KJ_DREQUIRE(...) do {} while (false)
|
||||
#endif
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
class Debug {
|
||||
public:
|
||||
Debug() = delete;
|
||||
|
||||
typedef LogSeverity Severity; // backwards-compatibility
|
||||
|
||||
#if _WIN32
|
||||
struct Win32Error {
|
||||
// Hack for overloading purposes.
|
||||
uint number;
|
||||
inline explicit Win32Error(uint number): number(number) {}
|
||||
};
|
||||
#endif
|
||||
|
||||
static inline bool shouldLog(LogSeverity severity) { return severity >= minSeverity; }
|
||||
// Returns whether messages of the given severity should be logged.
|
||||
|
||||
static inline void setLogLevel(LogSeverity severity) { minSeverity = severity; }
|
||||
// Set the minimum message severity which will be logged.
|
||||
//
|
||||
// TODO(someday): Expose publicly.
|
||||
|
||||
template <typename... Params>
|
||||
static void log(const char* file, int line, LogSeverity severity, const char* macroArgs,
|
||||
Params&&... params);
|
||||
|
||||
class Fault {
|
||||
public:
|
||||
template <typename Code, typename... Params>
|
||||
Fault(const char* file, int line, Code code,
|
||||
const char* condition, const char* macroArgs, Params&&... params);
|
||||
Fault(const char* file, int line, Exception::Type type,
|
||||
const char* condition, const char* macroArgs);
|
||||
Fault(const char* file, int line, int osErrorNumber,
|
||||
const char* condition, const char* macroArgs);
|
||||
#if _WIN32
|
||||
Fault(const char* file, int line, Win32Error osErrorNumber,
|
||||
const char* condition, const char* macroArgs);
|
||||
#endif
|
||||
~Fault() noexcept(false);
|
||||
|
||||
KJ_NOINLINE KJ_NORETURN(void fatal());
|
||||
// Throw the exception.
|
||||
|
||||
private:
|
||||
void init(const char* file, int line, Exception::Type type,
|
||||
const char* condition, const char* macroArgs, ArrayPtr<String> argValues);
|
||||
void init(const char* file, int line, int osErrorNumber,
|
||||
const char* condition, const char* macroArgs, ArrayPtr<String> argValues);
|
||||
#if _WIN32
|
||||
void init(const char* file, int line, Win32Error osErrorNumber,
|
||||
const char* condition, const char* macroArgs, ArrayPtr<String> argValues);
|
||||
#endif
|
||||
|
||||
Exception* exception;
|
||||
};
|
||||
|
||||
class SyscallResult {
|
||||
public:
|
||||
inline SyscallResult(int errorNumber): errorNumber(errorNumber) {}
|
||||
inline operator void*() { return errorNumber == 0 ? this : nullptr; }
|
||||
inline int getErrorNumber() { return errorNumber; }
|
||||
|
||||
private:
|
||||
int errorNumber;
|
||||
};
|
||||
|
||||
template <typename Call>
|
||||
static SyscallResult syscall(Call&& call, bool nonblocking);
|
||||
template <typename Call>
|
||||
static int syscallError(Call&& call, bool nonblocking);
|
||||
|
||||
#if _WIN32
|
||||
static bool isWin32Success(int boolean);
|
||||
static bool isWin32Success(void* handle);
|
||||
static Win32Error getWin32Error();
|
||||
#endif
|
||||
|
||||
class Context: public ExceptionCallback {
|
||||
public:
|
||||
Context();
|
||||
KJ_DISALLOW_COPY(Context);
|
||||
virtual ~Context() noexcept(false);
|
||||
|
||||
struct Value {
|
||||
const char* file;
|
||||
int line;
|
||||
String description;
|
||||
|
||||
inline Value(const char* file, int line, String&& description)
|
||||
: file(file), line(line), description(mv(description)) {}
|
||||
};
|
||||
|
||||
virtual Value evaluate() = 0;
|
||||
|
||||
virtual void onRecoverableException(Exception&& exception) override;
|
||||
virtual void onFatalException(Exception&& exception) override;
|
||||
virtual void logMessage(LogSeverity severity, const char* file, int line, int contextDepth,
|
||||
String&& text) override;
|
||||
|
||||
private:
|
||||
bool logged;
|
||||
Maybe<Value> value;
|
||||
|
||||
Value ensureInitialized();
|
||||
};
|
||||
|
||||
template <typename Func>
|
||||
class ContextImpl: public Context {
|
||||
public:
|
||||
inline ContextImpl(Func& func): func(func) {}
|
||||
KJ_DISALLOW_COPY(ContextImpl);
|
||||
|
||||
Value evaluate() override {
|
||||
return func();
|
||||
}
|
||||
private:
|
||||
Func& func;
|
||||
};
|
||||
|
||||
template <typename... Params>
|
||||
static String makeDescription(const char* macroArgs, Params&&... params);
|
||||
|
||||
private:
|
||||
static LogSeverity minSeverity;
|
||||
|
||||
static void logInternal(const char* file, int line, LogSeverity severity, const char* macroArgs,
|
||||
ArrayPtr<String> argValues);
|
||||
static String makeDescriptionInternal(const char* macroArgs, ArrayPtr<String> argValues);
|
||||
|
||||
static int getOsErrorNumber(bool nonblocking);
|
||||
// Get the error code of the last error (e.g. from errno). Returns -1 on EINTR.
|
||||
};
|
||||
|
||||
template <typename... Params>
|
||||
void Debug::log(const char* file, int line, LogSeverity severity, const char* macroArgs,
|
||||
Params&&... params) {
|
||||
String argValues[sizeof...(Params)] = {str(params)...};
|
||||
logInternal(file, line, severity, macroArgs, arrayPtr(argValues, sizeof...(Params)));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void Debug::log<>(const char* file, int line, LogSeverity severity, const char* macroArgs) {
|
||||
logInternal(file, line, severity, macroArgs, nullptr);
|
||||
}
|
||||
|
||||
template <typename Code, typename... Params>
|
||||
Debug::Fault::Fault(const char* file, int line, Code code,
|
||||
const char* condition, const char* macroArgs, Params&&... params)
|
||||
: exception(nullptr) {
|
||||
String argValues[sizeof...(Params)] = {str(params)...};
|
||||
init(file, line, code, condition, macroArgs,
|
||||
arrayPtr(argValues, sizeof...(Params)));
|
||||
}
|
||||
|
||||
inline Debug::Fault::Fault(const char* file, int line, int osErrorNumber,
|
||||
const char* condition, const char* macroArgs)
|
||||
: exception(nullptr) {
|
||||
init(file, line, osErrorNumber, condition, macroArgs, nullptr);
|
||||
}
|
||||
|
||||
inline Debug::Fault::Fault(const char* file, int line, kj::Exception::Type type,
|
||||
const char* condition, const char* macroArgs)
|
||||
: exception(nullptr) {
|
||||
init(file, line, type, condition, macroArgs, nullptr);
|
||||
}
|
||||
|
||||
#if _WIN32
|
||||
inline Debug::Fault::Fault(const char* file, int line, Win32Error osErrorNumber,
|
||||
const char* condition, const char* macroArgs)
|
||||
: exception(nullptr) {
|
||||
init(file, line, osErrorNumber, condition, macroArgs, nullptr);
|
||||
}
|
||||
|
||||
inline bool Debug::isWin32Success(int boolean) {
|
||||
return boolean;
|
||||
}
|
||||
inline bool Debug::isWin32Success(void* handle) {
|
||||
// Assume null and INVALID_HANDLE_VALUE mean failure.
|
||||
return handle != nullptr && handle != (void*)-1;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename Call>
|
||||
Debug::SyscallResult Debug::syscall(Call&& call, bool nonblocking) {
|
||||
while (call() < 0) {
|
||||
int errorNum = getOsErrorNumber(nonblocking);
|
||||
// getOsErrorNumber() returns -1 to indicate EINTR.
|
||||
// Also, if nonblocking is true, then it returns 0 on EAGAIN, which will then be treated as a
|
||||
// non-error.
|
||||
if (errorNum != -1) {
|
||||
return SyscallResult(errorNum);
|
||||
}
|
||||
}
|
||||
return SyscallResult(0);
|
||||
}
|
||||
|
||||
template <typename Call>
|
||||
int Debug::syscallError(Call&& call, bool nonblocking) {
|
||||
while (call() < 0) {
|
||||
int errorNum = getOsErrorNumber(nonblocking);
|
||||
// getOsErrorNumber() returns -1 to indicate EINTR.
|
||||
// Also, if nonblocking is true, then it returns 0 on EAGAIN, which will then be treated as a
|
||||
// non-error.
|
||||
if (errorNum != -1) {
|
||||
return errorNum;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename... Params>
|
||||
String Debug::makeDescription(const char* macroArgs, Params&&... params) {
|
||||
String argValues[sizeof...(Params)] = {str(params)...};
|
||||
return makeDescriptionInternal(macroArgs, arrayPtr(argValues, sizeof...(Params)));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline String Debug::makeDescription<>(const char* macroArgs) {
|
||||
return makeDescriptionInternal(macroArgs, nullptr);
|
||||
}
|
||||
|
||||
} // namespace _ (private)
|
||||
} // namespace kj
|
||||
|
||||
#endif // KJ_DEBUG_H_
|
||||
@@ -0,0 +1,363 @@
|
||||
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef KJ_EXCEPTION_H_
|
||||
#define KJ_EXCEPTION_H_
|
||||
|
||||
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include "memory.h"
|
||||
#include "array.h"
|
||||
#include "string.h"
|
||||
|
||||
namespace kj {
|
||||
|
||||
class ExceptionImpl;
|
||||
|
||||
class Exception {
|
||||
// Exception thrown in case of fatal errors.
|
||||
//
|
||||
// Actually, a subclass of this which also implements std::exception will be thrown, but we hide
|
||||
// that fact from the interface to avoid #including <exception>.
|
||||
|
||||
public:
|
||||
enum class Type {
|
||||
// What kind of failure?
|
||||
|
||||
FAILED = 0,
|
||||
// Something went wrong. This is the usual error type. KJ_ASSERT and KJ_REQUIRE throw this
|
||||
// error type.
|
||||
|
||||
OVERLOADED = 1,
|
||||
// The call failed because of a temporary lack of resources. This could be space resources
|
||||
// (out of memory, out of disk space) or time resources (request queue overflow, operation
|
||||
// timed out).
|
||||
//
|
||||
// The operation might work if tried again, but it should NOT be repeated immediately as this
|
||||
// may simply exacerbate the problem.
|
||||
|
||||
DISCONNECTED = 2,
|
||||
// The call required communication over a connection that has been lost. The callee will need
|
||||
// to re-establish connections and try again.
|
||||
|
||||
UNIMPLEMENTED = 3
|
||||
// The requested method is not implemented. The caller may wish to revert to a fallback
|
||||
// approach based on other methods.
|
||||
|
||||
// IF YOU ADD A NEW VALUE:
|
||||
// - Update the stringifier.
|
||||
// - Update Cap'n Proto's RPC protocol's Exception.Type enum.
|
||||
};
|
||||
|
||||
Exception(Type type, const char* file, int line, String description = nullptr) noexcept;
|
||||
Exception(Type type, String file, int line, String description = nullptr) noexcept;
|
||||
Exception(const Exception& other) noexcept;
|
||||
Exception(Exception&& other) = default;
|
||||
~Exception() noexcept;
|
||||
|
||||
const char* getFile() const { return file; }
|
||||
int getLine() const { return line; }
|
||||
Type getType() const { return type; }
|
||||
StringPtr getDescription() const { return description; }
|
||||
ArrayPtr<void* const> getStackTrace() const { return arrayPtr(trace, traceCount); }
|
||||
|
||||
struct Context {
|
||||
// Describes a bit about what was going on when the exception was thrown.
|
||||
|
||||
const char* file;
|
||||
int line;
|
||||
String description;
|
||||
Maybe<Own<Context>> next;
|
||||
|
||||
Context(const char* file, int line, String&& description, Maybe<Own<Context>>&& next)
|
||||
: file(file), line(line), description(mv(description)), next(mv(next)) {}
|
||||
Context(const Context& other) noexcept;
|
||||
};
|
||||
|
||||
inline Maybe<const Context&> getContext() const {
|
||||
KJ_IF_MAYBE(c, context) {
|
||||
return **c;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void wrapContext(const char* file, int line, String&& description);
|
||||
// Wraps the context in a new node. This becomes the head node returned by getContext() -- it
|
||||
// is expected that contexts will be added in reverse order as the exception passes up the
|
||||
// callback stack.
|
||||
|
||||
KJ_NOINLINE void extendTrace(uint ignoreCount);
|
||||
// Append the current stack trace to the exception's trace, ignoring the first `ignoreCount`
|
||||
// frames (see `getStackTrace()` for discussion of `ignoreCount`).
|
||||
|
||||
KJ_NOINLINE void truncateCommonTrace();
|
||||
// Remove the part of the stack trace which the exception shares with the caller of this method.
|
||||
// This is used by the async library to remove the async infrastructure from the stack trace
|
||||
// before replacing it with the async trace.
|
||||
|
||||
void addTrace(void* ptr);
|
||||
// Append the given pointer to the backtrace, if it is not already full. This is used by the
|
||||
// async library to trace through the promise chain that led to the exception.
|
||||
|
||||
private:
|
||||
String ownFile;
|
||||
const char* file;
|
||||
int line;
|
||||
Type type;
|
||||
String description;
|
||||
Maybe<Own<Context>> context;
|
||||
void* trace[32];
|
||||
uint traceCount;
|
||||
|
||||
friend class ExceptionImpl;
|
||||
};
|
||||
|
||||
StringPtr KJ_STRINGIFY(Exception::Type type);
|
||||
String KJ_STRINGIFY(const Exception& e);
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
enum class LogSeverity {
|
||||
INFO, // Information describing what the code is up to, which users may request to see
|
||||
// with a flag like `--verbose`. Does not indicate a problem. Not printed by
|
||||
// default; you must call setLogLevel(INFO) to enable.
|
||||
WARNING, // A problem was detected but execution can continue with correct output.
|
||||
ERROR, // Something is wrong, but execution can continue with garbage output.
|
||||
FATAL, // Something went wrong, and execution cannot continue.
|
||||
DBG // Temporary debug logging. See KJ_DBG.
|
||||
|
||||
// Make sure to update the stringifier if you add a new severity level.
|
||||
};
|
||||
|
||||
StringPtr KJ_STRINGIFY(LogSeverity severity);
|
||||
|
||||
class ExceptionCallback {
|
||||
// If you don't like C++ exceptions, you may implement and register an ExceptionCallback in order
|
||||
// to perform your own exception handling. For example, a reasonable thing to do is to have
|
||||
// onRecoverableException() set a flag indicating that an error occurred, and then check for that
|
||||
// flag just before writing to storage and/or returning results to the user. If the flag is set,
|
||||
// discard whatever you have and return an error instead.
|
||||
//
|
||||
// ExceptionCallbacks must always be allocated on the stack. When an exception is thrown, the
|
||||
// newest ExceptionCallback on the calling thread's stack is called. The default implementation
|
||||
// of each method calls the next-oldest ExceptionCallback for that thread. Thus the callbacks
|
||||
// behave a lot like try/catch blocks, except that they are called before any stack unwinding
|
||||
// occurs.
|
||||
|
||||
public:
|
||||
ExceptionCallback();
|
||||
KJ_DISALLOW_COPY(ExceptionCallback);
|
||||
virtual ~ExceptionCallback() noexcept(false);
|
||||
|
||||
virtual void onRecoverableException(Exception&& exception);
|
||||
// Called when an exception has been raised, but the calling code has the ability to continue by
|
||||
// producing garbage output. This method _should_ throw the exception, but is allowed to simply
|
||||
// return if garbage output is acceptable.
|
||||
//
|
||||
// The global default implementation throws an exception unless the library was compiled with
|
||||
// -fno-exceptions, in which case it logs an error and returns.
|
||||
|
||||
virtual void onFatalException(Exception&& exception);
|
||||
// Called when an exception has been raised and the calling code cannot continue. If this method
|
||||
// returns normally, abort() will be called. The method must throw the exception to avoid
|
||||
// aborting.
|
||||
//
|
||||
// The global default implementation throws an exception unless the library was compiled with
|
||||
// -fno-exceptions, in which case it logs an error and returns.
|
||||
|
||||
virtual void logMessage(LogSeverity severity, const char* file, int line, int contextDepth,
|
||||
String&& text);
|
||||
// Called when something wants to log some debug text. `contextDepth` indicates how many levels
|
||||
// of context the message passed through; it may make sense to indent the message accordingly.
|
||||
//
|
||||
// The global default implementation writes the text to stderr.
|
||||
|
||||
enum class StackTraceMode {
|
||||
FULL,
|
||||
// Stringifying a stack trace will attempt to determine source file and line numbers. This may
|
||||
// be expensive. For example, on Linux, this shells out to `addr2line`.
|
||||
//
|
||||
// This is the default in debug builds.
|
||||
|
||||
ADDRESS_ONLY,
|
||||
// Stringifying a stack trace will only generate a list of code addresses.
|
||||
//
|
||||
// This is the default in release builds.
|
||||
|
||||
NONE
|
||||
// Generating a stack trace will always return an empty array.
|
||||
//
|
||||
// This avoids ever unwinding the stack. On Windows in particular, the stack unwinding library
|
||||
// has been observed to be pretty slow, so exception-heavy code might benefit significantly
|
||||
// from this setting. (But exceptions should be rare...)
|
||||
};
|
||||
|
||||
virtual StackTraceMode stackTraceMode();
|
||||
// Returns the current preferred stack trace mode.
|
||||
|
||||
protected:
|
||||
ExceptionCallback& next;
|
||||
|
||||
private:
|
||||
ExceptionCallback(ExceptionCallback& next);
|
||||
|
||||
class RootExceptionCallback;
|
||||
friend ExceptionCallback& getExceptionCallback();
|
||||
};
|
||||
|
||||
ExceptionCallback& getExceptionCallback();
|
||||
// Returns the current exception callback.
|
||||
|
||||
KJ_NOINLINE KJ_NORETURN(void throwFatalException(kj::Exception&& exception, uint ignoreCount = 0));
|
||||
// Invoke the exception callback to throw the given fatal exception. If the exception callback
|
||||
// returns, abort.
|
||||
|
||||
KJ_NOINLINE void throwRecoverableException(kj::Exception&& exception, uint ignoreCount = 0);
|
||||
// Invoke the exception callback to throw the given recoverable exception. If the exception
|
||||
// callback returns, return normally.
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
namespace _ { class Runnable; }
|
||||
|
||||
template <typename Func>
|
||||
Maybe<Exception> runCatchingExceptions(Func&& func) noexcept;
|
||||
// Executes the given function (usually, a lambda returning nothing) catching any exceptions that
|
||||
// are thrown. Returns the Exception if there was one, or null if the operation completed normally.
|
||||
// Non-KJ exceptions will be wrapped.
|
||||
//
|
||||
// If exception are disabled (e.g. with -fno-exceptions), this will still detect whether any
|
||||
// recoverable exceptions occurred while running the function and will return those.
|
||||
|
||||
class UnwindDetector {
|
||||
// Utility for detecting when a destructor is called due to unwind. Useful for:
|
||||
// - Avoiding throwing exceptions in this case, which would terminate the program.
|
||||
// - Detecting whether to commit or roll back a transaction.
|
||||
//
|
||||
// To use this class, either inherit privately from it or declare it as a member. The detector
|
||||
// works by comparing the exception state against that when the constructor was called, so for
|
||||
// an object that was actually constructed during exception unwind, it will behave as if no
|
||||
// unwind is taking place. This is usually the desired behavior.
|
||||
|
||||
public:
|
||||
UnwindDetector();
|
||||
|
||||
bool isUnwinding() const;
|
||||
// Returns true if the current thread is in a stack unwind that it wasn't in at the time the
|
||||
// object was constructed.
|
||||
|
||||
template <typename Func>
|
||||
void catchExceptionsIfUnwinding(Func&& func) const;
|
||||
// Runs the given function (e.g., a lambda). If isUnwinding() is true, any exceptions are
|
||||
// caught and treated as secondary faults, meaning they are considered to be side-effects of the
|
||||
// exception that is unwinding the stack. Otherwise, exceptions are passed through normally.
|
||||
|
||||
private:
|
||||
uint uncaughtCount;
|
||||
|
||||
void catchExceptionsAsSecondaryFaults(_::Runnable& runnable) const;
|
||||
};
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
class Runnable {
|
||||
public:
|
||||
virtual void run() = 0;
|
||||
};
|
||||
|
||||
template <typename Func>
|
||||
class RunnableImpl: public Runnable {
|
||||
public:
|
||||
RunnableImpl(Func&& func): func(kj::mv(func)) {}
|
||||
void run() override {
|
||||
func();
|
||||
}
|
||||
private:
|
||||
Func func;
|
||||
};
|
||||
|
||||
Maybe<Exception> runCatchingExceptions(Runnable& runnable) noexcept;
|
||||
|
||||
} // namespace _ (private)
|
||||
|
||||
template <typename Func>
|
||||
Maybe<Exception> runCatchingExceptions(Func&& func) noexcept {
|
||||
_::RunnableImpl<Decay<Func>> runnable(kj::fwd<Func>(func));
|
||||
return _::runCatchingExceptions(runnable);
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
void UnwindDetector::catchExceptionsIfUnwinding(Func&& func) const {
|
||||
if (isUnwinding()) {
|
||||
_::RunnableImpl<Decay<Func>> runnable(kj::fwd<Func>(func));
|
||||
catchExceptionsAsSecondaryFaults(runnable);
|
||||
} else {
|
||||
func();
|
||||
}
|
||||
}
|
||||
|
||||
#define KJ_ON_SCOPE_SUCCESS(code) \
|
||||
::kj::UnwindDetector KJ_UNIQUE_NAME(_kjUnwindDetector); \
|
||||
KJ_DEFER(if (!KJ_UNIQUE_NAME(_kjUnwindDetector).isUnwinding()) { code; })
|
||||
// Runs `code` if the current scope is exited normally (not due to an exception).
|
||||
|
||||
#define KJ_ON_SCOPE_FAILURE(code) \
|
||||
::kj::UnwindDetector KJ_UNIQUE_NAME(_kjUnwindDetector); \
|
||||
KJ_DEFER(if (KJ_UNIQUE_NAME(_kjUnwindDetector).isUnwinding()) { code; })
|
||||
// Runs `code` if the current scope is exited due to an exception.
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
KJ_NOINLINE ArrayPtr<void* const> getStackTrace(ArrayPtr<void*> space, uint ignoreCount);
|
||||
// Attempt to get the current stack trace, returning a list of pointers to instructions. The
|
||||
// returned array is a slice of `space`. Provide a larger `space` to get a deeper stack trace.
|
||||
// If the platform doesn't support stack traces, returns an empty array.
|
||||
//
|
||||
// `ignoreCount` items will be truncated from the front of the trace. This is useful for chopping
|
||||
// off a prefix of the trace that is uninteresting to the developer because it's just locations
|
||||
// inside the debug infrastructure that is requesting the trace. Be careful to mark functions as
|
||||
// KJ_NOINLINE if you intend to count them in `ignoreCount`. Note that, unfortunately, the
|
||||
// ignored entries will still waste space in the `space` array (and the returned array's `begin()`
|
||||
// is never exactly equal to `space.begin()` due to this effect, even if `ignoreCount` is zero
|
||||
// since `getStackTrace()` needs to ignore its own internal frames).
|
||||
|
||||
String stringifyStackTrace(ArrayPtr<void* const>);
|
||||
// Convert the stack trace to a string with file names and line numbers. This may involve executing
|
||||
// suprocesses.
|
||||
|
||||
String getStackTrace();
|
||||
// Get a stack trace right now and stringify it. Useful for debugging.
|
||||
|
||||
void printStackTraceOnCrash();
|
||||
// Registers signal handlers on common "crash" signals like SIGSEGV that will (attempt to) print
|
||||
// a stack trace. You should call this as early as possible on program startup. Programs using
|
||||
// KJ_MAIN get this automatically.
|
||||
|
||||
kj::StringPtr trimSourceFilename(kj::StringPtr filename);
|
||||
// Given a source code file name, trim off noisy prefixes like "src/" or
|
||||
// "/ekam-provider/canonical/".
|
||||
|
||||
} // namespace kj
|
||||
|
||||
#endif // KJ_EXCEPTION_H_
|
||||
@@ -0,0 +1,277 @@
|
||||
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef KJ_FUNCTION_H_
|
||||
#define KJ_FUNCTION_H_
|
||||
|
||||
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include "memory.h"
|
||||
|
||||
namespace kj {
|
||||
|
||||
template <typename Signature>
|
||||
class Function;
|
||||
// Function wrapper using virtual-based polymorphism. Use this when template polymorphism is
|
||||
// not possible. You can, for example, accept a Function as a parameter:
|
||||
//
|
||||
// void setFilter(Function<bool(const Widget&)> filter);
|
||||
//
|
||||
// The caller of `setFilter()` may then pass any callable object as the parameter. The callable
|
||||
// object does not have to have the exact signature specified, just one that is "compatible" --
|
||||
// i.e. the return type is covariant and the parameters are contravariant.
|
||||
//
|
||||
// Unlike `std::function`, `kj::Function`s are movable but not copyable, just like `kj::Own`. This
|
||||
// is to avoid unexpected heap allocation or slow atomic reference counting.
|
||||
//
|
||||
// When a `Function` is constructed from an lvalue, it captures only a reference to the value.
|
||||
// When constructed from an rvalue, it invokes the value's move constructor. So, for example:
|
||||
//
|
||||
// struct AddN {
|
||||
// int n;
|
||||
// int operator(int i) { return i + n; }
|
||||
// }
|
||||
//
|
||||
// Function<int(int, int)> f1 = AddN{2};
|
||||
// // f1 owns an instance of AddN. It may safely be moved out
|
||||
// // of the local scope.
|
||||
//
|
||||
// AddN adder(2);
|
||||
// Function<int(int, int)> f2 = adder;
|
||||
// // f2 contains a reference to `adder`. Thus, it becomes invalid
|
||||
// // when `adder` goes out-of-scope.
|
||||
//
|
||||
// AddN adder2(2);
|
||||
// Function<int(int, int)> f3 = kj::mv(adder2);
|
||||
// // f3 owns an insatnce of AddN moved from `adder2`. f3 may safely
|
||||
// // be moved out of the local scope.
|
||||
//
|
||||
// Additionally, a Function may be bound to a class method using KJ_BIND_METHOD(object, methodName).
|
||||
// For example:
|
||||
//
|
||||
// class Printer {
|
||||
// public:
|
||||
// void print(int i);
|
||||
// void print(kj::StringPtr s);
|
||||
// };
|
||||
//
|
||||
// Printer p;
|
||||
//
|
||||
// Function<void(uint)> intPrinter = KJ_BIND_METHOD(p, print);
|
||||
// // Will call Printer::print(int).
|
||||
//
|
||||
// Function<void(const char*)> strPrinter = KJ_BIND_METHOD(p, print);
|
||||
// // Will call Printer::print(kj::StringPtr).
|
||||
//
|
||||
// Notice how KJ_BIND_METHOD is able to figure out which overload to use depending on the kind of
|
||||
// Function it is binding to.
|
||||
|
||||
template <typename Signature>
|
||||
class ConstFunction;
|
||||
// Like Function, but wraps a "const" (i.e. thread-safe) call.
|
||||
|
||||
template <typename Return, typename... Params>
|
||||
class Function<Return(Params...)> {
|
||||
public:
|
||||
template <typename F>
|
||||
inline Function(F&& f): impl(heap<Impl<F>>(kj::fwd<F>(f))) {}
|
||||
Function() = default;
|
||||
|
||||
// Make sure people don't accidentally end up wrapping a reference when they meant to return
|
||||
// a function.
|
||||
KJ_DISALLOW_COPY(Function);
|
||||
Function(Function&) = delete;
|
||||
Function& operator=(Function&) = delete;
|
||||
template <typename T> Function(const Function<T>&) = delete;
|
||||
template <typename T> Function& operator=(const Function<T>&) = delete;
|
||||
template <typename T> Function(const ConstFunction<T>&) = delete;
|
||||
template <typename T> Function& operator=(const ConstFunction<T>&) = delete;
|
||||
Function(Function&&) = default;
|
||||
Function& operator=(Function&&) = default;
|
||||
|
||||
inline Return operator()(Params... params) {
|
||||
return (*impl)(kj::fwd<Params>(params)...);
|
||||
}
|
||||
|
||||
Function reference() {
|
||||
// Forms a new Function of the same type that delegates to this Function by reference.
|
||||
// Therefore, this Function must outlive the returned Function, but otherwise they behave
|
||||
// exactly the same.
|
||||
|
||||
return *impl;
|
||||
}
|
||||
|
||||
private:
|
||||
class Iface {
|
||||
public:
|
||||
virtual Return operator()(Params... params) = 0;
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
class Impl final: public Iface {
|
||||
public:
|
||||
explicit Impl(F&& f): f(kj::fwd<F>(f)) {}
|
||||
|
||||
Return operator()(Params... params) override {
|
||||
return f(kj::fwd<Params>(params)...);
|
||||
}
|
||||
|
||||
private:
|
||||
F f;
|
||||
};
|
||||
|
||||
Own<Iface> impl;
|
||||
};
|
||||
|
||||
template <typename Return, typename... Params>
|
||||
class ConstFunction<Return(Params...)> {
|
||||
public:
|
||||
template <typename F>
|
||||
inline ConstFunction(F&& f): impl(heap<Impl<F>>(kj::fwd<F>(f))) {}
|
||||
ConstFunction() = default;
|
||||
|
||||
// Make sure people don't accidentally end up wrapping a reference when they meant to return
|
||||
// a function.
|
||||
KJ_DISALLOW_COPY(ConstFunction);
|
||||
ConstFunction(ConstFunction&) = delete;
|
||||
ConstFunction& operator=(ConstFunction&) = delete;
|
||||
template <typename T> ConstFunction(const ConstFunction<T>&) = delete;
|
||||
template <typename T> ConstFunction& operator=(const ConstFunction<T>&) = delete;
|
||||
template <typename T> ConstFunction(const Function<T>&) = delete;
|
||||
template <typename T> ConstFunction& operator=(const Function<T>&) = delete;
|
||||
ConstFunction(ConstFunction&&) = default;
|
||||
ConstFunction& operator=(ConstFunction&&) = default;
|
||||
|
||||
inline Return operator()(Params... params) const {
|
||||
return (*impl)(kj::fwd<Params>(params)...);
|
||||
}
|
||||
|
||||
ConstFunction reference() const {
|
||||
// Forms a new ConstFunction of the same type that delegates to this ConstFunction by reference.
|
||||
// Therefore, this ConstFunction must outlive the returned ConstFunction, but otherwise they
|
||||
// behave exactly the same.
|
||||
|
||||
return *impl;
|
||||
}
|
||||
|
||||
private:
|
||||
class Iface {
|
||||
public:
|
||||
virtual Return operator()(Params... params) const = 0;
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
class Impl final: public Iface {
|
||||
public:
|
||||
explicit Impl(F&& f): f(kj::fwd<F>(f)) {}
|
||||
|
||||
Return operator()(Params... params) const override {
|
||||
return f(kj::fwd<Params>(params)...);
|
||||
}
|
||||
|
||||
private:
|
||||
F f;
|
||||
};
|
||||
|
||||
Own<Iface> impl;
|
||||
};
|
||||
|
||||
#if 1
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
template <typename T, typename Signature, Signature method>
|
||||
class BoundMethod;
|
||||
|
||||
template <typename T, typename Return, typename... Params, Return (Decay<T>::*method)(Params...)>
|
||||
class BoundMethod<T, Return (Decay<T>::*)(Params...), method> {
|
||||
public:
|
||||
BoundMethod(T&& t): t(kj::fwd<T>(t)) {}
|
||||
|
||||
Return operator()(Params&&... params) {
|
||||
return (t.*method)(kj::fwd<Params>(params)...);
|
||||
}
|
||||
|
||||
private:
|
||||
T t;
|
||||
};
|
||||
|
||||
template <typename T, typename Return, typename... Params,
|
||||
Return (Decay<T>::*method)(Params...) const>
|
||||
class BoundMethod<T, Return (Decay<T>::*)(Params...) const, method> {
|
||||
public:
|
||||
BoundMethod(T&& t): t(kj::fwd<T>(t)) {}
|
||||
|
||||
Return operator()(Params&&... params) const {
|
||||
return (t.*method)(kj::fwd<Params>(params)...);
|
||||
}
|
||||
|
||||
private:
|
||||
T t;
|
||||
};
|
||||
|
||||
} // namespace _ (private)
|
||||
|
||||
#define KJ_BIND_METHOD(obj, method) \
|
||||
::kj::_::BoundMethod<KJ_DECLTYPE_REF(obj), \
|
||||
decltype(&::kj::Decay<decltype(obj)>::method), \
|
||||
&::kj::Decay<decltype(obj)>::method>(obj)
|
||||
// Macro that produces a functor object which forwards to the method `obj.name`. If `obj` is an
|
||||
// lvalue, the functor will hold a reference to it. If `obj` is an rvalue, the functor will
|
||||
// contain a copy (by move) of it.
|
||||
//
|
||||
// The current implementation requires that the method is not overloaded.
|
||||
//
|
||||
// TODO(someday): C++14's generic lambdas may be able to simplify this code considerably, and
|
||||
// probably make it work with overloaded methods.
|
||||
|
||||
#else
|
||||
// Here's a better implementation of the above that doesn't work with GCC (but does with Clang)
|
||||
// because it uses a local class with a template method. Sigh. This implementation supports
|
||||
// overloaded methods.
|
||||
|
||||
#define KJ_BIND_METHOD(obj, method) \
|
||||
({ \
|
||||
typedef KJ_DECLTYPE_REF(obj) T; \
|
||||
class F { \
|
||||
public: \
|
||||
inline F(T&& t): t(::kj::fwd<T>(t)) {} \
|
||||
template <typename... Params> \
|
||||
auto operator()(Params&&... params) \
|
||||
-> decltype(::kj::instance<T>().method(::kj::fwd<Params>(params)...)) { \
|
||||
return t.method(::kj::fwd<Params>(params)...); \
|
||||
} \
|
||||
private: \
|
||||
T t; \
|
||||
}; \
|
||||
(F(obj)); \
|
||||
})
|
||||
// Macro that produces a functor object which forwards to the method `obj.name`. If `obj` is an
|
||||
// lvalue, the functor will hold a reference to it. If `obj` is an rvalue, the functor will
|
||||
// contain a copy (by move) of it.
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace kj
|
||||
|
||||
#endif // KJ_FUNCTION_H_
|
||||
@@ -0,0 +1,419 @@
|
||||
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef KJ_IO_H_
|
||||
#define KJ_IO_H_
|
||||
|
||||
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include "common.h"
|
||||
#include "array.h"
|
||||
#include "exception.h"
|
||||
|
||||
namespace kj {
|
||||
|
||||
// =======================================================================================
|
||||
// Abstract interfaces
|
||||
|
||||
class InputStream {
|
||||
public:
|
||||
virtual ~InputStream() noexcept(false);
|
||||
|
||||
size_t read(void* buffer, size_t minBytes, size_t maxBytes);
|
||||
// Reads at least minBytes and at most maxBytes, copying them into the given buffer. Returns
|
||||
// the size read. Throws an exception on errors. Implemented in terms of tryRead().
|
||||
//
|
||||
// maxBytes is the number of bytes the caller really wants, but minBytes is the minimum amount
|
||||
// needed by the caller before it can start doing useful processing. If the stream returns less
|
||||
// than maxBytes, the caller will usually call read() again later to get the rest. Returning
|
||||
// less than maxBytes is useful when it makes sense for the caller to parallelize processing
|
||||
// with I/O.
|
||||
//
|
||||
// Never blocks if minBytes is zero. If minBytes is zero and maxBytes is non-zero, this may
|
||||
// attempt a non-blocking read or may just return zero. To force a read, use a non-zero minBytes.
|
||||
// To detect EOF without throwing an exception, use tryRead().
|
||||
//
|
||||
// If the InputStream can't produce minBytes, it MUST throw an exception, as the caller is not
|
||||
// expected to understand how to deal with partial reads.
|
||||
|
||||
virtual size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) = 0;
|
||||
// Like read(), but may return fewer than minBytes on EOF.
|
||||
|
||||
inline void read(void* buffer, size_t bytes) { read(buffer, bytes, bytes); }
|
||||
// Convenience method for reading an exact number of bytes.
|
||||
|
||||
virtual void skip(size_t bytes);
|
||||
// Skips past the given number of bytes, discarding them. The default implementation read()s
|
||||
// into a scratch buffer.
|
||||
};
|
||||
|
||||
class OutputStream {
|
||||
public:
|
||||
virtual ~OutputStream() noexcept(false);
|
||||
|
||||
virtual void write(const void* buffer, size_t size) = 0;
|
||||
// Always writes the full size. Throws exception on error.
|
||||
|
||||
virtual void write(ArrayPtr<const ArrayPtr<const byte>> pieces);
|
||||
// Equivalent to write()ing each byte array in sequence, which is what the default implementation
|
||||
// does. Override if you can do something better, e.g. use writev() to do the write in a single
|
||||
// syscall.
|
||||
};
|
||||
|
||||
class BufferedInputStream: public InputStream {
|
||||
// An input stream which buffers some bytes in memory to reduce system call overhead.
|
||||
// - OR -
|
||||
// An input stream that actually reads from some in-memory data structure and wants to give its
|
||||
// caller a direct pointer to that memory to potentially avoid a copy.
|
||||
|
||||
public:
|
||||
virtual ~BufferedInputStream() noexcept(false);
|
||||
|
||||
ArrayPtr<const byte> getReadBuffer();
|
||||
// Get a direct pointer into the read buffer, which contains the next bytes in the input. If the
|
||||
// caller consumes any bytes, it should then call skip() to indicate this. This always returns a
|
||||
// non-empty buffer or throws an exception. Implemented in terms of tryGetReadBuffer().
|
||||
|
||||
virtual ArrayPtr<const byte> tryGetReadBuffer() = 0;
|
||||
// Like getReadBuffer() but may return an empty buffer on EOF.
|
||||
};
|
||||
|
||||
class BufferedOutputStream: public OutputStream {
|
||||
// An output stream which buffers some bytes in memory to reduce system call overhead.
|
||||
// - OR -
|
||||
// An output stream that actually writes into some in-memory data structure and wants to give its
|
||||
// caller a direct pointer to that memory to potentially avoid a copy.
|
||||
|
||||
public:
|
||||
virtual ~BufferedOutputStream() noexcept(false);
|
||||
|
||||
virtual ArrayPtr<byte> getWriteBuffer() = 0;
|
||||
// Get a direct pointer into the write buffer. The caller may choose to fill in some prefix of
|
||||
// this buffer and then pass it to write(), in which case write() may avoid a copy. It is
|
||||
// incorrect to pass to write any slice of this buffer which is not a prefix.
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
// Buffered streams implemented as wrappers around regular streams
|
||||
|
||||
class BufferedInputStreamWrapper: public BufferedInputStream {
|
||||
// Implements BufferedInputStream in terms of an InputStream.
|
||||
//
|
||||
// Note that the underlying stream's position is unpredictable once the wrapper is destroyed,
|
||||
// unless the entire stream was consumed. To read a predictable number of bytes in a buffered
|
||||
// way without going over, you'd need this wrapper to wrap some other wrapper which itself
|
||||
// implements an artificial EOF at the desired point. Such a stream should be trivial to write
|
||||
// but is not provided by the library at this time.
|
||||
|
||||
public:
|
||||
explicit BufferedInputStreamWrapper(InputStream& inner, ArrayPtr<byte> buffer = nullptr);
|
||||
// Creates a buffered stream wrapping the given non-buffered stream. No guarantee is made about
|
||||
// the position of the inner stream after a buffered wrapper has been created unless the entire
|
||||
// input is read.
|
||||
//
|
||||
// If the second parameter is non-null, the stream uses the given buffer instead of allocating
|
||||
// its own. This may improve performance if the buffer can be reused.
|
||||
|
||||
KJ_DISALLOW_COPY(BufferedInputStreamWrapper);
|
||||
~BufferedInputStreamWrapper() noexcept(false);
|
||||
|
||||
// implements BufferedInputStream ----------------------------------
|
||||
ArrayPtr<const byte> tryGetReadBuffer() override;
|
||||
size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override;
|
||||
void skip(size_t bytes) override;
|
||||
|
||||
private:
|
||||
InputStream& inner;
|
||||
Array<byte> ownedBuffer;
|
||||
ArrayPtr<byte> buffer;
|
||||
ArrayPtr<byte> bufferAvailable;
|
||||
};
|
||||
|
||||
class BufferedOutputStreamWrapper: public BufferedOutputStream {
|
||||
// Implements BufferedOutputStream in terms of an OutputStream. Note that writes to the
|
||||
// underlying stream may be delayed until flush() is called or the wrapper is destroyed.
|
||||
|
||||
public:
|
||||
explicit BufferedOutputStreamWrapper(OutputStream& inner, ArrayPtr<byte> buffer = nullptr);
|
||||
// Creates a buffered stream wrapping the given non-buffered stream.
|
||||
//
|
||||
// If the second parameter is non-null, the stream uses the given buffer instead of allocating
|
||||
// its own. This may improve performance if the buffer can be reused.
|
||||
|
||||
KJ_DISALLOW_COPY(BufferedOutputStreamWrapper);
|
||||
~BufferedOutputStreamWrapper() noexcept(false);
|
||||
|
||||
void flush();
|
||||
// Force the wrapper to write any remaining bytes in its buffer to the inner stream. Note that
|
||||
// this only flushes this object's buffer; this object has no idea how to flush any other buffers
|
||||
// that may be present in the underlying stream.
|
||||
|
||||
// implements BufferedOutputStream ---------------------------------
|
||||
ArrayPtr<byte> getWriteBuffer() override;
|
||||
void write(const void* buffer, size_t size) override;
|
||||
|
||||
private:
|
||||
OutputStream& inner;
|
||||
Array<byte> ownedBuffer;
|
||||
ArrayPtr<byte> buffer;
|
||||
byte* bufferPos;
|
||||
UnwindDetector unwindDetector;
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
// Array I/O
|
||||
|
||||
class ArrayInputStream: public BufferedInputStream {
|
||||
public:
|
||||
explicit ArrayInputStream(ArrayPtr<const byte> array);
|
||||
KJ_DISALLOW_COPY(ArrayInputStream);
|
||||
~ArrayInputStream() noexcept(false);
|
||||
|
||||
// implements BufferedInputStream ----------------------------------
|
||||
ArrayPtr<const byte> tryGetReadBuffer() override;
|
||||
size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override;
|
||||
void skip(size_t bytes) override;
|
||||
|
||||
private:
|
||||
ArrayPtr<const byte> array;
|
||||
};
|
||||
|
||||
class ArrayOutputStream: public BufferedOutputStream {
|
||||
public:
|
||||
explicit ArrayOutputStream(ArrayPtr<byte> array);
|
||||
KJ_DISALLOW_COPY(ArrayOutputStream);
|
||||
~ArrayOutputStream() noexcept(false);
|
||||
|
||||
ArrayPtr<byte> getArray() {
|
||||
// Get the portion of the array which has been filled in.
|
||||
return arrayPtr(array.begin(), fillPos);
|
||||
}
|
||||
|
||||
// implements BufferedInputStream ----------------------------------
|
||||
ArrayPtr<byte> getWriteBuffer() override;
|
||||
void write(const void* buffer, size_t size) override;
|
||||
|
||||
private:
|
||||
ArrayPtr<byte> array;
|
||||
byte* fillPos;
|
||||
};
|
||||
|
||||
class VectorOutputStream: public BufferedOutputStream {
|
||||
public:
|
||||
explicit VectorOutputStream(size_t initialCapacity = 4096);
|
||||
KJ_DISALLOW_COPY(VectorOutputStream);
|
||||
~VectorOutputStream() noexcept(false);
|
||||
|
||||
ArrayPtr<byte> getArray() {
|
||||
// Get the portion of the array which has been filled in.
|
||||
return arrayPtr(vector.begin(), fillPos);
|
||||
}
|
||||
|
||||
// implements BufferedInputStream ----------------------------------
|
||||
ArrayPtr<byte> getWriteBuffer() override;
|
||||
void write(const void* buffer, size_t size) override;
|
||||
|
||||
private:
|
||||
Array<byte> vector;
|
||||
byte* fillPos;
|
||||
|
||||
void grow(size_t minSize);
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
// File descriptor I/O
|
||||
|
||||
class AutoCloseFd {
|
||||
// A wrapper around a file descriptor which automatically closes the descriptor when destroyed.
|
||||
// The wrapper supports move construction for transferring ownership of the descriptor. If
|
||||
// close() returns an error, the destructor throws an exception, UNLESS the destructor is being
|
||||
// called during unwind from another exception, in which case the close error is ignored.
|
||||
//
|
||||
// If your code is not exception-safe, you should not use AutoCloseFd. In this case you will
|
||||
// have to call close() yourself and handle errors appropriately.
|
||||
|
||||
public:
|
||||
inline AutoCloseFd(): fd(-1) {}
|
||||
inline AutoCloseFd(decltype(nullptr)): fd(-1) {}
|
||||
inline explicit AutoCloseFd(int fd): fd(fd) {}
|
||||
inline AutoCloseFd(AutoCloseFd&& other) noexcept: fd(other.fd) { other.fd = -1; }
|
||||
KJ_DISALLOW_COPY(AutoCloseFd);
|
||||
~AutoCloseFd() noexcept(false);
|
||||
|
||||
inline AutoCloseFd& operator=(AutoCloseFd&& other) {
|
||||
AutoCloseFd old(kj::mv(*this));
|
||||
fd = other.fd;
|
||||
other.fd = -1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline AutoCloseFd& operator=(decltype(nullptr)) {
|
||||
AutoCloseFd old(kj::mv(*this));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline operator int() const { return fd; }
|
||||
inline int get() const { return fd; }
|
||||
|
||||
operator bool() const = delete;
|
||||
// Deleting this operator prevents accidental use in boolean contexts, which
|
||||
// the int conversion operator above would otherwise allow.
|
||||
|
||||
inline bool operator==(decltype(nullptr)) { return fd < 0; }
|
||||
inline bool operator!=(decltype(nullptr)) { return fd >= 0; }
|
||||
|
||||
private:
|
||||
int fd;
|
||||
UnwindDetector unwindDetector;
|
||||
};
|
||||
|
||||
inline auto KJ_STRINGIFY(const AutoCloseFd& fd)
|
||||
-> decltype(kj::toCharSequence(implicitCast<int>(fd))) {
|
||||
return kj::toCharSequence(implicitCast<int>(fd));
|
||||
}
|
||||
|
||||
class FdInputStream: public InputStream {
|
||||
// An InputStream wrapping a file descriptor.
|
||||
|
||||
public:
|
||||
explicit FdInputStream(int fd): fd(fd) {}
|
||||
explicit FdInputStream(AutoCloseFd fd): fd(fd), autoclose(mv(fd)) {}
|
||||
KJ_DISALLOW_COPY(FdInputStream);
|
||||
~FdInputStream() noexcept(false);
|
||||
|
||||
size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override;
|
||||
|
||||
inline int getFd() const { return fd; }
|
||||
|
||||
private:
|
||||
int fd;
|
||||
AutoCloseFd autoclose;
|
||||
};
|
||||
|
||||
class FdOutputStream: public OutputStream {
|
||||
// An OutputStream wrapping a file descriptor.
|
||||
|
||||
public:
|
||||
explicit FdOutputStream(int fd): fd(fd) {}
|
||||
explicit FdOutputStream(AutoCloseFd fd): fd(fd), autoclose(mv(fd)) {}
|
||||
KJ_DISALLOW_COPY(FdOutputStream);
|
||||
~FdOutputStream() noexcept(false);
|
||||
|
||||
void write(const void* buffer, size_t size) override;
|
||||
void write(ArrayPtr<const ArrayPtr<const byte>> pieces) override;
|
||||
|
||||
inline int getFd() const { return fd; }
|
||||
|
||||
private:
|
||||
int fd;
|
||||
AutoCloseFd autoclose;
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
// Win32 Handle I/O
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
class AutoCloseHandle {
|
||||
// A wrapper around a Win32 HANDLE which automatically closes the handle when destroyed.
|
||||
// The wrapper supports move construction for transferring ownership of the handle. If
|
||||
// CloseHandle() returns an error, the destructor throws an exception, UNLESS the destructor is
|
||||
// being called during unwind from another exception, in which case the close error is ignored.
|
||||
//
|
||||
// If your code is not exception-safe, you should not use AutoCloseHandle. In this case you will
|
||||
// have to call close() yourself and handle errors appropriately.
|
||||
|
||||
public:
|
||||
inline AutoCloseHandle(): handle((void*)-1) {}
|
||||
inline AutoCloseHandle(decltype(nullptr)): handle((void*)-1) {}
|
||||
inline explicit AutoCloseHandle(void* handle): handle(handle) {}
|
||||
inline AutoCloseHandle(AutoCloseHandle&& other) noexcept: handle(other.handle) {
|
||||
other.handle = (void*)-1;
|
||||
}
|
||||
KJ_DISALLOW_COPY(AutoCloseHandle);
|
||||
~AutoCloseHandle() noexcept(false);
|
||||
|
||||
inline AutoCloseHandle& operator=(AutoCloseHandle&& other) {
|
||||
AutoCloseHandle old(kj::mv(*this));
|
||||
handle = other.handle;
|
||||
other.handle = (void*)-1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline AutoCloseHandle& operator=(decltype(nullptr)) {
|
||||
AutoCloseHandle old(kj::mv(*this));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline operator void*() const { return handle; }
|
||||
inline void* get() const { return handle; }
|
||||
|
||||
operator bool() const = delete;
|
||||
// Deleting this operator prevents accidental use in boolean contexts, which
|
||||
// the void* conversion operator above would otherwise allow.
|
||||
|
||||
inline bool operator==(decltype(nullptr)) { return handle != (void*)-1; }
|
||||
inline bool operator!=(decltype(nullptr)) { return handle == (void*)-1; }
|
||||
|
||||
private:
|
||||
void* handle; // -1 (aka INVALID_HANDLE_VALUE) if not valid.
|
||||
};
|
||||
|
||||
class HandleInputStream: public InputStream {
|
||||
// An InputStream wrapping a Win32 HANDLE.
|
||||
|
||||
public:
|
||||
explicit HandleInputStream(void* handle): handle(handle) {}
|
||||
explicit HandleInputStream(AutoCloseHandle handle): handle(handle), autoclose(mv(handle)) {}
|
||||
KJ_DISALLOW_COPY(HandleInputStream);
|
||||
~HandleInputStream() noexcept(false);
|
||||
|
||||
size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override;
|
||||
|
||||
private:
|
||||
void* handle;
|
||||
AutoCloseHandle autoclose;
|
||||
};
|
||||
|
||||
class HandleOutputStream: public OutputStream {
|
||||
// An OutputStream wrapping a Win32 HANDLE.
|
||||
|
||||
public:
|
||||
explicit HandleOutputStream(void* handle): handle(handle) {}
|
||||
explicit HandleOutputStream(AutoCloseHandle handle): handle(handle), autoclose(mv(handle)) {}
|
||||
KJ_DISALLOW_COPY(HandleOutputStream);
|
||||
~HandleOutputStream() noexcept(false);
|
||||
|
||||
void write(const void* buffer, size_t size) override;
|
||||
|
||||
private:
|
||||
void* handle;
|
||||
AutoCloseHandle autoclose;
|
||||
};
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
} // namespace kj
|
||||
|
||||
#endif // KJ_IO_H_
|
||||
@@ -0,0 +1,407 @@
|
||||
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef KJ_MAIN_H_
|
||||
#define KJ_MAIN_H_
|
||||
|
||||
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include "array.h"
|
||||
#include "string.h"
|
||||
#include "vector.h"
|
||||
#include "function.h"
|
||||
|
||||
namespace kj {
|
||||
|
||||
class ProcessContext {
|
||||
// Context for command-line programs.
|
||||
|
||||
public:
|
||||
virtual StringPtr getProgramName() = 0;
|
||||
// Get argv[0] as passed to main().
|
||||
|
||||
KJ_NORETURN(virtual void exit()) = 0;
|
||||
// Indicates program completion. The program is considered successful unless `error()` was
|
||||
// called. Typically this exits with _Exit(), meaning that the stack is not unwound, buffers
|
||||
// are not flushed, etc. -- it is the responsibility of the caller to flush any buffers that
|
||||
// matter. However, an alternate context implementation e.g. for unit testing purposes could
|
||||
// choose to throw an exception instead.
|
||||
//
|
||||
// At first this approach may sound crazy. Isn't it much better to shut down cleanly? What if
|
||||
// you lose data? However, it turns out that if you look at each common class of program, _Exit()
|
||||
// is almost always preferable. Let's break it down:
|
||||
//
|
||||
// * Commands: A typical program you might run from the command line is single-threaded and
|
||||
// exits quickly and deterministically. Commands often use buffered I/O and need to flush
|
||||
// those buffers before exit. However, most of the work performed by destructors is not
|
||||
// flushing buffers, but rather freeing up memory, placing objects into freelists, and closing
|
||||
// file descriptors. All of this is irrelevant if the process is about to exit anyway, and
|
||||
// for a command that runs quickly, time wasted freeing heap space may make a real difference
|
||||
// in the overall runtime of a script. Meanwhile, it is usually easy to determine exactly what
|
||||
// resources need to be flushed before exit, and easy to tell if they are not being flushed
|
||||
// (because the command fails to produce the expected output). Therefore, it is reasonably
|
||||
// easy for commands to explicitly ensure all output is flushed before exiting, and it is
|
||||
// probably a good idea for them to do so anyway, because write failures should be detected
|
||||
// and handled. For commands, a good strategy is to allocate any objects that require clean
|
||||
// destruction on the stack, and allow them to go out of scope before the command exits.
|
||||
// Meanwhile, any resources which do not need to be cleaned up should be allocated as members
|
||||
// of the command's main class, whose destructor normally will not be called.
|
||||
//
|
||||
// * Interactive apps: Programs that interact with the user (whether they be graphical apps
|
||||
// with windows or console-based apps like emacs) generally exit only when the user asks them
|
||||
// to. Such applications may store large data structures in memory which need to be synced
|
||||
// to disk, such as documents or user preferences. However, relying on stack unwind or global
|
||||
// destructors as the mechanism for ensuring such syncing occurs is probably wrong. First of
|
||||
// all, it's 2013, and applications ought to be actively syncing changes to non-volatile
|
||||
// storage the moment those changes are made. Applications can crash at any time and a crash
|
||||
// should never lose data that is more than half a second old. Meanwhile, if a user actually
|
||||
// does try to close an application while unsaved changes exist, the application UI should
|
||||
// prompt the user to decide what to do. Such a UI mechanism is obviously too high level to
|
||||
// be implemented via destructors, so KJ's use of _Exit() shouldn't make a difference here.
|
||||
//
|
||||
// * Servers: A good server is fault-tolerant, prepared for the possibility that at any time
|
||||
// it could crash, the OS could decide to kill it off, or the machine it is running on could
|
||||
// just die. So, using _Exit() should be no problem. In fact, servers generally never even
|
||||
// call exit anyway; they are killed externally.
|
||||
//
|
||||
// * Batch jobs: A long-running batch job is something between a command and a server. It
|
||||
// probably knows exactly what needs to be flushed before exiting, and it probably should be
|
||||
// fault-tolerant.
|
||||
//
|
||||
// Meanwhile, regardless of program type, if you are adhering to KJ style, then the use of
|
||||
// _Exit() shouldn't be a problem anyway:
|
||||
//
|
||||
// * KJ style forbids global mutable state (singletons) in general and global constructors and
|
||||
// destructors in particular. Therefore, everything that could possibly need cleanup either
|
||||
// lives on the stack or is transitively owned by something living on the stack.
|
||||
//
|
||||
// * Calling exit() simply means "Don't clean up anything older than this stack frame.". If you
|
||||
// have resources that require cleanup before exit, make sure they are owned by stack frames
|
||||
// beyond the one that eventually calls exit(). To be as safe as possible, don't place any
|
||||
// state in your program's main class, and don't call exit() yourself. Then, runMainAndExit()
|
||||
// will do it, and the only thing on the stack at that time will be your main class, which
|
||||
// has no state anyway.
|
||||
//
|
||||
// TODO(someday): Perhaps we should use the new std::quick_exit(), so that at_quick_exit() is
|
||||
// available for those who really think they need it. Unfortunately, it is not yet available
|
||||
// on many platforms.
|
||||
|
||||
virtual void warning(StringPtr message) = 0;
|
||||
// Print the given message to standard error. A newline is printed after the message if it
|
||||
// doesn't already have one.
|
||||
|
||||
virtual void error(StringPtr message) = 0;
|
||||
// Like `warning()`, but also sets a flag indicating that the process has failed, and that when
|
||||
// it eventually exits it should indicate an error status.
|
||||
|
||||
KJ_NORETURN(virtual void exitError(StringPtr message)) = 0;
|
||||
// Equivalent to `error(message)` followed by `exit()`.
|
||||
|
||||
KJ_NORETURN(virtual void exitInfo(StringPtr message)) = 0;
|
||||
// Displays the given non-error message to the user and then calls `exit()`. This is used to
|
||||
// implement things like --help.
|
||||
|
||||
virtual void increaseLoggingVerbosity() = 0;
|
||||
// Increase the level of detail produced by the debug logging system. `MainBuilder` invokes
|
||||
// this if the caller uses the -v flag.
|
||||
|
||||
// TODO(someday): Add interfaces representing standard OS resources like the filesystem, so that
|
||||
// these things can be mocked out.
|
||||
};
|
||||
|
||||
class TopLevelProcessContext final: public ProcessContext {
|
||||
// A ProcessContext implementation appropriate for use at the actual entry point of a process
|
||||
// (as opposed to when you are trying to call a program's main function from within some other
|
||||
// program). This implementation writes errors to stderr, and its `exit()` method actually
|
||||
// calls the C `quick_exit()` function.
|
||||
|
||||
public:
|
||||
explicit TopLevelProcessContext(StringPtr programName);
|
||||
|
||||
struct CleanShutdownException { int exitCode; };
|
||||
// If the environment variable KJ_CLEAN_SHUTDOWN is set, then exit() will actually throw this
|
||||
// exception rather than exiting. `kj::runMain()` catches this exception and returns normally.
|
||||
// This is useful primarily for testing purposes, to assist tools like memory leak checkers that
|
||||
// are easily confused by quick_exit().
|
||||
|
||||
StringPtr getProgramName() override;
|
||||
KJ_NORETURN(void exit() override);
|
||||
void warning(StringPtr message) override;
|
||||
void error(StringPtr message) override;
|
||||
KJ_NORETURN(void exitError(StringPtr message) override);
|
||||
KJ_NORETURN(void exitInfo(StringPtr message) override);
|
||||
void increaseLoggingVerbosity() override;
|
||||
|
||||
private:
|
||||
StringPtr programName;
|
||||
bool cleanShutdown;
|
||||
bool hadErrors = false;
|
||||
};
|
||||
|
||||
typedef Function<void(StringPtr programName, ArrayPtr<const StringPtr> params)> MainFunc;
|
||||
|
||||
int runMainAndExit(ProcessContext& context, MainFunc&& func, int argc, char* argv[]);
|
||||
// Runs the given main function and then exits using the given context. If an exception is thrown,
|
||||
// this will catch it, report it via the context and exit with an error code.
|
||||
//
|
||||
// Normally this function does not return, because returning would probably lead to wasting time
|
||||
// on cleanup when the process is just going to exit anyway. However, to facilitate memory leak
|
||||
// checkers and other tools that require a clean shutdown to do their job, if the environment
|
||||
// variable KJ_CLEAN_SHUTDOWN is set, the function will in fact return an exit code, which should
|
||||
// then be returned from main().
|
||||
//
|
||||
// Most users will use the KJ_MAIN() macro rather than call this function directly.
|
||||
|
||||
#define KJ_MAIN(MainClass) \
|
||||
int main(int argc, char* argv[]) { \
|
||||
::kj::TopLevelProcessContext context(argv[0]); \
|
||||
MainClass mainObject(context); \
|
||||
return ::kj::runMainAndExit(context, mainObject.getMain(), argc, argv); \
|
||||
}
|
||||
// Convenience macro for declaring a main function based on the given class. The class must have
|
||||
// a constructor that accepts a ProcessContext& and a method getMain() which returns
|
||||
// kj::MainFunc (probably building it using a MainBuilder).
|
||||
|
||||
class MainBuilder {
|
||||
// Builds a main() function with nice argument parsing. As options and arguments are parsed,
|
||||
// corresponding callbacks are called, so that you never have to write a massive switch()
|
||||
// statement to interpret arguments. Additionally, this approach encourages you to write
|
||||
// main classes that have a reasonable API that can be used as an alternative to their
|
||||
// command-line interface.
|
||||
//
|
||||
// All StringPtrs passed to MainBuilder must remain valid until option parsing completes. The
|
||||
// assumption is that these strings will all be literals, making this an easy requirement. If
|
||||
// not, consider allocating them in an Arena.
|
||||
//
|
||||
// Some flags are automatically recognized by the main functions built by this class:
|
||||
// --help: Prints help text and exits. The help text is constructed based on the
|
||||
// information you provide to the builder as you define each flag.
|
||||
// --verbose: Increase logging verbosity.
|
||||
// --version: Print version information and exit.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// class FooMain {
|
||||
// public:
|
||||
// FooMain(kj::ProcessContext& context): context(context) {}
|
||||
//
|
||||
// bool setAll() { all = true; return true; }
|
||||
// // Enable the --all flag.
|
||||
//
|
||||
// kj::MainBuilder::Validity setOutput(kj::StringPtr name) {
|
||||
// // Set the output file.
|
||||
//
|
||||
// if (name.endsWith(".foo")) {
|
||||
// outputFile = name;
|
||||
// return true;
|
||||
// } else {
|
||||
// return "Output file must have extension .foo.";
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// kj::MainBuilder::Validity processInput(kj::StringPtr name) {
|
||||
// // Process an input file.
|
||||
//
|
||||
// if (!exists(name)) {
|
||||
// return kj::str(name, ": file not found");
|
||||
// }
|
||||
// // ... process the input file ...
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// kj::MainFunc getMain() {
|
||||
// return MainBuilder(context, "Foo Builder v1.5", "Reads <source>s and builds a Foo.")
|
||||
// .addOption({'a', "all"}, KJ_BIND_METHOD(*this, setAll),
|
||||
// "Frob all the widgets. Otherwise, only some widgets are frobbed.")
|
||||
// .addOptionWithArg({'o', "output"}, KJ_BIND_METHOD(*this, setOutput),
|
||||
// "<filename>", "Output to <filename>. Must be a .foo file.")
|
||||
// .expectOneOrMoreArgs("<source>", KJ_BIND_METHOD(*this, processInput))
|
||||
// .build();
|
||||
// }
|
||||
//
|
||||
// private:
|
||||
// bool all = false;
|
||||
// kj::StringPtr outputFile;
|
||||
// kj::ProcessContext& context;
|
||||
// };
|
||||
|
||||
public:
|
||||
MainBuilder(ProcessContext& context, StringPtr version,
|
||||
StringPtr briefDescription, StringPtr extendedDescription = nullptr);
|
||||
~MainBuilder() noexcept(false);
|
||||
|
||||
class OptionName {
|
||||
public:
|
||||
OptionName() = default;
|
||||
inline OptionName(char shortName): isLong(false), shortName(shortName) {}
|
||||
inline OptionName(const char* longName): isLong(true), longName(longName) {}
|
||||
|
||||
private:
|
||||
bool isLong;
|
||||
union {
|
||||
char shortName;
|
||||
const char* longName;
|
||||
};
|
||||
friend class MainBuilder;
|
||||
};
|
||||
|
||||
class Validity {
|
||||
public:
|
||||
inline Validity(bool valid) {
|
||||
if (!valid) errorMessage = heapString("invalid argument");
|
||||
}
|
||||
inline Validity(const char* errorMessage)
|
||||
: errorMessage(heapString(errorMessage)) {}
|
||||
inline Validity(String&& errorMessage)
|
||||
: errorMessage(kj::mv(errorMessage)) {}
|
||||
|
||||
inline const Maybe<String>& getError() const { return errorMessage; }
|
||||
inline Maybe<String> releaseError() { return kj::mv(errorMessage); }
|
||||
|
||||
private:
|
||||
Maybe<String> errorMessage;
|
||||
friend class MainBuilder;
|
||||
};
|
||||
|
||||
MainBuilder& addOption(std::initializer_list<OptionName> names, Function<Validity()> callback,
|
||||
StringPtr helpText);
|
||||
// Defines a new option (flag). `names` is a list of characters and strings that can be used to
|
||||
// specify the option on the command line. Single-character names are used with "-" while string
|
||||
// names are used with "--". `helpText` is a natural-language description of the flag.
|
||||
//
|
||||
// `callback` is called when the option is seen. Its return value indicates whether the option
|
||||
// was accepted. If not, further option processing stops, and error is written, and the process
|
||||
// exits.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// builder.addOption({'a', "all"}, KJ_BIND_METHOD(*this, showAll), "Show all files.");
|
||||
//
|
||||
// This option could be specified in the following ways:
|
||||
//
|
||||
// -a
|
||||
// --all
|
||||
//
|
||||
// Note that single-character option names can be combined into a single argument. For example,
|
||||
// `-abcd` is equivalent to `-a -b -c -d`.
|
||||
//
|
||||
// The help text for this option would look like:
|
||||
//
|
||||
// -a, --all
|
||||
// Show all files.
|
||||
//
|
||||
// Note that help text is automatically word-wrapped.
|
||||
|
||||
MainBuilder& addOptionWithArg(std::initializer_list<OptionName> names,
|
||||
Function<Validity(StringPtr)> callback,
|
||||
StringPtr argumentTitle, StringPtr helpText);
|
||||
// Like `addOption()`, but adds an option which accepts an argument. `argumentTitle` is used in
|
||||
// the help text. The argument text is passed to the callback.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// builder.addOptionWithArg({'o', "output"}, KJ_BIND_METHOD(*this, setOutput),
|
||||
// "<filename>", "Output to <filename>.");
|
||||
//
|
||||
// This option could be specified with an argument of "foo" in the following ways:
|
||||
//
|
||||
// -ofoo
|
||||
// -o foo
|
||||
// --output=foo
|
||||
// --output foo
|
||||
//
|
||||
// Note that single-character option names can be combined, but only the last option can have an
|
||||
// argument, since the characters after the option letter are interpreted as the argument. E.g.
|
||||
// `-abofoo` would be equivalent to `-a -b -o foo`.
|
||||
//
|
||||
// The help text for this option would look like:
|
||||
//
|
||||
// -o FILENAME, --output=FILENAME
|
||||
// Output to FILENAME.
|
||||
|
||||
MainBuilder& addSubCommand(StringPtr name, Function<MainFunc()> getSubParser,
|
||||
StringPtr briefHelpText);
|
||||
// If exactly the given name is seen as an argument, invoke getSubParser() and then pass all
|
||||
// remaining arguments to the parser it returns. This is useful for implementing commands which
|
||||
// have lots of sub-commands, like "git" (which has sub-commands "checkout", "branch", "pull",
|
||||
// etc.).
|
||||
//
|
||||
// `getSubParser` is only called if the command is seen. This avoids building main functions
|
||||
// for commands that aren't used.
|
||||
//
|
||||
// `briefHelpText` should be brief enough to show immediately after the command name on a single
|
||||
// line. It will not be wrapped. Users can use the built-in "help" command to get extended
|
||||
// help on a particular command.
|
||||
|
||||
MainBuilder& expectArg(StringPtr title, Function<Validity(StringPtr)> callback);
|
||||
MainBuilder& expectOptionalArg(StringPtr title, Function<Validity(StringPtr)> callback);
|
||||
MainBuilder& expectZeroOrMoreArgs(StringPtr title, Function<Validity(StringPtr)> callback);
|
||||
MainBuilder& expectOneOrMoreArgs(StringPtr title, Function<Validity(StringPtr)> callback);
|
||||
// Set callbacks to handle arguments. `expectArg()` and `expectOptionalArg()` specify positional
|
||||
// arguments with special handling, while `expect{Zero,One}OrMoreArgs()` specifies a handler for
|
||||
// an argument list (the handler is called once for each argument in the list). `title`
|
||||
// specifies how the argument should be represented in the usage text.
|
||||
//
|
||||
// All options callbacks are called before argument callbacks, regardless of their ordering on
|
||||
// the command line. This matches GNU getopt's behavior of permuting non-flag arguments to the
|
||||
// end of the argument list. Also matching getopt, the special option "--" indicates that the
|
||||
// rest of the command line is all arguments, not options, even if they start with '-'.
|
||||
//
|
||||
// The interpretation of positional arguments is fairly flexible. The non-optional arguments can
|
||||
// be expected at the beginning, end, or in the middle. If more arguments are specified than
|
||||
// the number of non-optional args, they are assigned to the optional argument handlers in the
|
||||
// order of registration.
|
||||
//
|
||||
// For example, say you called:
|
||||
// builder.expectArg("<foo>", ...);
|
||||
// builder.expectOptionalArg("<bar>", ...);
|
||||
// builder.expectArg("<baz>", ...);
|
||||
// builder.expectZeroOrMoreArgs("<qux>", ...);
|
||||
// builder.expectArg("<corge>", ...);
|
||||
//
|
||||
// This command requires at least three arguments: foo, baz, and corge. If four arguments are
|
||||
// given, the second is assigned to bar. If five or more arguments are specified, then the
|
||||
// arguments between the third and last are assigned to qux. Note that it never makes sense
|
||||
// to call `expect*OrMoreArgs()` more than once since only the first call would ever be used.
|
||||
//
|
||||
// In practice, you probably shouldn't create such complicated commands as in the above example.
|
||||
// But, this flexibility seems necessary to support commands where the first argument is special
|
||||
// as well as commands (like `cp`) where the last argument is special.
|
||||
|
||||
MainBuilder& callAfterParsing(Function<Validity()> callback);
|
||||
// Call the given function after all arguments have been parsed.
|
||||
|
||||
MainFunc build();
|
||||
// Build the "main" function, which simply parses the arguments. Once this returns, the
|
||||
// `MainBuilder` is no longer valid.
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
Own<Impl> impl;
|
||||
|
||||
class MainImpl;
|
||||
};
|
||||
|
||||
} // namespace kj
|
||||
|
||||
#endif // KJ_MAIN_H_
|
||||
@@ -0,0 +1,406 @@
|
||||
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef KJ_MEMORY_H_
|
||||
#define KJ_MEMORY_H_
|
||||
|
||||
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace kj {
|
||||
|
||||
// =======================================================================================
|
||||
// Disposer -- Implementation details.
|
||||
|
||||
class Disposer {
|
||||
// Abstract interface for a thing that "disposes" of objects, where "disposing" usually means
|
||||
// calling the destructor followed by freeing the underlying memory. `Own<T>` encapsulates an
|
||||
// object pointer with corresponding Disposer.
|
||||
//
|
||||
// Few developers will ever touch this interface. It is primarily useful for those implementing
|
||||
// custom memory allocators.
|
||||
|
||||
protected:
|
||||
// Do not declare a destructor, as doing so will force a global initializer for each HeapDisposer
|
||||
// instance. Eww!
|
||||
|
||||
virtual void disposeImpl(void* pointer) const = 0;
|
||||
// Disposes of the object, given a pointer to the beginning of the object. If the object is
|
||||
// polymorphic, this pointer is determined by dynamic_cast<void*>(). For non-polymorphic types,
|
||||
// Own<T> does not allow any casting, so the pointer exactly matches the original one given to
|
||||
// Own<T>.
|
||||
|
||||
public:
|
||||
|
||||
template <typename T>
|
||||
void dispose(T* object) const;
|
||||
// Helper wrapper around disposeImpl().
|
||||
//
|
||||
// If T is polymorphic, calls `disposeImpl(dynamic_cast<void*>(object))`, otherwise calls
|
||||
// `disposeImpl(implicitCast<void*>(object))`.
|
||||
//
|
||||
// Callers must not call dispose() on the same pointer twice, even if the first call throws
|
||||
// an exception.
|
||||
|
||||
private:
|
||||
template <typename T, bool polymorphic = __is_polymorphic(T)>
|
||||
struct Dispose_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class DestructorOnlyDisposer: public Disposer {
|
||||
// A disposer that merely calls the type's destructor and nothing else.
|
||||
|
||||
public:
|
||||
static const DestructorOnlyDisposer instance;
|
||||
|
||||
void disposeImpl(void* pointer) const override {
|
||||
reinterpret_cast<T*>(pointer)->~T();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
const DestructorOnlyDisposer<T> DestructorOnlyDisposer<T>::instance = DestructorOnlyDisposer<T>();
|
||||
|
||||
class NullDisposer: public Disposer {
|
||||
// A disposer that does nothing.
|
||||
|
||||
public:
|
||||
static const NullDisposer instance;
|
||||
|
||||
void disposeImpl(void* pointer) const override {}
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
// 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 much
|
||||
// more powerful -- it allows the use of custom allocators, freelists, etc. This could
|
||||
// _almost_ be accomplished with unique_ptr by forcing everyone to use something like
|
||||
// std::unique_ptr<T, kj::Deleter>, except that things get hairy in the presence of multiple
|
||||
// inheritance and upcasting, and anyway if you force everyone to use a custom deleter
|
||||
// then you've lost any benefit to interoperating with the "standard" unique_ptr.
|
||||
|
||||
public:
|
||||
KJ_DISALLOW_COPY(Own);
|
||||
inline Own(): disposer(nullptr), ptr(nullptr) {}
|
||||
inline Own(Own&& other) noexcept
|
||||
: disposer(other.disposer), ptr(other.ptr) { other.ptr = nullptr; }
|
||||
inline Own(Own<RemoveConstOrDisable<T>>&& other) noexcept
|
||||
: disposer(other.disposer), ptr(other.ptr) { other.ptr = nullptr; }
|
||||
template <typename U, typename = EnableIf<canConvert<U*, T*>()>>
|
||||
inline Own(Own<U>&& other) noexcept
|
||||
: disposer(other.disposer), ptr(other.ptr) {
|
||||
static_assert(__is_polymorphic(T),
|
||||
"Casting owned pointers requires that the target type is polymorphic.");
|
||||
other.ptr = nullptr;
|
||||
}
|
||||
inline Own(T* ptr, const Disposer& disposer) noexcept: disposer(&disposer), ptr(ptr) {}
|
||||
|
||||
~Own() noexcept(false) { dispose(); }
|
||||
|
||||
inline Own& operator=(Own&& other) {
|
||||
// Move-assingnment operator.
|
||||
|
||||
// Careful, this might own `other`. Therefore we have to transfer the pointers first, then
|
||||
// dispose.
|
||||
const Disposer* disposerCopy = disposer;
|
||||
T* ptrCopy = ptr;
|
||||
disposer = other.disposer;
|
||||
ptr = other.ptr;
|
||||
other.ptr = nullptr;
|
||||
if (ptrCopy != nullptr) {
|
||||
disposerCopy->dispose(const_cast<RemoveConst<T>*>(ptrCopy));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Own& operator=(decltype(nullptr)) {
|
||||
dispose();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
Own<U> downcast() {
|
||||
// Downcast the pointer to Own<U>, destroying the original pointer. If this pointer does not
|
||||
// actually point at an instance of U, the results are undefined (throws an exception in debug
|
||||
// mode if RTTI is enabled, otherwise you're on your own).
|
||||
|
||||
Own<U> result;
|
||||
if (ptr != nullptr) {
|
||||
result.ptr = &kj::downcast<U>(*ptr);
|
||||
result.disposer = disposer;
|
||||
ptr = nullptr;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#define NULLCHECK KJ_IREQUIRE(ptr != nullptr, "null Own<> dereference")
|
||||
inline T* operator->() { NULLCHECK; return ptr; }
|
||||
inline const T* operator->() const { NULLCHECK; return ptr; }
|
||||
inline T& operator*() { NULLCHECK; return *ptr; }
|
||||
inline const T& operator*() const { NULLCHECK; return *ptr; }
|
||||
#undef NULLCHECK
|
||||
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:
|
||||
const Disposer* disposer; // Only valid if ptr != nullptr.
|
||||
T* ptr;
|
||||
|
||||
inline explicit Own(decltype(nullptr)): disposer(nullptr), ptr(nullptr) {}
|
||||
|
||||
inline bool operator==(decltype(nullptr)) { return ptr == nullptr; }
|
||||
inline bool operator!=(decltype(nullptr)) { return ptr != nullptr; }
|
||||
// Only called by Maybe<Own<T>>.
|
||||
|
||||
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.
|
||||
T* ptrCopy = ptr;
|
||||
if (ptrCopy != nullptr) {
|
||||
ptr = nullptr;
|
||||
disposer->dispose(const_cast<RemoveConst<T>*>(ptrCopy));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
friend class Own;
|
||||
friend class Maybe<Own<T>>;
|
||||
};
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
template <typename T>
|
||||
class OwnOwn {
|
||||
public:
|
||||
inline OwnOwn(Own<T>&& value) noexcept: value(kj::mv(value)) {}
|
||||
|
||||
inline Own<T>& operator*() & { return value; }
|
||||
inline const Own<T>& operator*() const & { return value; }
|
||||
inline Own<T>&& operator*() && { return kj::mv(value); }
|
||||
inline const Own<T>&& operator*() const && { return kj::mv(value); }
|
||||
inline Own<T>* operator->() { return &value; }
|
||||
inline const Own<T>* operator->() const { return &value; }
|
||||
inline operator Own<T>*() { return value ? &value : nullptr; }
|
||||
inline operator const Own<T>*() const { return value ? &value : nullptr; }
|
||||
|
||||
private:
|
||||
Own<T> value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
OwnOwn<T> readMaybe(Maybe<Own<T>>&& maybe) { return OwnOwn<T>(kj::mv(maybe.ptr)); }
|
||||
template <typename T>
|
||||
Own<T>* readMaybe(Maybe<Own<T>>& maybe) { return maybe.ptr ? &maybe.ptr : nullptr; }
|
||||
template <typename T>
|
||||
const Own<T>* readMaybe(const Maybe<Own<T>>& maybe) { return maybe.ptr ? &maybe.ptr : nullptr; }
|
||||
|
||||
} // namespace _ (private)
|
||||
|
||||
template <typename T>
|
||||
class Maybe<Own<T>> {
|
||||
public:
|
||||
inline Maybe(): ptr(nullptr) {}
|
||||
inline Maybe(Own<T>&& t) noexcept: ptr(kj::mv(t)) {}
|
||||
inline Maybe(Maybe&& other) noexcept: ptr(kj::mv(other.ptr)) {}
|
||||
|
||||
template <typename U>
|
||||
inline Maybe(Maybe<Own<U>>&& other): ptr(mv(other.ptr)) {}
|
||||
template <typename U>
|
||||
inline Maybe(Own<U>&& other): ptr(mv(other)) {}
|
||||
|
||||
inline Maybe(decltype(nullptr)) noexcept: ptr(nullptr) {}
|
||||
|
||||
inline operator Maybe<T&>() { return ptr.get(); }
|
||||
inline operator Maybe<const T&>() const { return ptr.get(); }
|
||||
|
||||
inline Maybe& operator=(Maybe&& other) { ptr = kj::mv(other.ptr); return *this; }
|
||||
|
||||
inline bool operator==(decltype(nullptr)) const { return ptr == nullptr; }
|
||||
inline bool operator!=(decltype(nullptr)) const { return ptr != nullptr; }
|
||||
|
||||
Own<T>& orDefault(Own<T>& defaultValue) {
|
||||
if (ptr == nullptr) {
|
||||
return defaultValue;
|
||||
} else {
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
const Own<T>& orDefault(const Own<T>& defaultValue) const {
|
||||
if (ptr == nullptr) {
|
||||
return defaultValue;
|
||||
} else {
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
auto map(Func&& f) & -> Maybe<decltype(f(instance<Own<T>&>()))> {
|
||||
if (ptr == nullptr) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return f(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
auto map(Func&& f) const & -> Maybe<decltype(f(instance<const Own<T>&>()))> {
|
||||
if (ptr == nullptr) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return f(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
auto map(Func&& f) && -> Maybe<decltype(f(instance<Own<T>&&>()))> {
|
||||
if (ptr == nullptr) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return f(kj::mv(ptr));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
auto map(Func&& f) const && -> Maybe<decltype(f(instance<const Own<T>&&>()))> {
|
||||
if (ptr == nullptr) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return f(kj::mv(ptr));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Own<T> ptr;
|
||||
|
||||
template <typename U>
|
||||
friend class Maybe;
|
||||
template <typename U>
|
||||
friend _::OwnOwn<U> _::readMaybe(Maybe<Own<U>>&& maybe);
|
||||
template <typename U>
|
||||
friend Own<U>* _::readMaybe(Maybe<Own<U>>& maybe);
|
||||
template <typename U>
|
||||
friend const Own<U>* _::readMaybe(const Maybe<Own<U>>& maybe);
|
||||
};
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
template <typename T>
|
||||
class HeapDisposer final: public Disposer {
|
||||
public:
|
||||
virtual void disposeImpl(void* pointer) const override { delete reinterpret_cast<T*>(pointer); }
|
||||
|
||||
static const HeapDisposer instance;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
const HeapDisposer<T> HeapDisposer<T>::instance = HeapDisposer<T>();
|
||||
|
||||
} // namespace _ (private)
|
||||
|
||||
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 this. (Since we know the object size at delete time, we could actually implement an
|
||||
// allocator that is more efficient than operator new.)
|
||||
|
||||
return Own<T>(new T(kj::fwd<Params>(params)...), _::HeapDisposer<T>::instance);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Own<Decay<T>> heap(T&& orig) {
|
||||
// Allocate a copy (or move) of the argument on the heap.
|
||||
//
|
||||
// The purpose of this overload is to allow you to omit the template parameter as there is only
|
||||
// one argument and the purpose is to copy it.
|
||||
|
||||
typedef Decay<T> T2;
|
||||
return Own<T2>(new T2(kj::fwd<T>(orig)), _::HeapDisposer<T2>::instance);
|
||||
}
|
||||
|
||||
// =======================================================================================
|
||||
// SpaceFor<T> -- assists in manual allocation
|
||||
|
||||
template <typename T>
|
||||
class SpaceFor {
|
||||
// A class which has the same size and alignment as T but does not call its constructor or
|
||||
// destructor automatically. Instead, call construct() to construct a T in the space, which
|
||||
// returns an Own<T> which will take care of calling T's destructor later.
|
||||
|
||||
public:
|
||||
inline SpaceFor() {}
|
||||
inline ~SpaceFor() {}
|
||||
|
||||
template <typename... Params>
|
||||
Own<T> construct(Params&&... params) {
|
||||
ctor(value, kj::fwd<Params>(params)...);
|
||||
return Own<T>(&value, DestructorOnlyDisposer<T>::instance);
|
||||
}
|
||||
|
||||
private:
|
||||
union {
|
||||
T value;
|
||||
};
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
// Inline implementation details
|
||||
|
||||
template <typename T>
|
||||
struct Disposer::Dispose_<T, true> {
|
||||
static void dispose(T* object, const Disposer& disposer) {
|
||||
// Note that dynamic_cast<void*> does not require RTTI to be enabled, because the offset to
|
||||
// the top of the object is in the vtable -- as it obviously needs to be to correctly implement
|
||||
// operator delete.
|
||||
disposer.disposeImpl(dynamic_cast<void*>(object));
|
||||
}
|
||||
};
|
||||
template <typename T>
|
||||
struct Disposer::Dispose_<T, false> {
|
||||
static void dispose(T* object, const Disposer& disposer) {
|
||||
disposer.disposeImpl(static_cast<void*>(object));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void Disposer::dispose(T* object) const {
|
||||
Dispose_<T>::dispose(object, *this);
|
||||
}
|
||||
|
||||
} // namespace kj
|
||||
|
||||
#endif // KJ_MEMORY_H_
|
||||
@@ -0,0 +1,369 @@
|
||||
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef KJ_MUTEX_H_
|
||||
#define KJ_MUTEX_H_
|
||||
|
||||
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include "memory.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
#if __linux__ && !defined(KJ_USE_FUTEX)
|
||||
#define KJ_USE_FUTEX 1
|
||||
#endif
|
||||
|
||||
#if !KJ_USE_FUTEX && !_WIN32
|
||||
// On Linux we use futex. On other platforms we wrap pthreads.
|
||||
// TODO(someday): Write efficient low-level locking primitives for other platforms.
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
namespace kj {
|
||||
|
||||
// =======================================================================================
|
||||
// Private details -- public interfaces follow below.
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
class Mutex {
|
||||
// Internal implementation details. See `MutexGuarded<T>`.
|
||||
|
||||
public:
|
||||
Mutex();
|
||||
~Mutex();
|
||||
KJ_DISALLOW_COPY(Mutex);
|
||||
|
||||
enum Exclusivity {
|
||||
EXCLUSIVE,
|
||||
SHARED
|
||||
};
|
||||
|
||||
void lock(Exclusivity exclusivity);
|
||||
void unlock(Exclusivity exclusivity);
|
||||
|
||||
void assertLockedByCaller(Exclusivity exclusivity);
|
||||
// In debug mode, assert that the mutex is locked by the calling thread, or if that is
|
||||
// non-trivial, assert that the mutex is locked (which should be good enough to catch problems
|
||||
// in unit tests). In non-debug builds, do nothing.
|
||||
|
||||
private:
|
||||
#if KJ_USE_FUTEX
|
||||
uint futex;
|
||||
// bit 31 (msb) = set if exclusive lock held
|
||||
// bit 30 (msb) = set if threads are waiting for exclusive lock
|
||||
// bits 0-29 = count of readers; If an exclusive lock is held, this is the count of threads
|
||||
// waiting for a read lock, otherwise it is the count of threads that currently hold a read
|
||||
// lock.
|
||||
|
||||
static constexpr uint EXCLUSIVE_HELD = 1u << 31;
|
||||
static constexpr uint EXCLUSIVE_REQUESTED = 1u << 30;
|
||||
static constexpr uint SHARED_COUNT_MASK = EXCLUSIVE_REQUESTED - 1;
|
||||
|
||||
#elif _WIN32
|
||||
uintptr_t srwLock; // Actually an SRWLOCK, but don't want to #include <windows.h> in header.
|
||||
|
||||
#else
|
||||
mutable pthread_rwlock_t mutex;
|
||||
#endif
|
||||
};
|
||||
|
||||
class Once {
|
||||
// Internal implementation details. See `Lazy<T>`.
|
||||
|
||||
public:
|
||||
#if KJ_USE_FUTEX
|
||||
inline Once(bool startInitialized = false)
|
||||
: futex(startInitialized ? INITIALIZED : UNINITIALIZED) {}
|
||||
#else
|
||||
Once(bool startInitialized = false);
|
||||
~Once();
|
||||
#endif
|
||||
KJ_DISALLOW_COPY(Once);
|
||||
|
||||
class Initializer {
|
||||
public:
|
||||
virtual void run() = 0;
|
||||
};
|
||||
|
||||
void runOnce(Initializer& init);
|
||||
|
||||
#if _WIN32 // TODO(perf): Can we make this inline on win32 somehow?
|
||||
bool isInitialized() noexcept;
|
||||
|
||||
#else
|
||||
inline bool isInitialized() noexcept {
|
||||
// Fast path check to see if runOnce() would simply return immediately.
|
||||
#if KJ_USE_FUTEX
|
||||
return __atomic_load_n(&futex, __ATOMIC_ACQUIRE) == INITIALIZED;
|
||||
#else
|
||||
return __atomic_load_n(&state, __ATOMIC_ACQUIRE) == INITIALIZED;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void reset();
|
||||
// Returns the state from initialized to uninitialized. It is an error to call this when
|
||||
// not already initialized, or when runOnce() or isInitialized() might be called concurrently in
|
||||
// another thread.
|
||||
|
||||
private:
|
||||
#if KJ_USE_FUTEX
|
||||
uint futex;
|
||||
|
||||
enum State {
|
||||
UNINITIALIZED,
|
||||
INITIALIZING,
|
||||
INITIALIZING_WITH_WAITERS,
|
||||
INITIALIZED
|
||||
};
|
||||
|
||||
#elif _WIN32
|
||||
uintptr_t initOnce; // Actually an INIT_ONCE, but don't want to #include <windows.h> in header.
|
||||
|
||||
#else
|
||||
enum State {
|
||||
UNINITIALIZED,
|
||||
INITIALIZED
|
||||
};
|
||||
State state;
|
||||
pthread_mutex_t mutex;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace _ (private)
|
||||
|
||||
// =======================================================================================
|
||||
// Public interface
|
||||
|
||||
template <typename T>
|
||||
class Locked {
|
||||
// Return type for `MutexGuarded<T>::lock()`. `Locked<T>` provides access to the bounded object
|
||||
// and unlocks the mutex when it goes out of scope.
|
||||
|
||||
public:
|
||||
KJ_DISALLOW_COPY(Locked);
|
||||
inline Locked(): mutex(nullptr), ptr(nullptr) {}
|
||||
inline Locked(Locked&& other): mutex(other.mutex), ptr(other.ptr) {
|
||||
other.mutex = nullptr;
|
||||
other.ptr = nullptr;
|
||||
}
|
||||
inline ~Locked() {
|
||||
if (mutex != nullptr) mutex->unlock(isConst<T>() ? _::Mutex::SHARED : _::Mutex::EXCLUSIVE);
|
||||
}
|
||||
|
||||
inline Locked& operator=(Locked&& other) {
|
||||
if (mutex != nullptr) mutex->unlock(isConst<T>() ? _::Mutex::SHARED : _::Mutex::EXCLUSIVE);
|
||||
mutex = other.mutex;
|
||||
ptr = other.ptr;
|
||||
other.mutex = nullptr;
|
||||
other.ptr = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void release() {
|
||||
if (mutex != nullptr) mutex->unlock(isConst<T>() ? _::Mutex::SHARED : _::Mutex::EXCLUSIVE);
|
||||
mutex = nullptr;
|
||||
ptr = nullptr;
|
||||
}
|
||||
|
||||
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:
|
||||
_::Mutex* mutex;
|
||||
T* ptr;
|
||||
|
||||
inline Locked(_::Mutex& mutex, T& value): mutex(&mutex), ptr(&value) {}
|
||||
|
||||
template <typename U>
|
||||
friend class MutexGuarded;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class MutexGuarded {
|
||||
// An object of type T, bounded by a mutex. In order to access the object, you must lock it.
|
||||
//
|
||||
// Write locks are not "recursive" -- trying to lock again in a thread that already holds a lock
|
||||
// will deadlock. Recursive write locks are usually a sign of bad design.
|
||||
//
|
||||
// Unfortunately, **READ LOCKS ARE NOT RECURSIVE** either. Common sense says they should be.
|
||||
// But on many operating systems (BSD, OSX), recursively read-locking a pthread_rwlock is
|
||||
// actually unsafe. The problem is that writers are "prioritized" over readers, so a read lock
|
||||
// request will block if any write lock requests are outstanding. So, if thread A takes a read
|
||||
// lock, thread B requests a write lock (and starts waiting), and then thread A tries to take
|
||||
// another read lock recursively, the result is deadlock.
|
||||
|
||||
public:
|
||||
template <typename... Params>
|
||||
explicit MutexGuarded(Params&&... params);
|
||||
// Initialize the mutex-bounded object by passing the given parameters to its constructor.
|
||||
|
||||
Locked<T> lockExclusive() const;
|
||||
// Exclusively locks the object and returns it. The returned `Locked<T>` can be passed by
|
||||
// move, similar to `Own<T>`.
|
||||
//
|
||||
// This method is declared `const` in accordance with KJ style rules which say that constness
|
||||
// should be used to indicate thread-safety. It is safe to share a const pointer between threads,
|
||||
// but it is not safe to share a mutable pointer. Since the whole point of MutexGuarded is to
|
||||
// be shared between threads, its methods should be const, even though locking it produces a
|
||||
// non-const pointer to the contained object.
|
||||
|
||||
Locked<const T> lockShared() const;
|
||||
// Lock the value for shared access. Multiple shared locks can be taken concurrently, but cannot
|
||||
// be held at the same time as a non-shared lock.
|
||||
|
||||
inline const T& getWithoutLock() const { return value; }
|
||||
inline T& getWithoutLock() { return value; }
|
||||
// Escape hatch for cases where some external factor guarantees that it's safe to get the
|
||||
// value. You should treat these like const_cast -- be highly suspicious of any use.
|
||||
|
||||
inline const T& getAlreadyLockedShared() const;
|
||||
inline T& getAlreadyLockedShared();
|
||||
inline T& getAlreadyLockedExclusive() const;
|
||||
// Like `getWithoutLock()`, but asserts that the lock is already held by the calling thread.
|
||||
|
||||
private:
|
||||
mutable _::Mutex mutex;
|
||||
mutable T value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class MutexGuarded<const T> {
|
||||
// MutexGuarded cannot guard a const type. This would be pointless anyway, and would complicate
|
||||
// the implementation of Locked<T>, which uses constness to decide what kind of lock it holds.
|
||||
static_assert(sizeof(T) < 0, "MutexGuarded's type cannot be const.");
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class Lazy {
|
||||
// A lazily-initialized value.
|
||||
|
||||
public:
|
||||
template <typename Func>
|
||||
T& get(Func&& init);
|
||||
template <typename Func>
|
||||
const T& get(Func&& init) const;
|
||||
// The first thread to call get() will invoke the given init function to construct the value.
|
||||
// Other threads will block until construction completes, then return the same value.
|
||||
//
|
||||
// `init` is a functor(typically a lambda) which takes `SpaceFor<T>&` as its parameter and returns
|
||||
// `Own<T>`. If `init` throws an exception, the exception is propagated out of that thread's
|
||||
// call to `get()`, and subsequent calls behave as if `get()` hadn't been called at all yet --
|
||||
// in other words, subsequent calls retry initialization until it succeeds.
|
||||
|
||||
private:
|
||||
mutable _::Once once;
|
||||
mutable SpaceFor<T> space;
|
||||
mutable Own<T> value;
|
||||
|
||||
template <typename Func>
|
||||
class InitImpl;
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
// Inline implementation details
|
||||
|
||||
template <typename T>
|
||||
template <typename... Params>
|
||||
inline MutexGuarded<T>::MutexGuarded(Params&&... params)
|
||||
: value(kj::fwd<Params>(params)...) {}
|
||||
|
||||
template <typename T>
|
||||
inline Locked<T> MutexGuarded<T>::lockExclusive() const {
|
||||
mutex.lock(_::Mutex::EXCLUSIVE);
|
||||
return Locked<T>(mutex, value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Locked<const T> MutexGuarded<T>::lockShared() const {
|
||||
mutex.lock(_::Mutex::SHARED);
|
||||
return Locked<const T>(mutex, value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline const T& MutexGuarded<T>::getAlreadyLockedShared() const {
|
||||
#ifdef KJ_DEBUG
|
||||
mutex.assertLockedByCaller(_::Mutex::SHARED);
|
||||
#endif
|
||||
return value;
|
||||
}
|
||||
template <typename T>
|
||||
inline T& MutexGuarded<T>::getAlreadyLockedShared() {
|
||||
#ifdef KJ_DEBUG
|
||||
mutex.assertLockedByCaller(_::Mutex::SHARED);
|
||||
#endif
|
||||
return value;
|
||||
}
|
||||
template <typename T>
|
||||
inline T& MutexGuarded<T>::getAlreadyLockedExclusive() const {
|
||||
#ifdef KJ_DEBUG
|
||||
mutex.assertLockedByCaller(_::Mutex::EXCLUSIVE);
|
||||
#endif
|
||||
return const_cast<T&>(value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename Func>
|
||||
class Lazy<T>::InitImpl: public _::Once::Initializer {
|
||||
public:
|
||||
inline InitImpl(const Lazy<T>& lazy, Func&& func): lazy(lazy), func(kj::fwd<Func>(func)) {}
|
||||
|
||||
void run() override {
|
||||
lazy.value = func(lazy.space);
|
||||
}
|
||||
|
||||
private:
|
||||
const Lazy<T>& lazy;
|
||||
Func func;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
template <typename Func>
|
||||
inline T& Lazy<T>::get(Func&& init) {
|
||||
if (!once.isInitialized()) {
|
||||
InitImpl<Func> initImpl(*this, kj::fwd<Func>(init));
|
||||
once.runOnce(initImpl);
|
||||
}
|
||||
return *value;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename Func>
|
||||
inline const T& Lazy<T>::get(Func&& init) const {
|
||||
if (!once.isInitialized()) {
|
||||
InitImpl<Func> initImpl(*this, kj::fwd<Func>(init));
|
||||
once.runOnce(initImpl);
|
||||
}
|
||||
return *value;
|
||||
}
|
||||
|
||||
} // namespace kj
|
||||
|
||||
#endif // KJ_MUTEX_H_
|
||||
@@ -0,0 +1,155 @@
|
||||
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef KJ_ONE_OF_H_
|
||||
#define KJ_ONE_OF_H_
|
||||
|
||||
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace kj {
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
template <uint i, typename Key, typename First, typename... Rest>
|
||||
struct TypeIndex_ { static constexpr uint value = TypeIndex_<i + 1, Key, Rest...>::value; };
|
||||
template <uint i, typename Key, typename... Rest>
|
||||
struct TypeIndex_<i, Key, Key, Rest...> { static constexpr uint value = i; };
|
||||
|
||||
} // namespace _ (private)
|
||||
|
||||
template <typename... Variants>
|
||||
class OneOf {
|
||||
template <typename Key>
|
||||
static inline constexpr uint typeIndex() { return _::TypeIndex_<1, Key, Variants...>::value; }
|
||||
// Get the 1-based index of Key within the type list Types.
|
||||
|
||||
public:
|
||||
inline OneOf(): tag(0) {}
|
||||
OneOf(const OneOf& other) { copyFrom(other); }
|
||||
OneOf(OneOf&& other) { moveFrom(other); }
|
||||
~OneOf() { destroy(); }
|
||||
|
||||
OneOf& operator=(const OneOf& other) { if (tag != 0) destroy(); copyFrom(other); return *this; }
|
||||
OneOf& operator=(OneOf&& other) { if (tag != 0) destroy(); moveFrom(other); return *this; }
|
||||
|
||||
inline bool operator==(decltype(nullptr)) const { return tag == 0; }
|
||||
inline bool operator!=(decltype(nullptr)) const { return tag != 0; }
|
||||
|
||||
template <typename T>
|
||||
bool is() const {
|
||||
return tag == typeIndex<T>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& get() {
|
||||
KJ_IREQUIRE(is<T>(), "Must check OneOf::is<T>() before calling get<T>().");
|
||||
return *reinterpret_cast<T*>(space);
|
||||
}
|
||||
template <typename T>
|
||||
const T& get() const {
|
||||
KJ_IREQUIRE(is<T>(), "Must check OneOf::is<T>() before calling get<T>().");
|
||||
return *reinterpret_cast<const T*>(space);
|
||||
}
|
||||
|
||||
template <typename T, typename... Params>
|
||||
T& init(Params&&... params) {
|
||||
if (tag != 0) destroy();
|
||||
ctor(*reinterpret_cast<T*>(space), kj::fwd<Params>(params)...);
|
||||
tag = typeIndex<T>();
|
||||
return *reinterpret_cast<T*>(space);
|
||||
}
|
||||
|
||||
private:
|
||||
uint tag;
|
||||
|
||||
static inline constexpr size_t maxSize(size_t a) {
|
||||
return a;
|
||||
}
|
||||
template <typename... Rest>
|
||||
static inline constexpr size_t maxSize(size_t a, size_t b, Rest... rest) {
|
||||
return maxSize(kj::max(a, b), rest...);
|
||||
}
|
||||
// Returns the maximum of all the parameters.
|
||||
// TODO(someday): Generalize the above template and make it common. I tried, but C++ decided to
|
||||
// be difficult so I cut my losses.
|
||||
|
||||
static constexpr auto spaceSize = maxSize(sizeof(Variants)...);
|
||||
// TODO(msvc): This constant could just as well go directly inside space's bracket's, where it's
|
||||
// used, but MSVC suffers a parse error on `...`.
|
||||
|
||||
union {
|
||||
byte space[spaceSize];
|
||||
|
||||
void* forceAligned;
|
||||
// TODO(someday): Use C++11 alignas() once we require GCC 4.8 / Clang 3.3.
|
||||
};
|
||||
|
||||
template <typename... T>
|
||||
inline void doAll(T... t) {}
|
||||
|
||||
template <typename T>
|
||||
inline bool destroyVariant() {
|
||||
if (tag == typeIndex<T>()) {
|
||||
tag = 0;
|
||||
dtor(*reinterpret_cast<T*>(space));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void destroy() {
|
||||
doAll(destroyVariant<Variants>()...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool copyVariantFrom(const OneOf& other) {
|
||||
if (other.is<T>()) {
|
||||
ctor(*reinterpret_cast<T*>(space), other.get<T>());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void copyFrom(const OneOf& other) {
|
||||
// Initialize as a copy of `other`. Expects that `this` starts out uninitialized, so the tag
|
||||
// is invalid.
|
||||
tag = other.tag;
|
||||
doAll(copyVariantFrom<Variants>(other)...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool moveVariantFrom(OneOf& other) {
|
||||
if (other.is<T>()) {
|
||||
ctor(*reinterpret_cast<T*>(space), kj::mv(other.get<T>()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void moveFrom(OneOf& other) {
|
||||
// Initialize as a copy of `other`. Expects that `this` starts out uninitialized, so the tag
|
||||
// is invalid.
|
||||
tag = other.tag;
|
||||
doAll(moveVariantFrom<Variants>(other)...);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace kj
|
||||
|
||||
#endif // KJ_ONE_OF_H_
|
||||
@@ -0,0 +1,361 @@
|
||||
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// This file contains parsers useful for character stream inputs, including parsers to parse
|
||||
// common kinds of tokens like identifiers, numbers, and quoted strings.
|
||||
|
||||
#ifndef KJ_PARSE_CHAR_H_
|
||||
#define KJ_PARSE_CHAR_H_
|
||||
|
||||
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
#include "../string.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
namespace kj {
|
||||
namespace parse {
|
||||
|
||||
// =======================================================================================
|
||||
// Exact char/string.
|
||||
|
||||
class ExactString_ {
|
||||
public:
|
||||
constexpr inline ExactString_(const char* str): str(str) {}
|
||||
|
||||
template <typename Input>
|
||||
Maybe<Tuple<>> operator()(Input& input) const {
|
||||
const char* ptr = str;
|
||||
|
||||
while (*ptr != '\0') {
|
||||
if (input.atEnd() || input.current() != *ptr) return nullptr;
|
||||
input.next();
|
||||
++ptr;
|
||||
}
|
||||
|
||||
return Tuple<>();
|
||||
}
|
||||
|
||||
private:
|
||||
const char* str;
|
||||
};
|
||||
|
||||
constexpr inline ExactString_ exactString(const char* str) {
|
||||
return ExactString_(str);
|
||||
}
|
||||
|
||||
template <char c>
|
||||
constexpr ExactlyConst_<char, c> exactChar() {
|
||||
// Returns a parser that matches exactly the character given by the template argument (returning
|
||||
// no result).
|
||||
return ExactlyConst_<char, c>();
|
||||
}
|
||||
|
||||
// =======================================================================================
|
||||
// Char ranges / sets
|
||||
|
||||
class CharGroup_ {
|
||||
public:
|
||||
constexpr inline CharGroup_(): bits{0, 0, 0, 0} {}
|
||||
|
||||
constexpr inline CharGroup_ orRange(unsigned char first, unsigned char last) const {
|
||||
return CharGroup_(bits[0] | (oneBits(last + 1) & ~oneBits(first )),
|
||||
bits[1] | (oneBits(last - 63) & ~oneBits(first - 64)),
|
||||
bits[2] | (oneBits(last - 127) & ~oneBits(first - 128)),
|
||||
bits[3] | (oneBits(last - 191) & ~oneBits(first - 192)));
|
||||
}
|
||||
|
||||
constexpr inline CharGroup_ orAny(const char* chars) const {
|
||||
return *chars == 0 ? *this : orChar(*chars).orAny(chars + 1);
|
||||
}
|
||||
|
||||
constexpr inline CharGroup_ orChar(unsigned char c) const {
|
||||
return CharGroup_(bits[0] | bit(c),
|
||||
bits[1] | bit(c - 64),
|
||||
bits[2] | bit(c - 128),
|
||||
bits[3] | bit(c - 256));
|
||||
}
|
||||
|
||||
constexpr inline CharGroup_ orGroup(CharGroup_ other) const {
|
||||
return CharGroup_(bits[0] | other.bits[0],
|
||||
bits[1] | other.bits[1],
|
||||
bits[2] | other.bits[2],
|
||||
bits[3] | other.bits[3]);
|
||||
}
|
||||
|
||||
constexpr inline CharGroup_ invert() const {
|
||||
return CharGroup_(~bits[0], ~bits[1], ~bits[2], ~bits[3]);
|
||||
}
|
||||
|
||||
constexpr inline bool contains(unsigned char c) const {
|
||||
return (bits[c / 64] & (1ll << (c % 64))) != 0;
|
||||
}
|
||||
|
||||
template <typename Input>
|
||||
Maybe<char> operator()(Input& input) const {
|
||||
if (input.atEnd()) return nullptr;
|
||||
unsigned char c = input.current();
|
||||
if (contains(c)) {
|
||||
input.next();
|
||||
return c;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
typedef unsigned long long Bits64;
|
||||
|
||||
constexpr inline CharGroup_(Bits64 a, Bits64 b, Bits64 c, Bits64 d): bits{a, b, c, d} {}
|
||||
Bits64 bits[4];
|
||||
|
||||
static constexpr inline Bits64 oneBits(int count) {
|
||||
return count <= 0 ? 0ll : count >= 64 ? -1ll : ((1ll << count) - 1);
|
||||
}
|
||||
static constexpr inline Bits64 bit(int index) {
|
||||
return index < 0 ? 0 : index >= 64 ? 0 : (1ll << index);
|
||||
}
|
||||
};
|
||||
|
||||
constexpr inline CharGroup_ charRange(char first, char last) {
|
||||
// Create a parser which accepts any character in the range from `first` to `last`, inclusive.
|
||||
// For example: `charRange('a', 'z')` matches all lower-case letters. The parser's result is the
|
||||
// character matched.
|
||||
//
|
||||
// The returned object has methods which can be used to match more characters. The following
|
||||
// produces a parser which accepts any letter as well as '_', '+', '-', and '.'.
|
||||
//
|
||||
// charRange('a', 'z').orRange('A', 'Z').orChar('_').orAny("+-.")
|
||||
//
|
||||
// You can also use `.invert()` to match the opposite set of characters.
|
||||
|
||||
return CharGroup_().orRange(first, last);
|
||||
}
|
||||
|
||||
#if _MSC_VER
|
||||
#define anyOfChars(chars) CharGroup_().orAny(chars)
|
||||
// TODO(msvc): MSVC ICEs on the proper definition of `anyOfChars()`, which in turn prevents us from
|
||||
// building the compiler or schema parser. We don't know why this happens, but Harris found that
|
||||
// this horrible, horrible hack makes things work. This is awful, but it's better than nothing.
|
||||
// Hopefully, MSVC will get fixed soon and we'll be able to remove this.
|
||||
#else
|
||||
constexpr inline CharGroup_ anyOfChars(const char* chars) {
|
||||
// Returns a parser that accepts any of the characters in the given string (which should usually
|
||||
// be a literal). The returned parser is of the same type as returned by `charRange()` -- see
|
||||
// that function for more info.
|
||||
|
||||
return CharGroup_().orAny(chars);
|
||||
}
|
||||
#endif
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
struct ArrayToString {
|
||||
inline String operator()(const Array<char>& arr) const {
|
||||
return heapString(arr);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace _ (private)
|
||||
|
||||
template <typename SubParser>
|
||||
constexpr inline auto charsToString(SubParser&& subParser)
|
||||
-> decltype(transform(kj::fwd<SubParser>(subParser), _::ArrayToString())) {
|
||||
// Wraps a parser that returns Array<char> such that it returns String instead.
|
||||
return parse::transform(kj::fwd<SubParser>(subParser), _::ArrayToString());
|
||||
}
|
||||
|
||||
// =======================================================================================
|
||||
// Basic character classes.
|
||||
|
||||
constexpr auto alpha = charRange('a', 'z').orRange('A', 'Z');
|
||||
constexpr auto digit = charRange('0', '9');
|
||||
constexpr auto alphaNumeric = alpha.orGroup(digit);
|
||||
constexpr auto nameStart = alpha.orChar('_');
|
||||
constexpr auto nameChar = alphaNumeric.orChar('_');
|
||||
constexpr auto hexDigit = charRange('0', '9').orRange('a', 'f').orRange('A', 'F');
|
||||
constexpr auto octDigit = charRange('0', '7');
|
||||
constexpr auto whitespaceChar = anyOfChars(" \f\n\r\t\v");
|
||||
constexpr auto controlChar = charRange(0, 0x1f).invert().orGroup(whitespaceChar).invert();
|
||||
|
||||
constexpr auto whitespace = many(anyOfChars(" \f\n\r\t\v"));
|
||||
|
||||
constexpr auto discardWhitespace = discard(many(discard(anyOfChars(" \f\n\r\t\v"))));
|
||||
// Like discard(whitespace) but avoids some memory allocation.
|
||||
|
||||
// =======================================================================================
|
||||
// Identifiers
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
struct IdentifierToString {
|
||||
inline String operator()(char first, const Array<char>& rest) const {
|
||||
String result = heapString(rest.size() + 1);
|
||||
result[0] = first;
|
||||
memcpy(result.begin() + 1, rest.begin(), rest.size());
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace _ (private)
|
||||
|
||||
constexpr auto identifier = transform(sequence(nameStart, many(nameChar)), _::IdentifierToString());
|
||||
// Parses an identifier (e.g. a C variable name).
|
||||
|
||||
// =======================================================================================
|
||||
// Integers
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
inline char parseDigit(char c) {
|
||||
if (c < 'A') return c - '0';
|
||||
if (c < 'a') return c - 'A' + 10;
|
||||
return c - 'a' + 10;
|
||||
}
|
||||
|
||||
template <uint base>
|
||||
struct ParseInteger {
|
||||
inline uint64_t operator()(const Array<char>& digits) const {
|
||||
return operator()('0', digits);
|
||||
}
|
||||
uint64_t operator()(char first, const Array<char>& digits) const {
|
||||
uint64_t result = parseDigit(first);
|
||||
for (char digit: digits) {
|
||||
result = result * base + parseDigit(digit);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace _ (private)
|
||||
|
||||
constexpr auto integer = sequence(
|
||||
oneOf(
|
||||
transform(sequence(exactChar<'0'>(), exactChar<'x'>(), oneOrMore(hexDigit)), _::ParseInteger<16>()),
|
||||
transform(sequence(exactChar<'0'>(), many(octDigit)), _::ParseInteger<8>()),
|
||||
transform(sequence(charRange('1', '9'), many(digit)), _::ParseInteger<10>())),
|
||||
notLookingAt(alpha.orAny("_.")));
|
||||
|
||||
// =======================================================================================
|
||||
// Numbers (i.e. floats)
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
struct ParseFloat {
|
||||
double operator()(const Array<char>& digits,
|
||||
const Maybe<Array<char>>& fraction,
|
||||
const Maybe<Tuple<Maybe<char>, Array<char>>>& exponent) const;
|
||||
};
|
||||
|
||||
} // namespace _ (private)
|
||||
|
||||
constexpr auto number = transform(
|
||||
sequence(
|
||||
oneOrMore(digit),
|
||||
optional(sequence(exactChar<'.'>(), many(digit))),
|
||||
optional(sequence(discard(anyOfChars("eE")), optional(anyOfChars("+-")), many(digit))),
|
||||
notLookingAt(alpha.orAny("_."))),
|
||||
_::ParseFloat());
|
||||
|
||||
// =======================================================================================
|
||||
// Quoted strings
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
struct InterpretEscape {
|
||||
char operator()(char c) const {
|
||||
switch (c) {
|
||||
case 'a': return '\a';
|
||||
case 'b': return '\b';
|
||||
case 'f': return '\f';
|
||||
case 'n': return '\n';
|
||||
case 'r': return '\r';
|
||||
case 't': return '\t';
|
||||
case 'v': return '\v';
|
||||
default: return c;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct ParseHexEscape {
|
||||
inline char operator()(char first, char second) const {
|
||||
return (parseDigit(first) << 4) | parseDigit(second);
|
||||
}
|
||||
};
|
||||
|
||||
struct ParseHexByte {
|
||||
inline byte operator()(char first, char second) const {
|
||||
return (parseDigit(first) << 4) | parseDigit(second);
|
||||
}
|
||||
};
|
||||
|
||||
struct ParseOctEscape {
|
||||
inline char operator()(char first, Maybe<char> second, Maybe<char> third) const {
|
||||
char result = first - '0';
|
||||
KJ_IF_MAYBE(digit1, second) {
|
||||
result = (result << 3) | (*digit1 - '0');
|
||||
KJ_IF_MAYBE(digit2, third) {
|
||||
result = (result << 3) | (*digit2 - '0');
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace _ (private)
|
||||
|
||||
constexpr auto escapeSequence =
|
||||
sequence(exactChar<'\\'>(), oneOf(
|
||||
transform(anyOfChars("abfnrtv'\"\\\?"), _::InterpretEscape()),
|
||||
transform(sequence(exactChar<'x'>(), hexDigit, hexDigit), _::ParseHexEscape()),
|
||||
transform(sequence(octDigit, optional(octDigit), optional(octDigit)),
|
||||
_::ParseOctEscape())));
|
||||
// A parser that parses a C-string-style escape sequence (starting with a backslash). Returns
|
||||
// a char.
|
||||
|
||||
constexpr auto doubleQuotedString = charsToString(sequence(
|
||||
exactChar<'\"'>(),
|
||||
many(oneOf(anyOfChars("\\\n\"").invert(), escapeSequence)),
|
||||
exactChar<'\"'>()));
|
||||
// Parses a C-style double-quoted string.
|
||||
|
||||
constexpr auto singleQuotedString = charsToString(sequence(
|
||||
exactChar<'\''>(),
|
||||
many(oneOf(anyOfChars("\\\n\'").invert(), escapeSequence)),
|
||||
exactChar<'\''>()));
|
||||
// Parses a C-style single-quoted string.
|
||||
|
||||
constexpr auto doubleQuotedHexBinary = sequence(
|
||||
exactChar<'0'>(), exactChar<'x'>(), exactChar<'\"'>(),
|
||||
oneOrMore(transform(sequence(discardWhitespace, hexDigit, hexDigit), _::ParseHexByte())),
|
||||
discardWhitespace,
|
||||
exactChar<'\"'>());
|
||||
// Parses a double-quoted hex binary literal. Returns Array<byte>.
|
||||
|
||||
} // namespace parse
|
||||
} // namespace kj
|
||||
|
||||
#endif // KJ_PARSE_CHAR_H_
|
||||
@@ -0,0 +1,824 @@
|
||||
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Parser combinator framework!
|
||||
//
|
||||
// This file declares several functions which construct parsers, usually taking other parsers as
|
||||
// input, thus making them parser combinators.
|
||||
//
|
||||
// A valid parser is any functor which takes a reference to an input cursor (defined below) as its
|
||||
// input and returns a Maybe. The parser returns null on parse failure, or returns the parsed
|
||||
// result on success.
|
||||
//
|
||||
// An "input cursor" is any type which implements the same interface as IteratorInput, below. Such
|
||||
// a type acts as a pointer to the current input location. When a parser returns successfully, it
|
||||
// will have updated the input cursor to point to the position just past the end of what was parsed.
|
||||
// On failure, the cursor position is unspecified.
|
||||
|
||||
#ifndef KJ_PARSE_COMMON_H_
|
||||
#define KJ_PARSE_COMMON_H_
|
||||
|
||||
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include "../common.h"
|
||||
#include "../memory.h"
|
||||
#include "../array.h"
|
||||
#include "../tuple.h"
|
||||
#include "../vector.h"
|
||||
#if _MSC_VER
|
||||
#include <type_traits> // result_of_t
|
||||
#endif
|
||||
|
||||
namespace kj {
|
||||
namespace parse {
|
||||
|
||||
template <typename Element, typename Iterator>
|
||||
class IteratorInput {
|
||||
// A parser input implementation based on an iterator range.
|
||||
|
||||
public:
|
||||
IteratorInput(Iterator begin, Iterator end)
|
||||
: parent(nullptr), pos(begin), end(end), best(begin) {}
|
||||
explicit IteratorInput(IteratorInput& parent)
|
||||
: parent(&parent), pos(parent.pos), end(parent.end), best(parent.pos) {}
|
||||
~IteratorInput() {
|
||||
if (parent != nullptr) {
|
||||
parent->best = kj::max(kj::max(pos, best), parent->best);
|
||||
}
|
||||
}
|
||||
KJ_DISALLOW_COPY(IteratorInput);
|
||||
|
||||
void advanceParent() {
|
||||
parent->pos = pos;
|
||||
}
|
||||
void forgetParent() {
|
||||
parent = nullptr;
|
||||
}
|
||||
|
||||
bool atEnd() { return pos == end; }
|
||||
auto current() -> decltype(*instance<Iterator>()) {
|
||||
KJ_IREQUIRE(!atEnd());
|
||||
return *pos;
|
||||
}
|
||||
auto consume() -> decltype(*instance<Iterator>()) {
|
||||
KJ_IREQUIRE(!atEnd());
|
||||
return *pos++;
|
||||
}
|
||||
void next() {
|
||||
KJ_IREQUIRE(!atEnd());
|
||||
++pos;
|
||||
}
|
||||
|
||||
Iterator getBest() { return kj::max(pos, best); }
|
||||
|
||||
Iterator getPosition() { return pos; }
|
||||
|
||||
private:
|
||||
IteratorInput* parent;
|
||||
Iterator pos;
|
||||
Iterator end;
|
||||
Iterator best; // furthest we got with any sub-input
|
||||
};
|
||||
|
||||
template <typename T> struct OutputType_;
|
||||
template <typename T> struct OutputType_<Maybe<T>> { typedef T Type; };
|
||||
template <typename Parser, typename Input>
|
||||
using OutputType = typename OutputType_<
|
||||
#if _MSC_VER
|
||||
std::result_of_t<Parser(Input)>
|
||||
// The instance<T&>() based version below results in:
|
||||
// C2064: term does not evaluate to a function taking 1 arguments
|
||||
#else
|
||||
decltype(instance<Parser&>()(instance<Input&>()))
|
||||
#endif
|
||||
>::Type;
|
||||
// Synonym for the output type of a parser, given the parser type and the input type.
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
template <typename Input, typename Output>
|
||||
class ParserRef {
|
||||
// Acts as a reference to some other parser, with simplified type. The referenced parser
|
||||
// is polymorphic by virtual call rather than templates. For grammars of non-trivial size,
|
||||
// it is important to inject refs into the grammar here and there to prevent the parser types
|
||||
// from becoming ridiculous. Using too many of them can hurt performance, though.
|
||||
|
||||
public:
|
||||
ParserRef(): parser(nullptr), wrapper(nullptr) {}
|
||||
ParserRef(const ParserRef&) = default;
|
||||
ParserRef(ParserRef&&) = default;
|
||||
ParserRef& operator=(const ParserRef& other) = default;
|
||||
ParserRef& operator=(ParserRef&& other) = default;
|
||||
|
||||
template <typename Other>
|
||||
constexpr ParserRef(Other&& other)
|
||||
: parser(&other), wrapper(&WrapperImplInstance<Decay<Other>>::instance) {
|
||||
static_assert(kj::isReference<Other>(), "ParserRef should not be assigned to a temporary.");
|
||||
}
|
||||
|
||||
template <typename Other>
|
||||
inline ParserRef& operator=(Other&& other) {
|
||||
static_assert(kj::isReference<Other>(), "ParserRef should not be assigned to a temporary.");
|
||||
parser = &other;
|
||||
wrapper = &WrapperImplInstance<Decay<Other>>::instance;
|
||||
return *this;
|
||||
}
|
||||
|
||||
KJ_ALWAYS_INLINE(Maybe<Output> operator()(Input& input) const) {
|
||||
// Always inline in the hopes that this allows branch prediction to kick in so the virtual call
|
||||
// doesn't hurt so much.
|
||||
return wrapper->parse(parser, input);
|
||||
}
|
||||
|
||||
private:
|
||||
struct Wrapper {
|
||||
virtual Maybe<Output> parse(const void* parser, Input& input) const = 0;
|
||||
};
|
||||
template <typename ParserImpl>
|
||||
struct WrapperImpl: public Wrapper {
|
||||
Maybe<Output> parse(const void* parser, Input& input) const override {
|
||||
return (*reinterpret_cast<const ParserImpl*>(parser))(input);
|
||||
}
|
||||
};
|
||||
template <typename ParserImpl>
|
||||
struct WrapperImplInstance {
|
||||
#if _MSC_VER
|
||||
// TODO(msvc): MSVC currently fails to initialize vtable pointers for constexpr values so
|
||||
// we have to make this just const instead.
|
||||
static const WrapperImpl<ParserImpl> instance;
|
||||
#else
|
||||
static constexpr WrapperImpl<ParserImpl> instance = WrapperImpl<ParserImpl>();
|
||||
#endif
|
||||
};
|
||||
|
||||
const void* parser;
|
||||
const Wrapper* wrapper;
|
||||
};
|
||||
|
||||
template <typename Input, typename Output>
|
||||
template <typename ParserImpl>
|
||||
#if _MSC_VER
|
||||
const typename ParserRef<Input, Output>::template WrapperImpl<ParserImpl>
|
||||
ParserRef<Input, Output>::WrapperImplInstance<ParserImpl>::instance = WrapperImpl<ParserImpl>();
|
||||
#else
|
||||
constexpr typename ParserRef<Input, Output>::template WrapperImpl<ParserImpl>
|
||||
ParserRef<Input, Output>::WrapperImplInstance<ParserImpl>::instance;
|
||||
#endif
|
||||
|
||||
template <typename Input, typename ParserImpl>
|
||||
constexpr ParserRef<Input, OutputType<ParserImpl, Input>> ref(ParserImpl& impl) {
|
||||
// Constructs a ParserRef. You must specify the input type explicitly, e.g.
|
||||
// `ref<MyInput>(myParser)`.
|
||||
|
||||
return ParserRef<Input, OutputType<ParserImpl, Input>>(impl);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// any
|
||||
// Output = one token
|
||||
|
||||
class Any_ {
|
||||
public:
|
||||
template <typename Input>
|
||||
Maybe<Decay<decltype(instance<Input>().consume())>> operator()(Input& input) const {
|
||||
if (input.atEnd()) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return input.consume();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
constexpr Any_ any = Any_();
|
||||
// A parser which matches any token and simply returns it.
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// exactly()
|
||||
// Output = Tuple<>
|
||||
|
||||
template <typename T>
|
||||
class Exactly_ {
|
||||
public:
|
||||
explicit constexpr Exactly_(T&& expected): expected(expected) {}
|
||||
|
||||
template <typename Input>
|
||||
Maybe<Tuple<>> operator()(Input& input) const {
|
||||
if (input.atEnd() || input.current() != expected) {
|
||||
return nullptr;
|
||||
} else {
|
||||
input.next();
|
||||
return Tuple<>();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
T expected;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
constexpr Exactly_<T> exactly(T&& expected) {
|
||||
// Constructs a parser which succeeds when the input is exactly the token specified. The
|
||||
// result is always the empty tuple.
|
||||
|
||||
return Exactly_<T>(kj::fwd<T>(expected));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// exactlyConst()
|
||||
// Output = Tuple<>
|
||||
|
||||
template <typename T, T expected>
|
||||
class ExactlyConst_ {
|
||||
public:
|
||||
explicit constexpr ExactlyConst_() {}
|
||||
|
||||
template <typename Input>
|
||||
Maybe<Tuple<>> operator()(Input& input) const {
|
||||
if (input.atEnd() || input.current() != expected) {
|
||||
return nullptr;
|
||||
} else {
|
||||
input.next();
|
||||
return Tuple<>();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, T expected>
|
||||
constexpr ExactlyConst_<T, expected> exactlyConst() {
|
||||
// Constructs a parser which succeeds when the input is exactly the token specified. The
|
||||
// result is always the empty tuple. This parser is templated on the token value which may cause
|
||||
// it to perform better -- or worse. Be sure to measure.
|
||||
|
||||
return ExactlyConst_<T, expected>();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// constResult()
|
||||
|
||||
template <typename SubParser, typename Result>
|
||||
class ConstResult_ {
|
||||
public:
|
||||
explicit constexpr ConstResult_(SubParser&& subParser, Result&& result)
|
||||
: subParser(kj::fwd<SubParser>(subParser)), result(kj::fwd<Result>(result)) {}
|
||||
|
||||
template <typename Input>
|
||||
Maybe<Result> operator()(Input& input) const {
|
||||
if (subParser(input) == nullptr) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SubParser subParser;
|
||||
Result result;
|
||||
};
|
||||
|
||||
template <typename SubParser, typename Result>
|
||||
constexpr ConstResult_<SubParser, Result> constResult(SubParser&& subParser, Result&& result) {
|
||||
// Constructs a parser which returns exactly `result` if `subParser` is successful.
|
||||
return ConstResult_<SubParser, Result>(kj::fwd<SubParser>(subParser), kj::fwd<Result>(result));
|
||||
}
|
||||
|
||||
template <typename SubParser>
|
||||
constexpr ConstResult_<SubParser, Tuple<>> discard(SubParser&& subParser) {
|
||||
// Constructs a parser which wraps `subParser` but discards the result.
|
||||
return constResult(kj::fwd<SubParser>(subParser), Tuple<>());
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// sequence()
|
||||
// Output = Flattened Tuple of outputs of sub-parsers.
|
||||
|
||||
template <typename... SubParsers> class Sequence_;
|
||||
|
||||
template <typename FirstSubParser, typename... SubParsers>
|
||||
class Sequence_<FirstSubParser, SubParsers...> {
|
||||
public:
|
||||
template <typename T, typename... U>
|
||||
explicit constexpr Sequence_(T&& firstSubParser, U&&... rest)
|
||||
: first(kj::fwd<T>(firstSubParser)), rest(kj::fwd<U>(rest)...) {}
|
||||
|
||||
// TODO(msvc): The trailing return types on `operator()` and `parseNext()` expose at least two
|
||||
// bugs in MSVC:
|
||||
//
|
||||
// 1. An ICE.
|
||||
// 2. 'error C2672: 'operator __surrogate_func': no matching overloaded function found)',
|
||||
// which crops up in numerous places when trying to build the capnp command line tools.
|
||||
//
|
||||
// The only workaround I found for both bugs is to omit the trailing return types and instead
|
||||
// rely on C++14's return type deduction.
|
||||
|
||||
template <typename Input>
|
||||
auto operator()(Input& input) const
|
||||
#ifndef _MSC_VER
|
||||
-> Maybe<decltype(tuple(
|
||||
instance<OutputType<FirstSubParser, Input>>(),
|
||||
instance<OutputType<SubParsers, Input>>()...))>
|
||||
#endif
|
||||
{
|
||||
return parseNext(input);
|
||||
}
|
||||
|
||||
template <typename Input, typename... InitialParams>
|
||||
auto parseNext(Input& input, InitialParams&&... initialParams) const
|
||||
#ifndef _MSC_VER
|
||||
-> Maybe<decltype(tuple(
|
||||
kj::fwd<InitialParams>(initialParams)...,
|
||||
instance<OutputType<FirstSubParser, Input>>(),
|
||||
instance<OutputType<SubParsers, Input>>()...))>
|
||||
#endif
|
||||
{
|
||||
KJ_IF_MAYBE(firstResult, first(input)) {
|
||||
return rest.parseNext(input, kj::fwd<InitialParams>(initialParams)...,
|
||||
kj::mv(*firstResult));
|
||||
} else {
|
||||
// TODO(msvc): MSVC depends on return type deduction to compile this function, so we need to
|
||||
// help it deduce the right type on this code path.
|
||||
return Maybe<decltype(tuple(
|
||||
kj::fwd<InitialParams>(initialParams)...,
|
||||
instance<OutputType<FirstSubParser, Input>>(),
|
||||
instance<OutputType<SubParsers, Input>>()...))>{nullptr};
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
FirstSubParser first;
|
||||
Sequence_<SubParsers...> rest;
|
||||
};
|
||||
|
||||
template <>
|
||||
class Sequence_<> {
|
||||
public:
|
||||
template <typename Input>
|
||||
Maybe<Tuple<>> operator()(Input& input) const {
|
||||
return parseNext(input);
|
||||
}
|
||||
|
||||
template <typename Input, typename... Params>
|
||||
auto parseNext(Input& input, Params&&... params) const ->
|
||||
Maybe<decltype(tuple(kj::fwd<Params>(params)...))> {
|
||||
return tuple(kj::fwd<Params>(params)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... SubParsers>
|
||||
constexpr Sequence_<SubParsers...> sequence(SubParsers&&... subParsers) {
|
||||
// Constructs a parser that executes each of the parameter parsers in sequence and returns a
|
||||
// tuple of their results.
|
||||
|
||||
return Sequence_<SubParsers...>(kj::fwd<SubParsers>(subParsers)...);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// many()
|
||||
// Output = Array of output of sub-parser, or just a uint count if the sub-parser returns Tuple<>.
|
||||
|
||||
template <typename SubParser, bool atLeastOne>
|
||||
class Many_ {
|
||||
template <typename Input, typename Output = OutputType<SubParser, Input>>
|
||||
struct Impl;
|
||||
public:
|
||||
explicit constexpr Many_(SubParser&& subParser)
|
||||
: subParser(kj::fwd<SubParser>(subParser)) {}
|
||||
|
||||
template <typename Input>
|
||||
auto operator()(Input& input) const
|
||||
-> decltype(Impl<Input>::apply(instance<const SubParser&>(), input));
|
||||
|
||||
private:
|
||||
SubParser subParser;
|
||||
};
|
||||
|
||||
template <typename SubParser, bool atLeastOne>
|
||||
template <typename Input, typename Output>
|
||||
struct Many_<SubParser, atLeastOne>::Impl {
|
||||
static Maybe<Array<Output>> apply(const SubParser& subParser, Input& input) {
|
||||
typedef Vector<OutputType<SubParser, Input>> Results;
|
||||
Results results;
|
||||
|
||||
while (!input.atEnd()) {
|
||||
Input subInput(input);
|
||||
|
||||
KJ_IF_MAYBE(subResult, subParser(subInput)) {
|
||||
subInput.advanceParent();
|
||||
results.add(kj::mv(*subResult));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (atLeastOne && results.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return results.releaseAsArray();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename SubParser, bool atLeastOne>
|
||||
template <typename Input>
|
||||
struct Many_<SubParser, atLeastOne>::Impl<Input, Tuple<>> {
|
||||
// If the sub-parser output is Tuple<>, just return a count.
|
||||
|
||||
static Maybe<uint> apply(const SubParser& subParser, Input& input) {
|
||||
uint count = 0;
|
||||
|
||||
while (!input.atEnd()) {
|
||||
Input subInput(input);
|
||||
|
||||
KJ_IF_MAYBE(subResult, subParser(subInput)) {
|
||||
subInput.advanceParent();
|
||||
++count;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (atLeastOne && count == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename SubParser, bool atLeastOne>
|
||||
template <typename Input>
|
||||
auto Many_<SubParser, atLeastOne>::operator()(Input& input) const
|
||||
-> decltype(Impl<Input>::apply(instance<const SubParser&>(), input)) {
|
||||
return Impl<Input, OutputType<SubParser, Input>>::apply(subParser, input);
|
||||
}
|
||||
|
||||
template <typename SubParser>
|
||||
constexpr Many_<SubParser, false> many(SubParser&& subParser) {
|
||||
// Constructs a parser that repeatedly executes the given parser until it fails, returning an
|
||||
// Array of the results (or a uint count if `subParser` returns an empty tuple).
|
||||
return Many_<SubParser, false>(kj::fwd<SubParser>(subParser));
|
||||
}
|
||||
|
||||
template <typename SubParser>
|
||||
constexpr Many_<SubParser, true> oneOrMore(SubParser&& subParser) {
|
||||
// Like `many()` but the parser must parse at least one item to be successful.
|
||||
return Many_<SubParser, true>(kj::fwd<SubParser>(subParser));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// times()
|
||||
// Output = Array of output of sub-parser, or Tuple<> if sub-parser returns Tuple<>.
|
||||
|
||||
template <typename SubParser>
|
||||
class Times_ {
|
||||
template <typename Input, typename Output = OutputType<SubParser, Input>>
|
||||
struct Impl;
|
||||
public:
|
||||
explicit constexpr Times_(SubParser&& subParser, uint count)
|
||||
: subParser(kj::fwd<SubParser>(subParser)), count(count) {}
|
||||
|
||||
template <typename Input>
|
||||
auto operator()(Input& input) const
|
||||
-> decltype(Impl<Input>::apply(instance<const SubParser&>(), instance<uint>(), input));
|
||||
|
||||
private:
|
||||
SubParser subParser;
|
||||
uint count;
|
||||
};
|
||||
|
||||
template <typename SubParser>
|
||||
template <typename Input, typename Output>
|
||||
struct Times_<SubParser>::Impl {
|
||||
static Maybe<Array<Output>> apply(const SubParser& subParser, uint count, Input& input) {
|
||||
auto results = heapArrayBuilder<OutputType<SubParser, Input>>(count);
|
||||
|
||||
while (results.size() < count) {
|
||||
if (input.atEnd()) {
|
||||
return nullptr;
|
||||
} else KJ_IF_MAYBE(subResult, subParser(input)) {
|
||||
results.add(kj::mv(*subResult));
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return results.finish();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename SubParser>
|
||||
template <typename Input>
|
||||
struct Times_<SubParser>::Impl<Input, Tuple<>> {
|
||||
// If the sub-parser output is Tuple<>, just return a count.
|
||||
|
||||
static Maybe<Tuple<>> apply(const SubParser& subParser, uint count, Input& input) {
|
||||
uint actualCount = 0;
|
||||
|
||||
while (actualCount < count) {
|
||||
if (input.atEnd()) {
|
||||
return nullptr;
|
||||
} else KJ_IF_MAYBE(subResult, subParser(input)) {
|
||||
++actualCount;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return tuple();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename SubParser>
|
||||
template <typename Input>
|
||||
auto Times_<SubParser>::operator()(Input& input) const
|
||||
-> decltype(Impl<Input>::apply(instance<const SubParser&>(), instance<uint>(), input)) {
|
||||
return Impl<Input, OutputType<SubParser, Input>>::apply(subParser, count, input);
|
||||
}
|
||||
|
||||
template <typename SubParser>
|
||||
constexpr Times_<SubParser> times(SubParser&& subParser, uint count) {
|
||||
// Constructs a parser that repeats the subParser exactly `count` times.
|
||||
return Times_<SubParser>(kj::fwd<SubParser>(subParser), count);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// optional()
|
||||
// Output = Maybe<output of sub-parser>
|
||||
|
||||
template <typename SubParser>
|
||||
class Optional_ {
|
||||
public:
|
||||
explicit constexpr Optional_(SubParser&& subParser)
|
||||
: subParser(kj::fwd<SubParser>(subParser)) {}
|
||||
|
||||
template <typename Input>
|
||||
Maybe<Maybe<OutputType<SubParser, Input>>> operator()(Input& input) const {
|
||||
typedef Maybe<OutputType<SubParser, Input>> Result;
|
||||
|
||||
Input subInput(input);
|
||||
KJ_IF_MAYBE(subResult, subParser(subInput)) {
|
||||
subInput.advanceParent();
|
||||
return Result(kj::mv(*subResult));
|
||||
} else {
|
||||
return Result(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SubParser subParser;
|
||||
};
|
||||
|
||||
template <typename SubParser>
|
||||
constexpr Optional_<SubParser> optional(SubParser&& subParser) {
|
||||
// Constructs a parser that accepts zero or one of the given sub-parser, returning a Maybe
|
||||
// of the sub-parser's result.
|
||||
return Optional_<SubParser>(kj::fwd<SubParser>(subParser));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// oneOf()
|
||||
// All SubParsers must have same output type, which becomes the output type of the
|
||||
// OneOfParser.
|
||||
|
||||
template <typename... SubParsers>
|
||||
class OneOf_;
|
||||
|
||||
template <typename FirstSubParser, typename... SubParsers>
|
||||
class OneOf_<FirstSubParser, SubParsers...> {
|
||||
public:
|
||||
explicit constexpr OneOf_(FirstSubParser&& firstSubParser, SubParsers&&... rest)
|
||||
: first(kj::fwd<FirstSubParser>(firstSubParser)), rest(kj::fwd<SubParsers>(rest)...) {}
|
||||
|
||||
template <typename Input>
|
||||
Maybe<OutputType<FirstSubParser, Input>> operator()(Input& input) const {
|
||||
{
|
||||
Input subInput(input);
|
||||
Maybe<OutputType<FirstSubParser, Input>> firstResult = first(subInput);
|
||||
|
||||
if (firstResult != nullptr) {
|
||||
subInput.advanceParent();
|
||||
return kj::mv(firstResult);
|
||||
}
|
||||
}
|
||||
|
||||
// Hoping for some tail recursion here...
|
||||
return rest(input);
|
||||
}
|
||||
|
||||
private:
|
||||
FirstSubParser first;
|
||||
OneOf_<SubParsers...> rest;
|
||||
};
|
||||
|
||||
template <>
|
||||
class OneOf_<> {
|
||||
public:
|
||||
template <typename Input>
|
||||
decltype(nullptr) operator()(Input& input) const {
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... SubParsers>
|
||||
constexpr OneOf_<SubParsers...> oneOf(SubParsers&&... parsers) {
|
||||
// Constructs a parser that accepts one of a set of options. The parser behaves as the first
|
||||
// sub-parser in the list which returns successfully. All of the sub-parsers must return the
|
||||
// same type.
|
||||
return OneOf_<SubParsers...>(kj::fwd<SubParsers>(parsers)...);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// transform()
|
||||
// Output = Result of applying transform functor to input value. If input is a tuple, it is
|
||||
// unpacked to form the transformation parameters.
|
||||
|
||||
template <typename Position>
|
||||
struct Span {
|
||||
public:
|
||||
inline const Position& begin() const { return begin_; }
|
||||
inline const Position& end() const { return end_; }
|
||||
|
||||
Span() = default;
|
||||
inline constexpr Span(Position&& begin, Position&& end): begin_(mv(begin)), end_(mv(end)) {}
|
||||
|
||||
private:
|
||||
Position begin_;
|
||||
Position end_;
|
||||
};
|
||||
|
||||
template <typename Position>
|
||||
constexpr Span<Decay<Position>> span(Position&& start, Position&& end) {
|
||||
return Span<Decay<Position>>(kj::fwd<Position>(start), kj::fwd<Position>(end));
|
||||
}
|
||||
|
||||
template <typename SubParser, typename TransformFunc>
|
||||
class Transform_ {
|
||||
public:
|
||||
explicit constexpr Transform_(SubParser&& subParser, TransformFunc&& transform)
|
||||
: subParser(kj::fwd<SubParser>(subParser)), transform(kj::fwd<TransformFunc>(transform)) {}
|
||||
|
||||
template <typename Input>
|
||||
Maybe<decltype(kj::apply(instance<TransformFunc&>(),
|
||||
instance<OutputType<SubParser, Input>&&>()))>
|
||||
operator()(Input& input) const {
|
||||
KJ_IF_MAYBE(subResult, subParser(input)) {
|
||||
return kj::apply(transform, kj::mv(*subResult));
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SubParser subParser;
|
||||
TransformFunc transform;
|
||||
};
|
||||
|
||||
template <typename SubParser, typename TransformFunc>
|
||||
class TransformOrReject_ {
|
||||
public:
|
||||
explicit constexpr TransformOrReject_(SubParser&& subParser, TransformFunc&& transform)
|
||||
: subParser(kj::fwd<SubParser>(subParser)), transform(kj::fwd<TransformFunc>(transform)) {}
|
||||
|
||||
template <typename Input>
|
||||
decltype(kj::apply(instance<TransformFunc&>(), instance<OutputType<SubParser, Input>&&>()))
|
||||
operator()(Input& input) const {
|
||||
KJ_IF_MAYBE(subResult, subParser(input)) {
|
||||
return kj::apply(transform, kj::mv(*subResult));
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SubParser subParser;
|
||||
TransformFunc transform;
|
||||
};
|
||||
|
||||
template <typename SubParser, typename TransformFunc>
|
||||
class TransformWithLocation_ {
|
||||
public:
|
||||
explicit constexpr TransformWithLocation_(SubParser&& subParser, TransformFunc&& transform)
|
||||
: subParser(kj::fwd<SubParser>(subParser)), transform(kj::fwd<TransformFunc>(transform)) {}
|
||||
|
||||
template <typename Input>
|
||||
Maybe<decltype(kj::apply(instance<TransformFunc&>(),
|
||||
instance<Span<Decay<decltype(instance<Input&>().getPosition())>>>(),
|
||||
instance<OutputType<SubParser, Input>&&>()))>
|
||||
operator()(Input& input) const {
|
||||
auto start = input.getPosition();
|
||||
KJ_IF_MAYBE(subResult, subParser(input)) {
|
||||
return kj::apply(transform, Span<decltype(start)>(kj::mv(start), input.getPosition()),
|
||||
kj::mv(*subResult));
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SubParser subParser;
|
||||
TransformFunc transform;
|
||||
};
|
||||
|
||||
template <typename SubParser, typename TransformFunc>
|
||||
constexpr Transform_<SubParser, TransformFunc> transform(
|
||||
SubParser&& subParser, TransformFunc&& functor) {
|
||||
// Constructs a parser which executes some other parser and then transforms the result by invoking
|
||||
// `functor` on it. Typically `functor` is a lambda. It is invoked using `kj::apply`,
|
||||
// meaning tuples will be unpacked as arguments.
|
||||
return Transform_<SubParser, TransformFunc>(
|
||||
kj::fwd<SubParser>(subParser), kj::fwd<TransformFunc>(functor));
|
||||
}
|
||||
|
||||
template <typename SubParser, typename TransformFunc>
|
||||
constexpr TransformOrReject_<SubParser, TransformFunc> transformOrReject(
|
||||
SubParser&& subParser, TransformFunc&& functor) {
|
||||
// Like `transform()` except that `functor` returns a `Maybe`. If it returns null, parsing fails,
|
||||
// otherwise the parser's result is the content of the `Maybe`.
|
||||
return TransformOrReject_<SubParser, TransformFunc>(
|
||||
kj::fwd<SubParser>(subParser), kj::fwd<TransformFunc>(functor));
|
||||
}
|
||||
|
||||
template <typename SubParser, typename TransformFunc>
|
||||
constexpr TransformWithLocation_<SubParser, TransformFunc> transformWithLocation(
|
||||
SubParser&& subParser, TransformFunc&& functor) {
|
||||
// Like `transform` except that `functor` also takes a `Span` as its first parameter specifying
|
||||
// the location of the parsed content. The span's position type is whatever the parser input's
|
||||
// getPosition() returns.
|
||||
return TransformWithLocation_<SubParser, TransformFunc>(
|
||||
kj::fwd<SubParser>(subParser), kj::fwd<TransformFunc>(functor));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// notLookingAt()
|
||||
// Fails if the given parser succeeds at the current location.
|
||||
|
||||
template <typename SubParser>
|
||||
class NotLookingAt_ {
|
||||
public:
|
||||
explicit constexpr NotLookingAt_(SubParser&& subParser)
|
||||
: subParser(kj::fwd<SubParser>(subParser)) {}
|
||||
|
||||
template <typename Input>
|
||||
Maybe<Tuple<>> operator()(Input& input) const {
|
||||
Input subInput(input);
|
||||
subInput.forgetParent();
|
||||
if (subParser(subInput) == nullptr) {
|
||||
return Tuple<>();
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SubParser subParser;
|
||||
};
|
||||
|
||||
template <typename SubParser>
|
||||
constexpr NotLookingAt_<SubParser> notLookingAt(SubParser&& subParser) {
|
||||
// Constructs a parser which fails at any position where the given parser succeeds. Otherwise,
|
||||
// it succeeds without consuming any input and returns an empty tuple.
|
||||
return NotLookingAt_<SubParser>(kj::fwd<SubParser>(subParser));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// endOfInput()
|
||||
// Output = Tuple<>, only succeeds if at end-of-input
|
||||
|
||||
class EndOfInput_ {
|
||||
public:
|
||||
template <typename Input>
|
||||
Maybe<Tuple<>> operator()(Input& input) const {
|
||||
if (input.atEnd()) {
|
||||
return Tuple<>();
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
constexpr EndOfInput_ endOfInput = EndOfInput_();
|
||||
// A parser that succeeds only if it is called with no input.
|
||||
|
||||
} // namespace parse
|
||||
} // namespace kj
|
||||
|
||||
#endif // KJ_PARSE_COMMON_H_
|
||||
@@ -0,0 +1,107 @@
|
||||
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#include "memory.h"
|
||||
|
||||
#ifndef KJ_REFCOUNT_H_
|
||||
#define KJ_REFCOUNT_H_
|
||||
|
||||
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
namespace kj {
|
||||
|
||||
class Refcounted: private Disposer {
|
||||
// Subclass this to create a class that contains a reference count. Then, use
|
||||
// `kj::refcounted<T>()` to allocate a new refcounted pointer.
|
||||
//
|
||||
// Do NOT use this lightly. Refcounting is a crutch. Good designs should strive to make object
|
||||
// ownership clear, so that refcounting is not necessary. All that said, reference counting can
|
||||
// sometimes simplify code that would otherwise become convoluted with explicit ownership, even
|
||||
// when ownership relationships are clear at an abstract level.
|
||||
//
|
||||
// NOT THREADSAFE: This refcounting implementation assumes that an object's references are
|
||||
// manipulated only in one thread, because atomic (thread-safe) refcounting is surprisingly slow.
|
||||
//
|
||||
// In general, abstract classes should _not_ subclass this. The concrete class at the bottom
|
||||
// of the hierarchy should be the one to decide how it implements refcounting. Interfaces should
|
||||
// expose only an `addRef()` method that returns `Own<InterfaceType>`. There are two reasons for
|
||||
// this rule:
|
||||
// 1. Interfaces would need to virtually inherit Refcounted, otherwise two refcounted interfaces
|
||||
// could not be inherited by the same subclass. Virtual inheritance is awkward and
|
||||
// inefficient.
|
||||
// 2. An implementation may decide that it would rather return a copy than a refcount, or use
|
||||
// some other strategy.
|
||||
//
|
||||
// TODO(cleanup): Rethink above. Virtual inheritance is not necessarily that bad. OTOH, a
|
||||
// virtual function call for every refcount is sad in its own way. A Ref<T> type to replace
|
||||
// Own<T> could also be nice.
|
||||
|
||||
public:
|
||||
virtual ~Refcounted() noexcept(false);
|
||||
|
||||
inline bool isShared() const { return refcount > 1; }
|
||||
// Check if there are multiple references to this object. This is sometimes useful for deciding
|
||||
// whether it's safe to modify the object vs. make a copy.
|
||||
|
||||
private:
|
||||
mutable uint refcount = 0;
|
||||
// "mutable" because disposeImpl() is const. Bleh.
|
||||
|
||||
void disposeImpl(void* pointer) const override;
|
||||
template <typename T>
|
||||
static Own<T> addRefInternal(T* object);
|
||||
|
||||
template <typename T>
|
||||
friend Own<T> addRef(T& object);
|
||||
template <typename T, typename... Params>
|
||||
friend Own<T> refcounted(Params&&... params);
|
||||
};
|
||||
|
||||
template <typename T, typename... Params>
|
||||
inline Own<T> refcounted(Params&&... params) {
|
||||
// Allocate a new refcounted instance of T, passing `params` to its constructor. Returns an
|
||||
// initial reference to the object. More references can be created with `kj::addRef()`.
|
||||
|
||||
return Refcounted::addRefInternal(new T(kj::fwd<Params>(params)...));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Own<T> addRef(T& object) {
|
||||
// Return a new reference to `object`, which must subclass Refcounted and have been allocated
|
||||
// using `kj::refcounted<>()`. It is suggested that subclasses implement a non-static addRef()
|
||||
// method which wraps this and returns the appropriate type.
|
||||
|
||||
KJ_IREQUIRE(object.Refcounted::refcount > 0, "Object not allocated with kj::refcounted().");
|
||||
return Refcounted::addRefInternal(&object);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Own<T> Refcounted::addRefInternal(T* object) {
|
||||
Refcounted* refcounted = object;
|
||||
++refcounted->refcount;
|
||||
return Own<T>(object, *refcounted);
|
||||
}
|
||||
|
||||
} // namespace kj
|
||||
|
||||
#endif // KJ_REFCOUNT_H_
|
||||
@@ -0,0 +1,88 @@
|
||||
// Copyright (c) 2014 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
/*
|
||||
* Compatibility layer for stdlib iostream
|
||||
*/
|
||||
|
||||
#ifndef KJ_STD_IOSTREAM_H_
|
||||
#define KJ_STD_IOSTREAM_H_
|
||||
|
||||
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include "../io.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace kj {
|
||||
namespace std {
|
||||
|
||||
class StdOutputStream: public kj::OutputStream {
|
||||
|
||||
public:
|
||||
explicit StdOutputStream(::std::ostream& stream) : stream_(stream) {}
|
||||
~StdOutputStream() noexcept(false) {}
|
||||
|
||||
virtual void write(const void* src, size_t size) override {
|
||||
// Always writes the full size.
|
||||
|
||||
stream_.write((char*)src, size);
|
||||
}
|
||||
|
||||
virtual void write(ArrayPtr<const ArrayPtr<const byte>> pieces) override {
|
||||
// Equivalent to write()ing each byte array in sequence, which is what the
|
||||
// default implementation does. Override if you can do something better,
|
||||
// e.g. use writev() to do the write in a single syscall.
|
||||
|
||||
for (auto piece : pieces) {
|
||||
write(piece.begin(), piece.size());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
::std::ostream& stream_;
|
||||
|
||||
};
|
||||
|
||||
class StdInputStream: public kj::InputStream {
|
||||
|
||||
public:
|
||||
explicit StdInputStream(::std::istream& stream) : stream_(stream) {}
|
||||
~StdInputStream() noexcept(false) {}
|
||||
|
||||
virtual size_t tryRead(
|
||||
void* buffer, size_t minBytes, size_t maxBytes) override {
|
||||
// Like read(), but may return fewer than minBytes on EOF.
|
||||
|
||||
stream_.read((char*)buffer, maxBytes);
|
||||
return stream_.gcount();
|
||||
}
|
||||
|
||||
private:
|
||||
::std::istream& stream_;
|
||||
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
} // namespace kj
|
||||
|
||||
#endif // KJ_STD_IOSTREAM_H_
|
||||
@@ -0,0 +1,212 @@
|
||||
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef KJ_STRING_TREE_H_
|
||||
#define KJ_STRING_TREE_H_
|
||||
|
||||
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include "string.h"
|
||||
|
||||
namespace kj {
|
||||
|
||||
class StringTree {
|
||||
// A long string, represented internally as a tree of strings. This data structure is like a
|
||||
// String, but optimized for concatenation and iteration at the expense of seek time. The
|
||||
// structure is intended to be used for building large text blobs from many small pieces, where
|
||||
// repeatedly concatenating smaller strings into larger ones would waste copies. This structure
|
||||
// is NOT intended for use cases requiring random access or computing substrings. For those,
|
||||
// you should use a Rope, which is a much more complicated data structure.
|
||||
//
|
||||
// The proper way to construct a StringTree is via kj::strTree(...), which works just like
|
||||
// kj::str(...) but returns a StringTree rather than a String.
|
||||
//
|
||||
// KJ_STRINGIFY() functions that construct large strings from many smaller strings are encouraged
|
||||
// to return StringTree rather than a flat char container.
|
||||
|
||||
public:
|
||||
inline StringTree(): size_(0) {}
|
||||
inline StringTree(String&& text): size_(text.size()), text(kj::mv(text)) {}
|
||||
|
||||
StringTree(Array<StringTree>&& pieces, StringPtr delim);
|
||||
// Build a StringTree by concatenating the given pieces, delimited by the given delimiter
|
||||
// (e.g. ", ").
|
||||
|
||||
inline size_t size() const { return size_; }
|
||||
|
||||
template <typename Func>
|
||||
void visit(Func&& func) const;
|
||||
|
||||
String flatten() const;
|
||||
// Return the contents as a string.
|
||||
|
||||
// TODO(someday): flatten() when *this is an rvalue and when branches.size() == 0 could simply
|
||||
// return `kj::mv(text)`. Requires reference qualifiers (Clang 3.3 / GCC 4.8).
|
||||
|
||||
void flattenTo(char* __restrict__ target) const;
|
||||
// Copy the contents to the given character array. Does not add a NUL terminator.
|
||||
|
||||
private:
|
||||
size_t size_;
|
||||
String text;
|
||||
|
||||
struct Branch;
|
||||
Array<Branch> branches; // In order.
|
||||
|
||||
inline void fill(char* pos, size_t branchIndex);
|
||||
template <typename First, typename... Rest>
|
||||
void fill(char* pos, size_t branchIndex, First&& first, Rest&&... rest);
|
||||
template <typename... Rest>
|
||||
void fill(char* pos, size_t branchIndex, StringTree&& first, Rest&&... rest);
|
||||
template <typename... Rest>
|
||||
void fill(char* pos, size_t branchIndex, Array<char>&& first, Rest&&... rest);
|
||||
template <typename... Rest>
|
||||
void fill(char* pos, size_t branchIndex, String&& first, Rest&&... rest);
|
||||
|
||||
template <typename... Params>
|
||||
static StringTree concat(Params&&... params);
|
||||
static StringTree&& concat(StringTree&& param) { return kj::mv(param); }
|
||||
|
||||
template <typename T>
|
||||
static inline size_t flatSize(const T& t) { return t.size(); }
|
||||
static inline size_t flatSize(String&& s) { return 0; }
|
||||
static inline size_t flatSize(StringTree&& s) { return 0; }
|
||||
|
||||
template <typename T>
|
||||
static inline size_t branchCount(const T& t) { return 0; }
|
||||
static inline size_t branchCount(String&& s) { return 1; }
|
||||
static inline size_t branchCount(StringTree&& s) { return 1; }
|
||||
|
||||
template <typename... Params>
|
||||
friend StringTree strTree(Params&&... params);
|
||||
};
|
||||
|
||||
inline StringTree&& KJ_STRINGIFY(StringTree&& tree) { return kj::mv(tree); }
|
||||
inline const StringTree& KJ_STRINGIFY(const StringTree& tree) { return tree; }
|
||||
|
||||
inline StringTree KJ_STRINGIFY(Array<StringTree>&& trees) { return StringTree(kj::mv(trees), ""); }
|
||||
|
||||
template <typename... Params>
|
||||
StringTree strTree(Params&&... params);
|
||||
// Build a StringTree by stringifying the given parameters and concatenating the results.
|
||||
// If any of the parameters stringify to StringTree rvalues, they will be incorporated as
|
||||
// branches to avoid a copy.
|
||||
|
||||
// =======================================================================================
|
||||
// Inline implementation details
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
template <typename... Rest>
|
||||
char* fill(char* __restrict__ target, const StringTree& first, Rest&&... rest) {
|
||||
// Make str() work with stringifiers that return StringTree by patching fill().
|
||||
|
||||
first.flattenTo(target);
|
||||
return fill(target + first.size(), kj::fwd<Rest>(rest)...);
|
||||
}
|
||||
|
||||
template <typename T> constexpr bool isStringTree() { return false; }
|
||||
template <> constexpr bool isStringTree<StringTree>() { return true; }
|
||||
|
||||
inline StringTree&& toStringTreeOrCharSequence(StringTree&& tree) { return kj::mv(tree); }
|
||||
inline StringTree toStringTreeOrCharSequence(String&& str) { return StringTree(kj::mv(str)); }
|
||||
|
||||
template <typename T>
|
||||
inline auto toStringTreeOrCharSequence(T&& value)
|
||||
-> decltype(toCharSequence(kj::fwd<T>(value))) {
|
||||
static_assert(!isStringTree<Decay<T>>(),
|
||||
"When passing a StringTree into kj::strTree(), either pass it by rvalue "
|
||||
"(use kj::mv(value)) or explicitly call value.flatten() to make a copy.");
|
||||
|
||||
return toCharSequence(kj::fwd<T>(value));
|
||||
}
|
||||
|
||||
} // namespace _ (private)
|
||||
|
||||
struct StringTree::Branch {
|
||||
size_t index;
|
||||
// Index in `text` where this branch should be inserted.
|
||||
|
||||
StringTree content;
|
||||
};
|
||||
|
||||
template <typename Func>
|
||||
void StringTree::visit(Func&& func) const {
|
||||
size_t pos = 0;
|
||||
for (auto& branch: branches) {
|
||||
if (branch.index > pos) {
|
||||
func(text.slice(pos, branch.index));
|
||||
pos = branch.index;
|
||||
}
|
||||
branch.content.visit(func);
|
||||
}
|
||||
if (text.size() > pos) {
|
||||
func(text.slice(pos, text.size()));
|
||||
}
|
||||
}
|
||||
|
||||
inline void StringTree::fill(char* pos, size_t branchIndex) {
|
||||
KJ_IREQUIRE(pos == text.end() && branchIndex == branches.size(),
|
||||
kj::str(text.end() - pos, ' ', branches.size() - branchIndex).cStr());
|
||||
}
|
||||
|
||||
template <typename First, typename... Rest>
|
||||
void StringTree::fill(char* pos, size_t branchIndex, First&& first, Rest&&... rest) {
|
||||
pos = _::fill(pos, kj::fwd<First>(first));
|
||||
fill(pos, branchIndex, kj::fwd<Rest>(rest)...);
|
||||
}
|
||||
|
||||
template <typename... Rest>
|
||||
void StringTree::fill(char* pos, size_t branchIndex, StringTree&& first, Rest&&... rest) {
|
||||
branches[branchIndex].index = pos - text.begin();
|
||||
branches[branchIndex].content = kj::mv(first);
|
||||
fill(pos, branchIndex + 1, kj::fwd<Rest>(rest)...);
|
||||
}
|
||||
|
||||
template <typename... Rest>
|
||||
void StringTree::fill(char* pos, size_t branchIndex, String&& first, Rest&&... rest) {
|
||||
branches[branchIndex].index = pos - text.begin();
|
||||
branches[branchIndex].content = StringTree(kj::mv(first));
|
||||
fill(pos, branchIndex + 1, kj::fwd<Rest>(rest)...);
|
||||
}
|
||||
|
||||
template <typename... Params>
|
||||
StringTree StringTree::concat(Params&&... params) {
|
||||
StringTree result;
|
||||
result.size_ = _::sum({params.size()...});
|
||||
result.text = heapString(
|
||||
_::sum({StringTree::flatSize(kj::fwd<Params>(params))...}));
|
||||
result.branches = heapArray<StringTree::Branch>(
|
||||
_::sum({StringTree::branchCount(kj::fwd<Params>(params))...}));
|
||||
result.fill(result.text.begin(), 0, kj::fwd<Params>(params)...);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename... Params>
|
||||
StringTree strTree(Params&&... params) {
|
||||
return StringTree::concat(_::toStringTreeOrCharSequence(kj::fwd<Params>(params))...);
|
||||
}
|
||||
|
||||
} // namespace kj
|
||||
|
||||
#endif // KJ_STRING_TREE_H_
|
||||
@@ -0,0 +1,534 @@
|
||||
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef KJ_STRING_H_
|
||||
#define KJ_STRING_H_
|
||||
|
||||
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include <initializer_list>
|
||||
#include "array.h"
|
||||
#include <string.h>
|
||||
|
||||
namespace kj {
|
||||
|
||||
class StringPtr;
|
||||
class String;
|
||||
|
||||
class StringTree; // string-tree.h
|
||||
|
||||
// Our STL string SFINAE trick does not work with GCC 4.7, but it works with Clang and GCC 4.8, so
|
||||
// we'll just preprocess it out if not supported.
|
||||
#if __clang__ || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || _MSC_VER
|
||||
#define KJ_COMPILER_SUPPORTS_STL_STRING_INTEROP 1
|
||||
#endif
|
||||
|
||||
// =======================================================================================
|
||||
// StringPtr -- A NUL-terminated ArrayPtr<const char> containing UTF-8 text.
|
||||
//
|
||||
// NUL bytes are allowed to appear before the end of the string. The only requirement is that
|
||||
// a NUL byte appear immediately after the last byte of the content. This terminator byte is not
|
||||
// counted in the string's size.
|
||||
|
||||
class StringPtr {
|
||||
public:
|
||||
inline StringPtr(): content("", 1) {}
|
||||
inline StringPtr(decltype(nullptr)): content("", 1) {}
|
||||
inline StringPtr(const char* value): content(value, strlen(value) + 1) {}
|
||||
inline StringPtr(const char* value, size_t size): content(value, size + 1) {
|
||||
KJ_IREQUIRE(value[size] == '\0', "StringPtr must be NUL-terminated.");
|
||||
}
|
||||
inline StringPtr(const char* begin, const char* end): StringPtr(begin, end - begin) {}
|
||||
inline StringPtr(const String& value);
|
||||
|
||||
#if KJ_COMPILER_SUPPORTS_STL_STRING_INTEROP
|
||||
template <typename T, typename = decltype(instance<T>().c_str())>
|
||||
inline StringPtr(const T& t): StringPtr(t.c_str()) {}
|
||||
// Allow implicit conversion from any class that has a c_str() method (namely, std::string).
|
||||
// We use a template trick to detect std::string in order to avoid including the header for
|
||||
// those who don't want it.
|
||||
|
||||
template <typename T, typename = decltype(instance<T>().c_str())>
|
||||
inline operator T() const { return cStr(); }
|
||||
// Allow implicit conversion to any class that has a c_str() method (namely, std::string).
|
||||
// We use a template trick to detect std::string in order to avoid including the header for
|
||||
// those who don't want it.
|
||||
#endif
|
||||
|
||||
inline operator ArrayPtr<const char>() const;
|
||||
inline ArrayPtr<const char> asArray() const;
|
||||
inline ArrayPtr<const byte> asBytes() const { return asArray().asBytes(); }
|
||||
// Result does not include NUL terminator.
|
||||
|
||||
inline const char* cStr() const { return content.begin(); }
|
||||
// Returns NUL-terminated string.
|
||||
|
||||
inline size_t size() const { return content.size() - 1; }
|
||||
// Result does not include NUL terminator.
|
||||
|
||||
inline char operator[](size_t index) const { return content[index]; }
|
||||
|
||||
inline const char* begin() const { return content.begin(); }
|
||||
inline const char* end() const { return content.end() - 1; }
|
||||
|
||||
inline bool operator==(decltype(nullptr)) const { return content.size() <= 1; }
|
||||
inline bool operator!=(decltype(nullptr)) const { return content.size() > 1; }
|
||||
|
||||
inline bool operator==(const StringPtr& other) const;
|
||||
inline bool operator!=(const StringPtr& other) const { return !(*this == other); }
|
||||
inline bool operator< (const StringPtr& other) const;
|
||||
inline bool operator> (const StringPtr& other) const { return other < *this; }
|
||||
inline bool operator<=(const StringPtr& other) const { return !(other < *this); }
|
||||
inline bool operator>=(const StringPtr& other) const { return !(*this < other); }
|
||||
|
||||
inline StringPtr slice(size_t start) const;
|
||||
inline ArrayPtr<const char> slice(size_t start, size_t end) const;
|
||||
// A string slice is only NUL-terminated if it is a suffix, so slice() has a one-parameter
|
||||
// version that assumes end = size().
|
||||
|
||||
inline bool startsWith(const StringPtr& other) const;
|
||||
inline bool endsWith(const StringPtr& other) const;
|
||||
|
||||
inline Maybe<size_t> findFirst(char c) const;
|
||||
inline Maybe<size_t> findLast(char c) const;
|
||||
|
||||
template <typename T>
|
||||
T parseAs() const;
|
||||
// Parse string as template number type.
|
||||
// Integer numbers prefixed by "0x" and "0X" are parsed in base 16 (like strtoi with base 0).
|
||||
// Integer numbers prefixed by "0" are parsed in base 10 (unlike strtoi with base 0).
|
||||
// Overflowed integer numbers throw exception.
|
||||
// Overflowed floating numbers return inf.
|
||||
|
||||
private:
|
||||
inline StringPtr(ArrayPtr<const char> content): content(content) {}
|
||||
|
||||
ArrayPtr<const char> content;
|
||||
};
|
||||
|
||||
inline bool operator==(const char* a, const StringPtr& b) { return b == a; }
|
||||
inline bool operator!=(const char* a, const StringPtr& b) { return b != a; }
|
||||
|
||||
template <> char StringPtr::parseAs<char>() const;
|
||||
template <> signed char StringPtr::parseAs<signed char>() const;
|
||||
template <> unsigned char StringPtr::parseAs<unsigned char>() const;
|
||||
template <> short StringPtr::parseAs<short>() const;
|
||||
template <> unsigned short StringPtr::parseAs<unsigned short>() const;
|
||||
template <> int StringPtr::parseAs<int>() const;
|
||||
template <> unsigned StringPtr::parseAs<unsigned>() const;
|
||||
template <> long StringPtr::parseAs<long>() const;
|
||||
template <> unsigned long StringPtr::parseAs<unsigned long>() const;
|
||||
template <> long long StringPtr::parseAs<long long>() const;
|
||||
template <> unsigned long long StringPtr::parseAs<unsigned long long>() const;
|
||||
template <> float StringPtr::parseAs<float>() const;
|
||||
template <> double StringPtr::parseAs<double>() const;
|
||||
|
||||
// =======================================================================================
|
||||
// String -- A NUL-terminated Array<char> containing UTF-8 text.
|
||||
//
|
||||
// NUL bytes are allowed to appear before the end of the string. The only requirement is that
|
||||
// a NUL byte appear immediately after the last byte of the content. This terminator byte is not
|
||||
// counted in the string's size.
|
||||
//
|
||||
// To allocate a String, you must call kj::heapString(). We do not implement implicit copying to
|
||||
// the heap because this hides potential inefficiency from the developer.
|
||||
|
||||
class String {
|
||||
public:
|
||||
String() = default;
|
||||
inline String(decltype(nullptr)): content(nullptr) {}
|
||||
inline String(char* value, size_t size, const ArrayDisposer& disposer);
|
||||
// Does not copy. `size` does not include NUL terminator, but `value` must be NUL-terminated.
|
||||
inline explicit String(Array<char> buffer);
|
||||
// Does not copy. Requires `buffer` ends with `\0`.
|
||||
|
||||
inline operator ArrayPtr<char>();
|
||||
inline operator ArrayPtr<const char>() const;
|
||||
inline ArrayPtr<char> asArray();
|
||||
inline ArrayPtr<const char> asArray() const;
|
||||
inline ArrayPtr<byte> asBytes() { return asArray().asBytes(); }
|
||||
inline ArrayPtr<const byte> asBytes() const { return asArray().asBytes(); }
|
||||
// Result does not include NUL terminator.
|
||||
|
||||
inline Array<char> releaseArray() { return kj::mv(content); }
|
||||
// Disowns the backing array (which includes the NUL terminator) and returns it. The String value
|
||||
// is clobbered (as if moved away).
|
||||
|
||||
inline const char* cStr() const;
|
||||
|
||||
inline size_t size() const;
|
||||
// Result does not include NUL terminator.
|
||||
|
||||
inline char operator[](size_t index) const;
|
||||
inline char& operator[](size_t index);
|
||||
|
||||
inline char* begin();
|
||||
inline char* end();
|
||||
inline const char* begin() const;
|
||||
inline const char* end() const;
|
||||
|
||||
inline bool operator==(decltype(nullptr)) const { return content.size() <= 1; }
|
||||
inline bool operator!=(decltype(nullptr)) const { return content.size() > 1; }
|
||||
|
||||
inline bool operator==(const StringPtr& other) const { return StringPtr(*this) == other; }
|
||||
inline bool operator!=(const StringPtr& other) const { return StringPtr(*this) != other; }
|
||||
inline bool operator< (const StringPtr& other) const { return StringPtr(*this) < other; }
|
||||
inline bool operator> (const StringPtr& other) const { return StringPtr(*this) > other; }
|
||||
inline bool operator<=(const StringPtr& other) const { return StringPtr(*this) <= other; }
|
||||
inline bool operator>=(const StringPtr& other) const { return StringPtr(*this) >= other; }
|
||||
|
||||
inline bool startsWith(const StringPtr& other) const { return StringPtr(*this).startsWith(other);}
|
||||
inline bool endsWith(const StringPtr& other) const { return StringPtr(*this).endsWith(other); }
|
||||
|
||||
inline StringPtr slice(size_t start) const { return StringPtr(*this).slice(start); }
|
||||
inline ArrayPtr<const char> slice(size_t start, size_t end) const {
|
||||
return StringPtr(*this).slice(start, end);
|
||||
}
|
||||
|
||||
inline Maybe<size_t> findFirst(char c) const { return StringPtr(*this).findFirst(c); }
|
||||
inline Maybe<size_t> findLast(char c) const { return StringPtr(*this).findLast(c); }
|
||||
|
||||
template <typename T>
|
||||
T parseAs() const { return StringPtr(*this).parseAs<T>(); }
|
||||
// Parse as number
|
||||
|
||||
private:
|
||||
Array<char> content;
|
||||
};
|
||||
|
||||
inline bool operator==(const char* a, const String& b) { return b == a; }
|
||||
inline bool operator!=(const char* a, const String& b) { return b != a; }
|
||||
|
||||
String heapString(size_t size);
|
||||
// Allocate a String of the given size on the heap, not including NUL terminator. The NUL
|
||||
// terminator will be initialized automatically but the rest of the content is not initialized.
|
||||
|
||||
String heapString(const char* value);
|
||||
String heapString(const char* value, size_t size);
|
||||
String heapString(StringPtr value);
|
||||
String heapString(const String& value);
|
||||
String heapString(ArrayPtr<const char> value);
|
||||
// Allocates a copy of the given value on the heap.
|
||||
|
||||
// =======================================================================================
|
||||
// Magic str() function which transforms parameters to text and concatenates them into one big
|
||||
// String.
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
inline size_t sum(std::initializer_list<size_t> nums) {
|
||||
size_t result = 0;
|
||||
for (auto num: nums) {
|
||||
result += num;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline char* fill(char* ptr) { return ptr; }
|
||||
|
||||
template <typename... Rest>
|
||||
char* fill(char* __restrict__ target, const StringTree& first, Rest&&... rest);
|
||||
// Make str() work with stringifiers that return StringTree by patching fill().
|
||||
//
|
||||
// Defined in string-tree.h.
|
||||
|
||||
template <typename First, typename... Rest>
|
||||
char* fill(char* __restrict__ target, const First& first, Rest&&... rest) {
|
||||
auto i = first.begin();
|
||||
auto end = first.end();
|
||||
while (i != end) {
|
||||
*target++ = *i++;
|
||||
}
|
||||
return fill(target, kj::fwd<Rest>(rest)...);
|
||||
}
|
||||
|
||||
template <typename... Params>
|
||||
String concat(Params&&... params) {
|
||||
// Concatenate a bunch of containers into a single Array. The containers can be anything that
|
||||
// is iterable and whose elements can be converted to `char`.
|
||||
|
||||
String result = heapString(sum({params.size()...}));
|
||||
fill(result.begin(), kj::fwd<Params>(params)...);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline String concat(String&& arr) {
|
||||
return kj::mv(arr);
|
||||
}
|
||||
|
||||
struct Stringifier {
|
||||
// This is a dummy type with only one instance: STR (below). To make an arbitrary type
|
||||
// stringifiable, define `operator*(Stringifier, T)` to return an iterable container of `char`.
|
||||
// The container type must have a `size()` method. Be sure to declare the operator in the same
|
||||
// namespace as `T` **or** in the global scope.
|
||||
//
|
||||
// A more usual way to accomplish what we're doing here would be to require that you define
|
||||
// a function like `toString(T)` and then rely on argument-dependent lookup. However, this has
|
||||
// the problem that it pollutes other people's namespaces and even the global namespace. For
|
||||
// example, some other project may already have functions called `toString` which do something
|
||||
// different. Declaring `operator*` with `Stringifier` as the left operand cannot conflict with
|
||||
// anything.
|
||||
|
||||
inline ArrayPtr<const char> operator*(ArrayPtr<const char> s) const { return s; }
|
||||
inline ArrayPtr<const char> operator*(ArrayPtr<char> s) const { return s; }
|
||||
inline ArrayPtr<const char> operator*(const Array<const char>& s) const { return s; }
|
||||
inline ArrayPtr<const char> operator*(const Array<char>& s) const { return s; }
|
||||
template<size_t n>
|
||||
inline ArrayPtr<const char> operator*(const CappedArray<char, n>& s) const { return s; }
|
||||
template<size_t n>
|
||||
inline ArrayPtr<const char> operator*(const FixedArray<char, n>& s) const { return s; }
|
||||
inline ArrayPtr<const char> operator*(const char* s) const { return arrayPtr(s, strlen(s)); }
|
||||
inline ArrayPtr<const char> operator*(const String& s) const { return s.asArray(); }
|
||||
inline ArrayPtr<const char> operator*(const StringPtr& s) const { return s.asArray(); }
|
||||
|
||||
inline Range<char> operator*(const Range<char>& r) const { return r; }
|
||||
inline Repeat<char> operator*(const Repeat<char>& r) const { return r; }
|
||||
|
||||
inline FixedArray<char, 1> operator*(char c) const {
|
||||
FixedArray<char, 1> result;
|
||||
result[0] = c;
|
||||
return result;
|
||||
}
|
||||
|
||||
StringPtr operator*(decltype(nullptr)) const;
|
||||
StringPtr operator*(bool b) const;
|
||||
|
||||
CappedArray<char, 5> operator*(signed char i) const;
|
||||
CappedArray<char, 5> operator*(unsigned char i) const;
|
||||
CappedArray<char, sizeof(short) * 3 + 2> operator*(short i) const;
|
||||
CappedArray<char, sizeof(unsigned short) * 3 + 2> operator*(unsigned short i) const;
|
||||
CappedArray<char, sizeof(int) * 3 + 2> operator*(int i) const;
|
||||
CappedArray<char, sizeof(unsigned int) * 3 + 2> operator*(unsigned int i) const;
|
||||
CappedArray<char, sizeof(long) * 3 + 2> operator*(long i) const;
|
||||
CappedArray<char, sizeof(unsigned long) * 3 + 2> operator*(unsigned long i) const;
|
||||
CappedArray<char, sizeof(long long) * 3 + 2> operator*(long long i) const;
|
||||
CappedArray<char, sizeof(unsigned long long) * 3 + 2> operator*(unsigned long long i) const;
|
||||
CappedArray<char, 24> operator*(float f) const;
|
||||
CappedArray<char, 32> operator*(double f) const;
|
||||
CappedArray<char, sizeof(const void*) * 3 + 2> operator*(const void* s) const;
|
||||
|
||||
template <typename T>
|
||||
String operator*(ArrayPtr<T> arr) const;
|
||||
template <typename T>
|
||||
String operator*(const Array<T>& arr) const;
|
||||
|
||||
#if KJ_COMPILER_SUPPORTS_STL_STRING_INTEROP // supports expression SFINAE?
|
||||
template <typename T, typename Result = decltype(instance<T>().toString())>
|
||||
inline Result operator*(T&& value) const { return kj::fwd<T>(value).toString(); }
|
||||
#endif
|
||||
};
|
||||
static KJ_CONSTEXPR(const) Stringifier STR = Stringifier();
|
||||
|
||||
} // namespace _ (private)
|
||||
|
||||
template <typename T>
|
||||
auto toCharSequence(T&& value) -> decltype(_::STR * kj::fwd<T>(value)) {
|
||||
// Returns an iterable of chars that represent a textual representation of the value, suitable
|
||||
// for debugging.
|
||||
//
|
||||
// Most users should use str() instead, but toCharSequence() may occasionally be useful to avoid
|
||||
// heap allocation overhead that str() implies.
|
||||
//
|
||||
// To specialize this function for your type, see KJ_STRINGIFY.
|
||||
|
||||
return _::STR * kj::fwd<T>(value);
|
||||
}
|
||||
|
||||
CappedArray<char, sizeof(unsigned char) * 2 + 1> hex(unsigned char i);
|
||||
CappedArray<char, sizeof(unsigned short) * 2 + 1> hex(unsigned short i);
|
||||
CappedArray<char, sizeof(unsigned int) * 2 + 1> hex(unsigned int i);
|
||||
CappedArray<char, sizeof(unsigned long) * 2 + 1> hex(unsigned long i);
|
||||
CappedArray<char, sizeof(unsigned long long) * 2 + 1> hex(unsigned long long i);
|
||||
|
||||
template <typename... Params>
|
||||
String str(Params&&... params) {
|
||||
// Magic function which builds a string from a bunch of arbitrary values. Example:
|
||||
// str(1, " / ", 2, " = ", 0.5)
|
||||
// returns:
|
||||
// "1 / 2 = 0.5"
|
||||
// To teach `str` how to stringify a type, see `Stringifier`.
|
||||
|
||||
return _::concat(toCharSequence(kj::fwd<Params>(params))...);
|
||||
}
|
||||
|
||||
inline String str(String&& s) { return mv(s); }
|
||||
// Overload to prevent redundant allocation.
|
||||
|
||||
template <typename T>
|
||||
String strArray(T&& arr, const char* delim) {
|
||||
size_t delimLen = strlen(delim);
|
||||
KJ_STACK_ARRAY(decltype(_::STR * arr[0]), pieces, kj::size(arr), 8, 32);
|
||||
size_t size = 0;
|
||||
for (size_t i = 0; i < kj::size(arr); i++) {
|
||||
if (i > 0) size += delimLen;
|
||||
pieces[i] = _::STR * arr[i];
|
||||
size += pieces[i].size();
|
||||
}
|
||||
|
||||
String result = heapString(size);
|
||||
char* pos = result.begin();
|
||||
for (size_t i = 0; i < kj::size(arr); i++) {
|
||||
if (i > 0) {
|
||||
memcpy(pos, delim, delimLen);
|
||||
pos += delimLen;
|
||||
}
|
||||
pos = _::fill(pos, pieces[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
template <typename T>
|
||||
inline String Stringifier::operator*(ArrayPtr<T> arr) const {
|
||||
return strArray(arr, ", ");
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline String Stringifier::operator*(const Array<T>& arr) const {
|
||||
return strArray(arr, ", ");
|
||||
}
|
||||
|
||||
} // namespace _ (private)
|
||||
|
||||
#define KJ_STRINGIFY(...) operator*(::kj::_::Stringifier, __VA_ARGS__)
|
||||
// Defines a stringifier for a custom type. Example:
|
||||
//
|
||||
// class Foo {...};
|
||||
// inline StringPtr KJ_STRINGIFY(const Foo& foo) { return foo.name(); }
|
||||
//
|
||||
// This allows Foo to be passed to str().
|
||||
//
|
||||
// The function should be declared either in the same namespace as the target type or in the global
|
||||
// namespace. It can return any type which is an iterable container of chars.
|
||||
|
||||
// =======================================================================================
|
||||
// Inline implementation details.
|
||||
|
||||
inline StringPtr::StringPtr(const String& value): content(value.begin(), value.size() + 1) {}
|
||||
|
||||
inline StringPtr::operator ArrayPtr<const char>() const {
|
||||
return content.slice(0, content.size() - 1);
|
||||
}
|
||||
|
||||
inline ArrayPtr<const char> StringPtr::asArray() const {
|
||||
return content.slice(0, content.size() - 1);
|
||||
}
|
||||
|
||||
inline bool StringPtr::operator==(const StringPtr& other) const {
|
||||
return content.size() == other.content.size() &&
|
||||
memcmp(content.begin(), other.content.begin(), content.size() - 1) == 0;
|
||||
}
|
||||
|
||||
inline bool StringPtr::operator<(const StringPtr& other) const {
|
||||
bool shorter = content.size() < other.content.size();
|
||||
int cmp = memcmp(content.begin(), other.content.begin(),
|
||||
shorter ? content.size() : other.content.size());
|
||||
return cmp < 0 || (cmp == 0 && shorter);
|
||||
}
|
||||
|
||||
inline StringPtr StringPtr::slice(size_t start) const {
|
||||
return StringPtr(content.slice(start, content.size()));
|
||||
}
|
||||
inline ArrayPtr<const char> StringPtr::slice(size_t start, size_t end) const {
|
||||
return content.slice(start, end);
|
||||
}
|
||||
|
||||
inline bool StringPtr::startsWith(const StringPtr& other) const {
|
||||
return other.content.size() <= content.size() &&
|
||||
memcmp(content.begin(), other.content.begin(), other.size()) == 0;
|
||||
}
|
||||
inline bool StringPtr::endsWith(const StringPtr& other) const {
|
||||
return other.content.size() <= content.size() &&
|
||||
memcmp(end() - other.size(), other.content.begin(), other.size()) == 0;
|
||||
}
|
||||
|
||||
inline Maybe<size_t> StringPtr::findFirst(char c) const {
|
||||
const char* pos = reinterpret_cast<const char*>(memchr(content.begin(), c, size()));
|
||||
if (pos == nullptr) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return pos - content.begin();
|
||||
}
|
||||
}
|
||||
|
||||
inline Maybe<size_t> StringPtr::findLast(char c) const {
|
||||
for (size_t i = size(); i > 0; --i) {
|
||||
if (content[i-1] == c) {
|
||||
return i-1;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline String::operator ArrayPtr<char>() {
|
||||
return content == nullptr ? ArrayPtr<char>(nullptr) : content.slice(0, content.size() - 1);
|
||||
}
|
||||
inline String::operator ArrayPtr<const char>() const {
|
||||
return content == nullptr ? ArrayPtr<const char>(nullptr) : content.slice(0, content.size() - 1);
|
||||
}
|
||||
|
||||
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<const char>(nullptr) : content.slice(0, content.size() - 1);
|
||||
}
|
||||
|
||||
inline const char* String::cStr() const { return content == nullptr ? "" : content.begin(); }
|
||||
|
||||
inline size_t String::size() const { return content == nullptr ? 0 : content.size() - 1; }
|
||||
|
||||
inline char String::operator[](size_t index) const { return content[index]; }
|
||||
inline char& String::operator[](size_t index) { return content[index]; }
|
||||
|
||||
inline char* String::begin() { return content == nullptr ? nullptr : content.begin(); }
|
||||
inline char* String::end() { return content == nullptr ? nullptr : content.end() - 1; }
|
||||
inline const char* String::begin() const { return content == nullptr ? nullptr : content.begin(); }
|
||||
inline const char* String::end() const { return content == nullptr ? nullptr : content.end() - 1; }
|
||||
|
||||
inline String::String(char* value, size_t size, const ArrayDisposer& disposer)
|
||||
: content(value, size + 1, disposer) {
|
||||
KJ_IREQUIRE(value[size] == '\0', "String must be NUL-terminated.");
|
||||
}
|
||||
|
||||
inline String::String(Array<char> buffer): content(kj::mv(buffer)) {
|
||||
KJ_IREQUIRE(content.size() > 0 && content.back() == '\0', "String must be NUL-terminated.");
|
||||
}
|
||||
|
||||
inline String heapString(const char* value) {
|
||||
return heapString(value, strlen(value));
|
||||
}
|
||||
inline String heapString(StringPtr value) {
|
||||
return heapString(value.begin(), value.size());
|
||||
}
|
||||
inline String heapString(const String& value) {
|
||||
return heapString(value.begin(), value.size());
|
||||
}
|
||||
inline String heapString(ArrayPtr<const char> value) {
|
||||
return heapString(value.begin(), value.size());
|
||||
}
|
||||
|
||||
} // namespace kj
|
||||
|
||||
#endif // KJ_STRING_H_
|
||||
@@ -0,0 +1,167 @@
|
||||
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef KJ_TEST_H_
|
||||
#define KJ_TEST_H_
|
||||
|
||||
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include "debug.h"
|
||||
#include "vector.h"
|
||||
#include "function.h"
|
||||
|
||||
namespace kj {
|
||||
|
||||
class TestRunner;
|
||||
|
||||
class TestCase {
|
||||
public:
|
||||
TestCase(const char* file, uint line, const char* description);
|
||||
~TestCase();
|
||||
|
||||
virtual void run() = 0;
|
||||
|
||||
private:
|
||||
const char* file;
|
||||
uint line;
|
||||
const char* description;
|
||||
TestCase* next;
|
||||
TestCase** prev;
|
||||
bool matchedFilter;
|
||||
|
||||
friend class TestRunner;
|
||||
};
|
||||
|
||||
#define KJ_TEST(description) \
|
||||
/* Make sure the linker fails if tests are not in anonymous namespaces. */ \
|
||||
extern int KJ_CONCAT(YouMustWrapTestsInAnonymousNamespace, __COUNTER__) KJ_UNUSED; \
|
||||
class KJ_UNIQUE_NAME(TestCase): public ::kj::TestCase { \
|
||||
public: \
|
||||
KJ_UNIQUE_NAME(TestCase)(): ::kj::TestCase(__FILE__, __LINE__, description) {} \
|
||||
void run() override; \
|
||||
} KJ_UNIQUE_NAME(testCase); \
|
||||
void KJ_UNIQUE_NAME(TestCase)::run()
|
||||
|
||||
#if _MSC_VER
|
||||
#define KJ_INDIRECT_EXPAND(m, vargs) m vargs
|
||||
#define KJ_FAIL_EXPECT(...) \
|
||||
KJ_INDIRECT_EXPAND(KJ_LOG, (ERROR , __VA_ARGS__));
|
||||
#define KJ_EXPECT(cond, ...) \
|
||||
if (cond); else KJ_INDIRECT_EXPAND(KJ_FAIL_EXPECT, ("failed: expected " #cond , __VA_ARGS__))
|
||||
#else
|
||||
#define KJ_FAIL_EXPECT(...) \
|
||||
KJ_LOG(ERROR, ##__VA_ARGS__);
|
||||
#define KJ_EXPECT(cond, ...) \
|
||||
if (cond); else KJ_FAIL_EXPECT("failed: expected " #cond, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define KJ_EXPECT_THROW_RECOVERABLE(type, code) \
|
||||
do { \
|
||||
KJ_IF_MAYBE(e, ::kj::runCatchingExceptions([&]() { code; })) { \
|
||||
KJ_EXPECT(e->getType() == ::kj::Exception::Type::type, \
|
||||
"code threw wrong exception type: " #code, e->getType()); \
|
||||
} else { \
|
||||
KJ_FAIL_EXPECT("code did not throw: " #code); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define KJ_EXPECT_THROW_RECOVERABLE_MESSAGE(message, code) \
|
||||
do { \
|
||||
KJ_IF_MAYBE(e, ::kj::runCatchingExceptions([&]() { code; })) { \
|
||||
KJ_EXPECT(::kj::_::hasSubstring(e->getDescription(), message), \
|
||||
"exception description didn't contain expected substring", e->getDescription()); \
|
||||
} else { \
|
||||
KJ_FAIL_EXPECT("code did not throw: " #code); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#if KJ_NO_EXCEPTIONS
|
||||
#define KJ_EXPECT_THROW(type, code) \
|
||||
do { \
|
||||
KJ_EXPECT(::kj::_::expectFatalThrow(type, nullptr, [&]() { code; })); \
|
||||
} while (false)
|
||||
#define KJ_EXPECT_THROW_MESSAGE(message, code) \
|
||||
do { \
|
||||
KJ_EXPECT(::kj::_::expectFatalThrow(nullptr, kj::StringPtr(message), [&]() { code; })); \
|
||||
} while (false)
|
||||
#else
|
||||
#define KJ_EXPECT_THROW KJ_EXPECT_THROW_RECOVERABLE
|
||||
#define KJ_EXPECT_THROW_MESSAGE KJ_EXPECT_THROW_RECOVERABLE_MESSAGE
|
||||
#endif
|
||||
|
||||
#define KJ_EXPECT_LOG(level, substring) \
|
||||
::kj::_::LogExpectation KJ_UNIQUE_NAME(_kjLogExpectation)(::kj::LogSeverity::level, substring)
|
||||
// Expects that a log message with the given level and substring text will be printed within
|
||||
// the current scope. This message will not cause the test to fail, even if it is an error.
|
||||
|
||||
// =======================================================================================
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
bool hasSubstring(kj::StringPtr haystack, kj::StringPtr needle);
|
||||
|
||||
#if KJ_NO_EXCEPTIONS
|
||||
bool expectFatalThrow(Maybe<Exception::Type> type, Maybe<StringPtr> message,
|
||||
Function<void()> code);
|
||||
// Expects that the given code will throw a fatal exception matching the given type and/or message.
|
||||
// Since exceptions are disabled, the test will fork() and run in a subprocess. On Windows, where
|
||||
// fork() is not available, this always returns true.
|
||||
#endif
|
||||
|
||||
class LogExpectation: public ExceptionCallback {
|
||||
public:
|
||||
LogExpectation(LogSeverity severity, StringPtr substring);
|
||||
~LogExpectation();
|
||||
|
||||
void logMessage(LogSeverity severity, const char* file, int line, int contextDepth,
|
||||
String&& text) override;
|
||||
|
||||
private:
|
||||
LogSeverity severity;
|
||||
StringPtr substring;
|
||||
bool seen;
|
||||
UnwindDetector unwindDetector;
|
||||
};
|
||||
|
||||
class GlobFilter {
|
||||
// Implements glob filters for the --filter flag.
|
||||
//
|
||||
// Exposed in header only for testing.
|
||||
|
||||
public:
|
||||
explicit GlobFilter(const char* pattern);
|
||||
explicit GlobFilter(ArrayPtr<const char> pattern);
|
||||
|
||||
bool matches(StringPtr name);
|
||||
|
||||
private:
|
||||
String pattern;
|
||||
Vector<uint> states;
|
||||
|
||||
void applyState(char c, int state);
|
||||
};
|
||||
|
||||
} // namespace _ (private)
|
||||
} // namespace kj
|
||||
|
||||
#endif // KJ_TEST_H_
|
||||
@@ -0,0 +1,82 @@
|
||||
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef KJ_THREAD_H_
|
||||
#define KJ_THREAD_H_
|
||||
|
||||
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
#include "function.h"
|
||||
#include "exception.h"
|
||||
|
||||
namespace kj {
|
||||
|
||||
class Thread {
|
||||
// A thread! Pass a lambda to the constructor, and it runs in the thread. The destructor joins
|
||||
// the thread. If the function throws an exception, it is rethrown from the thread's destructor
|
||||
// (if not unwinding from another exception).
|
||||
|
||||
public:
|
||||
explicit Thread(Function<void()> func);
|
||||
KJ_DISALLOW_COPY(Thread);
|
||||
|
||||
~Thread() noexcept(false);
|
||||
|
||||
#if !_WIN32
|
||||
void sendSignal(int signo);
|
||||
// Send a Unix signal to the given thread, using pthread_kill or an equivalent.
|
||||
#endif
|
||||
|
||||
void detach();
|
||||
// Don't join the thread in ~Thread().
|
||||
|
||||
private:
|
||||
struct ThreadState {
|
||||
Function<void()> func;
|
||||
kj::Maybe<kj::Exception> exception;
|
||||
|
||||
unsigned int refcount;
|
||||
// Owned by the parent thread and the child thread.
|
||||
|
||||
void unref();
|
||||
};
|
||||
ThreadState* state;
|
||||
|
||||
#if _WIN32
|
||||
void* threadHandle;
|
||||
#else
|
||||
unsigned long long threadId; // actually pthread_t
|
||||
#endif
|
||||
bool detached = false;
|
||||
|
||||
#if _WIN32
|
||||
static unsigned long __stdcall runThread(void* ptr);
|
||||
#else
|
||||
static void* runThread(void* ptr);
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace kj
|
||||
|
||||
#endif // KJ_THREAD_H_
|
||||
@@ -0,0 +1,136 @@
|
||||
// Copyright (c) 2014, Jason Choy <jjwchoy@gmail.com>
|
||||
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef KJ_THREADLOCAL_H_
|
||||
#define KJ_THREADLOCAL_H_
|
||||
|
||||
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
// This file declares a macro `KJ_THREADLOCAL_PTR` for declaring thread-local pointer-typed
|
||||
// variables. Use like:
|
||||
// KJ_THREADLOCAL_PTR(MyType) foo = nullptr;
|
||||
// This is equivalent to:
|
||||
// thread_local MyType* foo = nullptr;
|
||||
// This can only be used at the global scope.
|
||||
//
|
||||
// AVOID USING THIS. Use of thread-locals is discouraged because they often have many of the same
|
||||
// properties as singletons: http://www.object-oriented-security.org/lets-argue/singletons
|
||||
//
|
||||
// Also, thread-locals tend to be hostile to event-driven code, which can be particularly
|
||||
// surprising when using fibers (all fibers in the same thread will share the same threadlocals,
|
||||
// even though they do not share a stack).
|
||||
//
|
||||
// That said, thread-locals are sometimes needed for runtime logistics in the KJ framework. For
|
||||
// example, the current exception callback and current EventLoop are stored as thread-local
|
||||
// pointers. Since KJ only ever needs to store pointers, not values, we avoid the question of
|
||||
// whether these values' destructors need to be run, and we avoid the need for heap allocation.
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#if !defined(KJ_USE_PTHREAD_THREADLOCAL) && defined(__APPLE__)
|
||||
#include "TargetConditionals.h"
|
||||
#if TARGET_OS_IPHONE
|
||||
// iOS apparently does not support __thread (nor C++11 thread_local).
|
||||
#define KJ_USE_PTHREAD_TLS 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if KJ_USE_PTHREAD_TLS
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
namespace kj {
|
||||
|
||||
#if KJ_USE_PTHREAD_TLS
|
||||
// If __thread is unavailable, we'll fall back to pthreads.
|
||||
|
||||
#define KJ_THREADLOCAL_PTR(type) \
|
||||
namespace { struct KJ_UNIQUE_NAME(_kj_TlpTag); } \
|
||||
static ::kj::_::ThreadLocalPtr< type, KJ_UNIQUE_NAME(_kj_TlpTag)>
|
||||
// Hack: In order to ensure each thread-local results in a unique template instance, we declare
|
||||
// a one-off dummy type to use as the second type parameter.
|
||||
|
||||
namespace _ { // private
|
||||
|
||||
template <typename T, typename>
|
||||
class ThreadLocalPtr {
|
||||
// Hacky type to emulate __thread T*. We need a separate instance of the ThreadLocalPtr template
|
||||
// for every thread-local variable, because we don't want to require a global constructor, and in
|
||||
// order to initialize the TLS on first use we need to use a local static variable (in getKey()).
|
||||
// Each template instance will get a separate such local static variable, fulfilling our need.
|
||||
|
||||
public:
|
||||
ThreadLocalPtr() = default;
|
||||
constexpr ThreadLocalPtr(decltype(nullptr)) {}
|
||||
// Allow initialization to nullptr without a global constructor.
|
||||
|
||||
inline ThreadLocalPtr& operator=(T* val) {
|
||||
pthread_setspecific(getKey(), val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline operator T*() const {
|
||||
return get();
|
||||
}
|
||||
|
||||
inline T& operator*() const {
|
||||
return *get();
|
||||
}
|
||||
|
||||
inline T* operator->() const {
|
||||
return get();
|
||||
}
|
||||
|
||||
private:
|
||||
inline T* get() const {
|
||||
return reinterpret_cast<T*>(pthread_getspecific(getKey()));
|
||||
}
|
||||
|
||||
inline static pthread_key_t getKey() {
|
||||
static pthread_key_t key = createKey();
|
||||
return key;
|
||||
}
|
||||
|
||||
static pthread_key_t createKey() {
|
||||
pthread_key_t key;
|
||||
pthread_key_create(&key, 0);
|
||||
return key;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace _ (private)
|
||||
|
||||
#elif __GNUC__
|
||||
|
||||
#define KJ_THREADLOCAL_PTR(type) static __thread type*
|
||||
// GCC's __thread is lighter-weight than thread_local and is good enough for our purposes.
|
||||
|
||||
#else
|
||||
|
||||
#define KJ_THREADLOCAL_PTR(type) static thread_local type*
|
||||
|
||||
#endif // KJ_USE_PTHREAD_TLS
|
||||
|
||||
} // namespace kj
|
||||
|
||||
#endif // KJ_THREADLOCAL_H_
|
||||
@@ -0,0 +1,174 @@
|
||||
// Copyright (c) 2014 Google Inc. (contributed by Remy Blank <rblank@google.com>)
|
||||
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef KJ_TIME_H_
|
||||
#define KJ_TIME_H_
|
||||
|
||||
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include "async.h"
|
||||
#include "units.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
namespace kj {
|
||||
namespace _ { // private
|
||||
|
||||
class NanosecondLabel;
|
||||
class TimeLabel;
|
||||
class DateLabel;
|
||||
|
||||
} // namespace _ (private)
|
||||
|
||||
using Duration = Quantity<int64_t, _::NanosecondLabel>;
|
||||
// A time value, in nanoseconds.
|
||||
|
||||
constexpr Duration NANOSECONDS = unit<Duration>();
|
||||
constexpr Duration MICROSECONDS = 1000 * NANOSECONDS;
|
||||
constexpr Duration MILLISECONDS = 1000 * MICROSECONDS;
|
||||
constexpr Duration SECONDS = 1000 * MILLISECONDS;
|
||||
constexpr Duration MINUTES = 60 * SECONDS;
|
||||
constexpr Duration HOURS = 60 * MINUTES;
|
||||
constexpr Duration DAYS = 24 * HOURS;
|
||||
|
||||
using TimePoint = Absolute<Duration, _::TimeLabel>;
|
||||
// An absolute time measured by some particular instance of `Timer`. `Time`s from two different
|
||||
// `Timer`s may be measured from different origins and so are not necessarily compatible.
|
||||
|
||||
using Date = Absolute<Duration, _::DateLabel>;
|
||||
// A point in real-world time, measured relative to the Unix epoch (Jan 1, 1970 00:00:00 UTC).
|
||||
|
||||
constexpr Date UNIX_EPOCH = origin<Date>();
|
||||
// The `Date` representing Jan 1, 1970 00:00:00 UTC.
|
||||
|
||||
class Clock {
|
||||
// Interface to read the current date and time.
|
||||
public:
|
||||
virtual Date now() = 0;
|
||||
};
|
||||
|
||||
Clock& nullClock();
|
||||
// A clock which always returns UNIX_EPOCH as the current time. Useful when you don't care about
|
||||
// time.
|
||||
|
||||
class Timer {
|
||||
// Interface to time and timer functionality.
|
||||
//
|
||||
// Each `Timer` may have a different origin, and some `Timer`s may in fact tick at a different
|
||||
// rate than real time (e.g. a `Timer` could represent CPU time consumed by a thread). However,
|
||||
// all `Timer`s are monotonic: time will never appear to move backwards, even if the calendar
|
||||
// date as tracked by the system is manually modified.
|
||||
|
||||
public:
|
||||
virtual TimePoint now() = 0;
|
||||
// Returns the current value of a clock that moves steadily forward, independent of any
|
||||
// changes in the wall clock. The value is updated every time the event loop waits,
|
||||
// and is constant in-between waits.
|
||||
|
||||
virtual Promise<void> atTime(TimePoint time) = 0;
|
||||
// Returns a promise that returns as soon as now() >= time.
|
||||
|
||||
virtual Promise<void> afterDelay(Duration delay) = 0;
|
||||
// Equivalent to atTime(now() + delay).
|
||||
|
||||
template <typename T>
|
||||
Promise<T> timeoutAt(TimePoint time, Promise<T>&& promise) KJ_WARN_UNUSED_RESULT;
|
||||
// Return a promise equivalent to `promise` but which throws an exception (and cancels the
|
||||
// original promise) if it hasn't completed by `time`. The thrown exception is of type
|
||||
// "OVERLOADED".
|
||||
|
||||
template <typename T>
|
||||
Promise<T> timeoutAfter(Duration delay, Promise<T>&& promise) KJ_WARN_UNUSED_RESULT;
|
||||
// Return a promise equivalent to `promise` but which throws an exception (and cancels the
|
||||
// original promise) if it hasn't completed after `delay` from now. The thrown exception is of
|
||||
// type "OVERLOADED".
|
||||
|
||||
private:
|
||||
static kj::Exception makeTimeoutException();
|
||||
};
|
||||
|
||||
class TimerImpl final: public Timer {
|
||||
// Implementation of Timer that expects an external caller -- usually, the EventPort
|
||||
// implementation -- to tell it when time has advanced.
|
||||
|
||||
public:
|
||||
TimerImpl(TimePoint startTime);
|
||||
~TimerImpl() noexcept(false);
|
||||
|
||||
Maybe<TimePoint> nextEvent();
|
||||
// Returns the time at which the next scheduled timer event will occur, or null if no timer
|
||||
// events are scheduled.
|
||||
|
||||
Maybe<uint64_t> timeoutToNextEvent(TimePoint start, Duration unit, uint64_t max);
|
||||
// Convenience method which computes a timeout value to pass to an event-waiting system call to
|
||||
// cause it to time out when the next timer event occurs.
|
||||
//
|
||||
// `start` is the time at which the timeout starts counting. This is typically not the same as
|
||||
// now() since some time may have passed since the last time advanceTo() was called.
|
||||
//
|
||||
// `unit` is the time unit in which the timeout is measured. This is often MILLISECONDS. Note
|
||||
// that this method will fractional values *up*, to guarantee that the returned timeout waits
|
||||
// until just *after* the time the event is scheduled.
|
||||
//
|
||||
// The timeout will be clamped to `max`. Use this to avoid an overflow if e.g. the OS wants a
|
||||
// 32-bit value or a signed value.
|
||||
//
|
||||
// Returns nullptr if there are no future events.
|
||||
|
||||
void advanceTo(TimePoint newTime);
|
||||
// Set the time to `time` and fire any at() events that have been passed.
|
||||
|
||||
// implements Timer ----------------------------------------------------------
|
||||
TimePoint now() override;
|
||||
Promise<void> atTime(TimePoint time) override;
|
||||
Promise<void> afterDelay(Duration delay) override;
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
class TimerPromiseAdapter;
|
||||
TimePoint time;
|
||||
Own<Impl> impl;
|
||||
};
|
||||
|
||||
// =======================================================================================
|
||||
// inline implementation details
|
||||
|
||||
template <typename T>
|
||||
Promise<T> Timer::timeoutAt(TimePoint time, Promise<T>&& promise) {
|
||||
return promise.exclusiveJoin(atTime(time).then([]() -> kj::Promise<T> {
|
||||
return makeTimeoutException();
|
||||
}));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Promise<T> Timer::timeoutAfter(Duration delay, Promise<T>&& promise) {
|
||||
return promise.exclusiveJoin(afterDelay(delay).then([]() -> kj::Promise<T> {
|
||||
return makeTimeoutException();
|
||||
}));
|
||||
}
|
||||
|
||||
inline TimePoint TimerImpl::now() { return time; }
|
||||
|
||||
} // namespace kj
|
||||
|
||||
#endif // KJ_TIME_H_
|
||||
@@ -0,0 +1,364 @@
|
||||
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// This file defines a notion of tuples that is simpler that `std::tuple`. It works as follows:
|
||||
// - `kj::Tuple<A, B, C> is the type of a tuple of an A, a B, and a C.
|
||||
// - `kj::tuple(a, b, c)` returns a tuple containing a, b, and c. If any of these are themselves
|
||||
// tuples, they are flattened, so `tuple(a, tuple(b, c), d)` is equivalent to `tuple(a, b, c, d)`.
|
||||
// - `kj::get<n>(myTuple)` returns the element of `myTuple` at index n.
|
||||
// - `kj::apply(func, ...)` calls func on the following arguments after first expanding any tuples
|
||||
// in the argument list. So `kj::apply(foo, a, tuple(b, c), d)` would call `foo(a, b, c, d)`.
|
||||
//
|
||||
// Note that:
|
||||
// - The type `Tuple<T>` is a synonym for T. This is why `get` and `apply` are not members of the
|
||||
// type.
|
||||
// - It is illegal for an element of `Tuple` to itself be a tuple, as tuples are meant to be
|
||||
// flattened.
|
||||
// - It is illegal for an element of `Tuple` to be a reference, due to problems this would cause
|
||||
// with type inference and `tuple()`.
|
||||
|
||||
#ifndef KJ_TUPLE_H_
|
||||
#define KJ_TUPLE_H_
|
||||
|
||||
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace kj {
|
||||
namespace _ { // private
|
||||
|
||||
template <size_t index, typename... T>
|
||||
struct TypeByIndex_;
|
||||
template <typename First, typename... Rest>
|
||||
struct TypeByIndex_<0, First, Rest...> {
|
||||
typedef First Type;
|
||||
};
|
||||
template <size_t index, typename First, typename... Rest>
|
||||
struct TypeByIndex_<index, First, Rest...>
|
||||
: public TypeByIndex_<index - 1, Rest...> {};
|
||||
template <size_t index>
|
||||
struct TypeByIndex_<index> {
|
||||
static_assert(index != index, "Index out-of-range.");
|
||||
};
|
||||
template <size_t index, typename... T>
|
||||
using TypeByIndex = typename TypeByIndex_<index, T...>::Type;
|
||||
// Chose a particular type out of a list of types, by index.
|
||||
|
||||
template <size_t... s>
|
||||
struct Indexes {};
|
||||
// Dummy helper type that just encapsulates a sequential list of indexes, so that we can match
|
||||
// templates against them and unpack them with '...'.
|
||||
|
||||
template <size_t end, size_t... prefix>
|
||||
struct MakeIndexes_: public MakeIndexes_<end - 1, end - 1, prefix...> {};
|
||||
template <size_t... prefix>
|
||||
struct MakeIndexes_<0, prefix...> {
|
||||
typedef Indexes<prefix...> Type;
|
||||
};
|
||||
template <size_t end>
|
||||
using MakeIndexes = typename MakeIndexes_<end>::Type;
|
||||
// Equivalent to Indexes<0, 1, 2, ..., end>.
|
||||
|
||||
template <typename... T>
|
||||
class Tuple;
|
||||
template <size_t index, typename... U>
|
||||
inline TypeByIndex<index, U...>& getImpl(Tuple<U...>& tuple);
|
||||
template <size_t index, typename... U>
|
||||
inline TypeByIndex<index, U...>&& getImpl(Tuple<U...>&& tuple);
|
||||
template <size_t index, typename... U>
|
||||
inline const TypeByIndex<index, U...>& getImpl(const Tuple<U...>& tuple);
|
||||
|
||||
template <uint index, typename T>
|
||||
struct TupleElement {
|
||||
// Encapsulates one element of a tuple. The actual tuple implementation multiply-inherits
|
||||
// from a TupleElement for each element, which is more efficient than a recursive definition.
|
||||
|
||||
T value;
|
||||
TupleElement() = default;
|
||||
constexpr inline TupleElement(const T& value): value(value) {}
|
||||
constexpr inline TupleElement(T&& value): value(kj::mv(value)) {}
|
||||
};
|
||||
|
||||
template <uint index, typename T>
|
||||
struct TupleElement<index, T&> {
|
||||
// If tuples contained references, one of the following would have to be true:
|
||||
// - `auto x = tuple(y, z)` would cause x to be a tuple of references to y and z, which is
|
||||
// probably not what you expected.
|
||||
// - `Tuple<Foo&, Bar&> x = tuple(a, b)` would not work, because `tuple()` returned
|
||||
// Tuple<Foo, Bar>.
|
||||
static_assert(sizeof(T*) == 0, "Sorry, tuples cannot contain references.");
|
||||
};
|
||||
|
||||
template <uint index, typename... T>
|
||||
struct TupleElement<index, Tuple<T...>> {
|
||||
static_assert(sizeof(Tuple<T...>*) == 0,
|
||||
"Tuples cannot contain other tuples -- they should be flattened.");
|
||||
};
|
||||
|
||||
template <typename Indexes, typename... Types>
|
||||
struct TupleImpl;
|
||||
|
||||
template <size_t... indexes, typename... Types>
|
||||
struct TupleImpl<Indexes<indexes...>, Types...>
|
||||
: public TupleElement<indexes, Types>... {
|
||||
// Implementation of Tuple. The only reason we need this rather than rolling this into class
|
||||
// Tuple (below) is so that we can get "indexes" as an unpackable list.
|
||||
|
||||
static_assert(sizeof...(indexes) == sizeof...(Types), "Incorrect use of TupleImpl.");
|
||||
|
||||
template <typename... Params>
|
||||
inline TupleImpl(Params&&... params)
|
||||
: TupleElement<indexes, Types>(kj::fwd<Params>(params))... {
|
||||
// Work around Clang 3.2 bug 16303 where this is not detected. (Unfortunately, Clang sometimes
|
||||
// segfaults instead.)
|
||||
static_assert(sizeof...(params) == sizeof...(indexes),
|
||||
"Wrong number of parameters to Tuple constructor.");
|
||||
}
|
||||
|
||||
template <typename... U>
|
||||
constexpr inline TupleImpl(Tuple<U...>&& other)
|
||||
: TupleElement<indexes, Types>(kj::mv(getImpl<indexes>(other)))... {}
|
||||
template <typename... U>
|
||||
constexpr inline TupleImpl(Tuple<U...>& other)
|
||||
: TupleElement<indexes, Types>(getImpl<indexes>(other))... {}
|
||||
template <typename... U>
|
||||
constexpr inline TupleImpl(const Tuple<U...>& other)
|
||||
: TupleElement<indexes, Types>(getImpl<indexes>(other))... {}
|
||||
};
|
||||
|
||||
struct MakeTupleFunc;
|
||||
|
||||
template <typename... T>
|
||||
class Tuple {
|
||||
// The actual Tuple class (used for tuples of size other than 1).
|
||||
|
||||
public:
|
||||
template <typename... U>
|
||||
constexpr inline Tuple(Tuple<U...>&& other): impl(kj::mv(other)) {}
|
||||
template <typename... U>
|
||||
constexpr inline Tuple(Tuple<U...>& other): impl(other) {}
|
||||
template <typename... U>
|
||||
constexpr inline Tuple(const Tuple<U...>& other): impl(other) {}
|
||||
|
||||
private:
|
||||
template <typename... Params>
|
||||
constexpr Tuple(Params&&... params): impl(kj::fwd<Params>(params)...) {}
|
||||
|
||||
TupleImpl<MakeIndexes<sizeof...(T)>, T...> impl;
|
||||
|
||||
template <size_t index, typename... U>
|
||||
friend inline TypeByIndex<index, U...>& getImpl(Tuple<U...>& tuple);
|
||||
template <size_t index, typename... U>
|
||||
friend inline TypeByIndex<index, U...>&& getImpl(Tuple<U...>&& tuple);
|
||||
template <size_t index, typename... U>
|
||||
friend inline const TypeByIndex<index, U...>& getImpl(const Tuple<U...>& tuple);
|
||||
friend struct MakeTupleFunc;
|
||||
};
|
||||
|
||||
template <>
|
||||
class Tuple<> {
|
||||
// Simplified zero-member version of Tuple. In particular this is important to make sure that
|
||||
// Tuple<>() is constexpr.
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class Tuple<T>;
|
||||
// Single-element tuple should never be used. The public API should ensure this.
|
||||
|
||||
template <size_t index, typename... T>
|
||||
inline TypeByIndex<index, T...>& getImpl(Tuple<T...>& tuple) {
|
||||
// Get member of a Tuple by index, e.g. `get<2>(myTuple)`.
|
||||
static_assert(index < sizeof...(T), "Tuple element index out-of-bounds.");
|
||||
return implicitCast<TupleElement<index, TypeByIndex<index, T...>>&>(tuple.impl).value;
|
||||
}
|
||||
template <size_t index, typename... T>
|
||||
inline TypeByIndex<index, T...>&& getImpl(Tuple<T...>&& tuple) {
|
||||
// Get member of a Tuple by index, e.g. `get<2>(myTuple)`.
|
||||
static_assert(index < sizeof...(T), "Tuple element index out-of-bounds.");
|
||||
return kj::mv(implicitCast<TupleElement<index, TypeByIndex<index, T...>>&>(tuple.impl).value);
|
||||
}
|
||||
template <size_t index, typename... T>
|
||||
inline const TypeByIndex<index, T...>& getImpl(const Tuple<T...>& tuple) {
|
||||
// Get member of a Tuple by index, e.g. `get<2>(myTuple)`.
|
||||
static_assert(index < sizeof...(T), "Tuple element index out-of-bounds.");
|
||||
return implicitCast<const TupleElement<index, TypeByIndex<index, T...>>&>(tuple.impl).value;
|
||||
}
|
||||
template <size_t index, typename T>
|
||||
inline T&& getImpl(T&& value) {
|
||||
// Get member of a Tuple by index, e.g. `getImpl<2>(myTuple)`.
|
||||
|
||||
// Non-tuples are equivalent to one-element tuples.
|
||||
static_assert(index == 0, "Tuple element index out-of-bounds.");
|
||||
return kj::fwd<T>(value);
|
||||
}
|
||||
|
||||
|
||||
template <typename Func, typename SoFar, typename... T>
|
||||
struct ExpandAndApplyResult_;
|
||||
// Template which computes the return type of applying Func to T... after flattening tuples.
|
||||
// SoFar starts as Tuple<> and accumulates the flattened parameter types -- so after this template
|
||||
// is recursively expanded, T... is empty and SoFar is a Tuple containing all the parameters.
|
||||
|
||||
template <typename Func, typename First, typename... Rest, typename... T>
|
||||
struct ExpandAndApplyResult_<Func, Tuple<T...>, First, Rest...>
|
||||
: public ExpandAndApplyResult_<Func, Tuple<T..., First>, Rest...> {};
|
||||
template <typename Func, typename... FirstTypes, typename... Rest, typename... T>
|
||||
struct ExpandAndApplyResult_<Func, Tuple<T...>, Tuple<FirstTypes...>, Rest...>
|
||||
: public ExpandAndApplyResult_<Func, Tuple<T...>, FirstTypes&&..., Rest...> {};
|
||||
template <typename Func, typename... FirstTypes, typename... Rest, typename... T>
|
||||
struct ExpandAndApplyResult_<Func, Tuple<T...>, Tuple<FirstTypes...>&, Rest...>
|
||||
: public ExpandAndApplyResult_<Func, Tuple<T...>, FirstTypes&..., Rest...> {};
|
||||
template <typename Func, typename... FirstTypes, typename... Rest, typename... T>
|
||||
struct ExpandAndApplyResult_<Func, Tuple<T...>, const Tuple<FirstTypes...>&, Rest...>
|
||||
: public ExpandAndApplyResult_<Func, Tuple<T...>, const FirstTypes&..., Rest...> {};
|
||||
template <typename Func, typename... T>
|
||||
struct ExpandAndApplyResult_<Func, Tuple<T...>> {
|
||||
typedef decltype(instance<Func>()(instance<T&&>()...)) Type;
|
||||
};
|
||||
template <typename Func, typename... T>
|
||||
using ExpandAndApplyResult = typename ExpandAndApplyResult_<Func, Tuple<>, T...>::Type;
|
||||
// Computes the expected return type of `expandAndApply()`.
|
||||
|
||||
template <typename Func>
|
||||
inline auto expandAndApply(Func&& func) -> ExpandAndApplyResult<Func> {
|
||||
return func();
|
||||
}
|
||||
|
||||
template <typename Func, typename First, typename... Rest>
|
||||
struct ExpandAndApplyFunc {
|
||||
Func&& func;
|
||||
First&& first;
|
||||
ExpandAndApplyFunc(Func&& func, First&& first)
|
||||
: func(kj::fwd<Func>(func)), first(kj::fwd<First>(first)) {}
|
||||
template <typename... T>
|
||||
auto operator()(T&&... params)
|
||||
-> decltype(this->func(kj::fwd<First>(first), kj::fwd<T>(params)...)) {
|
||||
return this->func(kj::fwd<First>(first), kj::fwd<T>(params)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Func, typename First, typename... Rest>
|
||||
inline auto expandAndApply(Func&& func, First&& first, Rest&&... rest)
|
||||
-> ExpandAndApplyResult<Func, First, Rest...> {
|
||||
|
||||
return expandAndApply(
|
||||
ExpandAndApplyFunc<Func, First, Rest...>(kj::fwd<Func>(func), kj::fwd<First>(first)),
|
||||
kj::fwd<Rest>(rest)...);
|
||||
}
|
||||
|
||||
template <typename Func, typename... FirstTypes, typename... Rest>
|
||||
inline auto expandAndApply(Func&& func, Tuple<FirstTypes...>&& first, Rest&&... rest)
|
||||
-> ExpandAndApplyResult<Func, FirstTypes&&..., Rest...> {
|
||||
return expandAndApplyWithIndexes(MakeIndexes<sizeof...(FirstTypes)>(),
|
||||
kj::fwd<Func>(func), kj::mv(first), kj::fwd<Rest>(rest)...);
|
||||
}
|
||||
|
||||
template <typename Func, typename... FirstTypes, typename... Rest>
|
||||
inline auto expandAndApply(Func&& func, Tuple<FirstTypes...>& first, Rest&&... rest)
|
||||
-> ExpandAndApplyResult<Func, FirstTypes..., Rest...> {
|
||||
return expandAndApplyWithIndexes(MakeIndexes<sizeof...(FirstTypes)>(),
|
||||
kj::fwd<Func>(func), first, kj::fwd<Rest>(rest)...);
|
||||
}
|
||||
|
||||
template <typename Func, typename... FirstTypes, typename... Rest>
|
||||
inline auto expandAndApply(Func&& func, const Tuple<FirstTypes...>& first, Rest&&... rest)
|
||||
-> ExpandAndApplyResult<Func, FirstTypes..., Rest...> {
|
||||
return expandAndApplyWithIndexes(MakeIndexes<sizeof...(FirstTypes)>(),
|
||||
kj::fwd<Func>(func), first, kj::fwd<Rest>(rest)...);
|
||||
}
|
||||
|
||||
template <typename Func, typename... FirstTypes, typename... Rest, size_t... indexes>
|
||||
inline auto expandAndApplyWithIndexes(
|
||||
Indexes<indexes...>, Func&& func, Tuple<FirstTypes...>&& first, Rest&&... rest)
|
||||
-> ExpandAndApplyResult<Func, FirstTypes&&..., Rest...> {
|
||||
return expandAndApply(kj::fwd<Func>(func), kj::mv(getImpl<indexes>(first))...,
|
||||
kj::fwd<Rest>(rest)...);
|
||||
}
|
||||
|
||||
template <typename Func, typename... FirstTypes, typename... Rest, size_t... indexes>
|
||||
inline auto expandAndApplyWithIndexes(
|
||||
Indexes<indexes...>, Func&& func, const Tuple<FirstTypes...>& first, Rest&&... rest)
|
||||
-> ExpandAndApplyResult<Func, FirstTypes..., Rest...> {
|
||||
return expandAndApply(kj::fwd<Func>(func), getImpl<indexes>(first)...,
|
||||
kj::fwd<Rest>(rest)...);
|
||||
}
|
||||
|
||||
struct MakeTupleFunc {
|
||||
template <typename... Params>
|
||||
Tuple<Decay<Params>...> operator()(Params&&... params) {
|
||||
return Tuple<Decay<Params>...>(kj::fwd<Params>(params)...);
|
||||
}
|
||||
template <typename Param>
|
||||
Decay<Param> operator()(Param&& param) {
|
||||
return kj::fwd<Param>(param);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace _ (private)
|
||||
|
||||
template <typename... T> struct Tuple_ { typedef _::Tuple<T...> Type; };
|
||||
template <typename T> struct Tuple_<T> { typedef T Type; };
|
||||
|
||||
template <typename... T> using Tuple = typename Tuple_<T...>::Type;
|
||||
// Tuple type. `Tuple<T>` (i.e. a single-element tuple) is a synonym for `T`. Tuples of size
|
||||
// other than 1 expand to an internal type. Either way, you can construct a Tuple using
|
||||
// `kj::tuple(...)`, get an element by index `i` using `kj::get<i>(myTuple)`, and expand the tuple
|
||||
// as arguments to a function using `kj::apply(func, myTuple)`.
|
||||
//
|
||||
// Tuples are always flat -- that is, no element of a Tuple is ever itself a Tuple. If you
|
||||
// construct a tuple from other tuples, the elements are flattened and concatenated.
|
||||
|
||||
template <typename... Params>
|
||||
inline auto tuple(Params&&... params)
|
||||
-> decltype(_::expandAndApply(_::MakeTupleFunc(), kj::fwd<Params>(params)...)) {
|
||||
// Construct a new tuple from the given values. Any tuples in the argument list will be
|
||||
// flattened into the result.
|
||||
return _::expandAndApply(_::MakeTupleFunc(), kj::fwd<Params>(params)...);
|
||||
}
|
||||
|
||||
template <size_t index, typename Tuple>
|
||||
inline auto get(Tuple&& tuple) -> decltype(_::getImpl<index>(kj::fwd<Tuple>(tuple))) {
|
||||
// Unpack and return the tuple element at the given index. The index is specified as a template
|
||||
// parameter, e.g. `kj::get<3>(myTuple)`.
|
||||
return _::getImpl<index>(kj::fwd<Tuple>(tuple));
|
||||
}
|
||||
|
||||
template <typename Func, typename... Params>
|
||||
inline auto apply(Func&& func, Params&&... params)
|
||||
-> decltype(_::expandAndApply(kj::fwd<Func>(func), kj::fwd<Params>(params)...)) {
|
||||
// Apply a function to some arguments, expanding tuples into separate arguments.
|
||||
return _::expandAndApply(kj::fwd<Func>(func), kj::fwd<Params>(params)...);
|
||||
}
|
||||
|
||||
template <typename T> struct TupleSize_ { static constexpr size_t size = 1; };
|
||||
template <typename... T> struct TupleSize_<_::Tuple<T...>> {
|
||||
static constexpr size_t size = sizeof...(T);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
constexpr size_t tupleSize() { return TupleSize_<T>::size; }
|
||||
// Returns size of the tuple T.
|
||||
|
||||
} // namespace kj
|
||||
|
||||
#endif // KJ_TUPLE_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,144 @@
|
||||
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef KJ_VECTOR_H_
|
||||
#define KJ_VECTOR_H_
|
||||
|
||||
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#include "array.h"
|
||||
|
||||
namespace kj {
|
||||
|
||||
template <typename T>
|
||||
class Vector {
|
||||
// Similar to std::vector, but based on KJ framework.
|
||||
//
|
||||
// This implementation always uses move constructors when growing the backing array. If the
|
||||
// move constructor throws, the Vector is left in an inconsistent state. This is acceptable
|
||||
// under KJ exception theory which assumes that exceptions leave things in inconsistent states.
|
||||
|
||||
// TODO(someday): Allow specifying a custom allocator.
|
||||
|
||||
public:
|
||||
inline Vector() = default;
|
||||
inline explicit Vector(size_t capacity): builder(heapArrayBuilder<T>(capacity)) {}
|
||||
|
||||
inline operator ArrayPtr<T>() { return builder; }
|
||||
inline operator ArrayPtr<const T>() const { return builder; }
|
||||
inline ArrayPtr<T> asPtr() { return builder.asPtr(); }
|
||||
inline ArrayPtr<const T> asPtr() const { return builder.asPtr(); }
|
||||
|
||||
inline size_t size() const { return builder.size(); }
|
||||
inline bool empty() const { return size() == 0; }
|
||||
inline size_t capacity() const { return builder.capacity(); }
|
||||
inline T& operator[](size_t index) const { return builder[index]; }
|
||||
|
||||
inline const T* begin() const { return builder.begin(); }
|
||||
inline const T* end() const { return builder.end(); }
|
||||
inline const T& front() const { return builder.front(); }
|
||||
inline const T& back() const { return builder.back(); }
|
||||
inline T* begin() { return builder.begin(); }
|
||||
inline T* end() { return builder.end(); }
|
||||
inline T& front() { return builder.front(); }
|
||||
inline T& back() { return builder.back(); }
|
||||
|
||||
inline Array<T> releaseAsArray() {
|
||||
// TODO(perf): Avoid a copy/move by allowing Array<T> to point to incomplete space?
|
||||
if (!builder.isFull()) {
|
||||
setCapacity(size());
|
||||
}
|
||||
return builder.finish();
|
||||
}
|
||||
|
||||
template <typename... Params>
|
||||
inline T& add(Params&&... params) {
|
||||
if (builder.isFull()) grow();
|
||||
return builder.add(kj::fwd<Params>(params)...);
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
inline void addAll(Iterator begin, Iterator end) {
|
||||
size_t needed = builder.size() + (end - begin);
|
||||
if (needed > builder.capacity()) grow(needed);
|
||||
builder.addAll(begin, end);
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline void addAll(Container&& container) {
|
||||
addAll(container.begin(), container.end());
|
||||
}
|
||||
|
||||
inline void removeLast() {
|
||||
builder.removeLast();
|
||||
}
|
||||
|
||||
inline void resize(size_t size) {
|
||||
if (size > builder.capacity()) grow(size);
|
||||
builder.resize(size);
|
||||
}
|
||||
|
||||
inline void operator=(decltype(nullptr)) {
|
||||
builder = nullptr;
|
||||
}
|
||||
|
||||
inline void clear() {
|
||||
while (builder.size() > 0) {
|
||||
builder.removeLast();
|
||||
}
|
||||
}
|
||||
|
||||
inline void truncate(size_t size) {
|
||||
builder.truncate(size);
|
||||
}
|
||||
|
||||
inline void reserve(size_t size) {
|
||||
if (size > builder.capacity()) {
|
||||
setCapacity(size);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ArrayBuilder<T> builder;
|
||||
|
||||
void grow(size_t minCapacity = 0) {
|
||||
setCapacity(kj::max(minCapacity, capacity() == 0 ? 4 : capacity() * 2));
|
||||
}
|
||||
void setCapacity(size_t newSize) {
|
||||
if (builder.size() > newSize) {
|
||||
builder.truncate(newSize);
|
||||
}
|
||||
ArrayBuilder<T> newBuilder = heapArrayBuilder<T>(newSize);
|
||||
newBuilder.addAll(kj::mv(builder));
|
||||
builder = kj::mv(newBuilder);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline auto KJ_STRINGIFY(const Vector<T>& v) -> decltype(toCharSequence(v.asPtr())) {
|
||||
return toCharSequence(v.asPtr());
|
||||
}
|
||||
|
||||
} // namespace kj
|
||||
|
||||
#endif // KJ_VECTOR_H_
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
||||
// Licensed under the MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef KJ_WINDOWS_SANITY_H_
|
||||
#define KJ_WINDOWS_SANITY_H_
|
||||
|
||||
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
#ifndef _INC_WINDOWS
|
||||
#error "windows.h needs to be included before kj/windows-sanity.h (or perhaps you don't need either?)"
|
||||
#endif
|
||||
|
||||
namespace win32 {
|
||||
const auto ERROR_ = ERROR;
|
||||
#undef ERROR
|
||||
const auto ERROR = ERROR_;
|
||||
}
|
||||
|
||||
using win32::ERROR;
|
||||
|
||||
#endif // KJ_WINDOWS_SANITY_H_
|
||||
Reference in New Issue
Block a user