-
Notifications
You must be signed in to change notification settings - Fork 4
Feature/extended test suite #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
38cd3f1
9aaa042
764e2b7
2b6605c
31dc011
20448fc
556fe00
eef51c5
e916814
410b674
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,7 +4,7 @@ | |
| !*.view/ | ||
| *.user | ||
| *.user.* | ||
| thirtparty/*/ | ||
| thirdparty/*/ | ||
| .vagrant/ | ||
| .vscode/ | ||
| .vs/ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| #include "Partial.h" | ||
|
|
||
| #include "Partial.make.h" | ||
| #include "Partial.trait.h" | ||
|
|
||
| #include <meta17/Const.ops.h> | ||
| #include <meta17/Type.ops.h> | ||
|
|
||
| #include <gtest/gtest.h> | ||
|
|
||
| using namespace partial17; | ||
|
|
||
| using meta17::type; | ||
|
|
||
| TEST(Partial, make) { | ||
| using PM = MakePartial<TypePack<char, int, float>>; | ||
| using PC = Partial<char, int, float>; | ||
|
|
||
| static_assert(type<PM> == type<PC>); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| #pragma once | ||
| #include "Partial.h" | ||
| #include <iostream> | ||
| namespace partial17 { | ||
|
|
||
| template<class... Ts> | ||
| bool constexpr operator==(const Partial<Ts...>& a, const Partial<Ts...>& b) { | ||
| if (a.bitset() != b.bitset()) return false; | ||
|
|
||
| bool equal = true; | ||
| a.visitAll([&](auto i, auto) { equal &= (!a.has(i) || a.get(i) == b.get(i)); }); | ||
| return equal; | ||
| } | ||
|
|
||
| template<class... Ts> | ||
| bool constexpr operator!=(const Partial<Ts...>& a, const Partial<Ts...>& b) { | ||
| return !(a == b); | ||
| } | ||
|
|
||
| } // namespace partial17 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| #include "Partial.ops.h" | ||
|
|
||
| #include <gtest/gtest.h> | ||
|
|
||
| using namespace partial17; | ||
|
|
||
| TEST(Partial, ops) { | ||
| // using P1 = Partial<char, int, float, bool>; | ||
| // using P2 = Partial<bool, float, int, char>; | ||
|
|
||
| // auto p1 = P1{'c', 2.3f}; | ||
| // auto p2 = P2{'c', 2.3f}; | ||
| // EXPECT_EQ(p1, p2); | ||
|
|
||
| using P = Partial<char, int, float, bool>; | ||
| const P p1{3.2f}; | ||
| const P p2{3.2f}; | ||
| EXPECT_EQ(p1, p2); | ||
|
|
||
| const P p3{3.1f}; | ||
| const P p4{3.3f}; | ||
| EXPECT_NE(p3, p4); | ||
|
|
||
| const P p5{99}; | ||
| const P p6{'c'}; | ||
| EXPECT_NE(p5, p6); | ||
|
|
||
| const P p7{'c', 3.2f}; | ||
| const P p8{3.2f}; | ||
| EXPECT_NE(p7, p8); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| #pragma once | ||
| #include "Partial.h" | ||
|
|
||
| #include <ostream> | ||
|
|
||
| namespace partial17 { | ||
|
|
||
| template<class Chr, class Traits, class... Ts> | ||
| auto operator<<(std::basic_ostream<Chr, Traits>& out, const Partial<Ts...>& t) -> decltype(out)& { | ||
| out << "<["; | ||
| bool first = true; | ||
| t.visitInitialized([&](auto& v) { | ||
| if (first) | ||
| first = false; | ||
| else | ||
| out << "; "; | ||
| out << v; | ||
| }); | ||
| return out << "]>"; | ||
| } | ||
|
|
||
| } // namespace partial17 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| #include "Partial.ostream.h" | ||
|
|
||
| #include <gtest/gtest.h> | ||
| #include <sstream> | ||
|
|
||
| using namespace partial17; | ||
|
|
||
| TEST(Partial, ostream) { | ||
| using P = Partial<int, double, char, short, bool>; | ||
| const P p1{1, 'c', true}, p2{2.4, static_cast<short>(2)}; // see #workaround 1 | ||
| std::stringstream actual, expected; | ||
| actual << p1 << " " << p2; | ||
| expected << "<[1; c; 1]> <[2.4; 2]>"; | ||
| EXPECT_EQ(actual.str(), expected.str()); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| #include "Partial.h" | ||
|
|
||
| #include "Partial.make.h" | ||
| #include "Partial.ops.h" | ||
| #include "Partial.trait.h" | ||
|
|
||
| #include <meta17/Const.ops.h> // index == index | ||
|
|
@@ -11,16 +12,48 @@ using namespace partial17; | |
|
|
||
| using meta17::type; | ||
|
|
||
| TEST(Partial, basic) { | ||
| auto x = Partial<char, int, float>{}; // | ||
| auto y = x; // copy constructor | ||
| x = y; // copy operator | ||
| x = std::move(y); // move operator | ||
| auto z = Partial<char, int, float>{std::move(x)}; // move construct | ||
| TEST(Partial, construction) { | ||
| using P = Partial<char, int, float>; | ||
| auto p0 = P{}; | ||
| ASSERT_FALSE(p0.has<0>()); | ||
| ASSERT_FALSE(p0.has<1>()); | ||
| ASSERT_FALSE(p0.has<2>()); | ||
| // TODO CK: Should this be possible? - crashes, would suggest a graceful value for production | ||
| // EXPECT_EQ(p0.get<0>(), '\0'); | ||
| // EXPECT_EQ(p0.get<1>(), 0); | ||
| // EXPECT_EQ(p0.get<2>(), 0); | ||
|
|
||
| auto p1 = P{'c', 2.3f}; | ||
| auto p2 = p1; // copy constructor | ||
| auto p3 = P{std::move(p2)}; // move construct | ||
|
|
||
| EXPECT_EQ(p1.get<0>(), 'c'); | ||
| EXPECT_EQ(p1.get<2>(), 2.3f); | ||
| EXPECT_EQ(p1.countInitialized(), 2ul); | ||
| EXPECT_EQ(p1.countAll(), 3ul); | ||
| // TODO CK: Consider alignment - does this need to consider the size of the bitset | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, you are correct in your observation. It's best compared to |
||
| EXPECT_EQ(p1.size(), sizeof(int) + sizeof(float)); | ||
| EXPECT_EQ(p3.countInitialized(), 2ul); | ||
| EXPECT_EQ(p3.countAll(), 3ul); | ||
| EXPECT_EQ(p1.size(), sizeof(int) + sizeof(float)); | ||
| EXPECT_EQ(p1, p3); | ||
| } | ||
|
|
||
| TEST(Partial, assignment) { | ||
| using P = Partial<char, int, float>; | ||
| auto p0 = P{'c', 2.3f}; | ||
| auto p1 = P{}; | ||
| p1 = p0; // copy operator | ||
| auto p2 = P{}; | ||
| p2 = std::move(p1); // move operator | ||
|
|
||
| EXPECT_EQ(p0.get<0>(), 'c'); | ||
| EXPECT_EQ(p0.get<2>(), 2.3f); | ||
| EXPECT_EQ(p0, p2); | ||
| } | ||
|
|
||
| TEST(Partial, fromFactory) { | ||
| const auto created = Partial<char, int, float>::fromFactory( | ||
| const auto p = Partial<char, int, float>::fromFactory( | ||
| [](size_t i) { return (0 == i % 2); }, | ||
| [](auto i) { | ||
| if constexpr (i == index<0>) { | ||
|
|
@@ -33,36 +66,96 @@ TEST(Partial, fromFactory) { | |
| return 3.14f; | ||
| } | ||
| }); | ||
| ASSERT_TRUE(created.has<0>()); | ||
| ASSERT_FALSE(created.has<1>()); | ||
| ASSERT_TRUE(created.has<2>()); | ||
| ASSERT_TRUE(p.has<0>()); | ||
| ASSERT_FALSE(p.has<1>()); | ||
| ASSERT_TRUE(p.has<2>()); | ||
|
|
||
| EXPECT_EQ(created.get<0>(), 'a'); | ||
| EXPECT_EQ(created.get<2>(), 3.14f); | ||
| EXPECT_EQ(p.get<0>(), 'a'); | ||
| EXPECT_EQ(p.get<2>(), 3.14f); | ||
| } | ||
|
|
||
| auto copy = created; | ||
| ASSERT_TRUE(copy.has<0>()); | ||
| ASSERT_FALSE(copy.has<1>()); | ||
| ASSERT_TRUE(copy.has<2>()); | ||
| TEST(Partial, type) { | ||
| auto p = Partial<char, int, float>{'\x23', 23}; | ||
| ASSERT_TRUE(p.has(type<char>)); | ||
| ASSERT_TRUE(p.has(0)); | ||
| EXPECT_EQ(0x23, p.get(type<char>)); | ||
| EXPECT_EQ(0x23, p.get(index<0>)); | ||
| ASSERT_TRUE(p.has(type<int>)); | ||
| ASSERT_TRUE(p.has(1)); | ||
| ASSERT_EQ(23, p.get(type<int>)); | ||
| EXPECT_EQ(23, p.get(index<1>)); | ||
|
|
||
| EXPECT_EQ(copy.get<0>(), 'a'); | ||
| EXPECT_EQ(copy.get<2>(), 3.14f); | ||
| // TODO CK: Does prevent valid compilation? Microsoft Visual C++ BUG? | ||
| // auto m = Partial<int, int>{23, 32}; | ||
| // not allowed due to used TypePack | ||
| // ASSERT_TRUE(m.has(type<int>)); | ||
| // ASSERT_EQ(23, m.get(type<int>)); | ||
| } | ||
|
|
||
| TEST(Partial, fromArgs) { | ||
| const auto created = Partial<char, int, float>(3.14f, 'a'); // | ||
| ASSERT_TRUE(created.has<0>()); | ||
| ASSERT_FALSE(created.has<1>()); | ||
| ASSERT_TRUE(created.has<2>()); | ||
| TEST(Partial, merge) { | ||
| // Disjunct merge | ||
| using P = Partial<char, int, float>; | ||
| auto p0 = P{'\x23'}; | ||
| auto p1 = P{2.3f}; | ||
| auto p2 = p0.merge(p1); | ||
| ASSERT_TRUE(p2.has<0>()); | ||
| ASSERT_FALSE(p2.has<1>()); | ||
| ASSERT_TRUE(p2.has<2>()); | ||
|
|
||
| EXPECT_EQ(p2.get<0>(), '\x23'); | ||
| EXPECT_EQ(p2.get<2>(), 2.3f); | ||
|
|
||
| // Overwrite merge | ||
| auto p3 = P{2}; | ||
| auto p4 = P{4}; | ||
| auto p5 = p3.merge(p4); | ||
| ASSERT_FALSE(p5.has<0>()); | ||
| ASSERT_TRUE(p5.has<1>()); | ||
| ASSERT_FALSE(p5.has<2>()); | ||
|
|
||
| EXPECT_EQ(created.get<0>(), 'a'); | ||
| EXPECT_EQ(created.get<2>(), 3.14f); | ||
| EXPECT_EQ(p5.get<1>(), 4); | ||
|
|
||
| auto p6 = p4.merge(p3); | ||
| ASSERT_FALSE(p6.has<0>()); | ||
| ASSERT_TRUE(p6.has<1>()); | ||
| ASSERT_FALSE(p6.has<2>()); | ||
|
|
||
| EXPECT_EQ(p6.get<1>(), 2); | ||
| } | ||
|
|
||
| TEST(Partial, byType) { | ||
| TEST(Partial, visitAll) { | ||
| using P = Partial<char, int, float>; | ||
| auto p = P{'\x23'}; | ||
|
|
||
| ASSERT_EQ(p.countInitialized(), 1ul); | ||
| ASSERT_EQ(p.countAll(), 3ul); | ||
|
|
||
| size_t count = 0; | ||
| p.visitAll([&](auto i, auto t) { | ||
| ++count; | ||
| if (i == 0) { | ||
| EXPECT_TRUE(p.has(i)); | ||
| EXPECT_EQ(t, type<char>); | ||
| } | ||
| else { | ||
| EXPECT_FALSE(p.has(i)); | ||
| EXPECT_NE(t, type<char>); | ||
| } | ||
| }); | ||
| EXPECT_EQ(count, p.countAll()); | ||
| } | ||
|
|
||
| TEST(Partial, visitInitialized) { | ||
| using P = Partial<char, int, float>; | ||
| auto p = P{'\x23', 2.3f}; | ||
|
|
||
| ASSERT_EQ(p.countInitialized(), 2ul); | ||
| ASSERT_EQ(p.countAll(), 3ul); | ||
|
|
||
| auto x = Partial<char, int, float>{'\x23'}; // | ||
| if (x.has(type<char>)) { | ||
| ASSERT_EQ(35, x.get(type<char>)); | ||
| } | ||
| size_t count = 0; | ||
| p.visitInitialized([&](auto v) { | ||
| ++count; | ||
| EXPECT_TRUE(type<decltype(v)> == type<char> || type<decltype(v)> == type<float>); | ||
| }); | ||
| EXPECT_EQ(count, p.countInitialized()); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is by intention.
get<N>is like acast. You have to know that the type is there, otherwise ghosts will hunt you at night. If we throw exceptions here, the resulting program would suffer a huge performance hit.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there no way to prevent an memory access crash when trying to read uninitialized memory? Since there is the
m_bitsetto check, maybe we can return a reference to some static default for production mode while crashing with an assertion in debug mode?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Checking every time kills the optimizer.
The solution would be to rename
getintocastorasand add agetthat is checked. Likeoperator[]andaton astd::vector. That way we have options at the usage side.