Common: add ParamPackage
This commit is contained in:
		| @@ -35,6 +35,7 @@ set(SRCS | ||||
|             memory_util.cpp | ||||
|             microprofile.cpp | ||||
|             misc.cpp | ||||
|             param_package.cpp | ||||
|             scm_rev.cpp | ||||
|             string_util.cpp | ||||
|             symbols.cpp | ||||
| @@ -66,6 +67,7 @@ set(HEADERS | ||||
|             memory_util.h | ||||
|             microprofile.h | ||||
|             microprofileui.h | ||||
|             param_package.h | ||||
|             platform.h | ||||
|             quaternion.h | ||||
|             scm_rev.h | ||||
|   | ||||
							
								
								
									
										120
									
								
								src/common/param_package.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								src/common/param_package.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,120 @@ | ||||
| // Copyright 2017 Citra Emulator Project | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #include <array> | ||||
| #include <vector> | ||||
| #include "common/logging/log.h" | ||||
| #include "common/param_package.h" | ||||
| #include "common/string_util.h" | ||||
|  | ||||
| namespace Common { | ||||
|  | ||||
| constexpr char KEY_VALUE_SEPARATOR = ':'; | ||||
| constexpr char PARAM_SEPARATOR = ','; | ||||
| constexpr char ESCAPE_CHARACTER = '$'; | ||||
| const std::string KEY_VALUE_SEPARATOR_ESCAPE{ESCAPE_CHARACTER, '0'}; | ||||
| const std::string PARAM_SEPARATOR_ESCAPE{ESCAPE_CHARACTER, '1'}; | ||||
| const std::string ESCAPE_CHARACTER_ESCAPE{ESCAPE_CHARACTER, '2'}; | ||||
|  | ||||
| ParamPackage::ParamPackage(const std::string& serialized) { | ||||
|     std::vector<std::string> pairs; | ||||
|     Common::SplitString(serialized, PARAM_SEPARATOR, pairs); | ||||
|  | ||||
|     for (const std::string& pair : pairs) { | ||||
|         std::vector<std::string> key_value; | ||||
|         Common::SplitString(pair, KEY_VALUE_SEPARATOR, key_value); | ||||
|         if (key_value.size() != 2) { | ||||
|             LOG_ERROR(Common, "invalid key pair %s", pair.c_str()); | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         for (std::string& part : key_value) { | ||||
|             part = Common::ReplaceAll(part, KEY_VALUE_SEPARATOR_ESCAPE, {KEY_VALUE_SEPARATOR}); | ||||
|             part = Common::ReplaceAll(part, PARAM_SEPARATOR_ESCAPE, {PARAM_SEPARATOR}); | ||||
|             part = Common::ReplaceAll(part, ESCAPE_CHARACTER_ESCAPE, {ESCAPE_CHARACTER}); | ||||
|         } | ||||
|  | ||||
|         Set(key_value[0], key_value[1]); | ||||
|     } | ||||
| } | ||||
|  | ||||
| ParamPackage::ParamPackage(std::initializer_list<DataType::value_type> list) : data(list) {} | ||||
|  | ||||
| std::string ParamPackage::Serialize() const { | ||||
|     if (data.empty()) | ||||
|         return ""; | ||||
|  | ||||
|     std::string result; | ||||
|  | ||||
|     for (const auto& pair : data) { | ||||
|         std::array<std::string, 2> key_value{{pair.first, pair.second}}; | ||||
|         for (std::string& part : key_value) { | ||||
|             part = Common::ReplaceAll(part, {ESCAPE_CHARACTER}, ESCAPE_CHARACTER_ESCAPE); | ||||
|             part = Common::ReplaceAll(part, {PARAM_SEPARATOR}, PARAM_SEPARATOR_ESCAPE); | ||||
|             part = Common::ReplaceAll(part, {KEY_VALUE_SEPARATOR}, KEY_VALUE_SEPARATOR_ESCAPE); | ||||
|         } | ||||
|         result += key_value[0] + KEY_VALUE_SEPARATOR + key_value[1] + PARAM_SEPARATOR; | ||||
|     } | ||||
|  | ||||
|     result.pop_back(); // discard the trailing PARAM_SEPARATOR | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| std::string ParamPackage::Get(const std::string& key, const std::string& default_value) const { | ||||
|     auto pair = data.find(key); | ||||
|     if (pair == data.end()) { | ||||
|         LOG_DEBUG(Common, "key %s not found", key.c_str()); | ||||
|         return default_value; | ||||
|     } | ||||
|  | ||||
|     return pair->second; | ||||
| } | ||||
|  | ||||
| int ParamPackage::Get(const std::string& key, int default_value) const { | ||||
|     auto pair = data.find(key); | ||||
|     if (pair == data.end()) { | ||||
|         LOG_DEBUG(Common, "key %s not found", key.c_str()); | ||||
|         return default_value; | ||||
|     } | ||||
|  | ||||
|     try { | ||||
|         return std::stoi(pair->second); | ||||
|     } catch (const std::logic_error&) { | ||||
|         LOG_ERROR(Common, "failed to convert %s to int", pair->second.c_str()); | ||||
|         return default_value; | ||||
|     } | ||||
| } | ||||
|  | ||||
| float ParamPackage::Get(const std::string& key, float default_value) const { | ||||
|     auto pair = data.find(key); | ||||
|     if (pair == data.end()) { | ||||
|         LOG_DEBUG(Common, "key %s not found", key.c_str()); | ||||
|         return default_value; | ||||
|     } | ||||
|  | ||||
|     try { | ||||
|         return std::stof(pair->second); | ||||
|     } catch (const std::logic_error&) { | ||||
|         LOG_ERROR(Common, "failed to convert %s to float", pair->second.c_str()); | ||||
|         return default_value; | ||||
|     } | ||||
| } | ||||
|  | ||||
| void ParamPackage::Set(const std::string& key, const std::string& value) { | ||||
|     data[key] = value; | ||||
| } | ||||
|  | ||||
| void ParamPackage::Set(const std::string& key, int value) { | ||||
|     data[key] = std::to_string(value); | ||||
| } | ||||
|  | ||||
| void ParamPackage::Set(const std::string& key, float value) { | ||||
|     data[key] = std::to_string(value); | ||||
| } | ||||
|  | ||||
| bool ParamPackage::Has(const std::string& key) const { | ||||
|     return data.find(key) != data.end(); | ||||
| } | ||||
|  | ||||
| } // namespace Common | ||||
							
								
								
									
										40
									
								
								src/common/param_package.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/common/param_package.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| // Copyright 2017 Citra Emulator Project | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <initializer_list> | ||||
| #include <string> | ||||
| #include <unordered_map> | ||||
|  | ||||
| namespace Common { | ||||
|  | ||||
| /// A string-based key-value container supporting serializing to and deserializing from a string | ||||
| class ParamPackage { | ||||
| public: | ||||
|     using DataType = std::unordered_map<std::string, std::string>; | ||||
|  | ||||
|     ParamPackage() = default; | ||||
|     explicit ParamPackage(const std::string& serialized); | ||||
|     ParamPackage(std::initializer_list<DataType::value_type> list); | ||||
|     ParamPackage(const ParamPackage& other) = default; | ||||
|     ParamPackage(ParamPackage&& other) = default; | ||||
|  | ||||
|     ParamPackage& operator=(const ParamPackage& other) = default; | ||||
|     ParamPackage& operator=(ParamPackage&& other) = default; | ||||
|  | ||||
|     std::string Serialize() const; | ||||
|     std::string Get(const std::string& key, const std::string& default_value) const; | ||||
|     int Get(const std::string& key, int default_value) const; | ||||
|     float Get(const std::string& key, float default_value) const; | ||||
|     void Set(const std::string& key, const std::string& value); | ||||
|     void Set(const std::string& key, int value); | ||||
|     void Set(const std::string& key, float value); | ||||
|     bool Has(const std::string& key) const; | ||||
|  | ||||
| private: | ||||
|     DataType data; | ||||
| }; | ||||
|  | ||||
| } // namespace Common | ||||
| @@ -1,6 +1,7 @@ | ||||
| set(SRCS | ||||
|             glad.cpp | ||||
|             tests.cpp | ||||
|             common/param_package.cpp | ||||
|             core/file_sys/path_parser.cpp | ||||
|             ) | ||||
|  | ||||
|   | ||||
							
								
								
									
										25
									
								
								src/tests/common/param_package.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/tests/common/param_package.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| // Copyright 2017 Citra Emulator Project | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #include <catch.hpp> | ||||
| #include <math.h> | ||||
| #include "common/param_package.h" | ||||
|  | ||||
| namespace Common { | ||||
|  | ||||
| TEST_CASE("ParamPackage", "[common]") { | ||||
|     ParamPackage original{ | ||||
|         {"abc", "xyz"}, {"def", "42"}, {"jkl", "$$:1:$2$,3"}, | ||||
|     }; | ||||
|     original.Set("ghi", 3.14f); | ||||
|     ParamPackage copy(original.Serialize()); | ||||
|     REQUIRE(copy.Get("abc", "") == "xyz"); | ||||
|     REQUIRE(copy.Get("def", 0) == 42); | ||||
|     REQUIRE(std::abs(copy.Get("ghi", 0.0f) - 3.14f) < 0.01f); | ||||
|     REQUIRE(copy.Get("jkl", "") == "$$:1:$2$,3"); | ||||
|     REQUIRE(copy.Get("mno", "uvw") == "uvw"); | ||||
|     REQUIRE(copy.Get("abc", 42) == 42); | ||||
| } | ||||
|  | ||||
| } // namespace Common | ||||
		Reference in New Issue
	
	Block a user
	 wwylele
					wwylele