# configuration **Repository Path**: feaSYtech/configuration ## Basic Information - **Project Name**: configuration - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-03-12 - **Last Updated**: 2024-11-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ### CommandLine 如,命令行 `program.exe -i input.i --n-threads 4 --mesh-only mach=4 boundary='far wall sym'` ``` TEST(CommandLine, commandline) { CommandLine command_line; command_line.Set(argc, argv); EXPECT_TRUE(command_line.HaveArgv("exe")); EXPECT_TRUE(command_line.HaveArgv("-i")); EXPECT_TRUE(command_line.HaveArgv("input.i")); EXPECT_TRUE(command_line.HaveArgv("--mesh-only")); EXPECT_TRUE(command_line.HaveArgv("--n-threads")); EXPECT_EQ(command_line.Follow("--n-threads"), 4); EXPECT_EQ(command_line.Follow("-value", 101), 101); EXPECT_TRUE(command_line.Follow("-i") == "input.i"); EXPECT_TRUE(command_line.HaveVariable("mach")); EXPECT_FLOAT_EQ(command_line.Get("mach"), 4.0f); EXPECT_FLOAT_EQ(command_line.Get("mach", 0.31234), 4.0f); EXPECT_FLOAT_EQ(command_line.Get("reynolds", 1023.45), 1023.45f); EXPECT_EQ(command_line.VariableSize("mach"), 1); EXPECT_EQ(command_line.VariableSize("no_exit"), 0); EXPECT_EQ(command_line.VariableSize("boundary"), 3); std::vector bnds = command_line.Get>("boundary"); EXPECT_EQ(bnds.size(), 3); EXPECT_EQ(bnds[0], std::string{ "far" }); EXPECT_EQ(bnds[1], std::string{ "wall" }); EXPECT_EQ(bnds[2], std::string{ "sym" }); EXPECT_EQ(command_line.VariableSize("no_exist"), 0); std::vector no_exist = command_line.Get>("no_exist"); EXPECT_EQ(no_exist.size(), 0); command_line.Usage() = "hell world"; EXPECT_EQ(command_line.Usage(), std::string{ "hell world" }); } ``` ### AnyParser AnyParser类,通过Set/Get函数手动存取任意参数,包括, + 基本类型:int, float, double, string, bool + vector类型: vector + 任意指针类型: T* ``` TEST(AnyParser, parser) { AnyParser parser; parser.Set("a", 1); EXPECT_EQ(parser.Get("a"), 1); EXPECT_EQ(parser.Get("a", 2), 1); EXPECT_EQ(parser.Get("b", 2), 2); SomeStruct* app = new SomeStruct; parser.Set("_app", app); EXPECT_EQ(parser.Get("_app"), app); parser.Set("boundary", std::vector{ "far", "wall", "symm" }); auto bnds = parser.Get>("boundary"); EXPECT_EQ(bnds.size(), 3); EXPECT_EQ(bnds[0], std::string{ "far" }); EXPECT_EQ(bnds[1], std::string{ "wall" }); EXPECT_EQ(bnds[2], std::string{ "symm" }); auto blks = parser.Get>("no_exist"); EXPECT_EQ(blks.size(), 0); } ``` ### GetpotParser GetpotParser封装了GetPot类,解析字符串流或文件. GetPot支持多层级的.ini文件,形如 ``` [Parallel] type = cuda num_threads = 8 [] [Mesh] type = FileMesh file = 'f6.exo' boundary_name = 'far wall syms' boundary_id = '1 2 3' [] [BCs] [./wall] type = FarField boundary = 'farfield' [../] [./far] type = Wall boundary='far wall syms' [../] [] ``` ``` TEST(GetpotParser, stringstream) { std::stringstream ss; ss << str; GetpotParser parser; parser.Set(ss); auto& pot = parser.Getpot(); pot.print(); for (auto& i : pot.get_section_names()) { std::cout << i << std::endl; } std::cout << pot("Parallel/type", std::string{}) << std::endl; std::cout << pot.follow(std::string{ "123" }, "Parallel/num_threads=8") << std::endl; EXPECT_TRUE(parser.HaveArgv("Parallel/type=cuda1")); EXPECT_TRUE(parser.HaveVariable("Parallel/type")); EXPECT_TRUE(parser.HaveVariable("BCs/far/boundary")); EXPECT_TRUE(parser.VariableSize("BCs/far/boundary") == 3); parser.SetPrefix("BCs/far/"); std::vector bnds; bnds = parser.Get>("boundary"); EXPECT_EQ(bnds.size(), 3); EXPECT_EQ(bnds[0], std::string{ "far" }); EXPECT_EQ(bnds[1], std::string{ "wall" }); EXPECT_EQ(bnds[2], std::string{ "syms" }); EXPECT_TRUE(is_vector>::value); EXPECT_TRUE(!is_vector::value); EXPECT_TRUE(is_vector_v>); EXPECT_TRUE(!is_vector_v); parser.SetPrefix(""); EXPECT_TRUE(parser.HaveSection("BCs")); EXPECT_TRUE(parser.HaveSection("BCs/")); parser.SetPrefix("BCs"); EXPECT_TRUE(parser.HaveVariable("far/boundary")); parser.SetPrefix("BCs/"); EXPECT_TRUE(parser.HaveVariable("far/boundary")); } ``` ### YamlParser 参考:https://github.com/jbeder/yaml-cpp ### JsonParser 参考: https://github.com/nlohmann/json ### Configuration 由于GetPot不支持指针类型的存取,Configuration类中包含AnyParser和GetpotParser,根据`Get`的类型,从哪种Parser中取值。 ``` TEST(Configuration, operator) { Configuration cfg1; std::stringstream ss; ss << str; cfg1.Set(ss); SomeStruct* app = new SomeStruct; cfg1.Set("_app", app); cfg1.Set("a", 1); Configuration cfg = cfg1; EXPECT_TRUE(cfg.HaveVariable("Parallel/type")); EXPECT_TRUE(cfg.HaveVariable("BCs/far/boundary")); cfg.SetPrefix("Mesh/"); EXPECT_EQ(cfg.Get("file"), std::string{ "f6.exo" }); EXPECT_EQ(cfg.Get("uniform_refine", 1), 1); cfg.SetPrefix("BCs/far/"); std::vector bnds; bnds = cfg.Get>("boundary"); EXPECT_EQ(bnds.size(), 3); EXPECT_EQ(bnds[0], std::string{ "far" }); EXPECT_EQ(bnds[1], std::string{ "wall" }); EXPECT_EQ(bnds[2], std::string{ "syms" }); std::vector no_exist = cfg.Get>("no_exist"); EXPECT_EQ(no_exist.size(), 0); cfg.SetPrefix("BCs"); EXPECT_TRUE(cfg.HaveVariable("far/boundary")); cfg.SetPrefix("BCs/"); EXPECT_TRUE(cfg.HaveVariable("far/boundary")); EXPECT_EQ(cfg.Get("_app"), app); EXPECT_TRUE(cfg.HaveVariable("a")); EXPECT_EQ(cfg.Get("a"), 1); EXPECT_EQ(cfg.Get("a", 23), 1); EXPECT_EQ(cfg.Get("use_some", true), true); } ``` ### Object Object类统一构造函数,从`Configuration`取值,提供两种Get函数, + Get(const std::string& name): Configuration中必须提供参数,否则报错 + Get(const std::string& name, T&& default): 若Configuration中没有参数,返回默认值 ``` class Object { public: Object(const Configuration& cfg) : _cfg(cfg){}; virtual ~Object() = default; protected: template T Get(const std::string& name) const { return _cfg.Get(name); } template T Get(const std::string& name, T&& default) const { return _cfg.Get(name, default); } private: const Configuration& _cfg; }; ``` 子类通过Get函数取值,为属性赋值, ``` class Mesh : public Object { public: Mesh(const Configuration& cfg) : Object(cfg) , _file(Get("file")) , _bnd_names(Get>("boundary_name")) , _bnd_ids(Get>("boundary_id")) { } virtual ~Mesh() = default; public: std::string _file; std::vector _bnd_names; std::vector _bnd_ids; }; ``` ### Factory factory中保存type字符串到子类的构造函数的map,Register/Make函数实现注册/创建 ``` TEST(Factory, Register) { using ObjectFactory = Factory; ObjectFactory factory; factory.Register("FileMesh"); std::string para = R"( [Mesh] type = FileMesh file = 'f6.exo' boundary_name = 'far wall syms' boundary_id = '1 2 3' [] )"; std::stringstream ss(para); Configuration cfg; cfg.Set(ss); cfg.SetPrefix("Mesh/"); auto type = cfg.Get("type"); std::shared_ptr mesh = factory.Make(type, cfg); EXPECT_EQ(mesh->_file, std::string{ "f6.exo" }); auto bnds = mesh->_bnd_names; EXPECT_EQ(bnds.size(), 3); EXPECT_EQ(bnds[0], std::string{ "far" }); EXPECT_EQ(bnds[1], std::string{ "wall" }); EXPECT_EQ(bnds[2], std::string{ "syms" }); } ```