Commit 7001fc9d authored by Kenton Varda's avatar Kenton Varda

Refactor Tuple and split it and Vector out into their own headers.

parent b5cd7147
......@@ -68,10 +68,13 @@ includekj_HEADERS = \
src/kj/units.h \
src/kj/memory.h \
src/kj/array.h \
src/kj/vector.h \
src/kj/string.h \
src/kj/exception.h \
src/kj/debug.h \
src/kj/io.h
src/kj/io.h \
src/kj/tuple.h \
src/kj/parse.h
includecapnp_HEADERS = \
src/capnp/common.h \
......@@ -157,6 +160,7 @@ capnproto_test_SOURCES = \
src/kj/exception-test.c++ \
src/kj/debug-test.c++ \
src/kj/units-test.c++ \
src/kj/tuple-test.c++ \
src/kj/parse-test.c++ \
src/capnp/blob-test.c++ \
src/capnp/endian-test.c++ \
......
......@@ -180,6 +180,9 @@ template <typename T> struct Decay_ { typedef T Type; };
template <typename T> struct Decay_<T&> { typedef typename Decay_<T>::Type Type; };
template <typename T> struct Decay_<T&&> { typedef typename Decay_<T>::Type Type; };
template <typename T> struct Decay_<T[]> { typedef typename Decay_<T*>::Type Type; };
template <typename T> struct Decay_<const T[]> { typedef typename Decay_<const T*>::Type Type; };
template <typename T, size_t s> struct Decay_<T[s]> { typedef typename Decay_<T*>::Type Type; };
template <typename T, size_t s> struct Decay_<const T[s]> { typedef typename Decay_<const T*>::Type Type; };
template <typename T> struct Decay_<const T> { typedef typename Decay_<T>::Type Type; };
template <typename T> struct Decay_<volatile T> { typedef typename Decay_<T>::Type Type; };
template <typename T> using Decay = typename Decay_<T>::Type;
......
......@@ -29,22 +29,6 @@ namespace kj {
namespace parse {
namespace {
TEST(Tuple, Flatten) {
int output = 0;
Tuple<int, int, int> t =
tuple(tuple(tuple(), tuple(1)), tuple(), 20, tuple(tuple(tuple(), 300)));
applyTuple([&](int i, int j, int k) { output = i + j + k; }, t);
EXPECT_EQ(321, output);
EXPECT_EQ(321, applyTuple([](int i, int j, int k) { return i + j + k; }, t));
Tuple<Maybe<int>, String> t2 = tuple(Maybe<int>(123), heapString("foo"));
String t3 = tuple(heapString("foo"));
String t4 = tuple(heapString("foo"), Void());
}
typedef IteratorInput<char, const char*> Input;
ExactElementParser<Input> exactChar(char c) {
return exactElement<Input>(mv(c));
......@@ -56,7 +40,7 @@ TEST(Parsers, ExactElementParser) {
StringPtr text = "foo";
Input input(text.begin(), text.end());
Maybe<Void> result = exactChar('f')(input);
Maybe<Tuple<>> result = exactChar('f')(input);
EXPECT_TRUE(result != nullptr);
EXPECT_FALSE(input.atEnd());
......@@ -68,7 +52,7 @@ TEST(Parsers, ExactElementParser) {
EXPECT_TRUE(result == nullptr);
EXPECT_FALSE(input.atEnd());
Parser<Input, Void> wrapped = exactChar('o');
Parser<Input, Tuple<>> wrapped = exactChar('o');
result = wrapped(input);
EXPECT_TRUE(result != nullptr);
EXPECT_TRUE(input.atEnd());
......@@ -79,35 +63,37 @@ TEST(Parsers, SequenceParser) {
{
Input input(text.begin(), text.end());
Maybe<Void> result = sequence(exactChar('f'), exactChar('o'), exactChar('o'))(input);
Maybe<Tuple<>> result = sequence(exactChar('f'), exactChar('o'), exactChar('o'))(input);
EXPECT_TRUE(result != nullptr);
EXPECT_TRUE(input.atEnd());
}
{
Input input(text.begin(), text.end());
Maybe<Void> result = sequence(exactChar('f'), exactChar('o'))(input);
Maybe<Tuple<>> result = sequence(exactChar('f'), exactChar('o'))(input);
EXPECT_TRUE(result != nullptr);
EXPECT_FALSE(input.atEnd());
}
{
Input input(text.begin(), text.end());
Maybe<Void> result = sequence(exactChar('x'), exactChar('o'), exactChar('o'))(input);
Maybe<Tuple<>> result = sequence(exactChar('x'), exactChar('o'), exactChar('o'))(input);
EXPECT_TRUE(result == nullptr);
EXPECT_FALSE(input.atEnd());
}
{
Input input(text.begin(), text.end());
Maybe<Void> result = sequence(sequence(exactChar('f'), exactChar('o')), exactChar('o'))(input);
Maybe<Tuple<>> result =
sequence(sequence(exactChar('f'), exactChar('o')), exactChar('o'))(input);
EXPECT_TRUE(result != nullptr);
EXPECT_TRUE(input.atEnd());
}
{
Input input(text.begin(), text.end());
Maybe<Void> result = sequence(sequence(exactChar('f')), exactChar('o'), exactChar('o'))(input);
Maybe<Tuple<>> result =
sequence(sequence(exactChar('f')), exactChar('o'), exactChar('o'))(input);
EXPECT_TRUE(result != nullptr);
EXPECT_TRUE(input.atEnd());
}
......@@ -193,7 +179,7 @@ TEST(Parsers, RepeatedParser) {
auto parser = transform(
sequence(exactChar('f'), repeated(exactChar('o'))),
[](TestLocation, ArrayPtr<Void> values) -> int { return values.size(); });
[](TestLocation, ArrayPtr<Tuple<>> values) -> int { return values.size(); });
{
Input input(text.begin(), text.begin() + 3);
......
......@@ -27,175 +27,12 @@
#include "common.h"
#include "memory.h"
#include "array.h"
#include "tuple.h"
#include "vector.h"
namespace kj {
namespace parse {
// I don't understand std::tuple.
template <typename... T>
struct Tuple;
template <>
struct Tuple<> {
Tuple() {}
};
template <typename First, typename... Rest>
struct Tuple<First, Rest...> {
Tuple() {}
Tuple(Tuple&& other): first(kj::mv(other.first)), rest(kj::mv(other.rest)) {}
Tuple(const Tuple& other): first(other.first), rest(other.rest) {}
Tuple(Tuple& other): first(other.first), rest(other.rest) {}
template <typename First2, typename Rest2>
explicit Tuple(First2&& first2, Rest2&& rest2)
: first(kj::fwd<First2>(first2)),
rest(kj::fwd<Rest2>(rest2)) {}
First first;
Tuple<Rest...> rest;
};
typedef Tuple<> Void;
template <typename T, typename U>
struct ConsTuple {
typedef Tuple<Decay<T>, Decay<U>> Type;
};
template <typename T, typename... U>
struct ConsTuple<T, Tuple<U...>> {
typedef Tuple<Decay<T>, U...> Type;
};
template <typename T>
struct ConsTuple<T, Tuple<>> {
typedef Decay<T> Type;
};
template <typename... T>
struct MakeTuple;
template <>
struct MakeTuple<> {
typedef Tuple<> Type;
};
template <typename T>
struct MakeTuple<T> {
typedef Decay<T> Type;
};
template <typename T, typename U, typename... V>
struct MakeTuple<T, U, V...> {
typedef typename ConsTuple<T, typename MakeTuple<U, V...>::Type>::Type Type;
};
template <typename T, typename... U>
struct MakeTuple<Tuple<>, T, U...> {
typedef typename MakeTuple<T, U...>::Type Type;
};
template <typename T, typename... U, typename V, typename... W>
struct MakeTuple<Tuple<T, U...>, V, W...> {
typedef typename ConsTuple<T, typename MakeTuple<Tuple<U...>, V, W...>::Type>::Type Type;
};
template <typename T, typename U>
typename ConsTuple<T, U>::Type
inline consTuple(T&& t, U&& u) {
return typename ConsTuple<T, U>::Type(
kj::fwd<T>(t),
Tuple<Decay<U>>(kj::fwd<U>(u), Void()));
}
template <typename T, typename... U>
typename ConsTuple<T, Tuple<U...>>::Type
inline consTuple(T&& t, Tuple<U...>&& u) {
return typename ConsTuple<T, Tuple<U...>>::Type(kj::mv(t), kj::mv(u));
}
template <typename T>
typename ConsTuple<T, Tuple<>>::Type
inline consTuple(T&& t, Tuple<>&& u) {
return kj::fwd<T>(t);
}
typename MakeTuple<>::Type
inline tuple() {
return Tuple<>();
}
template <typename T>
typename MakeTuple<T>::Type
inline tuple(T&& first) {
return kj::fwd<T>(first);
}
template <typename T, typename U, typename... V>
typename MakeTuple<T, U, V...>::Type
inline tuple(T&& first, U&& second, V&&... rest) {
return consTuple(kj::fwd<T>(first),
tuple(kj::fwd<U>(second), kj::fwd<V>(rest)...));
}
template <typename T, typename... U>
typename MakeTuple<Tuple<>, T, U...>::Type
inline tuple(Tuple<>&&, T&& first, U&&... rest) {
return tuple(kj::fwd<T>(first), kj::fwd<U>(rest)...);
}
template <typename T, typename... U>
typename MakeTuple<Tuple<>, T, U...>::Type
inline tuple(const Tuple<>&, T&& first, U&&... rest) {
return tuple(kj::fwd<T>(first), kj::fwd<U>(rest)...);
}
template <typename T, typename... U, typename V, typename... W>
typename MakeTuple<Tuple<T, U...>, V, W...>::Type
inline tuple(Tuple<T, U...>&& first, V&& second, W&&... rest) {
return consTuple(kj::mv(first.first),
tuple(kj::mv(first.rest), kj::fwd<V>(second), kj::fwd<W>(rest)...));
}
template <typename T, typename... U, typename V, typename... W>
typename MakeTuple<Tuple<T, U...>, V, W...>::Type
inline tuple(const Tuple<T, U...>& first, V&& second, W&&... rest) {
return consTuple(first.first,
tuple(first.rest, kj::fwd<V>(second), kj::fwd<W>(rest)...));
}
template <typename Func, typename T, typename... Params>
inline auto applyTuple(Func&& func, T&& t, Params&&... params) ->
decltype(func(kj::fwd<Params>(params)..., kj::fwd<T>(t))) {
return func(kj::fwd<Params>(params)..., kj::fwd<T>(t));
}
template <typename Func, typename... Params>
inline auto applyTuple(Func&& func, Tuple<> t, Params&&... params) ->
decltype(func(kj::fwd<Params>(params)...)) {
return func(kj::fwd<Params>(params)...);
}
template <typename Func, typename T, typename... U, typename... Params>
inline auto applyTuple(Func&& func, Tuple<T, U...>&& t, Params&&... params) ->
decltype(func(kj::fwd<Params>(params)..., instance<T&&>(), instance<U&&>()...)) {
return applyTuple(kj::fwd<Func>(func), kj::mv(t.rest),
kj::fwd<Params>(params)..., kj::mv(t.first));
}
template <typename Func, typename T, typename... U, typename... Params>
inline auto applyTuple(Func&& func, const Tuple<T, U...>& t, Params&&... params) ->
decltype(func(kj::fwd<Params>(params)..., instance<const T&>(), instance<const U&>()...)) {
return applyTuple(kj::fwd<Func>(func), t.rest,
kj::fwd<Params>(params)..., t.first);
}
// =======================================================================================
template <typename Element, typename Iterator>
class IteratorInput {
public:
......@@ -244,7 +81,6 @@ private:
IteratorInput& operator=(IteratorInput&&) = delete;
};
template <typename T>
struct ExtractParseFuncType;
......@@ -393,19 +229,19 @@ struct WrapperParserConstructor {
// -------------------------------------------------------------------
// ExactElementParser
// Output = Void
// Output = Tuple<>
template <typename Input>
class ExactElementParser {
public:
explicit ExactElementParser(typename Input::ElementType&& expected): expected(expected) {}
virtual Maybe<Void> operator()(Input& input) const {
virtual Maybe<Tuple<>> operator()(Input& input) const {
if (input.atEnd() || input.current() != expected) {
return nullptr;
} else {
input.next();
return Void();
return Tuple<>();
}
}
......@@ -460,7 +296,7 @@ private:
template <typename Input>
class SequenceParser<Input> {
public:
Maybe<Void> operator()(Input& input) const {
Maybe<Tuple<>> operator()(Input& input) const {
return parseNext(input);
}
......@@ -487,56 +323,6 @@ sequence(FirstSubParser&& first, MoreSubParsers&&... rest) {
// RepeatedParser
// Output = Array of output of sub-parser.
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.
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(); }
template <typename... Params>
inline void add(Params&&... params) {
if (builder.isFull()) grow();
builder.add(kj::fwd<Params>(params)...);
}
private:
ArrayBuilder<T> builder;
void grow() {
size_t newSize = capacity() == 0 ? 4 : capacity() * 2;
ArrayBuilder<T> newBuilder = heapArrayBuilder<T>(newSize);
for (T& element: builder) {
newBuilder.add(kj::mv(element));
}
builder = kj::mv(newBuilder);
}
};
template <typename SubParser, bool atLeastOne>
class RepeatedParser {
public:
......@@ -705,14 +491,14 @@ public:
typedef typename ExtractParserType<SubParser>::InputType InputType;
typedef Decay<decltype(instance<InputType>().getPosition())> Position;
typedef typename ExtractParserType<SubParser>::OutputType SubOutput;
typedef decltype(applyTuple(instance<Transform&>(), instance<SubOutput&&>(),
instance<Span<Position>>())) Output;
typedef decltype(kj::apply(instance<Transform&>(), instance<Span<Position>>(),
instance<SubOutput&&>())) Output;
Maybe<Output> operator()(InputType& input) const {
auto start = input.getPosition();
KJ_IF_MAYBE(subResult, subParser(input)) {
return applyTuple(transform, kj::mv(*subResult),
Span<Position>(kj::mv(start), input.getPosition()));
return kj::apply(transform, Span<Position>(kj::mv(start), input.getPosition()),
kj::mv(*subResult));
} else {
return nullptr;
}
......@@ -763,14 +549,14 @@ acceptIf(SubParser&& subParser, Condition&& condition) {
// -------------------------------------------------------------------
// EndOfInputParser
// Output = Void, only succeeds if at end-of-input
// Output = Tuple<>, only succeeds if at end-of-input
template <typename Input>
class EndOfInputParser {
public:
Maybe<Void> operator()(Input& input) const {
Maybe<Tuple<>> operator()(Input& input) const {
if (input.atEnd()) {
return Void();
return Tuple<>();
} else {
return nullptr;
}
......
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "tuple.h"
#include "memory.h"
#include "string.h"
#include <gtest/gtest.h>
namespace kj {
struct Foo { uint foo; Foo(uint i): foo(i) {} };
struct Bar { uint bar; Bar(uint i): bar(i) {} };
struct Baz { uint baz; Baz(uint i): baz(i) {} };
struct Qux { uint qux; Qux(uint i): qux(i) {} };
struct Quux { uint quux; Quux(uint i): quux(i) {} };
TEST(Tuple, Tuple) {
Tuple<Foo, Bar> t = tuple(Foo(123), Bar(456));
EXPECT_EQ(123, get<0>(t).foo);
EXPECT_EQ(456, get<1>(t).bar);
Tuple<Foo, Bar, Baz, Qux, Quux> t2 = tuple(t, Baz(789), tuple(Qux(321), Quux(654)));
EXPECT_EQ(123, get<0>(t2).foo);
EXPECT_EQ(456, get<1>(t2).bar);
EXPECT_EQ(789, get<2>(t2).baz);
EXPECT_EQ(321, get<3>(t2).qux);
EXPECT_EQ(654, get<4>(t2).quux);
Tuple<Own<Foo>, Own<Bar>> t3 = tuple(heap<Foo>(123), heap<Bar>(456));
EXPECT_EQ(123, get<0>(t3)->foo);
EXPECT_EQ(456, get<1>(t3)->bar);
Tuple<Own<Foo>, Own<Bar>, Own<Baz>, Own<Qux>, Own<Quux>> t4 =
tuple(mv(t3), heap<Baz>(789), tuple(heap<Qux>(321), heap<Quux>(654)));
EXPECT_EQ(123, get<0>(t4)->foo);
EXPECT_EQ(456, get<1>(t4)->bar);
EXPECT_EQ(789, get<2>(t4)->baz);
EXPECT_EQ(321, get<3>(t4)->qux);
EXPECT_EQ(654, get<4>(t4)->quux);
Tuple<String, StringPtr> t5 = tuple(heapString("foo"), "bar");
EXPECT_EQ("foo", get<0>(t5));
EXPECT_EQ("bar", get<1>(t5));
Tuple<StringPtr, StringPtr, StringPtr, StringPtr, String> t6 =
tuple(Tuple<StringPtr, StringPtr>(t5), "baz", tuple("qux", heapString("quux")));
EXPECT_EQ("foo", get<0>(t6));
EXPECT_EQ("bar", get<1>(t6));
EXPECT_EQ("baz", get<2>(t6));
EXPECT_EQ("qux", get<3>(t6));
EXPECT_EQ("quux", get<4>(t6));
kj::apply([](Foo a, Bar b, Own<Foo> c, Own<Bar> d, uint e, StringPtr f, StringPtr g) {
EXPECT_EQ(123, a.foo);
EXPECT_EQ(456, b.bar);
EXPECT_EQ(123, c->foo);
EXPECT_EQ(456, d->bar);
EXPECT_EQ(789, e);
EXPECT_EQ("foo", f);
EXPECT_EQ("bar", g);
}, t, tuple(heap<Foo>(123), heap<Bar>(456)), 789, mv(t5));
uint i = tuple(123);
EXPECT_EQ(123, i);
i = tuple(tuple(), 456, tuple(tuple(), tuple()));
EXPECT_EQ(456, i);
}
} // namespace kj
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// 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_
#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;
inline TupleElement(const T& value): value(value) {}
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>
inline TupleImpl(Tuple<U...>&& other)
: TupleElement<indexes, Types>(kj::mv(getImpl<indexes>(other)))... {}
template <typename... U>
inline TupleImpl(Tuple<U...>& other)
: TupleElement<indexes, Types>(getImpl<indexes>(other))... {}
template <typename... U>
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:
Tuple() = default;
template <typename... U>
Tuple(Tuple<U...>&& other): impl(kj::mv(other)) {}
template <typename... U>
Tuple(Tuple<U...>& other): impl(other) {}
template <typename... U>
Tuple(const Tuple<U...>& other): impl(other) {}
private:
template <typename... Params>
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 <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 <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, size_t... indexes>
inline auto expandAndApplyWithIndexes(
Indexes<indexes...>, Func&& func, Tuple<FirstTypes...>&& first, Rest&&... rest)
-> ExpandAndApplyResult<Func, FirstTypes&&..., 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...>;
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)...);
}
} // namespace kj
#endif // KJ_TUPLE_H_
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef KJ_VECTOR_H_
#define KJ_VECTOR_H_
#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.
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(); }
template <typename... Params>
inline void add(Params&&... params) {
if (builder.isFull()) grow();
builder.add(kj::fwd<Params>(params)...);
}
private:
ArrayBuilder<T> builder;
void grow() {
size_t newSize = capacity() == 0 ? 4 : capacity() * 2;
ArrayBuilder<T> newBuilder = heapArrayBuilder<T>(newSize);
for (T& element: builder) {
newBuilder.add(kj::mv(element));
}
builder = kj::mv(newBuilder);
}
};
} // namespace kj
#endif // KJ_VECTOR_H_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment