17 #include "configurer.h"
18 #include "rapidjson/document.h"
19 #include "rapidjson/error/en.h"
22 #include <fmt/format.h>
24 #include <rapidjson/istreamwrapper.h>
25 #include <rapidjson/ostreamwrapper.h>
26 #include <rapidjson/prettywriter.h>
27 #include <unordered_map>
30 using namespace rapidjson;
31 using writer_type = PrettyWriter<OStreamWrapper>;
33 inline auto get_sc_objects(sc_core::sc_object* obj =
nullptr) ->
const std::vector<sc_core::sc_object*>& {
35 return obj->get_child_objects();
37 return sc_core::sc_get_top_level_objects();
40 #define FDECL(TYPE, FUNC) \
41 inline void writeValue(writer_type& writer, std::string const& key, TYPE value) { \
42 writer.Key(key.c_str()); \
46 FDECL(
unsigned int, Uint)
48 FDECL(
unsigned long, Uint64)
49 FDECL(
long long, Int64)
50 FDECL(
unsigned long long, Uint64)
54 FDECL(
char const*, String)
55 inline void writeValue(writer_type& writer, std::string
const& key, std::string
const& value) {
56 writer.Key(key.c_str());
57 writer.String(value.c_str());
60 template <
typename T>
auto check_n_assign(writer_type& writer, sc_core::sc_attr_base* attr_base) ->
bool {
61 auto* a =
dynamic_cast<sc_core::sc_attribute<T>*
>(attr_base);
63 writeValue(writer, a->name(), a->value);
69 template <>
auto check_n_assign<sc_core::sc_time>(writer_type& writer, sc_core::sc_attr_base* attr_base) ->
bool {
70 auto* a =
dynamic_cast<sc_core::sc_attribute<sc_core::sc_time>*
>(attr_base);
72 writeValue(writer, a->name(), a->value.to_double());
78 inline bool start_object(writer_type& writer,
char const* key,
bool started) {
86 struct config_dumper {
89 void dump_config(sc_core::sc_object* obj, writer_type& writer) {
90 auto start = std::string(obj->basename()).substr(0, 3);
93 auto obj_started =
false;
94 for(sc_core::sc_attr_base* attr_base : obj->attr_cltn()) {
95 obj_started = start_object(writer, obj->basename(), obj_started);
96 check_n_assign<int>(writer, attr_base) || check_n_assign<unsigned>(writer, attr_base) ||
97 check_n_assign<long>(writer, attr_base) || check_n_assign<unsigned long>(writer, attr_base) ||
98 check_n_assign<long long>(writer, attr_base) || check_n_assign<unsigned long long>(writer, attr_base) ||
99 check_n_assign<bool>(writer, attr_base) || check_n_assign<float>(writer, attr_base) ||
100 check_n_assign<double>(writer, attr_base) || check_n_assign<std::string>(writer, attr_base) ||
101 check_n_assign<char*>(writer, attr_base) || check_n_assign<sc_core::sc_time>(writer, attr_base);
103 for(
auto* o : get_sc_objects(obj)) {
104 obj_started = start_object(writer, obj->basename(), obj_started);
105 dump_config(o, writer);
112 #define CHECK_N_ASSIGN(TYPE, ATTR, VAL) \
114 auto* a = dynamic_cast<sc_core::sc_attribute<TYPE>*>(ATTR); \
121 void try_set_value(sc_core::sc_attr_base* attr_base, Value
const& hier_val) {
122 CHECK_N_ASSIGN(
int, attr_base, hier_val.Get<
int>());
123 CHECK_N_ASSIGN(
unsigned, attr_base, hier_val.Get<
unsigned>());
124 CHECK_N_ASSIGN(int64_t, attr_base, hier_val.Get<int64_t>());
125 CHECK_N_ASSIGN(uint64_t, attr_base, hier_val.Get<uint64_t>());
126 CHECK_N_ASSIGN(
bool, attr_base, hier_val.Get<
bool>());
127 CHECK_N_ASSIGN(
float, attr_base, hier_val.Get<
float>());
128 CHECK_N_ASSIGN(
double, attr_base, hier_val.Get<
double>());
129 CHECK_N_ASSIGN(std::string, attr_base, std::string(hier_val.GetString()));
130 CHECK_N_ASSIGN(
char*, attr_base, strdup(hier_val.GetString()));
132 auto* a =
dynamic_cast<sc_core::sc_attribute<sc_core::sc_time>*
>(attr_base);
134 a->value = sc_core::sc_time(hier_val.Get<
double>(), sc_core::SC_SEC);
140 void configure_sc_attribute_hierarchical(Value
const& node, std::string
const& prefix) {
141 for(
auto itr = node.MemberBegin(); itr != node.MemberEnd(); ++itr) {
142 if(!itr->name.IsString())
144 auto key_name = itr->name.GetString();
145 if(strncmp(key_name,
"log_level", 9) == 0)
147 auto hier_name = prefix.size() ? prefix +
"." + key_name : key_name;
148 Value
const& val = itr->value;
149 if(val.IsNull() || val.IsArray())
151 else if(val.IsObject()) {
152 if(sc_core::sc_find_object(hier_name.c_str())) {
153 configure_sc_attribute_hierarchical(val, hier_name);
156 auto pos = hier_name.rfind(
'.');
157 if(pos != std::string::npos) {
158 auto objname = hier_name.substr(0, pos);
159 auto attrname = hier_name.substr(pos + 1);
160 if(
auto* obj = sc_core::sc_find_object(objname.c_str()))
161 if(
auto attr = obj->get_attribute(attrname.c_str()))
162 try_set_value(attr, val);
168 void check_config_hierarchical(Value
const& node, std::string
const& prefix) {
169 for(
auto itr = node.MemberBegin(); itr != node.MemberEnd(); ++itr) {
170 if(!itr->name.IsString())
172 auto key_name = itr->name.GetString();
173 if(strncmp(key_name, SCC_LOG_LEVEL_PARAM_NAME, 9) == 0)
175 auto hier_name = prefix.size() ? prefix +
"." + key_name : key_name;
176 Value
const& val = itr->value;
177 if(val.IsNull() || val.IsArray())
179 else if(val.IsObject()) {
180 if(!sc_core::sc_find_object(hier_name.c_str())) {
182 throw std::domain_error(hier_name);
184 check_config_hierarchical(val, hier_name);
186 auto pos = hier_name.rfind(
'.');
187 if(pos != std::string::npos) {
188 auto objname = hier_name.substr(0, pos);
189 auto attrname = hier_name.substr(pos + 1);
190 auto* obj = sc_core::sc_find_object(objname.c_str());
191 if(!obj || !obj->get_attribute(attrname.c_str())) {
192 throw std::invalid_argument(hier_name);
200 struct configurer::ConfigHolder {
204 configurer::configurer(
const std::string& filename,
unsigned config_phases)
205 : configurer(filename, config_phases,
"$$$configurer$$$") {}
206 configurer::configurer(
const std::string& filename,
unsigned config_phases, sc_core::sc_module_name nm)
208 , config_phases(config_phases)
209 , cci_broker(nullptr)
210 , root(new ConfigHolder) {
211 if(filename.length() > 0)
212 read_input_file(filename);
215 configurer::~configurer() {}
217 void configurer::read_input_file(
const std::string& filename) {
218 std::ifstream is(filename);
221 IStreamWrapper stream(is);
222 root->document.ParseStream(stream);
223 if(root->document.HasParseError()) {
224 SCCERR() <<
"Could not parse input file " << filename <<
", location " << (unsigned)root->document.GetErrorOffset()
225 <<
", reason: " << GetParseError_En(root->document.GetParseError());
229 }
catch(std::runtime_error& e) {
230 SCCERR() <<
"Could not parse input file " << filename <<
", reason: " << e.what();
233 SCCERR() <<
"Could not open input file " << filename;
237 void configurer::dump_configuration(std::ostream& os,
bool as_yaml,
bool with_description, sc_core::sc_object* obj) {
238 OStreamWrapper stream(os);
239 writer_type writer(stream);
240 writer.StartObject();
241 config_dumper dumper;
242 for(
auto* o : get_sc_objects(obj)) {
243 dumper.dump_config(o, writer);
248 void configurer::configure() {
249 if(config_valid && root) {
250 configure_sc_attribute_hierarchical(root->document,
"");
254 auto get_value_from_hierarchy(
const std::string& hier_name, Value
const& value) -> Value
const& {
255 size_t npos = hier_name.find_first_of(
'.');
256 auto member = value.FindMember(hier_name.substr(0, npos).c_str());
257 auto& val = member->value;
258 if(val.IsNull() || npos == std::string::npos || !val.IsObject())
260 return get_value_from_hierarchy(hier_name.substr(npos + 1, hier_name.size()), val);
263 void configurer::set_configuration_value(sc_core::sc_attr_base* attr_base, sc_core::sc_object* owner) {
265 std::string name(owner->name());
267 name += attr_base->name();
268 size_t npos = name.find_first_of(
'.');
269 auto member = root->document.FindMember(name.substr(0, npos).c_str());
270 auto& val = get_value_from_hierarchy(name, member->value);
272 try_set_value(attr_base, val);
275 void configurer::config_check() {
278 check_config_hierarchical(root->document,
"");
280 }
catch(std::domain_error& e) {
281 SCCFATAL(
"scc::configurer") <<
"Illegal hierarchy name: '" << e.what() <<
"'";
282 }
catch(std::invalid_argument& e) {
283 SCCFATAL(
"scc::configurer") <<
"Illegal parameter name: '" << e.what() <<
"'";
287 void configurer::start_of_simulation() {
288 if(config_phases & START_OF_SIMULATION)
291 if(dump_file_name.size()) {
292 std::ofstream of{dump_file_name};
294 dump_configuration(of, with_description);