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 = \ ...@@ -68,10 +68,13 @@ includekj_HEADERS = \
src/kj/units.h \ src/kj/units.h \
src/kj/memory.h \ src/kj/memory.h \
src/kj/array.h \ src/kj/array.h \
src/kj/vector.h \
src/kj/string.h \ src/kj/string.h \
src/kj/exception.h \ src/kj/exception.h \
src/kj/debug.h \ src/kj/debug.h \
src/kj/io.h src/kj/io.h \
src/kj/tuple.h \
src/kj/parse.h
includecapnp_HEADERS = \ includecapnp_HEADERS = \
src/capnp/common.h \ src/capnp/common.h \
...@@ -157,6 +160,7 @@ capnproto_test_SOURCES = \ ...@@ -157,6 +160,7 @@ capnproto_test_SOURCES = \
src/kj/exception-test.c++ \ src/kj/exception-test.c++ \
src/kj/debug-test.c++ \ src/kj/debug-test.c++ \
src/kj/units-test.c++ \ src/kj/units-test.c++ \
src/kj/tuple-test.c++ \
src/kj/parse-test.c++ \ src/kj/parse-test.c++ \
src/capnp/blob-test.c++ \ src/capnp/blob-test.c++ \
src/capnp/endian-test.c++ \ src/capnp/endian-test.c++ \
......
...@@ -180,6 +180,9 @@ template <typename T> struct Decay_ { typedef T Type; }; ...@@ -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_<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_<const T> { typedef typename Decay_<T>::Type Type; };
template <typename T> struct Decay_<volatile 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; template <typename T> using Decay = typename Decay_<T>::Type;
......
...@@ -29,22 +29,6 @@ namespace kj { ...@@ -29,22 +29,6 @@ namespace kj {
namespace parse { namespace parse {
namespace { 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; typedef IteratorInput<char, const char*> Input;
ExactElementParser<Input> exactChar(char c) { ExactElementParser<Input> exactChar(char c) {
return exactElement<Input>(mv(c)); return exactElement<Input>(mv(c));
...@@ -56,7 +40,7 @@ TEST(Parsers, ExactElementParser) { ...@@ -56,7 +40,7 @@ TEST(Parsers, ExactElementParser) {
StringPtr text = "foo"; StringPtr text = "foo";
Input input(text.begin(), text.end()); Input input(text.begin(), text.end());
Maybe<Void> result = exactChar('f')(input); Maybe<Tuple<>> result = exactChar('f')(input);
EXPECT_TRUE(result != nullptr); EXPECT_TRUE(result != nullptr);
EXPECT_FALSE(input.atEnd()); EXPECT_FALSE(input.atEnd());
...@@ -68,7 +52,7 @@ TEST(Parsers, ExactElementParser) { ...@@ -68,7 +52,7 @@ TEST(Parsers, ExactElementParser) {
EXPECT_TRUE(result == nullptr); EXPECT_TRUE(result == nullptr);
EXPECT_FALSE(input.atEnd()); EXPECT_FALSE(input.atEnd());
Parser<Input, Void> wrapped = exactChar('o'); Parser<Input, Tuple<>> wrapped = exactChar('o');
result = wrapped(input); result = wrapped(input);
EXPECT_TRUE(result != nullptr); EXPECT_TRUE(result != nullptr);
EXPECT_TRUE(input.atEnd()); EXPECT_TRUE(input.atEnd());
...@@ -79,35 +63,37 @@ TEST(Parsers, SequenceParser) { ...@@ -79,35 +63,37 @@ TEST(Parsers, SequenceParser) {
{ {
Input input(text.begin(), text.end()); 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(result != nullptr);
EXPECT_TRUE(input.atEnd()); EXPECT_TRUE(input.atEnd());
} }
{ {
Input input(text.begin(), text.end()); 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_TRUE(result != nullptr);
EXPECT_FALSE(input.atEnd()); EXPECT_FALSE(input.atEnd());
} }
{ {
Input input(text.begin(), text.end()); 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_TRUE(result == nullptr);
EXPECT_FALSE(input.atEnd()); EXPECT_FALSE(input.atEnd());
} }
{ {
Input input(text.begin(), text.end()); 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(result != nullptr);
EXPECT_TRUE(input.atEnd()); EXPECT_TRUE(input.atEnd());
} }
{ {
Input input(text.begin(), text.end()); 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(result != nullptr);
EXPECT_TRUE(input.atEnd()); EXPECT_TRUE(input.atEnd());
} }
...@@ -193,7 +179,7 @@ TEST(Parsers, RepeatedParser) { ...@@ -193,7 +179,7 @@ TEST(Parsers, RepeatedParser) {
auto parser = transform( auto parser = transform(
sequence(exactChar('f'), repeated(exactChar('o'))), 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); Input input(text.begin(), text.begin() + 3);
......
...@@ -27,175 +27,12 @@ ...@@ -27,175 +27,12 @@
#include "common.h" #include "common.h"
#include "memory.h" #include "memory.h"
#include "array.h" #include "array.h"
#include "tuple.h"
#include "vector.h"
namespace kj { namespace kj {
namespace parse { 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> template <typename Element, typename Iterator>
class IteratorInput { class IteratorInput {
public: public:
...@@ -244,7 +81,6 @@ private: ...@@ -244,7 +81,6 @@ private:
IteratorInput& operator=(IteratorInput&&) = delete; IteratorInput& operator=(IteratorInput&&) = delete;
}; };
template <typename T> template <typename T>
struct ExtractParseFuncType; struct ExtractParseFuncType;
...@@ -393,19 +229,19 @@ struct WrapperParserConstructor { ...@@ -393,19 +229,19 @@ struct WrapperParserConstructor {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// ExactElementParser // ExactElementParser
// Output = Void // Output = Tuple<>
template <typename Input> template <typename Input>
class ExactElementParser { class ExactElementParser {
public: public:
explicit ExactElementParser(typename Input::ElementType&& expected): expected(expected) {} 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) { if (input.atEnd() || input.current() != expected) {
return nullptr; return nullptr;
} else { } else {
input.next(); input.next();
return Void(); return Tuple<>();
} }
} }
...@@ -460,7 +296,7 @@ private: ...@@ -460,7 +296,7 @@ private:
template <typename Input> template <typename Input>
class SequenceParser<Input> { class SequenceParser<Input> {
public: public:
Maybe<Void> operator()(Input& input) const { Maybe<Tuple<>> operator()(Input& input) const {
return parseNext(input); return parseNext(input);
} }
...@@ -487,56 +323,6 @@ sequence(FirstSubParser&& first, MoreSubParsers&&... rest) { ...@@ -487,56 +323,6 @@ sequence(FirstSubParser&& first, MoreSubParsers&&... rest) {
// RepeatedParser // RepeatedParser
// Output = Array of output of sub-parser. // 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> template <typename SubParser, bool atLeastOne>
class RepeatedParser { class RepeatedParser {
public: public:
...@@ -705,14 +491,14 @@ public: ...@@ -705,14 +491,14 @@ public:
typedef typename ExtractParserType<SubParser>::InputType InputType; typedef typename ExtractParserType<SubParser>::InputType InputType;
typedef Decay<decltype(instance<InputType>().getPosition())> Position; typedef Decay<decltype(instance<InputType>().getPosition())> Position;
typedef typename ExtractParserType<SubParser>::OutputType SubOutput; typedef typename ExtractParserType<SubParser>::OutputType SubOutput;
typedef decltype(applyTuple(instance<Transform&>(), instance<SubOutput&&>(), typedef decltype(kj::apply(instance<Transform&>(), instance<Span<Position>>(),
instance<Span<Position>>())) Output; instance<SubOutput&&>())) Output;
Maybe<Output> operator()(InputType& input) const { Maybe<Output> operator()(InputType& input) const {
auto start = input.getPosition(); auto start = input.getPosition();
KJ_IF_MAYBE(subResult, subParser(input)) { KJ_IF_MAYBE(subResult, subParser(input)) {
return applyTuple(transform, kj::mv(*subResult), return kj::apply(transform, Span<Position>(kj::mv(start), input.getPosition()),
Span<Position>(kj::mv(start), input.getPosition())); kj::mv(*subResult));
} else { } else {
return nullptr; return nullptr;
} }
...@@ -763,14 +549,14 @@ acceptIf(SubParser&& subParser, Condition&& condition) { ...@@ -763,14 +549,14 @@ acceptIf(SubParser&& subParser, Condition&& condition) {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// EndOfInputParser // EndOfInputParser
// Output = Void, only succeeds if at end-of-input // Output = Tuple<>, only succeeds if at end-of-input
template <typename Input> template <typename Input>
class EndOfInputParser { class EndOfInputParser {
public: public:
Maybe<Void> operator()(Input& input) const { Maybe<Tuple<>> operator()(Input& input) const {
if (input.atEnd()) { if (input.atEnd()) {
return Void(); return Tuple<>();
} else { } else {
return nullptr; 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