Fixed odr violation from trying to separate constexpr functions into declaration and definition in separate files. Modified code gen to be in line with current code.

This commit is contained in:
2022-10-24 20:37:40 +11:00
parent 188b462e68
commit 0048df1875
5 changed files with 192 additions and 144 deletions

View File

@@ -7,18 +7,13 @@ INDENT = 8
WIDTH = 80
LAST = "};"
SV = "std::string_view"
PREAMBLE = """#include "esx_reader.hpp"
using namespace esxr;
namespace esxr_lut {"""
POSTAMBLE = "}\n"
NS = "esxr::"
PREAMBLE = '#include "esx_reader.hpp"\n\nusing namespace esxr;'
def transpose(seq):
return list(zip(*seq))
def clean(seq):
return [x for x in seq if x is not None]
@@ -36,15 +31,12 @@ def indented_block(items):
lines += [line]
return "\n".join(lines)
def indented_list(items):
return ",\n".join([" " * INDENT + x for x in items])
def max_length(list):
return max(map(lambda x: len(x), list))
def wrap_bracket(list):
return ["{" + string + "}" for string in list]
def padded_join(lists):
maximums = [max_length(x) for x in lists]
padded = []
@@ -59,56 +51,71 @@ class Map:
second_type: str
first_name: str
second_name: str
reverse: bool
formats: list[str]
data: dict
F_DECL = "static constexpr std::pair<{0}, {1}> {2}_builtin[] {{"
F_SOA = """static constexpr auto {0}_std = utility::array_builtin_to_std({0}_builtin);
static constexpr auto {0} = utility::map_to_soa({0}_std);"""
F_FUNC_DECL = "[[nodiscard]] constexpr std::optional<{0}> {1}_to_{2}({3} {1}) noexcept"
F_FUNC_DECL = "[[nodiscard]] std::optional<{0}> {4}{1}_to_{2}({3} {1}) noexcept"
F_FUNC_BODY_FORWARD = " return utility::soa_first_to_second({0}, {1});"
F_FUNC_BODY_REVERSE = " return utility::soa_second_to_first({0}, {1});"
@property
def name(self):
return self.first_name + "_" + self.second_name + "_map"
@property
def decl(self):
return Map.F_DECL.format(self.first_type, self.second_type, self.name)
@property
def to_soa(self):
return Map.F_SOA.format(self.name)
def _forward_decl(self, namespace=""):
return Map.F_FUNC_DECL.format(self.second_type, self.first_name, self.second_name, self.first_type, namespace)
def _reverse_decl(self, namespace=""):
return Map.F_FUNC_DECL.format(self.first_type, self.second_name, self.first_name, self.second_type, namespace)
@property
def forward_decl(self):
return Map.F_FUNC_DECL.format(self.second_type, self.first_name, self.second_name, self.first_type)
return self._forward_decl()
@property
def reverse_decl(self):
return Map.F_FUNC_DECL.format(self.first_type, self.second_name, self.first_name, self.second_type)
return self._reverse_decl()
@property
def func_decls(self):
decls = [self.forward_decl] + ([self.reverse_decl] if self.reverse else [])
return "\n".join(decls)
@property
def forward_func(self):
return self.forward_decl + "\n{\n" + Map.F_FUNC_BODY_FORWARD.format(self.name, self.first_name) + "\n}"
return self._forward_decl(NS) + "\n{\n" + Map.F_FUNC_BODY_FORWARD.format(self.name, self.first_name) + "\n}"
@property
def reverse_func(self):
return self.reverse_decl + "\n{\n" + Map.F_FUNC_BODY_REVERSE.format(self.name, self.second_name) + "\n}"
return self._reverse_decl(NS) + "\n{\n" + Map.F_FUNC_BODY_REVERSE.format(self.name, self.second_name) + "\n}"
@property
def funcs(self):
f = [self.forward_func] + ([self.reverse_func] if self.reverse else [])
return "\n".join(f)
def data_to_list(self, data):
parts = []
for format in self.formats:
parts += [[format.format(*x) for x in data]]
return indented_block(wrap_bracket(padded_join(parts)))
def code(self, data, reverse = False):
parts = [self.decl, self.data_to_list(data), LAST, self.to_soa, self.forward_func]
decls = [self.forward_decl]
if reverse:
parts += [self.reverse_func]
decls += [self.reverse_decl]
return ["\n".join(parts), "\n".join([x + ';' for x in decls])]
@property
def lut(self):
parts = [self.decl, self.data_to_list(self.data), LAST]
return "\n".join(parts)
def add_extra(data):
@@ -117,61 +124,90 @@ def add_extra(data):
data += [grup, note]
data.sort(key=lambda x: x["fourcc"])
# read in our data sets
fdir = os.path.dirname(__file__)
with open(os.path.join(fdir, "records.json"), "r") as f:
record_data = json.load(f)
add_extra(record_data)
with open(os.path.join(fdir, "refr_flags.json"), "r") as f:
refr_data = json.load(f)
with open(os.path.join(fdir, "group_type.json"), "r") as f:
group_type_data = json.load(f)
# create our maps
group_name_map = Map(
first_type = "GroupType",
second_type = SV,
first_name = "group_type",
second_name = "name",
reverse = False,
formats = ["GroupType::{0}", ", \"{1}\""],
data = [(x['type'], x['name']) for x in group_type_data]
)
record_name_map = Map(
first_type = "RecordType",
second_type = SV,
first_name = "record_type",
second_name = "name",
reverse = False,
formats = ["RecordType::{0}", ", \"{1}\""],
data = [(x['fourcc'], x['name']) for x in record_data]
)
record_fourcc_map = Map(
first_type = "RecordType",
second_type = "FourCC",
first_name = "record_type",
second_name = "fourcc",
reverse = True,
formats = ["RecordType::{0}", ", FourCC(\"{0}\")"],
data = [(x['fourcc'], ) for x in record_data]
)
flag_desc_map = Map(
first_type = "Flag",
second_type = SV,
first_name = "flag",
second_name = "description",
reverse = False,
formats = ["{{RecordType::{0}, {1:>2}}}", ", \"{2}\""],
data = [(x['fourcc'], y['bit'], y['description']) for x in record_data for y in x['flags']]
)
refr_flag_desc_map = Map(
first_type = "RefrFlag",
second_type = SV,
first_name = "refr_flag",
second_name = "description",
reverse = False,
formats = ["{{RecordType::{0}, {1:>2}}}", ", \"{2}\""],
data = [(x['fourcc'], y['bit'], y['description']) for x in refr_data for y in x['flags']]
)
maps = [group_name_map, record_fourcc_map, record_name_map, flag_desc_map, refr_flag_desc_map]
def gen_enum(data):
# generate sorted list of signatures
sigs = [r["fourcc"] for r in data]
string = "enum class RecordType {\n" + indented_block(sigs) + LAST
return [None, string]
def gen_group_type(data):
map = Map("GroupType", SV, "group_type", "name", ["GroupType::{0}", ", \"{1}\""])
data = [(x['type'], x['name']) for x in data]
return map.code(data)
def gen_names(data):
map = Map("RecordType", SV, "record_type", "name", ["RecordType::{0}", ", \"{1}\""])
data = [(x['fourcc'], x['name']) for x in data]
return map.code(data)
def gen_fourcc(data):
map = Map("RecordType", "FourCC", "record_type", "fourcc", ["RecordType::{0}", ", FourCC(\"{0}\")"])
data = [(x['fourcc'], ) for x in data]
return map.code(data, reverse = True)
def gen_flags(data):
map = Map("Flag", SV, "flag", "description", ["{{RecordType::{0}, {1:>2}}}", ", \"{2}\""])
data = [(x['fourcc'], y['bit'], y['description']) for x in data for y in x['flags']]
return map.code(data)
def gen_refr_flags(data):
map = Map("RefrFlag", SV, "refr_flag", "description", ["{{RecordType::{0}, {1:>2}}}", ", \"{2}\""])
data = [(x['fourcc'], y['bit'], y['description']) for x in data for y in x['flags']]
return map.code(data)
string = "\n".join(("enum class RecordType {", indented_block(sigs), LAST))
return string
def main():
fdir = os.path.dirname(__file__)
with open(os.path.join(fdir, "records.json"), "r") as f:
data = json.load(f)
with open(os.path.join(fdir, "refr_flags.json"), "r") as f:
refr_data = json.load(f)
with open(os.path.join(fdir, "group_type.json"), "r") as f:
gt_data = json.load(f)
add_extra(data)
code = []
code += [gen_enum(data)]
code += [gen_group_type(gt_data)]
code += [gen_fourcc(data)]
code += [gen_names(data)]
code += [gen_flags(data)]
code += [gen_refr_flags(refr_data)]
code = transpose(code)
lut = [PREAMBLE] + clean(code[0]) + [POSTAMBLE]
lut = [PREAMBLE]
lut += map(lambda m: m.lut, maps)
lut += map(lambda m: m.to_soa, maps)
lut += map(lambda m: m.funcs, maps)
lut = "\n\n".join(lut)
header = clean(code[1])
header = "\n".join(header)
with open(os.path.join(fdir, "esx_reader_lut.cpp"), "w") as f:
f.write(lut)
with open(os.path.join(fdir, "esx_reader.hpp.fragment"), "w") as f:
header = []
header += [gen_enum(record_data)]
header += map(lambda m: m.func_decls, maps)
header = "\n".join(header)
with open(os.path.join(fdir, "esx_reader.fragment.hpp"), "w") as f:
f.write(header)