From c59b9d59b803a19a5c269c026b87e6ac84834bec Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Mon, 31 Mar 2014 09:24:56 -0700 Subject: [PATCH] Clean up OptionValue Make the vtables less absurdly huge (knocks 100KB off aegisub32.exe), eliminate some copies of the values when constructing the options, and use an enum class for the value type. --- libaegisub/common/option.cpp | 20 +- libaegisub/common/option_visit.cpp | 20 +- libaegisub/common/option_visit.h | 4 +- libaegisub/include/libaegisub/option_value.h | 191 ++++++++++++------- src/base_grid.cpp | 3 +- src/dialog_paste_over.cpp | 2 +- src/hotkey.cpp | 2 +- src/preferences_base.cpp | 18 +- src/subs_edit_ctrl.cpp | 2 +- tests/tests/option.cpp | 40 ++-- 10 files changed, 174 insertions(+), 128 deletions(-) diff --git a/libaegisub/common/option.cpp b/libaegisub/common/option.cpp index 749ec5a0b..fb011184c 100644 --- a/libaegisub/common/option.cpp +++ b/libaegisub/common/option.cpp @@ -125,43 +125,43 @@ void Options::Flush() const { for (auto const& ov : values) { switch (ov.second->GetType()) { - case OptionValue::Type_String: + case OptionType::String: put_option(obj_out, ov.first, ov.second->GetString()); break; - case OptionValue::Type_Int: + case OptionType::Int: put_option(obj_out, ov.first, ov.second->GetInt()); break; - case OptionValue::Type_Double: + case OptionType::Double: put_option(obj_out, ov.first, ov.second->GetDouble()); break; - case OptionValue::Type_Color: + case OptionType::Color: put_option(obj_out, ov.first, ov.second->GetColor().GetRgbFormatted()); break; - case OptionValue::Type_Bool: + case OptionType::Bool: put_option(obj_out, ov.first, ov.second->GetBool()); break; - case OptionValue::Type_List_String: + case OptionType::ListString: put_array(obj_out, ov.first, "string", ov.second->GetListString()); break; - case OptionValue::Type_List_Int: + case OptionType::ListInt: put_array(obj_out, ov.first, "int", ov.second->GetListInt()); break; - case OptionValue::Type_List_Double: + case OptionType::ListDouble: put_array(obj_out, ov.first, "double", ov.second->GetListDouble()); break; - case OptionValue::Type_List_Color: + case OptionType::ListColor: put_array(obj_out, ov.first, "color", ov.second->GetListColor()); break; - case OptionValue::Type_List_Bool: + case OptionType::ListBool: put_array(obj_out, ov.first, "bool", ov.second->GetListBool()); break; } diff --git a/libaegisub/common/option_visit.cpp b/libaegisub/common/option_visit.cpp index 2e99ef240..f2b57ca7b 100644 --- a/libaegisub/common/option_visit.cpp +++ b/libaegisub/common/option_visit.cpp @@ -59,9 +59,9 @@ void ConfigVisitor::Visit(const json::Object& object) { } } -template -std::unique_ptr ConfigVisitor::ReadArray(json::Array const& src, std::string const& array_type, void (OptionValueType::*)(const std::vector&)) { - std::vector arr; +template +std::unique_ptr ConfigVisitor::ReadArray(json::Array const& src, std::string const& array_type) { + typename OptionValueType::value_type arr; arr.reserve(src.size()); for (json::Object const& obj : src) { @@ -74,10 +74,10 @@ std::unique_ptr ConfigVisitor::ReadArray(json::Array const& src, st return nullptr; } - arr.push_back(ValueType(obj.begin()->second)); + arr.push_back((typename OptionValueType::value_type::value_type)(obj.begin()->second)); } - return util::make_unique(name, arr); + return util::make_unique(name, std::move(arr)); } void ConfigVisitor::Visit(const json::Array& array) { @@ -95,15 +95,15 @@ void ConfigVisitor::Visit(const json::Array& array) { const std::string& array_type = front.begin()->first; if (array_type == "string") - AddOptionValue(ReadArray(array, array_type, &OptionValueListString::SetListString)); + AddOptionValue(ReadArray(array, array_type)); else if (array_type == "int") - AddOptionValue(ReadArray(array, array_type, &OptionValueListInt::SetListInt)); + AddOptionValue(ReadArray(array, array_type)); else if (array_type == "double") - AddOptionValue(ReadArray(array, array_type, &OptionValueListDouble::SetListDouble)); + AddOptionValue(ReadArray(array, array_type)); else if (array_type == "bool") - AddOptionValue(ReadArray(array, array_type, &OptionValueListBool::SetListBool)); + AddOptionValue(ReadArray(array, array_type)); else if (array_type == "color") - AddOptionValue(ReadArray(array, array_type, &OptionValueListColor::SetListColor)); + AddOptionValue(ReadArray(array, array_type)); else Error("Array type not handled"); } diff --git a/libaegisub/common/option_visit.h b/libaegisub/common/option_visit.h index 33eb342d9..48988c0e1 100644 --- a/libaegisub/common/option_visit.h +++ b/libaegisub/common/option_visit.h @@ -46,8 +46,8 @@ class ConfigVisitor final : public json::ConstVisitor { template void Error(const char *message); - template - std::unique_ptr ReadArray(json::Array const& src, std::string const& array_type, void (OptionValueType::*set_list)(const std::vector&)); + template + std::unique_ptr ReadArray(json::Array const& src, std::string const& array_type); void AddOptionValue(std::unique_ptr&& opt); public: diff --git a/libaegisub/include/libaegisub/option_value.h b/libaegisub/include/libaegisub/option_value.h index 185e68a3f..152993c47 100644 --- a/libaegisub/include/libaegisub/option_value.h +++ b/libaegisub/include/libaegisub/option_value.h @@ -27,91 +27,119 @@ namespace agi { DEFINE_BASE_EXCEPTION_NOINNER(OptionValueError, Exception) DEFINE_SIMPLE_EXCEPTION_NOINNER(OptionValueErrorNotFound, OptionValueError, "options/not_found") DEFINE_SIMPLE_EXCEPTION_NOINNER(OptionValueErrorInvalidType, OptionValueError, "options/invalid_type") -DEFINE_SIMPLE_EXCEPTION_NOINNER(OptionValueErrorInvalidListType, OptionValueError, "options/array/invalid_type") + +/// Option type +/// No bitsets here. +enum class OptionType { + String = 0, ///< String + Int = 1, ///< Integer + Double = 2, ///< Double + Color = 3, ///< Color + Bool = 4, ///< Bool + ListString = 100, ///< List of Strings + ListInt = 101, ///< List of Integers + ListDouble = 102, ///< List of Doubles + ListColor = 103, ///< List of Colors + ListBool = 104 ///< List of Bools +}; /// @class OptionValue /// Holds an actual option. class OptionValue { agi::signal::Signal ValueChanged; std::string name; + + std::string TypeToString(OptionType type) const { + switch (type) { + case OptionType::String: return "String"; + case OptionType::Int: return "Integer"; + case OptionType::Double: return "Double"; + case OptionType::Color: return "Color"; + case OptionType::Bool: return "Bool"; + case OptionType::ListString: return "List of Strings"; + case OptionType::ListInt: return "List of Integers"; + case OptionType::ListDouble: return "List of Doubles"; + case OptionType::ListColor: return "List of Colors"; + case OptionType::ListBool: return "List of Bools"; + } + throw agi::InternalError("Invalid option type", nullptr); + } + + OptionValueErrorInvalidType TypeError(OptionType type) const { + return OptionValueErrorInvalidType("Invalid type for option " + name + ": expected " + TypeToString(type) + ", got " + TypeToString(GetType())); + } + + template + T *As(OptionType type) { + if (GetType() == type) + return static_cast(this); + throw TypeError(type); + } + + template + const T *As(OptionType type) const { + if (GetType() == type) + return static_cast(this); + throw TypeError(type); + } + protected: void NotifyChanged() { ValueChanged(*this); } - OptionValueErrorInvalidType TypeError(std::string type, std::string op = " retrieve ") const { - return OptionValueErrorInvalidType("Attempt to" + op + type + " with non-" + type + " value " + GetName()); - } - OptionValueErrorInvalidListType ListTypeError(std::string type, std::string op = " retrieve ") const { - return OptionValueErrorInvalidListType("Attempt to" + op + type + " with non-" + type + " list " + GetName()); - } - OptionValue(std::string name) : name(std::move(name)) { } public: - virtual ~OptionValue() {}; - - /// Option type - /// No bitsets here. - enum OptionType { - Type_String = 0, ///< String - Type_Int = 1, ///< Integer - Type_Double = 2, ///< Double - Type_Color = 3, ///< Color - Type_Bool = 4, ///< Bool - Type_List_String = 100, ///< List of Strings - Type_List_Int = 101, ///< List of Integers - Type_List_Double = 102, ///< List of Doubles - Type_List_Color = 103, ///< List of Colors - Type_List_Bool = 104 ///< List of Bools - }; + virtual ~OptionValue() {} std::string GetName() const { return name; } virtual OptionType GetType() const = 0; virtual bool IsDefault() const = 0; virtual void Reset() = 0; - virtual std::string GetString() const { throw TypeError("string"); } - virtual int64_t GetInt() const { throw TypeError("int"); } - virtual double GetDouble() const { throw TypeError("double"); } - virtual Color GetColor() const { throw TypeError("color"); } - virtual bool GetBool() const { throw TypeError("bool"); } + std::string const& GetString() const; + int64_t const& GetInt() const; + double const& GetDouble() const; + Color const& GetColor() const; + bool const& GetBool() const; - virtual void SetString(const std::string) { throw TypeError("string", " set "); } - virtual void SetInt(const int64_t) { throw TypeError("int", " set "); } - virtual void SetDouble(const double) { throw TypeError("double", " set "); } - virtual void SetColor(const Color) { throw TypeError("color", " set "); } - virtual void SetBool(const bool) { throw TypeError("bool", " set "); } + void SetString(const std::string); + void SetInt(const int64_t); + void SetDouble(const double); + void SetColor(const Color); + void SetBool(const bool); - virtual std::vector const& GetListString() const { throw ListTypeError("string"); } - virtual std::vector const& GetListInt() const { throw ListTypeError("int"); } - virtual std::vector const& GetListDouble() const { throw ListTypeError("double"); } - virtual std::vector const& GetListColor() const { throw ListTypeError("color"); } - virtual std::vector const& GetListBool() const { throw ListTypeError("string"); } + std::vector const& GetListString() const; + std::vector const& GetListInt() const; + std::vector const& GetListDouble() const; + std::vector const& GetListColor() const; + std::vector const& GetListBool() const; - virtual void SetListString(const std::vector&) { throw ListTypeError("string", " set "); } - virtual void SetListInt(const std::vector&) { throw ListTypeError("int", " set "); } - virtual void SetListDouble(const std::vector&) { throw ListTypeError("double", " set "); } - virtual void SetListColor(const std::vector&) { throw ListTypeError("color", " set "); } - virtual void SetListBool(const std::vector&) { throw ListTypeError("string", " set "); } + void SetListString(std::vector); + void SetListInt(std::vector); + void SetListDouble(std::vector); + void SetListColor(std::vector); + void SetListBool(std::vector); virtual void Set(const OptionValue *new_value)=0; DEFINE_SIGNAL_ADDERS(ValueChanged, Subscribe) }; -#define CONFIG_OPTIONVALUE(type_name, type) \ - class OptionValue##type_name final : public OptionValue { \ - type value; \ - type value_default; \ - public: \ - OptionValue##type_name(std::string member_name, type member_value) \ - : OptionValue(std::move(member_name)) \ - , value(member_value), value_default(member_value) { } \ - type Get##type_name() const { return value; } \ - void Set##type_name(const type new_val) { value = new_val; NotifyChanged(); } \ - OptionType GetType() const { return OptionValue::Type_##type_name; } \ - void Reset() { value = value_default; NotifyChanged(); } \ - bool IsDefault() const { return value == value_default; } \ - void Set(const OptionValue *new_val) { Set##type_name(new_val->Get##type_name()); } \ +#define CONFIG_OPTIONVALUE(type_name, type) \ + class OptionValue##type_name final : public OptionValue { \ + type value; \ + type value_default; \ + public: \ + typedef type value_type; \ + OptionValue##type_name(std::string member_name, type member_value) \ + : OptionValue(std::move(member_name)) \ + , value(member_value), value_default(member_value) { } \ + type const& GetValue() const { return value; } \ + void SetValue(type new_val) { value = std::move(new_val); NotifyChanged(); } \ + OptionType GetType() const { return OptionType::type_name; } \ + void Reset() { value = value_default; NotifyChanged(); } \ + bool IsDefault() const { return value == value_default; } \ + void Set(const OptionValue *new_val) { SetValue(new_val->Get##type_name()); } \ }; CONFIG_OPTIONVALUE(String, std::string) @@ -120,21 +148,22 @@ CONFIG_OPTIONVALUE(Double, double) CONFIG_OPTIONVALUE(Color, Color) CONFIG_OPTIONVALUE(Bool, bool) -#define CONFIG_OPTIONVALUE_LIST(type_name, type) \ - class OptionValueList##type_name final : public OptionValue { \ - std::vector array; \ - std::vector array_default; \ - std::string name; \ - public: \ +#define CONFIG_OPTIONVALUE_LIST(type_name, type) \ + class OptionValueList##type_name final : public OptionValue { \ + std::vector array; \ + std::vector array_default; \ + std::string name; \ + public: \ + typedef std::vector value_type; \ OptionValueList##type_name(std::string name, std::vector const& value = std::vector()) \ - : OptionValue(std::move(name)) \ - , array(value), array_default(value) { } \ - std::vector const& GetList##type_name() const { return array; } \ - void SetList##type_name(const std::vector& val) { array = val; NotifyChanged(); } \ - OptionType GetType() const { return OptionValue::Type_List_##type_name; } \ - void Reset() { array = array_default; NotifyChanged(); } \ - bool IsDefault() const { return array == array_default; } \ - void Set(const OptionValue *nv) { SetList##type_name(nv->GetList##type_name()); } \ + : OptionValue(std::move(name)) \ + , array(value), array_default(value) { } \ + std::vector const& GetValue() const { return array; } \ + void SetValue(std::vector val) { array = std::move(val); NotifyChanged(); } \ + OptionType GetType() const { return OptionType::List##type_name; } \ + void Reset() { array = array_default; NotifyChanged(); } \ + bool IsDefault() const { return array == array_default; } \ + void Set(const OptionValue *nv) { SetValue(nv->GetList##type_name()); } \ }; CONFIG_OPTIONVALUE_LIST(String, std::string) @@ -143,4 +172,22 @@ CONFIG_OPTIONVALUE_LIST(Double, double) CONFIG_OPTIONVALUE_LIST(Color, Color) CONFIG_OPTIONVALUE_LIST(Bool, bool) +#define CONFIG_OPTIONVALUE_ACCESSORS(ReturnType, Type) \ + inline ReturnType const& OptionValue::Get##Type() const { return As(OptionType::Type)->GetValue(); } \ + inline void OptionValue::Set##Type(ReturnType v) { As(OptionType::Type)->SetValue(std::move(v)); } + +CONFIG_OPTIONVALUE_ACCESSORS(std::string, String) +CONFIG_OPTIONVALUE_ACCESSORS(int64_t, Int) +CONFIG_OPTIONVALUE_ACCESSORS(double, Double) +CONFIG_OPTIONVALUE_ACCESSORS(Color, Color) +CONFIG_OPTIONVALUE_ACCESSORS(bool, Bool) +CONFIG_OPTIONVALUE_ACCESSORS(std::vector, ListString) +CONFIG_OPTIONVALUE_ACCESSORS(std::vector, ListInt) +CONFIG_OPTIONVALUE_ACCESSORS(std::vector, ListDouble) +CONFIG_OPTIONVALUE_ACCESSORS(std::vector, ListColor) +CONFIG_OPTIONVALUE_ACCESSORS(std::vector, ListBool) + +#undef CONFIG_OPTIONVALUE +#undef CONFIG_OPTIONVALUE_LIST +#undef CONFIG_OPTIONVALUE_ACCESSORS } // namespace agi diff --git a/src/base_grid.cpp b/src/base_grid.cpp index 77040ed87..b412dd589 100644 --- a/src/base_grid.cpp +++ b/src/base_grid.cpp @@ -176,8 +176,7 @@ void BaseGrid::OnShowColMenu(wxCommandEvent &event) { int item = event.GetId() - MENU_SHOW_COL; showCol[item] = !showCol[item]; - std::vector map(std::begin(showCol), std::end(showCol)); - OPT_SET("Subtitle/Grid/Column")->SetListBool(map); + OPT_SET("Subtitle/Grid/Column")->SetListBool(std::vector(std::begin(showCol), std::end(showCol))); SetColumnWidths(); Refresh(false); diff --git a/src/dialog_paste_over.cpp b/src/dialog_paste_over.cpp index 4f638ad7e..189289f54 100644 --- a/src/dialog_paste_over.cpp +++ b/src/dialog_paste_over.cpp @@ -106,7 +106,7 @@ void DialogPasteOver::OnOK(wxCommandEvent &) { std::vector options; for (size_t i = 0; i < ListBox->GetCount(); ++i) options.push_back(ListBox->IsChecked(i)); - OPT_SET("Tool/Paste Lines Over/Fields")->SetListBool(options); + OPT_SET("Tool/Paste Lines Over/Fields")->SetListBool(std::move(options)); EndModal(0); } diff --git a/src/hotkey.cpp b/src/hotkey.cpp index 7fe9ae73a..d07006eb9 100644 --- a/src/hotkey.cpp +++ b/src/hotkey.cpp @@ -117,7 +117,7 @@ void init() { migrations.emplace_back("duplicate -> split"); } - OPT_SET("App/Hotkey Migrations")->SetListString(migrations); + OPT_SET("App/Hotkey Migrations")->SetListString(std::move(migrations)); } void clear() { diff --git a/src/preferences_base.cpp b/src/preferences_base.cpp index 668504398..ff8b75d1b 100644 --- a/src/preferences_base.cpp +++ b/src/preferences_base.cpp @@ -117,7 +117,7 @@ wxControl *OptionPage::OptionAdd(wxFlexGridSizer *flex, const wxString &name, co const agi::OptionValue *opt = OPT_GET(opt_name); switch (opt->GetType()) { - case agi::OptionValue::Type_Bool: { + case agi::OptionType::Bool: { wxCheckBox *cb = new wxCheckBox(this, -1, name); flex->Add(cb, 1, wxEXPAND, 0); cb->SetValue(opt->GetBool()); @@ -125,28 +125,28 @@ wxControl *OptionPage::OptionAdd(wxFlexGridSizer *flex, const wxString &name, co return cb; } - case agi::OptionValue::Type_Int: { + case agi::OptionType::Int: { wxSpinCtrl *sc = new wxSpinCtrl(this, -1, std::to_wstring((int)opt->GetInt()), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, min, max, opt->GetInt()); sc->Bind(wxEVT_SPINCTRL, IntUpdater(opt_name, parent)); Add(flex, name, sc); return sc; } - case agi::OptionValue::Type_Double: { + case agi::OptionType::Double: { wxSpinCtrlDouble *scd = new wxSpinCtrlDouble(this, -1, wxString::Format("%g", opt->GetDouble()), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, min, max, opt->GetDouble(), inc); scd->Bind(wxEVT_SPINCTRL, DoubleUpdater(opt_name, parent)); Add(flex, name, scd); return scd; } - case agi::OptionValue::Type_String: { + case agi::OptionType::String: { wxTextCtrl *text = new wxTextCtrl(this, -1 , to_wx(opt->GetString())); text->Bind(wxEVT_TEXT, StringUpdater(opt_name, parent)); Add(flex, name, text); return text; } - case agi::OptionValue::Type_Color: { + case agi::OptionType::Color: { auto cb = new ColourButton(this, wxSize(40,10), false, opt->GetColor()); cb->Bind(EVT_COLOR, ColourUpdater(opt_name, parent)); Add(flex, name, cb); @@ -166,13 +166,13 @@ void OptionPage::OptionChoice(wxFlexGridSizer *flex, const wxString &name, const Add(flex, name, cb); switch (opt->GetType()) { - case agi::OptionValue::Type_Int: { + case agi::OptionType::Int: { int val = opt->GetInt(); cb->Select(val < (int)choices.size() ? val : 0); cb->Bind(wxEVT_COMBOBOX, IntCBUpdater(opt_name, parent)); break; } - case agi::OptionValue::Type_String: { + case agi::OptionType::String: { wxString val(to_wx(opt->GetString())); if (cb->FindString(val) != wxNOT_FOUND) cb->SetStringSelection(val); @@ -201,8 +201,8 @@ void OptionPage::OptionBrowse(wxFlexGridSizer *flex, const wxString &name, const parent->AddChangeableOption(opt_name); const agi::OptionValue *opt = OPT_GET(opt_name); - if (opt->GetType() != agi::OptionValue::Type_String) - throw PreferenceIncorrectType("Option must be agi::OptionValue::Type_String for BrowseButton."); + if (opt->GetType() != agi::OptionType::String) + throw PreferenceIncorrectType("Option must be agi::OptionType::String for BrowseButton."); wxTextCtrl *text = new wxTextCtrl(this, -1 , to_wx(opt->GetString())); text->SetMinSize(wxSize(160, -1)); diff --git a/src/subs_edit_ctrl.cpp b/src/subs_edit_ctrl.cpp index 970acff67..a6c4bf4bc 100644 --- a/src/subs_edit_ctrl.cpp +++ b/src/subs_edit_ctrl.cpp @@ -200,7 +200,7 @@ void SubsTextEditCtrl::SetSyntaxStyle(int id, wxFont &font, std::string const& n StyleSetBold(id, OPT_GET("Colour/Subtitle/Syntax/Bold/" + name)->GetBool()); StyleSetForeground(id, to_wx(OPT_GET("Colour/Subtitle/Syntax/" + name)->GetColor())); const agi::OptionValue *background = OPT_GET("Colour/Subtitle/Syntax/Background/" + name); - if (background->GetType() == agi::OptionValue::Type_Color) + if (background->GetType() == agi::OptionType::Color) StyleSetBackground(id, to_wx(background->GetColor())); } diff --git a/tests/tests/option.cpp b/tests/tests/option.cpp index 237227757..e5f588b14 100644 --- a/tests/tests/option.cpp +++ b/tests/tests/option.cpp @@ -212,50 +212,50 @@ TEST_F(lagi_option, empty_array_decays_to_first_used_type) { empty_arr_options opt; EXPECT_NO_THROW(opt.Get("arr")->GetListBool()); - EXPECT_THROW(opt.Get("arr")->GetListColor(), agi::OptionValueErrorInvalidListType); - EXPECT_THROW(opt.Get("arr")->GetListDouble(), agi::OptionValueErrorInvalidListType); - EXPECT_THROW(opt.Get("arr")->GetListInt(), agi::OptionValueErrorInvalidListType); - EXPECT_THROW(opt.Get("arr")->GetListString(), agi::OptionValueErrorInvalidListType); + EXPECT_THROW(opt.Get("arr")->GetListColor(), agi::OptionValueErrorInvalidType); + EXPECT_THROW(opt.Get("arr")->GetListDouble(), agi::OptionValueErrorInvalidType); + EXPECT_THROW(opt.Get("arr")->GetListInt(), agi::OptionValueErrorInvalidType); + EXPECT_THROW(opt.Get("arr")->GetListString(), agi::OptionValueErrorInvalidType); } { empty_arr_options opt; EXPECT_NO_THROW(opt.Get("arr")->GetListColor()); - EXPECT_THROW(opt.Get("arr")->GetListBool(), agi::OptionValueErrorInvalidListType); - EXPECT_THROW(opt.Get("arr")->GetListDouble(), agi::OptionValueErrorInvalidListType); - EXPECT_THROW(opt.Get("arr")->GetListInt(), agi::OptionValueErrorInvalidListType); - EXPECT_THROW(opt.Get("arr")->GetListString(), agi::OptionValueErrorInvalidListType); + EXPECT_THROW(opt.Get("arr")->GetListBool(), agi::OptionValueErrorInvalidType); + EXPECT_THROW(opt.Get("arr")->GetListDouble(), agi::OptionValueErrorInvalidType); + EXPECT_THROW(opt.Get("arr")->GetListInt(), agi::OptionValueErrorInvalidType); + EXPECT_THROW(opt.Get("arr")->GetListString(), agi::OptionValueErrorInvalidType); } { empty_arr_options opt; EXPECT_NO_THROW(opt.Get("arr")->GetListDouble()); - EXPECT_THROW(opt.Get("arr")->GetListBool(), agi::OptionValueErrorInvalidListType); - EXPECT_THROW(opt.Get("arr")->GetListColor(), agi::OptionValueErrorInvalidListType); - EXPECT_THROW(opt.Get("arr")->GetListInt(), agi::OptionValueErrorInvalidListType); - EXPECT_THROW(opt.Get("arr")->GetListString(), agi::OptionValueErrorInvalidListType); + EXPECT_THROW(opt.Get("arr")->GetListBool(), agi::OptionValueErrorInvalidType); + EXPECT_THROW(opt.Get("arr")->GetListColor(), agi::OptionValueErrorInvalidType); + EXPECT_THROW(opt.Get("arr")->GetListInt(), agi::OptionValueErrorInvalidType); + EXPECT_THROW(opt.Get("arr")->GetListString(), agi::OptionValueErrorInvalidType); } { empty_arr_options opt; EXPECT_NO_THROW(opt.Get("arr")->GetListInt()); - EXPECT_THROW(opt.Get("arr")->GetListBool(), agi::OptionValueErrorInvalidListType); - EXPECT_THROW(opt.Get("arr")->GetListColor(), agi::OptionValueErrorInvalidListType); - EXPECT_THROW(opt.Get("arr")->GetListDouble(), agi::OptionValueErrorInvalidListType); - EXPECT_THROW(opt.Get("arr")->GetListString(), agi::OptionValueErrorInvalidListType); + EXPECT_THROW(opt.Get("arr")->GetListBool(), agi::OptionValueErrorInvalidType); + EXPECT_THROW(opt.Get("arr")->GetListColor(), agi::OptionValueErrorInvalidType); + EXPECT_THROW(opt.Get("arr")->GetListDouble(), agi::OptionValueErrorInvalidType); + EXPECT_THROW(opt.Get("arr")->GetListString(), agi::OptionValueErrorInvalidType); } { empty_arr_options opt; EXPECT_NO_THROW(opt.Get("arr")->GetListString()); - EXPECT_THROW(opt.Get("arr")->GetListBool(), agi::OptionValueErrorInvalidListType); - EXPECT_THROW(opt.Get("arr")->GetListColor(), agi::OptionValueErrorInvalidListType); - EXPECT_THROW(opt.Get("arr")->GetListDouble(), agi::OptionValueErrorInvalidListType); - EXPECT_THROW(opt.Get("arr")->GetListInt(), agi::OptionValueErrorInvalidListType); + EXPECT_THROW(opt.Get("arr")->GetListBool(), agi::OptionValueErrorInvalidType); + EXPECT_THROW(opt.Get("arr")->GetListColor(), agi::OptionValueErrorInvalidType); + EXPECT_THROW(opt.Get("arr")->GetListDouble(), agi::OptionValueErrorInvalidType); + EXPECT_THROW(opt.Get("arr")->GetListInt(), agi::OptionValueErrorInvalidType); } }