1 #pragma once 2 3 #include <wayfire/config/types.hpp> 4 #include <wayfire/config/option.hpp> 5 #include <wayfire/util/log.hpp> 6 #include <vector> 7 #include <map> 8 #include <cassert> 9 10 namespace wf 11 { 12 namespace config 13 { 14 template<class... Args> 15 using compound_list_t = 16 std::vector<std::tuple<std::string, Args...>>; 17 18 /** 19 * A base class containing information about an entry in a tuple. 20 */ 21 class compound_option_entry_base_t 22 { 23 public: 24 25 virtual ~compound_option_entry_base_t() = default; 26 27 /** @return The prefix of the tuple entry. */ get_prefix() const28 virtual std::string get_prefix() const 29 { 30 return prefix; 31 } 32 33 /** 34 * Try to parse the given value. 35 * 36 * @param update Whether to override the stored value. 37 */ 38 virtual bool is_parsable(const std::string&) const = 0; 39 40 /** Clone this entry */ 41 virtual compound_option_entry_base_t *clone() const = 0; 42 43 protected: 44 compound_option_entry_base_t() = default; 45 std::string prefix; 46 }; 47 48 template<class Type> 49 class compound_option_entry_t : public compound_option_entry_base_t 50 { 51 public: compound_option_entry_t(const std::string & prefix)52 compound_option_entry_t(const std::string& prefix) 53 { 54 this->prefix = prefix; 55 } 56 clone() const57 compound_option_entry_base_t *clone() const override 58 { 59 return new compound_option_entry_t<Type>(this->get_prefix()); 60 } 61 62 /** 63 * Try to parse the given value. 64 * 65 * @param update Whether to override the stored value. 66 */ is_parsable(const std::string & str) const67 bool is_parsable(const std::string& str) const override 68 { 69 return option_type::from_string<Type>(str).has_value(); 70 } 71 }; 72 73 /** 74 * Compound options are a special class of options which can hold multiple 75 * string-tagged tuples. They are constructed from multiple untyped options 76 * in the config file. 77 */ 78 79 class compound_option_t : public option_base_t 80 { 81 public: 82 using entries_t = std::vector<std::unique_ptr<compound_option_entry_base_t>>; 83 /** 84 * Construct a new compound option, with the types given in the template 85 * arguments. 86 * 87 * @param name The name of the option. 88 * @param prefixes The prefixes used for grouping in the config file. 89 * Example: Consider a compound option with type <int, double> and two 90 * prefixes {"prefix1_", "prefix2_"}. In the config file, the options are: 91 * 92 * prefix1_key1 = v11 93 * prefix2_key1 = v21 94 * prefix1_key2 = v12 95 * prefix2_key2 = v22 96 * 97 * Options are grouped by suffixes (key1 and key2), and the tuples then 98 * are formed by taking the values of the options with each prefix. 99 * So, the tuples contained in the compound option in the end are: 100 * 101 * (key1, v11, v21) 102 * (key2, v12, v22) 103 */ 104 compound_option_t(const std::string& name, entries_t&& entries); 105 106 /** 107 * Parse the compound option with the given types. 108 * 109 * Throws an exception in case of wrong template types. 110 */ 111 template<class... Args> get_value() const112 compound_list_t<Args...> get_value() const 113 { 114 compound_list_t<Args...> result; 115 result.resize(value.size()); 116 build_recursive<0, Args...>(result); 117 return result; 118 } 119 120 /** 121 * Set the value of the option. 122 * 123 * Throws an exception in case of wrong template types. 124 */ 125 template<class... Args> set_value(const compound_list_t<Args...> & value)126 void set_value(const compound_list_t<Args...>& value) 127 { 128 assert(sizeof...(Args) == this->entries.size()); 129 this->value.assign(value.size(), {}); 130 push_recursive<0>(value); 131 notify_updated(); 132 } 133 134 using stored_type_t = std::vector<std::vector<std::string>>; 135 /** 136 * Get the string data stored in the compound option. 137 */ 138 stored_type_t get_value_untyped(); 139 140 /** 141 * Set the data contained in the option, from a vector containing 142 * strings which describe the individual elements. 143 * 144 * @return True if the operation was successful. 145 */ 146 bool set_value_untyped(stored_type_t value); 147 148 /** 149 * Get the type information about entries in the option. 150 */ 151 const entries_t& get_entries() const; 152 153 private: 154 /** 155 * Current value stored in the option. 156 * The first element is the name of the tuple, followed by the string values 157 * of each element. 158 */ 159 stored_type_t value; 160 161 /** Entry types with which the option was created. */ 162 entries_t entries; 163 164 /** 165 * Set the n-th element in the result tuples by reading from the stored 166 * values in this option. 167 */ 168 template<size_t n, class... Args> build_recursive(compound_list_t<Args...> & result) const169 void build_recursive(compound_list_t<Args...>& result) const 170 { 171 for (size_t i = 0; i < result.size(); i++) 172 { 173 using type_t = typename std::tuple_element<n, 174 std::tuple<std::string, Args...>>::type; 175 176 std::get<n>(result[i]) = option_type::from_string<type_t>( 177 this->value[i][n]).value(); 178 } 179 180 // Recursively build the (N+1)'th entries 181 if constexpr (n < sizeof...(Args)) 182 { 183 build_recursive<n + 1>(result); 184 } 185 } 186 187 template<size_t n, class... Args> push_recursive(const compound_list_t<Args...> & new_value)188 void push_recursive(const compound_list_t<Args...>& new_value) 189 { 190 for (size_t i = 0; i < new_value.size(); i++) 191 { 192 using type_t = typename std::tuple_element<n, 193 std::tuple<std::string, Args...>>::type; 194 195 this->value[i].push_back(option_type::to_string<type_t>( 196 std::get<n>(new_value[i]))); 197 } 198 199 // Recursively build the (N+1)'th entries 200 if constexpr (n < sizeof...(Args)) 201 { 202 push_recursive<n + 1>(new_value); 203 } 204 } 205 206 public: // Implementation of option_base_t 207 std::shared_ptr<option_base_t> clone_option() const override; 208 bool set_value_str(const std::string&) override; 209 void reset_to_default() override; 210 bool set_default_value_str(const std::string&) override; 211 std::string get_value_str() const override; 212 std::string get_default_value_str() const override; 213 }; 214 } 215 } 216