winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

AppInstallerLanguageUtilities.h (7550B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #pragma once
      4 #include <initializer_list>
      5 #include <map>
      6 #include <string>
      7 #include <string_view>
      8 #include <tuple>
      9 #include <type_traits>
     10 #include <utility>
     11 #include <variant>
     12 #include <vector>
     13 
     14 namespace AppInstaller
     15 {
     16     // A helper type that resets itself when it is moved from.
     17     template <typename T>
     18     struct ResetWhenMovedFrom
     19     {
     20         ResetWhenMovedFrom() : m_var{} {}
     21 
     22         ResetWhenMovedFrom(T t) : m_var{ t } {}
     23 
     24         // Not copyable
     25         ResetWhenMovedFrom(const ResetWhenMovedFrom&) = delete;
     26         ResetWhenMovedFrom& operator=(const ResetWhenMovedFrom&) = delete;
     27 
     28         ResetWhenMovedFrom(ResetWhenMovedFrom&& other) noexcept :
     29             m_var(std::move(other.m_var))
     30         {
     31             other.m_var = T{};
     32         }
     33 
     34         ResetWhenMovedFrom& operator=(ResetWhenMovedFrom&& other) noexcept
     35         {
     36             m_var = std::move(other.m_var);
     37             other.m_var = T{};
     38             return *this;
     39         }
     40 
     41         operator T& () { return m_var; }
     42         operator const T& () const { return m_var; }
     43 
     44     private:
     45         T m_var;
     46     };
     47 
     48     // Enables a bool to be used as a destruction indicator.
     49     // Default construction *sets the value to false!*
     50     using DestructionToken = ResetWhenMovedFrom<bool>;
     51 
     52     // Enable use of folding to execute functions across parameter packs.
     53     struct FoldHelper
     54     {
     55         template <typename T>
     56         FoldHelper& operator,(T&&) { return *this; }
     57     };
     58 
     59     // Get the integral value for an enum.
     60     template <typename E>
     61     constexpr inline std::enable_if_t<std::is_enum_v<E>, std::underlying_type_t<E>> ToIntegral(E e)
     62     {
     63         return static_cast<std::underlying_type_t<E>>(e);
     64     }
     65 
     66     // Get the enum value for an integral.
     67     template <typename E>
     68     constexpr inline std::enable_if_t<std::is_enum_v<E>, E> ToEnum(std::underlying_type_t<E> ut)
     69     {
     70         return static_cast<E>(ut);
     71     }
     72 
     73     // Enum based variant helper.
     74     // Enum must be an enum whose first member has the value 0, each subsequent member increases by 1, and the final member is named Max.
     75     // Mapping is a template type that takes one template parameter of type Enum, and whose members define value_t as the type for that enum value.
     76     template <typename Enum, template<Enum> typename Mapping>
     77     struct EnumBasedVariant
     78     {
     79     private:
     80         // Used to deduce the variant type; making a variant that includes std::monostate and all Mapping types.
     81         template <size_t... I>
     82         static inline auto Deduce(std::index_sequence<I...>) { return std::variant<std::monostate, typename Mapping<static_cast<Enum>(I)>::value_t...>{}; }
     83 
     84     public:
     85         // Holds data of any type listed in Mapping.
     86         using variant_t = decltype(Deduce(std::make_index_sequence<static_cast<size_t>(Enum::Max)>()));
     87 
     88         // Gets the index into the variant for the given Data.
     89         static constexpr inline size_t Index(Enum e) { return static_cast<size_t>(e) + 1; }
     90     };
     91 
     92     // An action that can be taken on an EnumBasedVariantMap.
     93     enum class EnumBasedVariantMapAction
     94     {
     95         Add,
     96         Contains,
     97         Get,
     98     };
     99 
    100     // A callback function that can be used for logging map actions.
    101     template <typename Enum>
    102     using EnumBasedVariantMapActionCallback = void (*)(const void* map, Enum value, EnumBasedVariantMapAction action);
    103 
    104     // Provides a map of the Enum to the mapped types.
    105     template <typename Enum, template<Enum> typename Mapping, EnumBasedVariantMapActionCallback<Enum> Callback = nullptr>
    106     struct EnumBasedVariantMap
    107     {
    108         using Variant = EnumBasedVariant<Enum, Mapping>;
    109 
    110         template <Enum E>
    111         using mapping_t = typename Mapping<E>::value_t;
    112 
    113         // Adds a value to the map, or overwrites an existing entry.
    114         // This must be used to create the initial data entry, but Get can be used to modify.
    115         template <Enum E>
    116         void Add(mapping_t<E>&& v)
    117         {
    118             if constexpr (Callback)
    119             {
    120                 Callback(this, E, EnumBasedVariantMapAction::Add);
    121             }
    122             m_data[E].emplace<Variant::Index(E)>(std::move(std::forward<mapping_t<E>>(v)));
    123         }
    124 
    125         template <Enum E>
    126         void Add(const mapping_t<E>& v)
    127         {
    128             if constexpr (Callback)
    129             {
    130                 Callback(this, E, EnumBasedVariantMapAction::Add);
    131             }
    132             m_data[E].emplace<Variant::Index(E)>(v);
    133         }
    134 
    135         // Return a value indicating whether the given enum is stored in the map.
    136         bool Contains(Enum e) const
    137         {
    138             if constexpr (Callback)
    139             {
    140                 Callback(this, e, EnumBasedVariantMapAction::Contains);
    141             }
    142             return (m_data.find(e) != m_data.end());
    143         }
    144 
    145         // Gets the value.
    146         template <Enum E>
    147         mapping_t<E>& Get()
    148         {
    149             if constexpr (Callback)
    150             {
    151                 Callback(this, E, EnumBasedVariantMapAction::Get);
    152             }
    153             return std::get<Variant::Index(E)>(GetVariant(E));
    154         }
    155 
    156         template <Enum E>
    157         const mapping_t<E>& Get() const
    158         {
    159             if constexpr (Callback)
    160             {
    161                 Callback(this, E, EnumBasedVariantMapAction::Get);
    162             }
    163             return std::get<Variant::Index(E)>(GetVariant(E));
    164         }
    165 
    166     private:
    167         typename Variant::variant_t& GetVariant(Enum e)
    168         {
    169             auto itr = m_data.find(e);
    170             THROW_HR_IF_MSG(E_NOT_SET, itr == m_data.end(), "GetVariant(%d)", static_cast<int>(e));
    171             return itr->second;
    172         }
    173 
    174         const typename Variant::variant_t& GetVariant(Enum e) const
    175         {
    176             auto itr = m_data.find(e);
    177             THROW_HR_IF_MSG(E_NOT_SET, itr == m_data.cend(), "GetVariant(%d)", static_cast<int>(e));
    178             return itr->second;
    179         }
    180 
    181         std::map<Enum, typename Variant::variant_t> m_data;
    182     };
    183 
    184     template<typename E>
    185     std::vector<E> GetAllSequentialEnumValues(E initialToSkip)
    186     {
    187         std::vector<E> result;
    188         using underlying_t = std::underlying_type_t<E>;
    189 
    190         for (underlying_t i = 1 + static_cast<underlying_t>(initialToSkip); i < static_cast<underlying_t>(E::Max); ++i)
    191         {
    192             result.emplace_back(static_cast<E>(i));
    193         }
    194 
    195         return result;
    196     }
    197 
    198     template<typename E>
    199     std::vector<E> GetAllExponentialEnumValues(E initialToSkip)
    200     {
    201         std::vector<E> result;
    202         using underlying_t = std::underlying_type_t<E>;
    203 
    204         for (underlying_t i = 1 + static_cast<underlying_t>(initialToSkip); i < static_cast<underlying_t>(E::Max); i <<= 1)
    205         {
    206             result.emplace_back(static_cast<E>(i));
    207         }
    208 
    209         return result;
    210     }
    211 }
    212 
    213 // Enable enums to be output generically (as their integral value).
    214 template <typename E>
    215 std::enable_if_t<std::is_enum_v<E>, std::ostream&> operator<<(std::ostream& out, E e)
    216 {
    217     return out << AppInstaller::ToIntegral(e);
    218 }
    219 
    220 template <typename T>
    221 struct CopyConstructibleAtomic : public std::atomic<T>
    222 {
    223     using std::atomic<T>::atomic;
    224     using std::atomic<T>::operator=;
    225 
    226     CopyConstructibleAtomic(const CopyConstructibleAtomic& other) :
    227         std::atomic<T>(other.load()) {}
    228 };