diff --git a/.clang-format b/.clang-format index d60feb1..ee2da09 100644 --- a/.clang-format +++ b/.clang-format @@ -48,7 +48,7 @@ BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: BeforeColon BreakAfterJavaFieldAnnotations: false BreakStringLiterals: true -ColumnLimit: 100 +ColumnLimit: 120 CommentPragmas: '^ IWYU pragma:' CompactNamespaces: false ConstructorInitializerAllOnOneLineOrOnePerLine: false diff --git a/conanfile.py b/conanfile.py index c356e55..2c766c4 100644 --- a/conanfile.py +++ b/conanfile.py @@ -7,7 +7,7 @@ class NamedConan(ConanFile): name = 'named' - version = '0.0.4' + version = '0.0.5' license = 'MIT' author = 'Matthew Guidry' diff --git a/include/Named/NamedTuple.hpp b/include/Named/NamedTuple.hpp index ca5f69a..29fe156 100644 --- a/include/Named/NamedTuple.hpp +++ b/include/Named/NamedTuple.hpp @@ -29,8 +29,8 @@ * @endcond */ -#ifndef MGUID_NAMEDTUPLE_H -#define MGUID_NAMEDTUPLE_H +#ifndef MGUID_NAMED_NAMEDTUPLE_H +#define MGUID_NAMED_NAMEDTUPLE_H #include #include @@ -61,8 +61,31 @@ struct NamedTuple : std::tuple::type...> { * @param init_values values to initialize each tuple element */ template - constexpr explicit NamedTuple(InitTypes&&... init_values) - : Base{std::forward(init_values)...} {} + requires(!IsNamedTypeValueHelper && ...) + constexpr explicit NamedTuple(InitTypes&&... init_values) : Base{std::forward(init_values)...} {} + + template + requires((sizeof...(Helpers) > 0u) && (IsNamedTypeValueHelper && ...)) + constexpr explicit NamedTuple(Helpers&&... helpers) { + ( + [this](NamedValueHelper&& value_helper) { + this->template get() = value_helper.value; + }(std::forward(helpers)), + ...); + } + + // /** + // * @brief Construct a NamedTuple, initializing values by tag + // * @tparam InitTags Tags to initialize + // * @tparam InitTypes Types of values to initialize + // * @param named_type_vs Variadic pack of NamedTypeValueHelpers + // */ + // template + // requires(AllUniqueTags && sizeof...(InitTags) == sizeof...(InitTypes) && + // sizeof...(InitTypes) != 0) + // constexpr NamedTuple(NamedTypeValueHelper&&... named_type_vs) { + // ( + // } /** * @brief Get the number of elements this NamedTuple holds @@ -74,9 +97,7 @@ struct NamedTuple : std::tuple::type...> { * @brief Explicit conversion operator to Base * @return Const reference to Base */ - [[nodiscard]] constexpr explicit operator const Base&() const { - return static_cast(*this); - } + [[nodiscard]] constexpr explicit operator const Base&() const { return static_cast(*this); } /** * @brief Explicit conversion operator to Base @@ -91,9 +112,8 @@ struct NamedTuple : std::tuple::type...> { * @param value value to set */ template - requires( - sizeof...(NamedTypes) > 0 && is_one_of() && - std::is_convertible_v(), Base>>) + requires(sizeof...(NamedTypes) > 0 && is_one_of() && + std::is_convertible_v(), Base>>) constexpr void set(Value&& value) { constexpr std::size_t Index = index_in_pack(); std::get(static_cast(*this)) = std::forward(value); @@ -250,12 +270,10 @@ struct NamedTuple : std::tuple::type...> { template [[nodiscard]] constexpr auto operator<=>(const NamedTuple& other) const { static_assert(sizeof...(NamedTypes) == sizeof...(OtherNamedTypes)); - if constexpr (sizeof...(NamedTypes) == 0 && sizeof...(OtherNamedTypes) == 0) { - return std::strong_ordering::equal; - } + if constexpr (sizeof...(NamedTypes) == 0 && sizeof...(OtherNamedTypes) == 0) { return std::strong_ordering::equal; } - std::common_comparison_category_t::type, typename ExtractType::type>...> + std::common_comparison_category_t< + SynthThreeWayResultT::type, typename ExtractType::type>...> result = std::strong_ordering::equivalent; ([this, &other, &result]() { @@ -271,10 +289,12 @@ struct NamedTuple : std::tuple::type...> { * @brief Get the array of tags as a tuple * @return A tuple of the tags */ - [[nodiscard]] static constexpr auto tags() { - return std::tuple{NamedTypes::tag()...}; - } + [[nodiscard]] static constexpr auto tags() { return std::tuple{NamedTypes::tag()...}; } }; + +template + requires(IsNamedTypeValueHelper && ...) +explicit NamedTuple(Helpers&&... helpers) -> NamedTuple...>; } // namespace mguid // NOLINTBEGIN(cert-dcl58-cpp) @@ -284,8 +304,7 @@ namespace std { * @tparam NamedTypes type list for a NamedTuple */ template -struct tuple_size> - : std::integral_constant {}; +struct tuple_size> : std::integral_constant {}; /** * @brief Specialization of std::tuple_element for NamedTuple @@ -318,7 +337,8 @@ template } /** - * @brief Constructs a NamedTuple of references to the arguments in args suitable for forwarding as an argument to a function. + * @brief Constructs a NamedTuple of references to the arguments in args suitable for forwarding as + * an argument to a function. * @tparam NamedTypeVs pack of zero or more named type value helpers * @param args zero or more arguments to construct the tuple from * @return A NamedTuple object containing the given values @@ -345,10 +365,9 @@ template typename Tuple, typename... Name [[nodiscard]] constexpr decltype(auto) apply(Func&& func, Tuple&& named_tuple) { return std::apply( [&](Args&&... args) { - return std::invoke( - std::forward(func), - std::pair(NamedTypes{}.tag(), std::forward(args))...); - }, named_tuple); + return std::invoke(std::forward(func), std::pair(NamedTypes{}.tag(), std::forward(args))...); + }, + named_tuple); } /** @@ -364,10 +383,9 @@ template typename Tuple, typename... Name [[nodiscard]] constexpr decltype(auto) apply(Func&& func, const Tuple&& named_tuple) { return std::apply( [&](Args&&... args) { - return std::invoke( - std::forward(func), - std::pair(NamedTypes{}.tag(), std::forward(args))...); - }, named_tuple); + return std::invoke(std::forward(func), std::pair(NamedTypes{}.tag(), std::forward(args))...); + }, + named_tuple); } /** @@ -383,10 +401,9 @@ template typename Tuple, typename... Name [[nodiscard]] constexpr decltype(auto) apply(Func&& func, const Tuple& named_tuple) { return std::apply( [&](Args&&... args) { - return std::invoke( - std::forward(func), - std::pair(NamedTypes{}.tag(), std::forward(args))...); - }, named_tuple); + return std::invoke(std::forward(func), std::pair(NamedTypes{}.tag(), std::forward(args))...); + }, + named_tuple); } /** @@ -402,27 +419,32 @@ template typename Tuple, typename... Name [[nodiscard]] constexpr decltype(auto) apply(Func&& func, Tuple& named_tuple) { return std::apply( [&](Args&&... args) { - return std::invoke( - std::forward(func), - std::pair(NamedTypes{}.tag(), std::forward(args))...); - }, named_tuple); + return std::invoke(std::forward(func), std::pair(NamedTypes{}.tag(), std::forward(args))...); + }, + named_tuple); } template constexpr auto TupleCatHelper(Tuple1 t1, Tuple2 t2) { - return [&](mguid::NamedTuple){ - return [&](mguid::NamedTuple){ - return std::apply([&](ArgsOuter&&... outer_args){ - return std::apply([&](ArgsInner&&... inner_args){ - return mguid::NamedTuple(std::forward(outer_args)..., std::forward(inner_args)...); - }, static_cast::Base&>(t2)); - }, static_cast::Base&>(t1)); + return [&](mguid::NamedTuple) { + return [&](mguid::NamedTuple) { + return std::apply( + [&](ArgsOuter&&... outer_args) { + return std::apply( + [&](ArgsInner&&... inner_args) { + return mguid::NamedTuple(std::forward(outer_args)..., + std::forward(inner_args)...); + }, + static_cast::Base&>(t2)); + }, + static_cast::Base&>(t1)); }(t2); }(t1); } -template -using TupleCat2T = decltype(TupleCatHelper(std::declval>(), std::declval>())); +template +using TupleCat2T = + decltype(TupleCatHelper(std::declval>(), std::declval>())); template struct TupleCatResult { @@ -452,9 +474,9 @@ constexpr TupleCatT my_tuple_cat(Tuples&&... tuples) { if constexpr (sizeof...(Tuples) < 2) { return (tuples, ...); } else { - return std::apply([](Types&&... elements){ - return TupleCatT{std::forward(elements)...}; - }, std::tuple_cat(static_cast::Base&>(tuples)...)); + return std::apply( + [](Types&&... elements) { return TupleCatT{std::forward(elements)...}; }, + std::tuple_cat(static_cast::Base&>(tuples)...)); } } @@ -468,8 +490,8 @@ constexpr TupleCatT my_tuple_cat(Tuples&&... tuples) { */ template requires(sizeof...(NamedTypes) > 0 && is_one_of()) -[[nodiscard]] constexpr std::tuple_element_t(), NamedTuple>& - get(NamedTuple& nt) noexcept { +[[nodiscard]] constexpr std::tuple_element_t(), NamedTuple>& get( + NamedTuple& nt) noexcept { return nt.template get(); } @@ -483,9 +505,8 @@ template */ template requires(sizeof...(NamedTypes) > 0 && is_one_of()) -[[nodiscard]] constexpr std::tuple_element_t(), - NamedTuple>&& -get(NamedTuple&& nt) noexcept { +[[nodiscard]] constexpr std::tuple_element_t(), NamedTuple>&& get( + NamedTuple&& nt) noexcept { return nt.template get(); } @@ -499,8 +520,7 @@ get(NamedTuple&& nt) noexcept { */ template requires(sizeof...(NamedTypes) > 0 && is_one_of()) -[[nodiscard]] constexpr const std::tuple_element_t(), - NamedTuple>& +[[nodiscard]] constexpr const std::tuple_element_t(), NamedTuple>& get(const NamedTuple& nt) noexcept { return nt.template get(); } @@ -515,11 +535,23 @@ get(const NamedTuple& nt) noexcept { */ template requires(sizeof...(NamedTypes) > 0 && is_one_of()) -[[nodiscard]] constexpr const std::tuple_element_t(), - NamedTuple>&& +[[nodiscard]] constexpr const std::tuple_element_t(), NamedTuple>&& get(const NamedTuple&& nt) noexcept { return nt.template get(); } + +template +struct IsNamedTupleTrait : std::false_type {}; + +template +struct IsNamedTupleTrait> : std::true_type {}; + +template +concept IsNamedTuple = IsNamedTupleTrait::value; + +template +constexpr auto IsNamedTupleV = IsNamedTupleTrait::value; + } // namespace mguid -#endif // MGUID_NAMEDTUPLE_H +#endif // MGUID_NAMED_NAMEDTUPLE_H diff --git a/include/Named/TaggedArray.hpp b/include/Named/TaggedArray.hpp index 4a006f7..60d66ef 100644 --- a/include/Named/TaggedArray.hpp +++ b/include/Named/TaggedArray.hpp @@ -30,8 +30,8 @@ * @endcond */ -#ifndef NAMED_TAGGEDARRAY_HPP -#define NAMED_TAGGEDARRAY_HPP +#ifndef MGUID_NAMED_TAGGEDARRAY_HPP +#define MGUID_NAMED_TAGGEDARRAY_HPP #include #include @@ -58,8 +58,7 @@ struct TaggedArray : std::array { * @param vals variadic list of values */ template - constexpr explicit(false) TaggedArray(ValueTypes&&... vals) - : Base{std::forward(vals)...} {} + constexpr explicit(false) TaggedArray(ValueTypes&&... vals) : Base{std::forward(vals)...} {} /** * @brief Get the array element at the Tag provided @@ -169,8 +168,7 @@ struct TaggedArray : std::array { * @param other a std::array to compare against * @return Returns true if all pairs of corresponding elements are equal; otherwise false */ - [[nodiscard]] constexpr bool operator==( - const std::array& other) const { + [[nodiscard]] constexpr bool operator==(const std::array& other) const { return static_cast(*this) == other; } @@ -185,8 +183,8 @@ struct TaggedArray : std::array { // NOLINTBEGIN(cert-dcl58-cpp) template -struct std::tuple_size> - : std::integral_constant {}; +struct std::tuple_size> : std::integral_constant { +}; // Specialization of std::tuple_element for TaggedArray template @@ -246,8 +244,7 @@ constexpr ValueType&& get(TaggedArray&& arr) noexcept { */ template constexpr const ValueType&& get(const TaggedArray&& arr) noexcept { - return std::move( - std::get(static_cast&>(arr))); + return std::move(std::get(static_cast&>(arr))); } /** @@ -304,4 +301,4 @@ constexpr const ValueType&& get(const TaggedArray&& arr) noe } // namespace mguid -#endif // NAMED_TAGGEDARRAY_HPP +#endif // MGUID_NAMED_TAGGEDARRAY_HPP diff --git a/include/Named/TaggedBitset.hpp b/include/Named/TaggedBitset.hpp index a46a369..99fd2ee 100644 --- a/include/Named/TaggedBitset.hpp +++ b/include/Named/TaggedBitset.hpp @@ -1,43 +1,43 @@ /** -* @brief Definitions for tagged bitset type -* @author Matthew Guidry (github: mguid65) -* @date 2024-11-1 -* -* @cond IGNORE_LICENSE -* -* MIT License -* -* Copyright (c) 2024 Matthew Guidry -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -* -* @endcond -*/ - -#ifndef NAMED_TAGGEDBITSET_HPP -#define NAMED_TAGGEDBITSET_HPP + * @brief Definitions for tagged bitset type + * @author Matthew Guidry (github: mguid65) + * @date 2024-11-1 + * + * @cond IGNORE_LICENSE + * + * MIT License + * + * Copyright (c) 2024 Matthew Guidry + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * @endcond + */ + +#ifndef MGUID_NAMED_TAGGEDBITSET_HPP +#define MGUID_NAMED_TAGGEDBITSET_HPP #include #include -#include "Named/detail/StringLiteral.hpp" #include "Named/detail/Common.hpp" +#include "Named/detail/StringLiteral.hpp" namespace mguid { @@ -167,11 +167,9 @@ struct TaggedBitset : std::bitset { * @brief Get tags as a tuple * @return A tuple of the tags */ - [[nodiscard]] static constexpr auto tags() { - return std::tuple{Tags...}; - } + [[nodiscard]] static constexpr auto tags() { return std::tuple{Tags...}; } }; -} // namespace mguid +} // namespace mguid -#endif // NAMED_TAGGEDBITSET_HPP +#endif // MGUID_NAMED_TAGGEDBITSET_HPP diff --git a/include/Named/detail/Common.hpp b/include/Named/detail/Common.hpp index 78473ce..1307e3d 100644 --- a/include/Named/detail/Common.hpp +++ b/include/Named/detail/Common.hpp @@ -76,7 +76,8 @@ constexpr std::size_t reverse_index_in_pack() { ++index; return true; } - }.template operator()() && ...); + }.template operator()() && + ...); if (index >= sizeof...(Haystack)) { throw std::out_of_range("Value does not exist in pack"); } return sizeof...(Haystack) - 1 - index; } @@ -93,11 +94,7 @@ consteval bool all_unique_nttps() { } else { bool seen[sizeof...(Nttps)] = {false}; - ( - [&seen]() { - seen[index_in_pack()] = true; - }.template operator()(), - ...); + ([&seen]() { seen[index_in_pack()] = true; }.template operator()(), ...); return std::all_of(std::begin(seen), std::end(seen), [](bool val) { return val; }); } diff --git a/include/Named/detail/NamedTupleUtil.hpp b/include/Named/detail/NamedTupleUtil.hpp index 73a96e1..eec3604 100644 --- a/include/Named/detail/NamedTupleUtil.hpp +++ b/include/Named/detail/NamedTupleUtil.hpp @@ -39,8 +39,8 @@ #include #include -#include "Named/detail/StringLiteral.hpp" #include "Named/detail/Common.hpp" +#include "Named/detail/StringLiteral.hpp" namespace mguid { @@ -107,9 +107,19 @@ template struct NamedTypeValueHelper { using DecayT = NamedType>; using TypeRRef = NamedType; + static constexpr auto tag = Tag; std::unwrap_ref_decay_t value{}; }; +template +struct IsNamedTypeValueHelperImpl : std::false_type {}; + +template +struct IsNamedTypeValueHelperImpl> : std::true_type {}; + +template +concept IsNamedTypeValueHelper = IsNamedTypeValueHelperImpl::value; + /** * @brief A helper to associate a value with a named type for use in make_tuple * @tparam Tag StringLiteral element name @@ -122,6 +132,45 @@ constexpr NamedTypeValueHelper NamedTypeV(ValueType value) { return NamedTypeValueHelper{value}; } +// Deduce the tag and type from a helper +template +struct NamedTypeFromHelper; + +template +struct NamedTypeFromHelper> { + using type = NamedType>; +}; + +// Convenience alias +template +using NamedTypeFromHelperT = typename NamedTypeFromHelper>::type; + +namespace literals { + +template +struct NamedTypeValueUDLHelper { + template + constexpr NamedTypeValueHelper operator=(ValueType value) const { + return NamedTypeValueHelper{value}; + } +}; + +template +constexpr NamedTypeValueUDLHelper operator""_nt() { + return NamedTypeValueUDLHelper{}; +} + +template +constexpr NamedTypeValueUDLHelper operator""_tag() { + return NamedTypeValueUDLHelper{}; +} + +template +constexpr NamedTypeValueUDLHelper operator""_name() { + return NamedTypeValueUDLHelper{}; +} +} // namespace literals + /** * @brief Base template of helper template to extract the type from a NamedType * @tparam Type unconstrained type @@ -157,6 +206,6 @@ constexpr bool is_one_of() { return (... || (Key == NamedTypes)); } -} // namespace mguid +} // namespace mguid -#endif // NAMED_NAMEDTUPLEUTIL_HPP +#endif // NAMED_NAMEDTUPLEUTIL_HPP diff --git a/include/Named/detail/StringLiteral.hpp b/include/Named/detail/StringLiteral.hpp index 83443f0..b3113bf 100644 --- a/include/Named/detail/StringLiteral.hpp +++ b/include/Named/detail/StringLiteral.hpp @@ -30,8 +30,8 @@ * @endcond */ -#ifndef NAMED_STRINGLITERAL_HPP -#define NAMED_STRINGLITERAL_HPP +#ifndef MGUID_NAMED_STRINGLITERAL_HPP +#define MGUID_NAMED_STRINGLITERAL_HPP #include #include @@ -51,9 +51,7 @@ struct StringLiteral { * @brief Construct a StringLiteral from a string literal * @param str a string literal as a const reference to a sized char array */ - constexpr explicit(false) StringLiteral(char const (&str)[NSize]) : value{'\0'} { - std::copy_n(str, NSize, value); - } + constexpr explicit(false) StringLiteral(char const (&str)[NSize]) : value{'\0'} { std::copy_n(str, NSize, value); } // NOLINTEND(google-explicit-constructor) /** @@ -93,17 +91,13 @@ struct StringLiteral { * @brief Convert this StringLiteral to a string_view * @return a string_view of the data in this StringLiteral */ - [[nodiscard]] constexpr explicit operator std::string_view() const { - return std::string_view{value, size - 1}; - } + [[nodiscard]] constexpr explicit operator std::string_view() const { return std::string_view{value, size - 1}; } /** * @brief Convert this StringLiteral to a string_view * @return a string_view of the data in this StringLiteral */ - [[nodiscard]] constexpr std::string_view view() const { - return std::string_view{value, size - 1}; - } + [[nodiscard]] constexpr std::string_view view() const { return std::string_view{value, size - 1}; } char value[NSize]; static constexpr size_t size{NSize}; @@ -173,4 +167,4 @@ std::ostream& operator<<(std::ostream& os, const StringLiteral& lit) { } // namespace mguid -#endif // NAMED_STRINGLITERAL_HPP +#endif // MGUID_NAMED_STRINGLITERAL_HPP diff --git a/include/Named/detail/SynthThreeWayResult.hpp b/include/Named/detail/SynthThreeWayResult.hpp index 29c6698..fbd6d36 100644 --- a/include/Named/detail/SynthThreeWayResult.hpp +++ b/include/Named/detail/SynthThreeWayResult.hpp @@ -1,37 +1,37 @@ /** -* @brief Definitions for SynthThreeWay/ResultT -* @author Matthew Guidry (github: mguid65) -* @date 2024-11-1 -* -* @cond IGNORE_LICENSE -* -* MIT License -* -* Copyright (c) 2024 Matthew Guidry -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -* SOFTWARE. -* -* @endcond -*/ + * @brief Definitions for SynthThreeWay/ResultT + * @author Matthew Guidry (github: mguid65) + * @date 2024-11-1 + * + * @cond IGNORE_LICENSE + * + * MIT License + * + * Copyright (c) 2024 Matthew Guidry + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * @endcond + */ -#ifndef NAMED_SYNTHTHREEWAYRESULT_HPP -#define NAMED_SYNTHTHREEWAYRESULT_HPP +#ifndef MGUID_NAMED_SYNTHTHREEWAYRESULT_HPP +#define MGUID_NAMED_SYNTHTHREEWAYRESULT_HPP #include #include @@ -68,6 +68,6 @@ constexpr auto SynthThreeWay = [](const T& t, const U& u) template using SynthThreeWayResultT = decltype(SynthThreeWay(std::declval(), std::declval())); -} +} // namespace mguid -#endif // NAMED_SYNTHTHREEWAYRESULT_HPP +#endif // MGUID_NAMED_SYNTHTHREEWAYRESULT_HPP diff --git a/source/sample/main.cpp b/source/sample/main.cpp index 1789d4d..c77c38a 100644 --- a/source/sample/main.cpp +++ b/source/sample/main.cpp @@ -9,21 +9,51 @@ using mguid::NamedType; using mguid::NamedTypeV; int main() { + using namespace mguid::literals; + + using Vec3i = NamedTuple, NamedType<"y", int>, NamedType<"z", int>>; + + Vec3i vec1{NamedTypeV<"x">(11), NamedTypeV<"z">(13), NamedTypeV<"y">(12)}; + Vec3i vec2{1, 2, 3}; + + Vec3i vec3{"x"_tag = 4, "y"_tag = 5, "z"_tag = 6}; + + std::cout << vec1.get<"x">() << std::endl; + std::cout << vec1.get<"y">() << std::endl; + std::cout << vec1.get<"z">() << std::endl; + + std::cout << vec2.get<"x">() << std::endl; + std::cout << vec2.get<"y">() << std::endl; + std::cout << vec2.get<"z">() << std::endl; + + std::cout << vec3.get<"x">() << std::endl; + std::cout << vec3.get<"y">() << std::endl; + std::cout << vec3.get<"z">() << std::endl; + int i = 5; const std::reference_wrapper i_ref{i}; - const auto nt = mguid::make_tuple(NamedTypeV<"int_key">(i_ref), NamedTypeV<"float_key">(1.0f), - NamedTypeV<"char_key">('c')); + const auto nt = + mguid::make_tuple(NamedTypeV<"int_key">(i_ref), NamedTypeV<"float_key">(1.0f), NamedTypeV<"char_key">('c')); - mguid::apply( - [](const auto&&... args) { - std::cout << "{"; - std::size_t count{1}; - ((std::cout << args.first.view() << ":" << args.second - << ((count++ != sizeof...(args)) ? "," : "")), - ...); - std::cout << "}\n"; - }, - nt); + const auto nt2 = mguid::make_tuple("int_key"_nt = i_ref, "float_key"_nt = 42.0f, "char_key"_nt = 'm'); + + auto print_named_tuple = [](const auto& tup) { + mguid::apply( + [](const auto&&... args) { + std::cout << "{"; + std::size_t count{1}; + ((std::cout << args.first.view() << ":" << args.second << ((count++ != sizeof...(args)) ? "," : "")), ...); + std::cout << "}\n"; + }, + tup); + }; + + print_named_tuple(nt); + + print_named_tuple(nt2); + + const auto nt_deduced = NamedTuple{"a"_name = 'a', "b"_name = "b", "c"_name = 2}; + print_named_tuple(nt_deduced); std::cout << nt.get<"int_key">() << '\n'; std::cout << nt.get<"float_key">() << '\n'; diff --git a/test/unit_test_named_tuple.cpp b/test/unit_test_named_tuple.cpp index a90b0f3..fd71362 100644 --- a/test/unit_test_named_tuple.cpp +++ b/test/unit_test_named_tuple.cpp @@ -72,6 +72,66 @@ TEST_CASE("NamedTuple Constructor") { REQUIRE(std::is_same_v())>, double>); REQUIRE(std::is_same_v())>, std::string>); } + SECTION("Tagged Single Type") { + [[maybe_unused]] mguid::NamedTuple> nt{}; + REQUIRE(std::tuple_size_v == std::size_t{1}); + REQUIRE(std::same_as, int>); + } + SECTION("Tagged Single Type UDL") { + using namespace mguid::literals; + [[maybe_unused]] mguid::NamedTuple> nt("key"_nt = 5); + REQUIRE(std::tuple_size_v == std::size_t{1}); + REQUIRE(std::same_as, int>); + REQUIRE(nt.get<"key">() == 5); + // Deduce types from tags + [[maybe_unused]] auto nt2 = mguid::NamedTuple{"key"_nt = 5}; + REQUIRE(std::tuple_size_v == std::size_t{1}); + REQUIRE(std::same_as, int>); + REQUIRE(nt2.get<"key">() == 5); + } + + SECTION("Tagged Multiple Types") { + [[maybe_unused]] mguid::NamedTuple, mguid::NamedType<"key2", char>> nt{}; + REQUIRE(std::tuple_size_v == std::size_t{2}); + STATIC_REQUIRE(std::same_as, int>); + STATIC_REQUIRE(std::same_as, char>); + } + SECTION("Tagged Multiple Types UDL") { + using namespace mguid::literals; + // In order + { + [[maybe_unused]] mguid::NamedTuple, mguid::NamedType<"key2", char>> nt("key1"_nt = 5, "key2"_nt = 'c'); + REQUIRE(std::tuple_size_v == std::size_t{2}); + STATIC_REQUIRE(std::same_as, int>); + STATIC_REQUIRE(std::same_as, char>); + REQUIRE(nt.get<"key1">() == 5); + REQUIRE(nt.get<"key2">() == 'c'); + // Deduce types from tags + [[maybe_unused]] auto nt2 = mguid::NamedTuple{"key1"_nt = 5, "key2"_nt = 'c'}; + REQUIRE(std::tuple_size_v == std::size_t{2}); + STATIC_REQUIRE(std::same_as, int>); + STATIC_REQUIRE(std::same_as, char>); + REQUIRE(nt2.get<"key1">() == 5); + REQUIRE(nt2.get<"key2">() == 'c'); + } + + // Out of order + { + [[maybe_unused]] mguid::NamedTuple, mguid::NamedType<"key2", char>> nt("key2"_nt = 'c', "key1"_nt = 5); + REQUIRE(std::tuple_size_v == std::size_t{2}); + STATIC_REQUIRE(std::same_as, int>); + STATIC_REQUIRE(std::same_as, char>); + REQUIRE(nt.get<"key1">() == 5); + REQUIRE(nt.get<"key2">() == 'c'); + // Deduce types from tags + [[maybe_unused]] auto nt2 = mguid::NamedTuple{"key2"_nt = 'c', "key1"_nt = 5}; + REQUIRE(std::tuple_size_v == std::size_t{2}); + STATIC_REQUIRE(std::same_as, char>); + STATIC_REQUIRE(std::same_as, int>); + REQUIRE(nt2.get<"key1">() == 5); + REQUIRE(nt2.get<"key2">() == 'c'); + } + } } TEST_CASE("NamedTuple Setter") { @@ -157,7 +217,7 @@ TEST_CASE("NamedTuple Getter") { } } -TEST_CASE("Comparison") { +TEST_CASE("NamedTuple Comparison") { SECTION("Empty Equality") { mguid::NamedTuple<> nt1; mguid::NamedTuple<> nt2; @@ -375,7 +435,7 @@ TEST_CASE("Comparison") { } } -TEST_CASE("Specialization of std::tuple_element") { +TEST_CASE("NamedTuple Specialization of std::tuple_element") { SECTION("Single Element") { REQUIRE( std::is_same_v>>, @@ -403,7 +463,7 @@ TEST_CASE("Specialization of std::tuple_element") { } } -TEST_CASE("Specialization of std::tuple_size") { +TEST_CASE("NamedTuple Specialization of std::tuple_size") { SECTION("Empty") { REQUIRE(std::tuple_size_v> == 0); } SECTION("Single Element") { REQUIRE(std::tuple_size_v>> == 1); @@ -415,7 +475,7 @@ TEST_CASE("Specialization of std::tuple_size") { } } -TEST_CASE("Forward As Tuple") { +TEST_CASE("NamedTuple Forward As Tuple") { int i{1}; int j{2}; int k{3}; @@ -436,7 +496,7 @@ TEST_CASE("Forward As Tuple") { mguid::NamedTypeV<"third">(k))); } -TEST_CASE("Make Tuple") { +TEST_CASE("NamedTuple Make Tuple") { int i{1}; int j{2}; int k{3}; @@ -464,7 +524,7 @@ TEST_CASE("Make Tuple") { mguid::NamedTypeV<"third">(k))); } -TEST_CASE("Apply") { +TEST_CASE("NamedTuple Apply") { SECTION("Empty Apply") { mguid::NamedTuple<> nt; const mguid::NamedTuple<> const_nt; @@ -527,3 +587,9 @@ TEST_CASE("Apply") { const_nt); } } + +TEST_CASE("NamedTuple Trait") { + STATIC_REQUIRE(mguid::IsNamedTuple>); + STATIC_REQUIRE(mguid::IsNamedTuple>>); + STATIC_REQUIRE_FALSE(mguid::IsNamedTuple); +} \ No newline at end of file