diff --git a/module-1/homework/Variant/variant.h b/module-1/homework/Variant/variant.h index 647742e7..f073fb2d 100644 --- a/module-1/homework/Variant/variant.h +++ b/module-1/homework/Variant/variant.h @@ -5,7 +5,145 @@ namespace task { -template +template +struct TypeList { + using head = Head; + using tail = TypeList; +}; + +template +struct TypeAt; + +template +struct TypeAt<0, TypeList> { + using result = Head; +}; + +template +struct TypeAt> { + using result = typename TypeAt>::result; +}; + +template +struct InPlaceIndex { + explicit InPlaceIndex() = default; +}; + +template +constexpr InPlaceIndex kInPlaceIndex{}; + +template +union Union; + +template +union Union {}; + +template +union Union { +public: + Union() : tail() { + if (!std::is_trivially_constructible_v) { + new (&head) T(); + } + } + + ~Union() { + if (!std::is_trivially_destructible_v) { + head.~T(); + } + } + +public: + T head; + Union tail; + + friend struct UnionHelper; +}; + +struct UnionHelper { + template + static constexpr auto&& GetAlt(U&& v, InPlaceIndex<0>) { + return std::forward(v).head; + } + + template + static constexpr auto&& GetAlt(U&& v, InPlaceIndex) { + return GetAlt(std::forward(v).tail, kInPlaceIndex); + } +}; + +struct VariantHelper { + template + static constexpr auto&& GetAlt(T&& v) { + return UnionHelper::GetAlt(std::forward(v).data_, kInPlaceIndex); + } +}; + +struct AssignUnion { + template + static void AssignHelper(U&& value, InPlaceIndex<0>, Union& u) { + u.head = value; + } + + template + static void AssignHelper(U&& value, InPlaceIndex, Union& u) { + AssignUnion::AssignHelper(std::forward(value), kInPlaceIndex, u.tail); + } +}; + +const static int16_t kNotFound{-1}; +const static int16_t kAmbiguity{kNotFound - 1}; + +constexpr size_t ProcessBackward(size_t i, int16_t res, const bool* found, + const bool* found_convertible) { + if (res == kAmbiguity) { + return res; + } + + if (found[i]) { + if (res == kNotFound || !(!found[res] && found_convertible[res])) { + return i; + } + return kAmbiguity; + } + + if (res == kNotFound && found_convertible[i]) { + return i; + } + + return res; +} + +template +constexpr size_t ProcessForward(size_t currnet, const bool (&found)[SizeofFound], + const bool (&convertible)[SizeofFound]) { + if (currnet == SizeofFound) { + return kNotFound; + } + return ProcessBackward(currnet, ProcessForward(currnet + 1, found, convertible), found, + convertible); +} + +template +struct FindExactlyOneChecked { + constexpr static bool kFound[sizeof...(Type)] = {std::is_same::value...}; + constexpr static bool kFoundConvertible[sizeof...(Type)] = { + std::is_convertible::value...}; + constexpr static size_t kValue = ProcessForward(0, kFound, kFoundConvertible); + + static_assert(kValue != kNotFound); + static_assert(kValue != kAmbiguity); +}; + +template +struct FindExactlyOneChecked { + static_assert(!std::is_same::value); +}; + +template +struct FindExactlyOne : public FindExactlyOneChecked {}; + +template class Variant; template @@ -14,35 +152,61 @@ struct VariantAlternative; template using variant_alternative_t = typename VariantAlternative::type; -template -struct VariantAlternative> { - using type = // Your code goes here +template +struct VariantAlternative> { + using type = typename TypeAt>::result; }; -template +template class Variant { public: // Special member functions constexpr Variant() noexcept; - template + template ::kValue> Variant& operator=(T&& t) noexcept; private: - // Your code goes here + Union<0, Type...> data_; + + friend VariantHelper; }; +template +constexpr Variant::Variant() noexcept { +} + +template +template +Variant& Variant::operator=(T&& t) noexcept { + AssignUnion::AssignHelper(std::forward(t), kInPlaceIndex, data_); + return *this; +} + +template +auto&& GenericGet(T&& v) { + return VariantHelper::GetAlt(std::forward(v)); +} + // Non-member functions -template -constexpr const variant_alternative_t>& Get(Variant& v); +template +constexpr const variant_alternative_t>& Get(Variant& v) { + return GenericGet(v); +} -template -constexpr variant_alternative_t>&& Get(Variant&& v); +template +constexpr variant_alternative_t>&& Get(Variant&& v) { + return GenericGet(v); +} -template -constexpr const T& Get(Variant& v); +template +constexpr const T& Get(Variant& v) { + return GenericGet::kValue>(v); +} -template -constexpr T&& Get(Variant&& v); +template +constexpr T&& Get(Variant&& v) { + return GenericGet::kValue>(v); +} }; // namespace task \ No newline at end of file