216 lines
6.2 KiB
Python
216 lines
6.2 KiB
Python
import json
|
|
import os
|
|
from dataclasses import dataclass
|
|
|
|
|
|
INDENT = 8
|
|
WIDTH = 80
|
|
LAST = "};"
|
|
SV = "std::string_view"
|
|
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]
|
|
|
|
def indented_block(items):
|
|
lines = []
|
|
line = ""
|
|
for item in items:
|
|
if len(line) + len(item) + 1 > WIDTH:
|
|
lines += [line[:-1]]
|
|
line = ""
|
|
if not line:
|
|
line = " " * INDENT
|
|
line += item + ", "
|
|
if line.strip():
|
|
lines += [line]
|
|
return "\n".join(lines)
|
|
|
|
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 = []
|
|
for max, l in zip(maximums, lists):
|
|
padded += [[x + " " * (max - len(x)) for x in l]]
|
|
padded_transposed = transpose(padded)
|
|
return ["".join(x) for x in padded_transposed]
|
|
|
|
@dataclass
|
|
class Map:
|
|
first_type: str
|
|
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]] 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 self._forward_decl()
|
|
|
|
@property
|
|
def reverse_decl(self):
|
|
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(NS) + "\n{\n" + Map.F_FUNC_BODY_FORWARD.format(self.name, self.first_name) + "\n}"
|
|
|
|
@property
|
|
def reverse_func(self):
|
|
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)))
|
|
|
|
@property
|
|
def lut(self):
|
|
parts = [self.decl, self.data_to_list(self.data), LAST]
|
|
return "\n".join(parts)
|
|
|
|
|
|
def add_extra(data):
|
|
grup = {"fourcc": "GRUP", "name": "Group", "flags": []}
|
|
note = {"fourcc": "NOTE", "name": "Note", "flags": []}
|
|
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 = "\n".join(("enum class RecordType {", indented_block(sigs), LAST))
|
|
return string
|
|
|
|
def main():
|
|
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)
|
|
with open(os.path.join(fdir, "esx_reader_lut.cpp"), "w") as f:
|
|
f.write(lut)
|
|
|
|
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)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|