From d7ad69536dd78ee39d589724012cc455e220a0c6 Mon Sep 17 00:00:00 2001 From: Ben Deane Date: Mon, 17 Nov 2025 16:21:44 -0700 Subject: [PATCH] :sparkles: Allow string ID ranges to be reserved on the command line Problem: - When generating a string catalog, it can be useful to reserve string IDs cheaply without having to incur the overhead of keeping "stable strings" around. Solution: - Allow reserved string ID ranges to be passed on the command line to `gen_str_catalog.py`. --- cmake/string_catalog.cmake | 6 ++++- test/log/CMakeLists.txt | 2 ++ tools/gen_str_catalog.py | 44 +++++++++++++++++++++++++++++++---- tools/gen_str_catalog_test.py | 24 +++++++++++++++++++ 4 files changed, 70 insertions(+), 6 deletions(-) diff --git a/cmake/string_catalog.cmake b/cmake/string_catalog.cmake index 234938c8..2b7ee83b 100644 --- a/cmake/string_catalog.cmake +++ b/cmake/string_catalog.cmake @@ -11,6 +11,7 @@ function(gen_str_catalog) GUID_ID GUID_MASK MODULE_ID_MAX + RESERVED_IDS OUTPUTS_TARGET) set(multiValueArgs INPUT_JSON INPUT_LIBS INPUT_HEADERS STABLE_JSON) cmake_parse_arguments(SC "${options}" "${oneValueArgs}" "${multiValueArgs}" @@ -68,6 +69,9 @@ function(gen_str_catalog) if(SC_MODULE_ID_MAX) set(MODULE_ID_MAX_ARG --module_id_max ${SC_MODULE_ID_MAX}) endif() + if(SC_RESERVED_IDS) + set(RESERVED_IDS_ARG --reserved_ids ${SC_RESERVED_IDS}) + endif() if(NOT SC_GEN_STR_CATALOG) set(SC_GEN_STR_CATALOG ${GEN_STR_CATALOG}) endif() @@ -80,7 +84,7 @@ function(gen_str_catalog) --cpp_output ${SC_OUTPUT_CPP} --json_output ${SC_OUTPUT_JSON} --xml_output ${SC_OUTPUT_XML} --stable_json ${STABLE_JSON} ${FORGET_ARG} ${CLIENT_NAME_ARG} ${VERSION_ARG} ${GUID_ID_ARG} - ${GUID_MASK_ARG} ${MODULE_ID_MAX_ARG} + ${GUID_MASK_ARG} ${MODULE_ID_MAX_ARG} ${RESERVED_IDS_ARG} DEPENDS ${UNDEFS} ${INPUT_JSON} ${SC_GEN_STR_CATALOG} ${STABLE_JSON} COMMAND_EXPAND_LISTS) diff --git a/test/log/CMakeLists.txt b/test/log/CMakeLists.txt index aab0a43c..2a71b550 100644 --- a/test/log/CMakeLists.txt +++ b/test/log/CMakeLists.txt @@ -40,6 +40,8 @@ gen_str_catalog( "01234567-89ab-cdef-0123-456789abcdef" GUID_MASK "ffffffff-ffff-ffff-ffff-ffffffffffff" + RESERVED_IDS + "1,1000-1005,1010" OUTPUTS_TARGET test_catalog_json) diff --git a/tools/gen_str_catalog.py b/tools/gen_str_catalog.py index 2291a57e..c302ace1 100755 --- a/tools/gen_str_catalog.py +++ b/tools/gen_str_catalog.py @@ -31,6 +31,31 @@ def split_args(s: str) -> list[str]: return args +class Intervals: + def __init__(self, text: str): + self.intervals = [] + for i in text.split(","): + rng = i.split("-") + if rng != [""]: + start = int(rng[0], 0) + self.intervals.append( + (start, int(rng[1], 0) if len(rng) == 2 else start) + ) + + def contains(self, v: int) -> bool: + return any(map(lambda x: v >= x[0] and v <= x[1], self.intervals)) + + def __str__(self): + rngs = map( + lambda x: f"{x[0]}-{x[1]}" if x[0] != x[1] else f"{x[0]}", + self.intervals, + ) + return ",".join(rngs) + + def __repr__(self): + return f'Intervals("{self}")' + + class Message: cpp_prefix: str = "sc::message\(\)$") def read_file(filename): @@ -199,7 +227,7 @@ def read_file(filename): modules = filter(lambda x: isinstance(x, Module), items) unique_modules = {m.key(): m for m in modules}.values() - return assign_ids(unique_messages, unique_modules, stable_data) + return assign_ids(unique_messages, unique_modules, stable_data, reserved_ids) def make_cpp_scoped_enum_decl(e: str, ut: str) -> str: @@ -542,6 +570,12 @@ def parse_cmdline(): default=127, help="The maximum value of a module ID.", ) + parser.add_argument( + "--reserved_ids", + type=lambda x: Intervals(x), + default="", + help="A list of (inclusive) ranges of string IDs that should be reserved and not used. e.g. '1-5,10-15,20'", + ) return parser.parse_args() @@ -565,7 +599,7 @@ def main(): stable_data = read_stable(args.stable_json) try: - messages, modules = read_input(args.input, stable_data) + messages, modules = read_input(args.input, stable_data, args.reserved_ids) except Exception as e: raise Exception(f"{str(e)} from file {args.input}") diff --git a/tools/gen_str_catalog_test.py b/tools/gen_str_catalog_test.py index 4883eafb..41643981 100644 --- a/tools/gen_str_catalog_test.py +++ b/tools/gen_str_catalog_test.py @@ -70,3 +70,27 @@ def test_module_cpp_type(): def test_module_json(): m = gen.Module("abc", 42) assert m.to_json() == {"string": "abc", "id": 42} + + +test_ints = "1-5,8-10,15" + + +def test_intervals(): + m = gen.Intervals(test_ints) + assert m.contains(1) + assert m.contains(5) + assert not m.contains(6) + assert m.contains(8) + assert m.contains(10) + assert m.contains(15) + + +def test_empty_intervals(): + m = gen.Intervals("") + assert not m.contains(1) + + +def test_intervals_repr(): + m = gen.Intervals(test_ints) + assert f"{m}" == "1-5,8-10,15" + assert repr(m) == 'Intervals("1-5,8-10,15")'