diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 91346af..a3d5aa9 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -5,11 +5,13 @@ jobs: steps: - checkout: self submodules: true - - script: - docker run -v${PWD}:/build - arbmind/qbs-clang7:1 - build --file /build/BasiC++17.qbs --build-directory /tmp/build - -p autotest-runner + - task: ShellScript@2 + inputs: + scriptPath: thirdparty/git_clone_googletest.sh + - script: docker run -v${PWD}:/build + arbmind/qbs-clang7:1 + build --file /build/BasiC++17.qbs --build-directory /tmp/build + -p autotest-runner - job: Windows pool: @@ -21,6 +23,9 @@ jobs: - script: qbs config --list profiles - checkout: self submodules: true + - task: ShellScript@2 + inputs: + scriptPath: thirdparty/git_clone_googletest.sh - script: qbs - build profile:MSVC2019-x64 --file BasiC++17.qbs --build-directory %TMP%\build - -p autotest-runner + build profile:MSVC2019-x64 --file BasiC++17.qbs --build-directory %TMP%\build + -p autotest-runner diff --git a/src/meta17.lib/meta17/IndexPack.extract.h b/src/meta17.lib/meta17/IndexPack.extract.h index 04063d8..e4210c2 100644 --- a/src/meta17.lib/meta17/IndexPack.extract.h +++ b/src/meta17.lib/meta17/IndexPack.extract.h @@ -13,8 +13,8 @@ constexpr auto extract_index_pack = META17_STATIC_ERROR_EXPR(T, "no index_pack t template class Template, size_t... Is> constexpr auto extract_index_pack> = index_pack; -template class Template, size_t... Is> -constexpr auto extract_index_pack> = index_pack; +template class Template, class T, T... Is> +constexpr auto extract_index_pack> = index_pack; template using ExtractIndexPack = decltype(extract_index_pack); diff --git a/src/meta17.lib/meta17/IndexPack.iterate.h b/src/meta17.lib/meta17/IndexPack.iterate.h new file mode 100644 index 0000000..b1a14ff --- /dev/null +++ b/src/meta17.lib/meta17/IndexPack.iterate.h @@ -0,0 +1,13 @@ +#pragma once +#include "Index.h" +#include "IndexPack.h" + +namespace meta17 { + +/// "constexpr for": Iterate over a sequence with compile-time available indices +template +constexpr auto forEachIndex(IndexPack, Callable&& callable) { + return (..., callable(_index)); +} + +} // namespace meta17 diff --git a/src/meta17.lib/meta17/IndexPack.iterate.test.cpp b/src/meta17.lib/meta17/IndexPack.iterate.test.cpp new file mode 100644 index 0000000..7f18a63 --- /dev/null +++ b/src/meta17.lib/meta17/IndexPack.iterate.test.cpp @@ -0,0 +1,11 @@ +#include "IndexPack.iterate.h" + +#include "Index.wrap.h" // UnwrapType +#include + +using namespace meta17; + +static_assert(forEachIndex(index_pack<12, 23>, [s = 0](auto i) mutable { + s += to_value; + return s; + }) == 35); diff --git a/src/meta17.lib/meta17/TemplateOfTypes.indexOf.h b/src/meta17.lib/meta17/TemplateOfTypes.indexOf.h index 4e379ab..61b1985 100644 --- a/src/meta17.lib/meta17/TemplateOfTypes.indexOf.h +++ b/src/meta17.lib/meta17/TemplateOfTypes.indexOf.h @@ -44,7 +44,7 @@ constexpr auto indexed_type_template_index_of = META17_STATIC_ERROR_EXPR(size_t, template class Template, class... Ts, size_t... Is> constexpr auto indexed_type_template_index_of, IndexPack> = // 1 == countOf() ? (((type == type) ? Is : 0) + ...) - : META17_STATIC_ERROR_EXPR(size_t, "type not found"); + : META17_STATIC_ASSERT_EXPR(size_t, (1 == countOf()), "type not found"); template constexpr auto type_template_index_of = indexed_type_template_index_of>; diff --git a/src/meta17.lib/meta17/TemplateOfTypes.indexOf.test.cpp b/src/meta17.lib/meta17/TemplateOfTypes.indexOf.test.cpp index d0c17be..496e5a7 100644 --- a/src/meta17.lib/meta17/TemplateOfTypes.indexOf.test.cpp +++ b/src/meta17.lib/meta17/TemplateOfTypes.indexOf.test.cpp @@ -12,3 +12,4 @@ static_assert(type_template_overflow_index_of static_assert(type_template_overflow_index_of> == 2); static_assert(type_template_index_of> == 2); +// static_assert(type_template_index_of> == 0); diff --git a/src/meta17.lib/meta17/meta17.qbs b/src/meta17.lib/meta17/meta17.qbs index 52b8909..c9d8221 100644 --- a/src/meta17.lib/meta17/meta17.qbs +++ b/src/meta17.lib/meta17/meta17.qbs @@ -1,6 +1,8 @@ import qbs Product { + Depends { name: "cpp17" } + Group { name: "Bool" files: [ @@ -48,6 +50,7 @@ Product { "IndexPack.extract.h", "IndexPack.for.h", "IndexPack.h", + "IndexPack.iterate.h", "IndexPack.make.h", "IndexPack.ops.h", "IndexPack.trait.h", @@ -150,6 +153,7 @@ Product { "Unreachable.h", "align.h", "same.h", + "ptr.h", ] Export { diff --git a/src/meta17.lib/meta17/meta17.tests.qbs b/src/meta17.lib/meta17/meta17.tests.qbs index 3b198f8..c0da832 100644 --- a/src/meta17.lib/meta17/meta17.tests.qbs +++ b/src/meta17.lib/meta17/meta17.tests.qbs @@ -53,6 +53,7 @@ Application { files: [ "IndexPack.extract.test.cpp", "IndexPack.for.test.cpp", + "IndexPack.iterate.test.cpp", "IndexPack.make.test.cpp", "IndexPack.ops.test.cpp", "IndexPack.test.cpp", @@ -150,5 +151,6 @@ Application { "StaticErrorExpr.test.cpp", "align.test.cpp", "main.cpp", + "ptr.test.cpp", ] } diff --git a/src/meta17.lib/meta17/ptr.h b/src/meta17.lib/meta17/ptr.h new file mode 100644 index 0000000..fd42184 --- /dev/null +++ b/src/meta17.lib/meta17/ptr.h @@ -0,0 +1,8 @@ +#pragma once + +namespace meta17 { + +template +constexpr T* nullptr_to = nullptr; + +} diff --git a/src/meta17.lib/meta17/ptr.test.cpp b/src/meta17.lib/meta17/ptr.test.cpp new file mode 100644 index 0000000..0a6dfb8 --- /dev/null +++ b/src/meta17.lib/meta17/ptr.test.cpp @@ -0,0 +1,7 @@ +#include "ptr.h" +#include "same.h" + +using namespace meta17; + +static_assert(same), int* const>); +static_assert(nullptr_to == nullptr); diff --git a/src/string17.lib/string17/StringView.ostream.h b/src/string17.lib/string17/StringView.ostream.h index a2aeb46..fba6a98 100644 --- a/src/string17.lib/string17/StringView.ostream.h +++ b/src/string17.lib/string17/StringView.ostream.h @@ -5,7 +5,7 @@ namespace string17 { -auto operator<<(std::ostream& out, StringView v) -> std::ostream& { +inline auto operator<<(std::ostream& out, StringView v) -> std::ostream& { return out.write(v.begin, v.size()); // } diff --git a/src/strong17.lib/strong17/Strong.opaque.h b/src/strong17.lib/strong17/Strong.opaque.h index 5156e44..e80f7de 100644 --- a/src/strong17.lib/strong17/Strong.opaque.h +++ b/src/strong17.lib/strong17/Strong.opaque.h @@ -4,8 +4,6 @@ #include "Strong.make.h" #include "meta17/Type.h" -#include "meta17/TypePack.h" -#include "meta17/TypePack.recurse.h" #define STRONG_OPAQUE(NAME, TYPE, ...) \ struct NAME; \ diff --git a/src/strong17.lib/strong17/Strong.opaque.test.cpp b/src/strong17.lib/strong17/Strong.opaque.test.cpp new file mode 100644 index 0000000..a45549e --- /dev/null +++ b/src/strong17.lib/strong17/Strong.opaque.test.cpp @@ -0,0 +1,19 @@ +#include "Strong.opaque.h" + +#include + +namespace testing { + +STRONG_OPAQUE(HelloTest, int, struct HelloTag); + +} // namespace testing + +STRONG_OPAQUE(HelloGlobal, int, struct HelloTag); + +TEST(Strong, opaque) { + constexpr auto ht = testing::HelloTest{15}; + static_assert(ht.v == 15); + + constexpr auto hg = HelloGlobal{23}; + static_assert(hg.v == 23); +} diff --git a/src/strong17.lib/strong17/Strong.trait.h b/src/strong17.lib/strong17/Strong.trait.h index 26bfe1a..e297591 100644 --- a/src/strong17.lib/strong17/Strong.trait.h +++ b/src/strong17.lib/strong17/Strong.trait.h @@ -12,14 +12,11 @@ using meta17::False; using meta17::is_type_template; using meta17::same; -template -struct IsStrong : False {}; - -template -struct IsStrong>> : Bool, Strong>> {}; +template +constexpr auto is_strong = false; template -constexpr auto is_strong = IsStrong>{}; +constexpr auto is_strong>> = is_type_template, Strong>; template struct IsOpaque : False {}; diff --git a/src/strong17.lib/strong17/Strong.weaken.h b/src/strong17.lib/strong17/Strong.weaken.h index 2e64f45..64f44c7 100644 --- a/src/strong17.lib/strong17/Strong.weaken.h +++ b/src/strong17.lib/strong17/Strong.weaken.h @@ -18,11 +18,11 @@ using meta17::UnwrapType; /// like extractValue, but does nothing for non-strong types template -constexpr auto weakenType(Type = {}) -> std::enable_if_t.v, Type>>> { +constexpr auto weakenType(Type = {}) -> std::enable_if_t, Type>>> { return {}; } template -constexpr auto weakenType(Type = {}) -> std::enable_if_t.v, Type> { +constexpr auto weakenType(Type = {}) -> std::enable_if_t, Type> { return {}; } template diff --git a/src/strong17.lib/strong17/strong17.tests.qbs b/src/strong17.lib/strong17/strong17.tests.qbs index 181c003..688cd11 100644 --- a/src/strong17.lib/strong17/strong17.tests.qbs +++ b/src/strong17.lib/strong17/strong17.tests.qbs @@ -16,6 +16,7 @@ Application { "Strong.inspect.test.cpp", "Strong.make.test.cpp", "Strong.manip.test.cpp", + "Strong.opaque.test.cpp", "Strong.ops.test.cpp", "Strong.ostream.cpp", "Strong.test.cpp", diff --git a/src/tuple17.lib/tuple17/Tuple.h b/src/tuple17.lib/tuple17/Tuple.h index f1690f8..c23b2a3 100644 --- a/src/tuple17.lib/tuple17/Tuple.h +++ b/src/tuple17.lib/tuple17/Tuple.h @@ -250,12 +250,12 @@ struct Tuple { template constexpr void visitIndexTypes(IndexPack, F&& f) { - (f(_const, type_at), ...); + (f(_const, type), ...); } template constexpr void visitIndexTypes(IndexPack, F&& f) const { - (f(_const, type_at), ...); + (f(_const, type), ...); } template diff --git a/src/tuple17.lib/tuple17/tuple17.qbs b/src/tuple17.lib/tuple17/tuple17.qbs index ae0c931..b2f1240 100644 --- a/src/tuple17.lib/tuple17/tuple17.qbs +++ b/src/tuple17.lib/tuple17/tuple17.qbs @@ -1,6 +1,9 @@ import qbs Product { + Depends { name: "cpp" } + Depends { name: "meta17" } + files: [ "Tuple.h", "Tuple.make.h", diff --git a/src/variant17.lib/variant17/Variant.h b/src/variant17.lib/variant17/Variant.h index db2db36..db26bcd 100644 --- a/src/variant17.lib/variant17/Variant.h +++ b/src/variant17.lib/variant17/Variant.h @@ -29,6 +29,7 @@ using meta17::indexPackFor; using meta17::to_type_pack; using meta17::type; using meta17::Type; +using meta17::type_head; using meta17::type_pack; using meta17::TypeHead; using meta17::TypePack; @@ -59,40 +60,98 @@ auto selectType() { template using SelectType = UnwrapType())>; -/// Variant != std::variant -/// * unchecked invalid state (only destruction is valid!) -/// * simple recursive vistor -/// * allows uncheck casts (you have to check before!) -/// * sizeof(index) limits +/// VariantWhich is an enum-like type used in Variant to determine which type is currently present in the Variant. template -struct Variant { +struct VariantWhich { static constexpr auto pack = to_type_pack; static constexpr auto indices = indexPackFor(pack); - using First = TypeHead; using WhichValue = UnwrapType>; // enough for npos! - enum { npos = sizeof...(Ts) }; // invalid state after exception - only destruction checks! - struct Which { - explicit constexpr Which(WhichValue v) - : value(v) {} + constexpr VariantWhich() = default; + explicit constexpr VariantWhich(WhichValue v) + : value(v) {} + + constexpr operator WhichValue() const { return value; } + + constexpr bool operator==(VariantWhich w) const { return w.value == value; } + constexpr bool operator!=(VariantWhich w) const { return w.value != value; } + + template + constexpr bool operator==(Type) const { + return of() == *this; + } + template + constexpr bool operator!=(Type) const { + return of() != *this; + } + + template + constexpr static auto of(Type = {}) -> VariantWhich { + return VariantWhich{static_cast(indexedTypePackIndexOf(pack, indices))}; + } + + template + constexpr auto visit(F&& f) -> decltype(auto) { + return visitImpl(*this, std::forward(f)); + } + template + constexpr auto visit(F&& f) const -> decltype(auto) { + return visitImpl(*this, std::forward(f)); + } + + /// overloaded visitor + template + constexpr auto visit(F&& f, F2&& f2, Fs&&... fs) -> decltype(auto) { + return visit(Overloaded{std::forward(f), std::forward(f2), std::forward(fs)...}); + } + template + constexpr auto visit(F&& f, F2&& f2, Fs&&... fs) const -> decltype(auto) { + return visit(Overloaded{std::forward(f), std::forward(f2), std::forward(fs)...}); + } - constexpr operator WhichValue() const { return value; } +private: + WhichValue value{}; - constexpr bool operator==(Which w) const { return w.value == value; } - constexpr bool operator!=(Which w) const { return w.value != value; } + template + static constexpr auto visitImpl(V&& v, F&& f) -> decltype(auto) { + using R = std::remove_cv_t))>; + if constexpr (type == type) + visitVoidImpl(std::forward(v), std::forward(f), indices); + else + return visitRecursiveImpl(std::forward(v), std::forward(f), pack, indices); + } - template - constexpr bool operator==(Type) const { - return whichOf() == *this; + template + static constexpr auto visitVoidImpl(V&& v, F&& f, IndexPack) { + return (void)((Is == v ? (f(type), true) : false) || ...); + } + template + static constexpr auto visitRecursiveImpl(V&& v, F&& f, TypePack, IndexPack) -> decltype(auto) { + if (I == v) { + return f(type); } - template - constexpr bool operator!=(Type) const { - return whichOf() != *this; + if constexpr (0 != sizeof...(TTs)) { + return visitRecursiveImpl(std::forward(v), std::forward(f), type_pack, index_pack); + } + else { + UNREACHABLE(); } + } +}; - private: - WhichValue value; - }; +/// Variant != std::variant +/// * unchecked invalid state (only destruction is valid!) +/// * simple recursive vistor +/// * allows uncheck casts (you have to check before!) +/// * sizeof(index) limits +template +struct Variant { + using Which = VariantWhich; + static constexpr auto pack = Which::pack; + static constexpr auto indices = Which::indices; + using First = TypeHead; + using WhichValue = typename Which::WhichValue; + enum { npos = sizeof...(Ts) }; // invalid state after exception - only destruction checks! private: std::aligned_union_t<0, Ts...> m{}; @@ -171,7 +230,7 @@ struct Variant { Variant(T&& t) { static_assert(containsOf(pack), "type not part of variant"); constructOf(type, std::forward(t)); - whichValue = whichOf(); + whichValue = whichOf(type); } /// inplace construct of type @@ -179,7 +238,7 @@ struct Variant { Variant(Type, Args&&... args) { static_assert(containsOf(pack), "type not part of variant"); constructOf(type, std::forward(args)...); - whichValue = whichOf(); + whichValue = whichOf(type); } template @@ -207,12 +266,12 @@ struct Variant { if (whichValue != npos) destruct(); whichValue = npos; constructOf(type, std::forward(args)...); - whichValue = whichOf(); + whichValue = whichOf(type); } template constexpr static auto whichOf(Type = {}) -> Which { - return Which{static_cast(indexedTypePackIndexOf(pack, indices))}; + return Which::of(type); } template diff --git a/src/variant17.lib/variant17/Variant.trait.h b/src/variant17.lib/variant17/Variant.trait.h index e62b708..164fad8 100644 --- a/src/variant17.lib/variant17/Variant.trait.h +++ b/src/variant17.lib/variant17/Variant.trait.h @@ -9,4 +9,10 @@ constexpr auto is_variant = false; template constexpr auto is_variant> = true; +template +constexpr auto is_variant_which = false; + +template +constexpr auto is_variant_which> = true; + } // namespace variant17 diff --git a/src/variant17.lib/variant17/Variant.trait.test.cpp b/src/variant17.lib/variant17/Variant.trait.test.cpp index de0d50a..0a6333e 100644 --- a/src/variant17.lib/variant17/Variant.trait.test.cpp +++ b/src/variant17.lib/variant17/Variant.trait.test.cpp @@ -8,14 +8,21 @@ using namespace variant17; TEST(Variant, trait) { using T = Variant; static_assert(is_variant); + static_assert(!is_variant_which); + + static_assert(!is_variant); + static_assert(is_variant_which); struct S { int i; }; static_assert(!is_variant); + static_assert(!is_variant_which); using P = std::pair; static_assert(!is_variant

); + static_assert(!is_variant_which

); static_assert(!is_variant); + static_assert(!is_variant_which); }