python - 如何在 C++ 中高效地创建和编译大地图
问题描述
目前,我有多个 json 文件和一个 python 代码,它读取 json 文件 main.json 之一,并基于 json 文件创建完整的 c++ 代码。在该 c++ 的 main() 中,我需要使用 numberToString.json 将数字输出转换为字符串。我找不到及时(<1 分钟)成功编译 c++ 代码的方法
我在 c++ 文件中创建了一个嵌套映射 "std::map< std::string, std::map< std::string, std::string>> enumMap" 并填充了来自 numberToString.json 的所有值(~20,000值),但代码没有及时编译(我在大约 5 分钟后将其关闭。CMAKE 使用 gcc 4.8.5 进行编译。)
示例代码:
main.json
{"example" : {
"FRUIT" : "ex_fruit"
},
...
}}
numberToString.json
{"FRUIT" : {
"1" : "fresh",
...,
"10" : "not fresh"
},
...
}}
someHeader.h
typedef struct FRUIT
{
int val;
};
typedef struct Example
{
FRUIT ex_fruit;
};
python.py
def someFunc(typename)
//input is struct name in string ex."Example"
"already implemented"
return memberVariables
//returns member variable accessors
print "#include \"someHeader.h\""
print "int main() {"
print " Example ex = {1};"
print " printf(%s, %s);" %("%s", someFunc("Example")
print "return 0;"
print "}"
pythonOutput.cxx
#include "someHeader.h"
int main() {
Example ex = {1};
printf(%s, ***ex.ex_fruit.val***);
return 0;
}
因此,在 pythonOutput.cxx 上,我需要ex.ex_fruit.val(即 1)通过使用 numberToString.json以“新鲜”的形式出现。
我正在使用 python 2.7
解决方案
您绝对不应该自动生成对这样的地图进行硬编码的 C++ 代码。有一些库可以将 json 文件直接读取到 C++ 中(例如,参见rapid json),应该使用这些库。代码将编译得更快,读取 20,000 个文件所需的时间大约为几毫秒(而不是编译需要超过 5 分钟)。
如果您想避免在 C++ 代码中添加对 json 解析器的依赖,我建议将 JSON 文件转换为更简单的格式,以便使用 C++ 阅读。
从文件中读取和写入地图的一种非常简单的格式
我们来一张简单的地图:
map<string, map<string, string>> test_map {
{"Hello", {
{"A", "B"},
{"C", "D"}}},
{"World", {
{"Blarg", "glug glug glug"},
{"idek what to put here", "felt cute might delete later"}}}};
我们将使用一种非常简单的格式将其写入文件。字符串将写为<string length> <string text>
,映射将写为<map length> <map key-value pairs>
。因此,例如,"Hello world"
将被写为11 Hello world
. 对于上面的地图,对应的文件是
2 5 Hello2 1 A1 B1 C1 D5 World2 5 Blarg14 glug glug glug21 idek what to put here28 felt cute might delete later
你有 2,这意味着顶层地图有 2 个元素。后面跟着一个 5,这意味着第一个键中有 5 个字符。接下来是第一个映射的键和值等。
以这种格式将地图写入文件
因为格式很简单,所以做起来也很简单。
namespace output {
using std::map;
using std::string;
void write(FILE* file, string const& str) {
// Write the length of the string, followed by a space
fprintf(file, "%lu ", str.size());
// Write the string itself
fwrite(str.data(), 1, str.size(), file);
}
template<class Key, class Value>
void write(FILE* file, map<Key, Value> const& m) {
// Write the length of the map, followed by a space
fprintf(file, "%lu ", m.size());
for(auto& entry : m) {
// Write the key
write(file, entry.first);
// Write the value
write(file, entry.second);
}
}
}
从文件中读取地图
这也很简单。例如,要读取一个字符串,我们先读取长度,然后再读取所有字符。
namespace input {
using std::map;
using std::string;
void read(FILE* file, size_t& length) {
int result = fscanf(file, "%lu ", &length);
if(result < 0) throw std::logic_error("Couldn't read from file");
}
void read(FILE* file, string& str) {
size_t length; // Read the length
read(file, length);
str.resize(length);
size_t n_read = fread(&str[0], 1, length, file); // Read the characters
if(n_read != length) { // Handle errors
throw std::logic_error("Unable to read entirety of string from file");
}
}
template<class Key, class Value>
void read(FILE* file, map<Key, Value>& text) {
size_t length; // Read the length of the map
read(file, length);
text.clear();
for(size_t i = 0; i < length; i++) {
Key key;
read(file, key); // Read the key
read(file, text[key]); // Read the value
}
}
}
使用此代码
写地图:
void write_map(string file, map<string, map<string, string>> test_map) {
auto output_file = fopen(file.c_str(), "w");
output::write(output_file, test_map);
fclose(output_file);
}
阅读地图:
map<string, map<string, string>> read_map(string file) {
auto input_file = fopen(file.c_str(), "r");
map<string, map<string, string>> m;
input::read(file, m);
fclose(input_file);
return m;
}
测试此代码
这个主函数会将测试映射写入文件,然后将其读回不同的映射,然后比较两者。
int main() {
using std::map;
using std::string;
map<string, map<string, string>> test_map {
{"Hello", {{"A", "B"}, {"C", "D"}}},
{"World", {{"Blarg", "glug glug glug"}, {"idek what to put here", "felt cute might delete later"}}}
};
{
auto output_file = fopen("example.txt", "w");
output::write(output_file, test_map);
fclose(output_file);
}
map<string, map<string, string>> map_from_file;
{
auto input_file = fopen("example.txt", "r");
try {
input::read(input_file, map_from_file);
} catch(std::logic_error& err) {
std::cerr << "Reading example.txt failed: " << err.what() << '\n';
}
fclose(input_file);
}
std::cout << std::boolalpha << "Maps equivilant? " << (test_map == map_from_file) << '\n';
for(auto pair : map_from_file) {
std::cout << '"' << pair.first << "\" -> {\n";
for(auto kv : pair.second) {
std::cout << " \"" << kv.first << "\" -> \"" << kv.second << '"' << "\n";
}
std::cout << "}\n";
}
}
推荐阅读
- javascript - 错误消息“app.js:1 Uncaught TypeError: window.addEventListner is not a function at app.js:1”
- php - nginx 工作正常,但 php7.2-fpm 不能正常工作
- c++ - 从二进制文件中读取无符号整数
- python - 终端和 vim 文件显示不同的 python 路径和版本
- javascript - 如何比较 JavaScript 中的两个数组?但关键是一个字符串
- c# - 如何在 POSTING 数据时将其保存给已登录的用户?(Asp 网络核心 API)
- botframework - 如何在 bot 命令 msbot for Teams (Nodejs) 上调用任务模块
- ruby-on-rails - 当我使用 su 或从我的用户“jruby”启动时,当我从 su 启动时,它会打开 ruby,如何解决这个问题?
- node.js - Open Weather API Heroku 在本地系统上运行良好,但在 Heroku 上崩溃
- node.js - Postgresql 查询超过 30 秒,在 Heroku 上失败