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
This diff is collapsed.
// 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