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 };