From 8991b936a7fa97e7909470516ba7908b4b693970 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Otto?= Date: Wed, 9 Oct 2024 01:05:53 +0200 Subject: [PATCH 01/14] Add tests for parse/list_of_primitives --- .../int/expected_symbol_table.txt | 33 +++++++++++++++++++ .../list_of_primitives/int/meta_model.py | 11 +++++++ .../string/expected_symbol_table.txt | 33 +++++++++++++++++++ .../list_of_primitives/string/meta_model.py | 11 +++++++ 4 files changed, 88 insertions(+) create mode 100644 test_data/parse/expected/list_of_primitives/int/expected_symbol_table.txt create mode 100644 test_data/parse/expected/list_of_primitives/int/meta_model.py create mode 100644 test_data/parse/expected/list_of_primitives/string/expected_symbol_table.txt create mode 100644 test_data/parse/expected/list_of_primitives/string/meta_model.py diff --git a/test_data/parse/expected/list_of_primitives/int/expected_symbol_table.txt b/test_data/parse/expected/list_of_primitives/int/expected_symbol_table.txt new file mode 100644 index 000000000..1691513cf --- /dev/null +++ b/test_data/parse/expected/list_of_primitives/int/expected_symbol_table.txt @@ -0,0 +1,33 @@ +UnverifiedSymbolTable( + our_types=[ + ConcreteClass( + name='Something', + is_implementation_specific=False, + inheritances=[], + properties=[ + Property( + name='something', + type_annotation=SubscriptedTypeAnnotation( + identifier='List', + subscripts=[ + AtomicTypeAnnotation( + identifier='int', + node=...)], + node=...), + description=None, + node=...)], + methods=[], + invariants=[], + serialization=None, + description=Description( + document=..., + node=...), + node=..., + properties_by_name=..., + methods_by_name=...)], + constants=[], + verification_functions=[], + meta_model=MetaModel( + description=None, + version='dummy', + xml_namespace='https://dummy.com')) \ No newline at end of file diff --git a/test_data/parse/expected/list_of_primitives/int/meta_model.py b/test_data/parse/expected/list_of_primitives/int/meta_model.py new file mode 100644 index 000000000..f65d61fb8 --- /dev/null +++ b/test_data/parse/expected/list_of_primitives/int/meta_model.py @@ -0,0 +1,11 @@ +class Something: + """ + Represent something. + + Indented. + """ + something: List[int] + + +__version__ = "dummy" +__xml_namespace__ = "https://dummy.com" diff --git a/test_data/parse/expected/list_of_primitives/string/expected_symbol_table.txt b/test_data/parse/expected/list_of_primitives/string/expected_symbol_table.txt new file mode 100644 index 000000000..4a9d8664c --- /dev/null +++ b/test_data/parse/expected/list_of_primitives/string/expected_symbol_table.txt @@ -0,0 +1,33 @@ +UnverifiedSymbolTable( + our_types=[ + ConcreteClass( + name='Something', + is_implementation_specific=False, + inheritances=[], + properties=[ + Property( + name='something', + type_annotation=SubscriptedTypeAnnotation( + identifier='List', + subscripts=[ + AtomicTypeAnnotation( + identifier='str', + node=...)], + node=...), + description=None, + node=...)], + methods=[], + invariants=[], + serialization=None, + description=Description( + document=..., + node=...), + node=..., + properties_by_name=..., + methods_by_name=...)], + constants=[], + verification_functions=[], + meta_model=MetaModel( + description=None, + version='dummy', + xml_namespace='https://dummy.com')) \ No newline at end of file diff --git a/test_data/parse/expected/list_of_primitives/string/meta_model.py b/test_data/parse/expected/list_of_primitives/string/meta_model.py new file mode 100644 index 000000000..36f159e7c --- /dev/null +++ b/test_data/parse/expected/list_of_primitives/string/meta_model.py @@ -0,0 +1,11 @@ +class Something: + """ + Represent something. + + Indented. + """ + something: List[str] + + +__version__ = "dummy" +__xml_namespace__ = "https://dummy.com" From d2f768d90ca0515a2d5ac4165ef936fe9a1cb689 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Otto?= Date: Thu, 10 Oct 2024 11:22:58 +0200 Subject: [PATCH 02/14] Add test for type missmatch between constructor and property --- .../type_missmatch/expected_error.txt | 1 + .../type_missmatch/meta_model.py | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 test_data/intermediate/unexpected/properties_and_constructor_arguments_do_not_match/type_missmatch/expected_error.txt create mode 100644 test_data/intermediate/unexpected/properties_and_constructor_arguments_do_not_match/type_missmatch/meta_model.py diff --git a/test_data/intermediate/unexpected/properties_and_constructor_arguments_do_not_match/type_missmatch/expected_error.txt b/test_data/intermediate/unexpected/properties_and_constructor_arguments_do_not_match/type_missmatch/expected_error.txt new file mode 100644 index 000000000..14db0c0d5 --- /dev/null +++ b/test_data/intermediate/unexpected/properties_and_constructor_arguments_do_not_match/type_missmatch/expected_error.txt @@ -0,0 +1 @@ +The constructor argument 'x' and the property 'x' for the class 'SomeContainerClass' mismatch in type. The argument is typed as List[int] while the property is typed as List[str]. We expect the constructors and the properties to match in type. \ No newline at end of file diff --git a/test_data/intermediate/unexpected/properties_and_constructor_arguments_do_not_match/type_missmatch/meta_model.py b/test_data/intermediate/unexpected/properties_and_constructor_arguments_do_not_match/type_missmatch/meta_model.py new file mode 100644 index 000000000..f3c3efa79 --- /dev/null +++ b/test_data/intermediate/unexpected/properties_and_constructor_arguments_do_not_match/type_missmatch/meta_model.py @@ -0,0 +1,9 @@ +class SomeContainerClass: + x: List[str] + + def __init__(self, x: List[int]) -> None: + self.x = x + + +__version__ = "dummy" +__xml_namespace__ = "https://dummy.com" From a63c8a0f2385c0829c8f20cd6c11f81cc73aaa7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Otto?= Date: Thu, 10 Oct 2024 11:25:56 +0200 Subject: [PATCH 03/14] Intermediate: allow list of primitives --- aas_core_codegen/intermediate/_translate.py | 9 +- .../{ => class}/expected_symbol_table.txt | 0 .../subscripted/{ => class}/meta_model.py | 0 .../primitive/expected_symbol_table.txt | 85 +++++++++++++++++++ .../subscripted/primitive/meta_model.py | 9 ++ 5 files changed, 100 insertions(+), 3 deletions(-) rename test_data/intermediate/expected/type_annotation/subscripted/{ => class}/expected_symbol_table.txt (100%) rename test_data/intermediate/expected/type_annotation/subscripted/{ => class}/meta_model.py (100%) create mode 100644 test_data/intermediate/expected/type_annotation/subscripted/primitive/expected_symbol_table.txt create mode 100644 test_data/intermediate/expected/type_annotation/subscripted/primitive/meta_model.py diff --git a/aas_core_codegen/intermediate/_translate.py b/aas_core_codegen/intermediate/_translate.py index d9d316786..34499225d 100644 --- a/aas_core_codegen/intermediate/_translate.py +++ b/aas_core_codegen/intermediate/_translate.py @@ -4415,9 +4415,12 @@ def _verify_only_simple_type_patterns(symbol_table: SymbolTable) -> List[Error]: type_anno = beneath_optional(prop.type_annotation) if isinstance(type_anno, ListTypeAnnotation): if not ( - isinstance(type_anno.items, OurTypeAnnotation) - and isinstance( + isinstance(type_anno.items, PrimitiveTypeAnnotation) + or ( + isinstance(type_anno.items, OurTypeAnnotation) + and isinstance( type_anno.items.our_type, (AbstractClass, ConcreteClass) + ) ) ): errors.append( @@ -4425,7 +4428,7 @@ def _verify_only_simple_type_patterns(symbol_table: SymbolTable) -> List[Error]: prop.parsed.node, f"We currently support only a limited set of " f"type annotation patterns. At the moment, we handle " - f"only lists of classes (both concrete or abstract), " + f"only lists of classes (both concrete or abstract) or primitive types, " f"but the property {prop.name!r} " f"of the class {cls.name!r} " f"has type: {prop.type_annotation}. " diff --git a/test_data/intermediate/expected/type_annotation/subscripted/expected_symbol_table.txt b/test_data/intermediate/expected/type_annotation/subscripted/class/expected_symbol_table.txt similarity index 100% rename from test_data/intermediate/expected/type_annotation/subscripted/expected_symbol_table.txt rename to test_data/intermediate/expected/type_annotation/subscripted/class/expected_symbol_table.txt diff --git a/test_data/intermediate/expected/type_annotation/subscripted/meta_model.py b/test_data/intermediate/expected/type_annotation/subscripted/class/meta_model.py similarity index 100% rename from test_data/intermediate/expected/type_annotation/subscripted/meta_model.py rename to test_data/intermediate/expected/type_annotation/subscripted/class/meta_model.py diff --git a/test_data/intermediate/expected/type_annotation/subscripted/primitive/expected_symbol_table.txt b/test_data/intermediate/expected/type_annotation/subscripted/primitive/expected_symbol_table.txt new file mode 100644 index 000000000..409ed86fb --- /dev/null +++ b/test_data/intermediate/expected/type_annotation/subscripted/primitive/expected_symbol_table.txt @@ -0,0 +1,85 @@ +SymbolTable( + our_types=[ + ConcreteClass( + name='SomeContainerClass', + inheritances=[], + inheritance_id_set=..., + ancestors=[], + ancestor_id_set=..., + is_implementation_specific=False, + interface=None, + descendant_id_set=..., + descendants=[], + concrete_descendant_id_set=..., + concrete_descendants=[], + properties=[ + Property( + name='x', + type_annotation=ListTypeAnnotation( + items=PrimitiveTypeAnnotation( + a_type='STR', + parsed=...), + parsed=...), + description=None, + specified_for='Reference to ConcreteClass SomeContainerClass', + parsed=...)], + methods=[], + constructor=Constructor( + name='__init__', + arguments=[ + Argument( + name='x', + type_annotation=ListTypeAnnotation( + items=PrimitiveTypeAnnotation( + a_type='STR', + parsed=...), + parsed=...), + default=None, + parsed=...)], + returns=None, + description=None, + contracts=Contracts( + preconditions=[], + snapshots=[], + postconditions=[]), + parsed=..., + arguments_by_name=..., + is_implementation_specific=False, + statements=[ + textwrap.dedent("""\ + AssignArgument( + name='x', + argument='x', + default=None)""")], + inlined_statements=[ + textwrap.dedent("""\ + AssignArgument( + name='x', + argument='x', + default=None)""")]), + invariants=[], + serialization=Serialization( + with_model_type=False), + description=None, + parsed=..., + properties_by_name=..., + property_id_set=..., + methods_by_name=..., + method_id_set=..., + invariant_id_set=...)], + our_types_topologically_sorted=[ + 'Reference to our type SomeContainerClass'], + enumerations=[], + constrained_primitives=[], + classes=[ + 'Reference to our type SomeContainerClass'], + concrete_classes=[ + 'Reference to our type SomeContainerClass'], + constants=[], + constants_by_name=..., + verification_functions=[], + verification_functions_by_name=..., + meta_model=MetaModel( + description=None, + version='dummy', + xml_namespace='https://dummy.com')) \ No newline at end of file diff --git a/test_data/intermediate/expected/type_annotation/subscripted/primitive/meta_model.py b/test_data/intermediate/expected/type_annotation/subscripted/primitive/meta_model.py new file mode 100644 index 000000000..345a02a6c --- /dev/null +++ b/test_data/intermediate/expected/type_annotation/subscripted/primitive/meta_model.py @@ -0,0 +1,9 @@ +class SomeContainerClass: + x: List[str] + + def __init__(self, x: List[str]) -> None: + self.x = x + + +__version__ = "dummy" +__xml_namespace__ = "https://dummy.com" From eb8cefb1272949f80b2371adf5fa4ebff6748f05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Otto?= Date: Wed, 13 Nov 2024 00:08:35 +0100 Subject: [PATCH 04/14] JSON Schema generation --- .../expected_output/schema.json | 40 +++++++++++++++++++ .../expected_output/stdout.txt | 1 + .../input/snippets/schema_base.json | 5 +++ .../list_of_primitives/meta_model.py | 16 ++++++++ 4 files changed, 62 insertions(+) create mode 100644 test_data/jsonschema/test_main/list_of_primitives/expected_output/schema.json create mode 100644 test_data/jsonschema/test_main/list_of_primitives/expected_output/stdout.txt create mode 100644 test_data/jsonschema/test_main/list_of_primitives/input/snippets/schema_base.json create mode 100644 test_data/jsonschema/test_main/list_of_primitives/meta_model.py diff --git a/test_data/jsonschema/test_main/list_of_primitives/expected_output/schema.json b/test_data/jsonschema/test_main/list_of_primitives/expected_output/schema.json new file mode 100644 index 000000000..da3d8d0bd --- /dev/null +++ b/test_data/jsonschema/test_main/list_of_primitives/expected_output/schema.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "title": "AssetAdministrationShellEnvironment", + "type": "object", + "$id": "https://dummy.com", + "definitions": { + "ListOfPrimitives": { + "type": "object", + "properties": { + "strings": { + "type": "array", + "items": { + "type": "string" + } + }, + "integers": { + "type": "array", + "items": { + "type": "integer" + } + }, + "booleans": { + "type": "array", + "items": { + "type": "boolean" + } + } + }, + "required": [ + "strings", + "integers", + "booleans" + ] + }, + "ModelType": { + "type": "string", + "enum": [] + } + } +} \ No newline at end of file diff --git a/test_data/jsonschema/test_main/list_of_primitives/expected_output/stdout.txt b/test_data/jsonschema/test_main/list_of_primitives/expected_output/stdout.txt new file mode 100644 index 000000000..2d755fc5a --- /dev/null +++ b/test_data/jsonschema/test_main/list_of_primitives/expected_output/stdout.txt @@ -0,0 +1 @@ +Code generated to: diff --git a/test_data/jsonschema/test_main/list_of_primitives/input/snippets/schema_base.json b/test_data/jsonschema/test_main/list_of_primitives/input/snippets/schema_base.json new file mode 100644 index 000000000..fe668c922 --- /dev/null +++ b/test_data/jsonschema/test_main/list_of_primitives/input/snippets/schema_base.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "title": "AssetAdministrationShellEnvironment", + "type": "object" +} diff --git a/test_data/jsonschema/test_main/list_of_primitives/meta_model.py b/test_data/jsonschema/test_main/list_of_primitives/meta_model.py new file mode 100644 index 000000000..6c446e748 --- /dev/null +++ b/test_data/jsonschema/test_main/list_of_primitives/meta_model.py @@ -0,0 +1,16 @@ +from typing import List + + +class List_of_primitives(): + strings: List[str] + integers: List[int] + booleans: List[bool] + + def __init__(self, strings: List[str], integers: List[int], booleans: List[bool]) -> None: + self.strings = strings + self.integers = integers + self.booleans = booleans + + +__version__ = "dummy" +__xml_namespace__ = "https://dummy.com" From fe08978c0f5e7f21ac06d4f32e5b2c572a70d0f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Otto?= Date: Mon, 3 Feb 2025 16:07:17 +0100 Subject: [PATCH 05/14] Code formatting --- aas_core_codegen/intermediate/_translate.py | 2 +- .../jsonschema/test_main/list_of_primitives/meta_model.py | 6 ++++-- .../parse/expected/list_of_primitives/int/meta_model.py | 1 + .../parse/expected/list_of_primitives/string/meta_model.py | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/aas_core_codegen/intermediate/_translate.py b/aas_core_codegen/intermediate/_translate.py index 34499225d..669c58458 100644 --- a/aas_core_codegen/intermediate/_translate.py +++ b/aas_core_codegen/intermediate/_translate.py @@ -4419,7 +4419,7 @@ def _verify_only_simple_type_patterns(symbol_table: SymbolTable) -> List[Error]: or ( isinstance(type_anno.items, OurTypeAnnotation) and isinstance( - type_anno.items.our_type, (AbstractClass, ConcreteClass) + type_anno.items.our_type, (AbstractClass, ConcreteClass) ) ) ): diff --git a/test_data/jsonschema/test_main/list_of_primitives/meta_model.py b/test_data/jsonschema/test_main/list_of_primitives/meta_model.py index 6c446e748..531303f43 100644 --- a/test_data/jsonschema/test_main/list_of_primitives/meta_model.py +++ b/test_data/jsonschema/test_main/list_of_primitives/meta_model.py @@ -1,12 +1,14 @@ from typing import List -class List_of_primitives(): +class List_of_primitives: strings: List[str] integers: List[int] booleans: List[bool] - def __init__(self, strings: List[str], integers: List[int], booleans: List[bool]) -> None: + def __init__( + self, strings: List[str], integers: List[int], booleans: List[bool] + ) -> None: self.strings = strings self.integers = integers self.booleans = booleans diff --git a/test_data/parse/expected/list_of_primitives/int/meta_model.py b/test_data/parse/expected/list_of_primitives/int/meta_model.py index f65d61fb8..2acc8d822 100644 --- a/test_data/parse/expected/list_of_primitives/int/meta_model.py +++ b/test_data/parse/expected/list_of_primitives/int/meta_model.py @@ -4,6 +4,7 @@ class Something: Indented. """ + something: List[int] diff --git a/test_data/parse/expected/list_of_primitives/string/meta_model.py b/test_data/parse/expected/list_of_primitives/string/meta_model.py index 36f159e7c..c1c359bf5 100644 --- a/test_data/parse/expected/list_of_primitives/string/meta_model.py +++ b/test_data/parse/expected/list_of_primitives/string/meta_model.py @@ -4,6 +4,7 @@ class Something: Indented. """ + something: List[str] From 4f6bbf09295f6bbacbde546f16742fafedeef146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Otto?= Date: Tue, 4 Feb 2025 13:57:25 +0100 Subject: [PATCH 06/14] Add cpp code generation --- aas_core_codegen/cpp/enhancing/_generate.py | 11 +- aas_core_codegen/cpp/iteration/_generate.py | 24 +- aas_core_codegen/cpp/jsonization/_generate.py | 63 +- .../cpp/verification/_generate.py | 12 +- aas_core_codegen/cpp/visitation/_generate.py | 12 +- aas_core_codegen/cpp/xmlization/_generate.py | 75 +- .../expected_output/common.cpp | 14069 ++++++++++++++++ .../expected_output/common.hpp | 10092 +++++++++++ .../expected_output/constants.cpp | 27 + .../expected_output/constants.hpp | 40 + .../expected_output/enhancing.hpp | 638 + .../expected_output/iteration.cpp | 1229 ++ .../expected_output/iteration.hpp | 338 + .../expected_output/jsonization.cpp | 1587 ++ .../expected_output/jsonization.hpp | 202 + .../expected_output/pattern.cpp | 16 + .../expected_output/pattern.hpp | 36 + .../expected_output/revm.cpp | 863 + .../expected_output/revm.hpp | 215 + .../expected_output/stdout.txt | 1 + .../expected_output/stringification.cpp | 365 + .../expected_output/stringification.hpp | 93 + .../expected_output/types.cpp | 158 + .../expected_output/types.hpp | 253 + .../expected_output/verification.cpp | 727 + .../expected_output/verification.hpp | 225 + .../expected_output/visitation.cpp | 109 + .../expected_output/visitation.hpp | 93 + .../expected_output/wstringification.cpp | 84 + .../expected_output/wstringification.hpp | 65 + .../expected_output/xmlization.cpp | 4718 ++++++ .../expected_output/xmlization.hpp | 290 + .../input/snippets/namespace.txt | 1 + .../list_of_primitives/meta_model.py | 28 + tests/cpp/test_main.py | 62 +- 35 files changed, 36715 insertions(+), 106 deletions(-) create mode 100644 test_data/cpp/test_main/list_of_primitives/expected_output/common.cpp create mode 100644 test_data/cpp/test_main/list_of_primitives/expected_output/common.hpp create mode 100644 test_data/cpp/test_main/list_of_primitives/expected_output/constants.cpp create mode 100644 test_data/cpp/test_main/list_of_primitives/expected_output/constants.hpp create mode 100644 test_data/cpp/test_main/list_of_primitives/expected_output/enhancing.hpp create mode 100644 test_data/cpp/test_main/list_of_primitives/expected_output/iteration.cpp create mode 100644 test_data/cpp/test_main/list_of_primitives/expected_output/iteration.hpp create mode 100644 test_data/cpp/test_main/list_of_primitives/expected_output/jsonization.cpp create mode 100644 test_data/cpp/test_main/list_of_primitives/expected_output/jsonization.hpp create mode 100644 test_data/cpp/test_main/list_of_primitives/expected_output/pattern.cpp create mode 100644 test_data/cpp/test_main/list_of_primitives/expected_output/pattern.hpp create mode 100644 test_data/cpp/test_main/list_of_primitives/expected_output/revm.cpp create mode 100644 test_data/cpp/test_main/list_of_primitives/expected_output/revm.hpp create mode 100644 test_data/cpp/test_main/list_of_primitives/expected_output/stdout.txt create mode 100644 test_data/cpp/test_main/list_of_primitives/expected_output/stringification.cpp create mode 100644 test_data/cpp/test_main/list_of_primitives/expected_output/stringification.hpp create mode 100644 test_data/cpp/test_main/list_of_primitives/expected_output/types.cpp create mode 100644 test_data/cpp/test_main/list_of_primitives/expected_output/types.hpp create mode 100644 test_data/cpp/test_main/list_of_primitives/expected_output/verification.cpp create mode 100644 test_data/cpp/test_main/list_of_primitives/expected_output/verification.hpp create mode 100644 test_data/cpp/test_main/list_of_primitives/expected_output/visitation.cpp create mode 100644 test_data/cpp/test_main/list_of_primitives/expected_output/visitation.hpp create mode 100644 test_data/cpp/test_main/list_of_primitives/expected_output/wstringification.cpp create mode 100644 test_data/cpp/test_main/list_of_primitives/expected_output/wstringification.hpp create mode 100644 test_data/cpp/test_main/list_of_primitives/expected_output/xmlization.cpp create mode 100644 test_data/cpp/test_main/list_of_primitives/expected_output/xmlization.hpp create mode 100644 test_data/cpp/test_main/list_of_primitives/input/snippets/namespace.txt create mode 100644 test_data/cpp/test_main/list_of_primitives/meta_model.py diff --git a/aas_core_codegen/cpp/enhancing/_generate.py b/aas_core_codegen/cpp/enhancing/_generate.py index 9ba9f0252..445a2cbb1 100644 --- a/aas_core_codegen/cpp/enhancing/_generate.py +++ b/aas_core_codegen/cpp/enhancing/_generate.py @@ -379,11 +379,12 @@ def _generate_wrap_snippet_for_required_property( else: assert_never(type_anno.our_type) elif isinstance(type_anno, intermediate.ListTypeAnnotation): - assert isinstance( - type_anno.items, intermediate.OurTypeAnnotation - ) and isinstance( - type_anno.items.our_type, - (intermediate.AbstractClass, intermediate.ConcreteClass), + assert isinstance(type_anno.items, intermediate.PrimitiveTypeAnnotation) or ( + isinstance(type_anno.items, intermediate.OurTypeAnnotation) + and isinstance( + type_anno.items.our_type, + (intermediate.AbstractClass, intermediate.ConcreteClass), + ) ), ( f"NOTE (mristin, 2023-07-07): We expect only lists of classes " f"at the moment, but you specified {type_anno}. " diff --git a/aas_core_codegen/cpp/iteration/_generate.py b/aas_core_codegen/cpp/iteration/_generate.py index 25fb66792..9f0b5e32e 100644 --- a/aas_core_codegen/cpp/iteration/_generate.py +++ b/aas_core_codegen/cpp/iteration/_generate.py @@ -782,11 +782,13 @@ def __init__(self, cls: intermediate.ConcreteClass) -> None: relevant_properties.append(prop) elif isinstance(type_anno, intermediate.ListTypeAnnotation): - assert isinstance( - type_anno.items, intermediate.OurTypeAnnotation - ) and isinstance( - type_anno.items.our_type, - (intermediate.AbstractClass, intermediate.ConcreteClass), + assert ( + isinstance(type_anno.items, intermediate.PrimitiveTypeAnnotation) + or isinstance(type_anno.items, intermediate.OurTypeAnnotation) + and isinstance( + type_anno.items.our_type, + (intermediate.AbstractClass, intermediate.ConcreteClass), + ) ), ( f"NOTE (mristin, 2023-09-27): We expect only lists of classes " f"at the moment, but you specified {prop.type_annotation} " @@ -947,11 +949,13 @@ def _generate_iterator_over_cls_execute_implementation( flow.append(yielding_flow.Yield()) elif isinstance(type_anno, intermediate.ListTypeAnnotation): - assert isinstance( - type_anno.items, intermediate.OurTypeAnnotation - ) and isinstance( - type_anno.items.our_type, - (intermediate.AbstractClass, intermediate.ConcreteClass), + assert ( + isinstance(type_anno.items, intermediate.PrimitiveTypeAnnotation) + or isinstance(type_anno.items, intermediate.OurTypeAnnotation) + and isinstance( + type_anno.items.our_type, + (intermediate.AbstractClass, intermediate.ConcreteClass), + ) ), ( f"NOTE (mristin, 2023-09-27): We expect only lists of classes " f"at the moment, but you specified {prop.type_annotation} " diff --git a/aas_core_codegen/cpp/jsonization/_generate.py b/aas_core_codegen/cpp/jsonization/_generate.py index b464fcbd2..94caea708 100644 --- a/aas_core_codegen/cpp/jsonization/_generate.py +++ b/aas_core_codegen/cpp/jsonization/_generate.py @@ -741,6 +741,18 @@ def _generate_deserialize_bytearray() -> Stripped: for primitive_type in intermediate.PrimitiveType ) +_PRIMITIVE_TYPE_TO_NATIVE_TYPE = { + intermediate.PrimitiveType.BOOL: "bool", + intermediate.PrimitiveType.INT: "int64_t", + intermediate.PrimitiveType.FLOAT: "double", + intermediate.PrimitiveType.STR: "std::wstring", + intermediate.PrimitiveType.BYTEARRAY: "std::vector", +} +assert all( + primitive_type in _PRIMITIVE_TYPE_TO_NATIVE_TYPE + for primitive_type in intermediate.PrimitiveType +) + def _generate_get_model_type() -> Stripped: """Generate the getter of the model type from JSON object for dispatches.""" @@ -1158,20 +1170,27 @@ def _generate_deserialize_list_property( """ type_anno = intermediate.beneath_optional(prop.type_annotation) assert isinstance(type_anno, intermediate.ListTypeAnnotation) - assert isinstance(type_anno.items, intermediate.OurTypeAnnotation) and isinstance( - type_anno.items.our_type, - (intermediate.AbstractClass, intermediate.ConcreteClass), + assert ( + isinstance(type_anno.items, intermediate.PrimitiveTypeAnnotation) + or isinstance(type_anno.items, intermediate.OurTypeAnnotation) + and isinstance( + type_anno.items.our_type, + (intermediate.AbstractClass, intermediate.ConcreteClass), + ) ), ( f"NOTE (mristin, 2023-11-10): We expect only lists of classes " f"at the moment, but you specified {type_anno}. " f"Please contact the developers if you need this feature." ) - cls = type_anno.items.our_type - - interface_name = cpp_naming.interface_name(cls.name) - - deserialize_function = _determine_deserialize_function_to_call(cls=cls) + if isinstance(type_anno.items, intermediate.PrimitiveTypeAnnotation): + primitive_type = intermediate.try_primitive_type(type_anno.items) + interface_name = _PRIMITIVE_TYPE_TO_NATIVE_TYPE[primitive_type] + deserialize_function = _PRIMITIVE_TYPE_TO_DESERIALIZE[primitive_type] + else: + cls = type_anno.items.our_type + interface_name = f"types::{cpp_naming.interface_name(cls.name)}" + deserialize_function = _determine_deserialize_function_to_call(cls=cls) var_name = cpp_naming.variable_name(Identifier(f"the_{prop.name}")) json_prop_name = naming.json_property(prop.name) @@ -1211,7 +1230,7 @@ def _generate_deserialize_list_property( {var_name} = common::make_optional< {I}std::vector< -{II}std::shared_ptr +{II}std::shared_ptr<{interface_name}> {I}> >(); @@ -1224,7 +1243,7 @@ def _generate_deserialize_list_property( {I}: {var_json} ) {{ {I}common::optional< -{II}std::shared_ptr +{II}std::shared_ptr<{interface_name}> {I}> deserialized; {I}std::tie( @@ -1300,11 +1319,13 @@ def _generate_deserialize_property( else: assert_never(type_anno.our_type) elif isinstance(type_anno, intermediate.ListTypeAnnotation): - assert isinstance( - type_anno.items, intermediate.OurTypeAnnotation - ) and isinstance( - type_anno.items.our_type, - (intermediate.AbstractClass, intermediate.ConcreteClass), + assert ( + isinstance(type_anno.items, intermediate.PrimitiveTypeAnnotation) + or isinstance(type_anno.items, intermediate.OurTypeAnnotation) + and isinstance( + type_anno.items.our_type, + (intermediate.AbstractClass, intermediate.ConcreteClass), + ) ), ( f"NOTE (mristin, 2023-11-10): We expect only lists of classes " f"at the moment, but you specified {type_anno}. " @@ -2192,11 +2213,13 @@ def _generate_serialize_property(prop: intermediate.Property) -> Stripped: else: assert_never(type_anno.our_type) elif isinstance(type_anno, intermediate.ListTypeAnnotation): - assert isinstance( - type_anno.items, intermediate.OurTypeAnnotation - ) and isinstance( - type_anno.items.our_type, - (intermediate.AbstractClass, intermediate.ConcreteClass), + assert ( + isinstance(type_anno.items, intermediate.PrimitiveTypeAnnotation) + or isinstance(type_anno.items, intermediate.OurTypeAnnotation) + and isinstance( + type_anno.items.our_type, + (intermediate.AbstractClass, intermediate.ConcreteClass), + ) ), ( f"NOTE (mristin, 2023-11-21): We expect only lists of classes " f"at the moment, but you specified {type_anno}. " diff --git a/aas_core_codegen/cpp/verification/_generate.py b/aas_core_codegen/cpp/verification/_generate.py index 74a3bc842..07391810d 100644 --- a/aas_core_codegen/cpp/verification/_generate.py +++ b/aas_core_codegen/cpp/verification/_generate.py @@ -842,11 +842,13 @@ def _collect_constrained_primitive_properties( assert_never(type_anno.our_type) elif isinstance(type_anno, intermediate.ListTypeAnnotation): - assert isinstance( - type_anno.items, intermediate.OurTypeAnnotation - ) and isinstance( - type_anno.items.our_type, - (intermediate.AbstractClass, intermediate.ConcreteClass), + assert ( + isinstance(type_anno.items, intermediate.PrimitiveTypeAnnotation) + or isinstance(type_anno.items, intermediate.OurTypeAnnotation) + and isinstance( + type_anno.items.our_type, + (intermediate.AbstractClass, intermediate.ConcreteClass), + ) ), ( f"NOTE (mristin, 2023-03-29): We expect only lists of classes " f"at the moment, but you specified {type_anno}. " diff --git a/aas_core_codegen/cpp/visitation/_generate.py b/aas_core_codegen/cpp/visitation/_generate.py index 40c444655..727a0d345 100644 --- a/aas_core_codegen/cpp/visitation/_generate.py +++ b/aas_core_codegen/cpp/visitation/_generate.py @@ -341,11 +341,13 @@ def _generate_recursive_visit_for_property( else: assert_never(type_anno.our_type) elif isinstance(type_anno, intermediate.ListTypeAnnotation): - assert isinstance( - type_anno.items, intermediate.OurTypeAnnotation - ) and isinstance( - type_anno.items.our_type, - (intermediate.AbstractClass, intermediate.ConcreteClass), + assert ( + isinstance(type_anno.items, intermediate.PrimitiveTypeAnnotation) + or isinstance(type_anno.items, intermediate.OurTypeAnnotation) + and isinstance( + type_anno.items.our_type, + (intermediate.AbstractClass, intermediate.ConcreteClass), + ) ), ( f"NOTE (mristin, 2023-03-29): We expect only lists of classes " f"at the moment, but you specified {type_anno}. " diff --git a/aas_core_codegen/cpp/xmlization/_generate.py b/aas_core_codegen/cpp/xmlization/_generate.py index afec7a5b3..09adf6160 100644 --- a/aas_core_codegen/cpp/xmlization/_generate.py +++ b/aas_core_codegen/cpp/xmlization/_generate.py @@ -3022,23 +3022,30 @@ def _generate_deserialize_list_property( type_anno = intermediate.beneath_optional(prop.type_annotation) assert isinstance(type_anno, intermediate.ListTypeAnnotation) - assert isinstance(type_anno.items, intermediate.OurTypeAnnotation) and isinstance( - type_anno.items.our_type, - (intermediate.AbstractClass, intermediate.ConcreteClass), + assert ( + isinstance(type_anno.items, intermediate.PrimitiveTypeAnnotation) + or isinstance(type_anno.items, intermediate.OurTypeAnnotation) + and isinstance( + type_anno.items.our_type, + (intermediate.AbstractClass, intermediate.ConcreteClass), + ) ), ( f"NOTE (mristin, 2023-12-10): We expect only lists of classes " f"at the moment, but you specified {type_anno}. " f"Please contact the developers if you need this feature." ) - item_type = cpp_common.generate_type( - type_annotation=type_anno.items, types_namespace=cpp_common.TYPES_NAMESPACE - ) - - from_element_name = cpp_naming.function_name( - Identifier(f"{type_anno.items.our_type.name}_from_element") - ) - + if isinstance(type_anno.items, intermediate.PrimitiveTypeAnnotation): + primitive_type = intermediate.try_primitive_type(type_anno.items) + item_type = _PRIMITIVE_TYPE_TO_NATIVE_TYPE[primitive_type] + from_element_name = _PRIMITIVE_TYPE_TO_DESERIALIZE[primitive_type] + else: + item_type = cpp_common.generate_type( + type_annotation=type_anno.items, types_namespace=cpp_common.TYPES_NAMESPACE + ) + from_element_name = cpp_naming.function_name( + Identifier(f"{type_anno.items.our_type.name}_from_element") + ) var_name = cpp_naming.variable_name(Identifier(f"the_{prop.name}")) # NOTE (mristin, 2023-12-12): @@ -4418,6 +4425,18 @@ class SelfClosingWriter {{ for primitive_type in intermediate.PrimitiveType ) +_PRIMITIVE_TYPE_TO_NATIVE_TYPE = { + intermediate.PrimitiveType.BOOL: "bool", + intermediate.PrimitiveType.INT: "int64_t", + intermediate.PrimitiveType.FLOAT: "double", + intermediate.PrimitiveType.STR: "std::wstring", + intermediate.PrimitiveType.BYTEARRAY: "std::vector", +} +assert all( + primitive_type in _PRIMITIVE_TYPE_TO_NATIVE_TYPE + for primitive_type in intermediate.PrimitiveType +) + def _generate_serialize_primitive_value( primitive_type: intermediate.PrimitiveType, var_name: Identifier @@ -4462,26 +4481,32 @@ def _generate_serialize_list( item_type_annotation: intermediate.TypeAnnotationUnion, var_name: Identifier ) -> Stripped: """Serialize the list at ``var_name``.""" - assert isinstance( - item_type_annotation, intermediate.OurTypeAnnotation - ) and isinstance( - item_type_annotation.our_type, - (intermediate.AbstractClass, intermediate.ConcreteClass), + assert ( + isinstance(item_type_annotation, intermediate.PrimitiveTypeAnnotation) + or isinstance(item_type_annotation, intermediate.OurTypeAnnotation) + and isinstance( + item_type_annotation.our_type, + (intermediate.AbstractClass, intermediate.ConcreteClass), + ) ), ( f"NOTE (mristin, 2023-12-20): We expect only lists of classes " f"at the moment, but you specified a list of {item_type_annotation}. " f"Please contact the developers if you need this feature." ) - item_cls = item_type_annotation.our_type - - item_serialize_function = cpp_naming.function_name( - Identifier(f"serialize_{item_cls.name}_as_element") - ) - - item_type = cpp_common.generate_type_with_const_ref_if_applicable( - type_annotation=item_type_annotation, types_namespace=cpp_common.TYPES_NAMESPACE - ) + if isinstance(item_type_annotation, intermediate.PrimitiveTypeAnnotation): + primitive_type = intermediate.try_primitive_type(item_type_annotation) + item_type = _PRIMITIVE_TYPE_TO_NATIVE_TYPE[primitive_type] + item_serialize_function = _PRIMITIVE_TYPE_TO_DESERIALIZE[primitive_type] + else: + item_cls = item_type_annotation.our_type + item_serialize_function = cpp_naming.function_name( + Identifier(f"serialize_{item_cls.name}_as_element") + ) + item_type = cpp_common.generate_type_with_const_ref_if_applicable( + type_annotation=item_type_annotation, + types_namespace=cpp_common.TYPES_NAMESPACE, + ) return Stripped( f"""\ diff --git a/test_data/cpp/test_main/list_of_primitives/expected_output/common.cpp b/test_data/cpp/test_main/list_of_primitives/expected_output/common.cpp new file mode 100644 index 000000000..7689d23b2 --- /dev/null +++ b/test_data/cpp/test_main/list_of_primitives/expected_output/common.cpp @@ -0,0 +1,14069 @@ +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#include "aas_core/aas_3_0/common.hpp" + +#pragma warning(push, 0) +#include +#pragma warning(pop) + +// NOTE (mristin): +// We use MultiByteToWideChar and WideCharToMulitByte from on Windows +// as std::codecvt is not robust enough on Windows, and produces invalid UTF-16 +// sequences as std::wstring. See: +// https://stackoverflow.com/questions/2573834/c-convert-string-or-char-to-wstring-or-wchar-t, +// especially the comment: +// https://stackoverflow.com/questions/2573834/c-convert-string-or-char-to-wstring-or-wchar-t#comment110447503_18597384 +#ifdef _WIN32 +#pragma warning(push, 0) +#include +#include +#include +#pragma warning(pop) +#else +// NOTE (mristin): +// We use codecvt although it has been deprecated. There has been not +// suitable replacement proposed yet, so we simply stick to it +// until there is. See: +// https://stackoverflow.com/questions/42946335/deprecated-header-codecvt-replacement + +#pragma warning(push, 0) +#include +#include +#pragma warning(pop) +#endif + +namespace aas_core { +namespace aas_3_0 { +namespace common { + +std::string Concat( + const std::string& part0, + const std::string& part1 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49, + const std::string& part50 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + size += part50.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + result.append(part50); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49, + const std::string& part50, + const std::string& part51 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + size += part50.size(); + size += part51.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + result.append(part50); + result.append(part51); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49, + const std::string& part50, + const std::string& part51, + const std::string& part52 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + size += part50.size(); + size += part51.size(); + size += part52.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + result.append(part50); + result.append(part51); + result.append(part52); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49, + const std::string& part50, + const std::string& part51, + const std::string& part52, + const std::string& part53 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + size += part50.size(); + size += part51.size(); + size += part52.size(); + size += part53.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + result.append(part50); + result.append(part51); + result.append(part52); + result.append(part53); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49, + const std::string& part50, + const std::string& part51, + const std::string& part52, + const std::string& part53, + const std::string& part54 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + size += part50.size(); + size += part51.size(); + size += part52.size(); + size += part53.size(); + size += part54.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + result.append(part50); + result.append(part51); + result.append(part52); + result.append(part53); + result.append(part54); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49, + const std::string& part50, + const std::string& part51, + const std::string& part52, + const std::string& part53, + const std::string& part54, + const std::string& part55 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + size += part50.size(); + size += part51.size(); + size += part52.size(); + size += part53.size(); + size += part54.size(); + size += part55.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + result.append(part50); + result.append(part51); + result.append(part52); + result.append(part53); + result.append(part54); + result.append(part55); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49, + const std::string& part50, + const std::string& part51, + const std::string& part52, + const std::string& part53, + const std::string& part54, + const std::string& part55, + const std::string& part56 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + size += part50.size(); + size += part51.size(); + size += part52.size(); + size += part53.size(); + size += part54.size(); + size += part55.size(); + size += part56.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + result.append(part50); + result.append(part51); + result.append(part52); + result.append(part53); + result.append(part54); + result.append(part55); + result.append(part56); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49, + const std::string& part50, + const std::string& part51, + const std::string& part52, + const std::string& part53, + const std::string& part54, + const std::string& part55, + const std::string& part56, + const std::string& part57 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + size += part50.size(); + size += part51.size(); + size += part52.size(); + size += part53.size(); + size += part54.size(); + size += part55.size(); + size += part56.size(); + size += part57.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + result.append(part50); + result.append(part51); + result.append(part52); + result.append(part53); + result.append(part54); + result.append(part55); + result.append(part56); + result.append(part57); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49, + const std::string& part50, + const std::string& part51, + const std::string& part52, + const std::string& part53, + const std::string& part54, + const std::string& part55, + const std::string& part56, + const std::string& part57, + const std::string& part58 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + size += part50.size(); + size += part51.size(); + size += part52.size(); + size += part53.size(); + size += part54.size(); + size += part55.size(); + size += part56.size(); + size += part57.size(); + size += part58.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + result.append(part50); + result.append(part51); + result.append(part52); + result.append(part53); + result.append(part54); + result.append(part55); + result.append(part56); + result.append(part57); + result.append(part58); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49, + const std::string& part50, + const std::string& part51, + const std::string& part52, + const std::string& part53, + const std::string& part54, + const std::string& part55, + const std::string& part56, + const std::string& part57, + const std::string& part58, + const std::string& part59 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + size += part50.size(); + size += part51.size(); + size += part52.size(); + size += part53.size(); + size += part54.size(); + size += part55.size(); + size += part56.size(); + size += part57.size(); + size += part58.size(); + size += part59.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + result.append(part50); + result.append(part51); + result.append(part52); + result.append(part53); + result.append(part54); + result.append(part55); + result.append(part56); + result.append(part57); + result.append(part58); + result.append(part59); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49, + const std::string& part50, + const std::string& part51, + const std::string& part52, + const std::string& part53, + const std::string& part54, + const std::string& part55, + const std::string& part56, + const std::string& part57, + const std::string& part58, + const std::string& part59, + const std::string& part60 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + size += part50.size(); + size += part51.size(); + size += part52.size(); + size += part53.size(); + size += part54.size(); + size += part55.size(); + size += part56.size(); + size += part57.size(); + size += part58.size(); + size += part59.size(); + size += part60.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + result.append(part50); + result.append(part51); + result.append(part52); + result.append(part53); + result.append(part54); + result.append(part55); + result.append(part56); + result.append(part57); + result.append(part58); + result.append(part59); + result.append(part60); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49, + const std::string& part50, + const std::string& part51, + const std::string& part52, + const std::string& part53, + const std::string& part54, + const std::string& part55, + const std::string& part56, + const std::string& part57, + const std::string& part58, + const std::string& part59, + const std::string& part60, + const std::string& part61 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + size += part50.size(); + size += part51.size(); + size += part52.size(); + size += part53.size(); + size += part54.size(); + size += part55.size(); + size += part56.size(); + size += part57.size(); + size += part58.size(); + size += part59.size(); + size += part60.size(); + size += part61.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + result.append(part50); + result.append(part51); + result.append(part52); + result.append(part53); + result.append(part54); + result.append(part55); + result.append(part56); + result.append(part57); + result.append(part58); + result.append(part59); + result.append(part60); + result.append(part61); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49, + const std::string& part50, + const std::string& part51, + const std::string& part52, + const std::string& part53, + const std::string& part54, + const std::string& part55, + const std::string& part56, + const std::string& part57, + const std::string& part58, + const std::string& part59, + const std::string& part60, + const std::string& part61, + const std::string& part62 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + size += part50.size(); + size += part51.size(); + size += part52.size(); + size += part53.size(); + size += part54.size(); + size += part55.size(); + size += part56.size(); + size += part57.size(); + size += part58.size(); + size += part59.size(); + size += part60.size(); + size += part61.size(); + size += part62.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + result.append(part50); + result.append(part51); + result.append(part52); + result.append(part53); + result.append(part54); + result.append(part55); + result.append(part56); + result.append(part57); + result.append(part58); + result.append(part59); + result.append(part60); + result.append(part61); + result.append(part62); + + return result; +} + +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49, + const std::string& part50, + const std::string& part51, + const std::string& part52, + const std::string& part53, + const std::string& part54, + const std::string& part55, + const std::string& part56, + const std::string& part57, + const std::string& part58, + const std::string& part59, + const std::string& part60, + const std::string& part61, + const std::string& part62, + const std::string& part63 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + size += part50.size(); + size += part51.size(); + size += part52.size(); + size += part53.size(); + size += part54.size(); + size += part55.size(); + size += part56.size(); + size += part57.size(); + size += part58.size(); + size += part59.size(); + size += part60.size(); + size += part61.size(); + size += part62.size(); + size += part63.size(); + + std::string result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + result.append(part50); + result.append(part51); + result.append(part52); + result.append(part53); + result.append(part54); + result.append(part55); + result.append(part56); + result.append(part57); + result.append(part58); + result.append(part59); + result.append(part60); + result.append(part61); + result.append(part62); + result.append(part63); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49, + const std::wstring& part50 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + size += part50.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + result.append(part50); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49, + const std::wstring& part50, + const std::wstring& part51 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + size += part50.size(); + size += part51.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + result.append(part50); + result.append(part51); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49, + const std::wstring& part50, + const std::wstring& part51, + const std::wstring& part52 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + size += part50.size(); + size += part51.size(); + size += part52.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + result.append(part50); + result.append(part51); + result.append(part52); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49, + const std::wstring& part50, + const std::wstring& part51, + const std::wstring& part52, + const std::wstring& part53 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + size += part50.size(); + size += part51.size(); + size += part52.size(); + size += part53.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + result.append(part50); + result.append(part51); + result.append(part52); + result.append(part53); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49, + const std::wstring& part50, + const std::wstring& part51, + const std::wstring& part52, + const std::wstring& part53, + const std::wstring& part54 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + size += part50.size(); + size += part51.size(); + size += part52.size(); + size += part53.size(); + size += part54.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + result.append(part50); + result.append(part51); + result.append(part52); + result.append(part53); + result.append(part54); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49, + const std::wstring& part50, + const std::wstring& part51, + const std::wstring& part52, + const std::wstring& part53, + const std::wstring& part54, + const std::wstring& part55 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + size += part50.size(); + size += part51.size(); + size += part52.size(); + size += part53.size(); + size += part54.size(); + size += part55.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + result.append(part50); + result.append(part51); + result.append(part52); + result.append(part53); + result.append(part54); + result.append(part55); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49, + const std::wstring& part50, + const std::wstring& part51, + const std::wstring& part52, + const std::wstring& part53, + const std::wstring& part54, + const std::wstring& part55, + const std::wstring& part56 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + size += part50.size(); + size += part51.size(); + size += part52.size(); + size += part53.size(); + size += part54.size(); + size += part55.size(); + size += part56.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + result.append(part50); + result.append(part51); + result.append(part52); + result.append(part53); + result.append(part54); + result.append(part55); + result.append(part56); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49, + const std::wstring& part50, + const std::wstring& part51, + const std::wstring& part52, + const std::wstring& part53, + const std::wstring& part54, + const std::wstring& part55, + const std::wstring& part56, + const std::wstring& part57 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + size += part50.size(); + size += part51.size(); + size += part52.size(); + size += part53.size(); + size += part54.size(); + size += part55.size(); + size += part56.size(); + size += part57.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + result.append(part50); + result.append(part51); + result.append(part52); + result.append(part53); + result.append(part54); + result.append(part55); + result.append(part56); + result.append(part57); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49, + const std::wstring& part50, + const std::wstring& part51, + const std::wstring& part52, + const std::wstring& part53, + const std::wstring& part54, + const std::wstring& part55, + const std::wstring& part56, + const std::wstring& part57, + const std::wstring& part58 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + size += part50.size(); + size += part51.size(); + size += part52.size(); + size += part53.size(); + size += part54.size(); + size += part55.size(); + size += part56.size(); + size += part57.size(); + size += part58.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + result.append(part50); + result.append(part51); + result.append(part52); + result.append(part53); + result.append(part54); + result.append(part55); + result.append(part56); + result.append(part57); + result.append(part58); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49, + const std::wstring& part50, + const std::wstring& part51, + const std::wstring& part52, + const std::wstring& part53, + const std::wstring& part54, + const std::wstring& part55, + const std::wstring& part56, + const std::wstring& part57, + const std::wstring& part58, + const std::wstring& part59 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + size += part50.size(); + size += part51.size(); + size += part52.size(); + size += part53.size(); + size += part54.size(); + size += part55.size(); + size += part56.size(); + size += part57.size(); + size += part58.size(); + size += part59.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + result.append(part50); + result.append(part51); + result.append(part52); + result.append(part53); + result.append(part54); + result.append(part55); + result.append(part56); + result.append(part57); + result.append(part58); + result.append(part59); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49, + const std::wstring& part50, + const std::wstring& part51, + const std::wstring& part52, + const std::wstring& part53, + const std::wstring& part54, + const std::wstring& part55, + const std::wstring& part56, + const std::wstring& part57, + const std::wstring& part58, + const std::wstring& part59, + const std::wstring& part60 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + size += part50.size(); + size += part51.size(); + size += part52.size(); + size += part53.size(); + size += part54.size(); + size += part55.size(); + size += part56.size(); + size += part57.size(); + size += part58.size(); + size += part59.size(); + size += part60.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + result.append(part50); + result.append(part51); + result.append(part52); + result.append(part53); + result.append(part54); + result.append(part55); + result.append(part56); + result.append(part57); + result.append(part58); + result.append(part59); + result.append(part60); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49, + const std::wstring& part50, + const std::wstring& part51, + const std::wstring& part52, + const std::wstring& part53, + const std::wstring& part54, + const std::wstring& part55, + const std::wstring& part56, + const std::wstring& part57, + const std::wstring& part58, + const std::wstring& part59, + const std::wstring& part60, + const std::wstring& part61 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + size += part50.size(); + size += part51.size(); + size += part52.size(); + size += part53.size(); + size += part54.size(); + size += part55.size(); + size += part56.size(); + size += part57.size(); + size += part58.size(); + size += part59.size(); + size += part60.size(); + size += part61.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + result.append(part50); + result.append(part51); + result.append(part52); + result.append(part53); + result.append(part54); + result.append(part55); + result.append(part56); + result.append(part57); + result.append(part58); + result.append(part59); + result.append(part60); + result.append(part61); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49, + const std::wstring& part50, + const std::wstring& part51, + const std::wstring& part52, + const std::wstring& part53, + const std::wstring& part54, + const std::wstring& part55, + const std::wstring& part56, + const std::wstring& part57, + const std::wstring& part58, + const std::wstring& part59, + const std::wstring& part60, + const std::wstring& part61, + const std::wstring& part62 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + size += part50.size(); + size += part51.size(); + size += part52.size(); + size += part53.size(); + size += part54.size(); + size += part55.size(); + size += part56.size(); + size += part57.size(); + size += part58.size(); + size += part59.size(); + size += part60.size(); + size += part61.size(); + size += part62.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + result.append(part50); + result.append(part51); + result.append(part52); + result.append(part53); + result.append(part54); + result.append(part55); + result.append(part56); + result.append(part57); + result.append(part58); + result.append(part59); + result.append(part60); + result.append(part61); + result.append(part62); + + return result; +} + +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49, + const std::wstring& part50, + const std::wstring& part51, + const std::wstring& part52, + const std::wstring& part53, + const std::wstring& part54, + const std::wstring& part55, + const std::wstring& part56, + const std::wstring& part57, + const std::wstring& part58, + const std::wstring& part59, + const std::wstring& part60, + const std::wstring& part61, + const std::wstring& part62, + const std::wstring& part63 +) { + size_t size = 0; + size += part0.size(); + size += part1.size(); + size += part2.size(); + size += part3.size(); + size += part4.size(); + size += part5.size(); + size += part6.size(); + size += part7.size(); + size += part8.size(); + size += part9.size(); + size += part10.size(); + size += part11.size(); + size += part12.size(); + size += part13.size(); + size += part14.size(); + size += part15.size(); + size += part16.size(); + size += part17.size(); + size += part18.size(); + size += part19.size(); + size += part20.size(); + size += part21.size(); + size += part22.size(); + size += part23.size(); + size += part24.size(); + size += part25.size(); + size += part26.size(); + size += part27.size(); + size += part28.size(); + size += part29.size(); + size += part30.size(); + size += part31.size(); + size += part32.size(); + size += part33.size(); + size += part34.size(); + size += part35.size(); + size += part36.size(); + size += part37.size(); + size += part38.size(); + size += part39.size(); + size += part40.size(); + size += part41.size(); + size += part42.size(); + size += part43.size(); + size += part44.size(); + size += part45.size(); + size += part46.size(); + size += part47.size(); + size += part48.size(); + size += part49.size(); + size += part50.size(); + size += part51.size(); + size += part52.size(); + size += part53.size(); + size += part54.size(); + size += part55.size(); + size += part56.size(); + size += part57.size(); + size += part58.size(); + size += part59.size(); + size += part60.size(); + size += part61.size(); + size += part62.size(); + size += part63.size(); + + std::wstring result; + result.reserve(size); + + result.append(part0); + result.append(part1); + result.append(part2); + result.append(part3); + result.append(part4); + result.append(part5); + result.append(part6); + result.append(part7); + result.append(part8); + result.append(part9); + result.append(part10); + result.append(part11); + result.append(part12); + result.append(part13); + result.append(part14); + result.append(part15); + result.append(part16); + result.append(part17); + result.append(part18); + result.append(part19); + result.append(part20); + result.append(part21); + result.append(part22); + result.append(part23); + result.append(part24); + result.append(part25); + result.append(part26); + result.append(part27); + result.append(part28); + result.append(part29); + result.append(part30); + result.append(part31); + result.append(part32); + result.append(part33); + result.append(part34); + result.append(part35); + result.append(part36); + result.append(part37); + result.append(part38); + result.append(part39); + result.append(part40); + result.append(part41); + result.append(part42); + result.append(part43); + result.append(part44); + result.append(part45); + result.append(part46); + result.append(part47); + result.append(part48); + result.append(part49); + result.append(part50); + result.append(part51); + result.append(part52); + result.append(part53); + result.append(part54); + result.append(part55); + result.append(part56); + result.append(part57); + result.append(part58); + result.append(part59); + result.append(part60); + result.append(part61); + result.append(part62); + result.append(part63); + + return result; +} + +std::string WstringToUtf8(const std::wstring& text) { + #ifdef _WIN32 + // Inspired by: + // https://stackoverflow.com/a/69410299/1600678 + + if (text.empty()) { + return ""; + } + + // NOTE (mristin): + // We put `max` into parentheses to avoid conflicts with + // `max` macro, see: + // https://stackoverflow.com/questions/11544073/how-do-i-deal-with-the-max-macro-in-windows-h-colliding-with-max-in-std + + const size_t text_size = text.size(); + if ( + text_size + > static_cast( + (std::numeric_limits::max)() + ) + ) { + throw std::out_of_range( + common::Concat( + "The size of the text to be converted to UTF-8, ", + std::to_string(text_size), + ", exceeds the maximum int value ", + std::to_string((std::numeric_limits::max)()) + ) + ); + } + const int text_size_int = static_cast(text_size); + + const auto size_needed = WideCharToMultiByte( + CP_UTF8, + 0, + &(text[0]), + text_size_int, + nullptr, + 0, + nullptr, + nullptr + ); + + if (size_needed <= 0) { + throw std::runtime_error( + "WideCharToMultiByte() failed: " + std::to_string(size_needed) + ); + } + + std::string result(size_needed, 0); + + WideCharToMultiByte( + CP_UTF8, + 0, + &(text[0]), + text_size_int, + &(result[0]), + size_needed, + nullptr, + nullptr + ); + + return result; + #else + // NOTE (mristin): + // We use codecvt although it has been deprecated. There has been not + // suitable replacement proposed yet, so we simply stick to it + // until there is. See: + // https://stackoverflow.com/questions/42946335/deprecated-header-codecvt-replacement + + std::wstring_convert > conv; + return conv.to_bytes(text.data()); + #endif +} + +std::wstring Utf8ToWstring( + const char* utf8_text, + size_t utf8_text_size +) { + if (utf8_text_size == 0) { + return std::wstring(); + } + + #ifdef _WIN32 + // NOTE (mristin): + // We have to use MultiByteToWideChar from on Windows + // as std::codecvt is not robust enough on Windows and produces invalid UTF-16 + // sequences as std::wstring. See: + // https://stackoverflow.com/questions/2573834/c-convert-string-or-char-to-wstring-or-wchar-t, + // especially the comment: + // https://stackoverflow.com/questions/2573834/c-convert-string-or-char-to-wstring-or-wchar-t#comment110447503_18597384 + + // Inspired by: + // https://stackoverflow.com/a/69410299/1600678 + + if (utf8_text_size == std::string::npos) { + utf8_text_size = strlen(utf8_text); + } + + // NOTE (mristin): + // We put `max` into parentheses to avoid conflicts with + // `max` macro, see: + // https://stackoverflow.com/questions/11544073/how-do-i-deal-with-the-max-macro-in-windows-h-colliding-with-max-in-std + + if ( + utf8_text_size + > static_cast( + (std::numeric_limits::max)() + ) + ) { + throw std::out_of_range( + common::Concat( + "The size of the UTF-8 text to be converted to wide string, ", + std::to_string(utf8_text_size), + ", exceeds the maximum int value ", + std::to_string((std::numeric_limits::max)()) + ) + ); + } + const int utf8_text_size_int = static_cast(utf8_text_size); + + const auto size_needed = MultiByteToWideChar( + CP_UTF8, + 0, + utf8_text, + utf8_text_size_int, + nullptr, + 0 + ); + if (size_needed <= 0) { + throw std::runtime_error( + "MultiByteToWideChar() failed: " + std::to_string(size_needed) + ); + } + + std::wstring result(size_needed, 0); + + MultiByteToWideChar( + CP_UTF8, + 0, + utf8_text, + utf8_text_size_int, + &(result[0]), + size_needed + ); + + return result; + + #else + // NOTE (mristin): + // We use codecvt although it has been deprecated. There has been not + // suitable replacement proposed yet, so we simply stick to it + // until there is. See: + // https://stackoverflow.com/questions/42946335/deprecated-header-codecvt-replacement + + std::wstring_convert,wchar_t> conv; + return conv.from_bytes(utf8_text); + #endif +} + +std::wstring Utf8ToWstring(const std::string& utf8_text) { + return Utf8ToWstring(&(utf8_text[0]), utf8_text.size()); +} + +} // namespace common +} // namespace aas_3_0 +} // namespace aas_core + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. diff --git a/test_data/cpp/test_main/list_of_primitives/expected_output/common.hpp b/test_data/cpp/test_main/list_of_primitives/expected_output/common.hpp new file mode 100644 index 000000000..1fa0aba2a --- /dev/null +++ b/test_data/cpp/test_main/list_of_primitives/expected_output/common.hpp @@ -0,0 +1,10092 @@ +#ifndef AAS_CORE_AAS_3_0_GUARD_ +#define AAS_CORE_AAS_3_0_GUARD_ + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#pragma warning(push, 0) +#include +#include +#include +#include +#include +#include +#pragma warning(pop) + +// See: https://stackoverflow.com/questions/2324658/how-to-determine-the-version-of-the-c-standard-used-by-the-compiler +#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) +// Standard library provides std::optional in C++17 and above. +#pragma warning(push, 0) +#include +#pragma warning(pop) +#else +// We rely on https://github.com/TartanLlama/optional for optional structure. +#pragma warning(push, 0) +#include +#pragma warning(pop) +#endif + +// NOTE (mristin): +// We check for the version above C++20 as there is no C++23 literal yet, and +// std::expected is available only in C++23. +// See: https://stackoverflow.com/questions/2324658/how-to-determine-the-version-of-the-c-standard-used-by-the-compiler +// and: http://eel.is/c++draft/cpp.predefined#1.1 +#if ((defined(_MSVC_LANG) && _MSVC_LANG > 202002L) || __cplusplus > 202002L) +// Standard library provides std::expected in C++23 and above. +#pragma warning(push, 0) +#include +#pragma warning(pop) +#else +// We rely on https://github.com/TartanLlama/expected for expected structure. +#pragma warning(push, 0) +#include +#pragma warning(pop) +#endif + +namespace aas_core { +namespace aas_3_0 { + +/** + * \defgroup common Common functionality used throughout the library + * @{ + */ +namespace common { + +// Please keep in sync with the preprocessing directives above in the include block. +#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) +// Standard library provides std::optional in C++17 and above. +using std::optional; +using std::nullopt; +using std::make_optional; +#else +using tl::optional; +using tl::nullopt; +using tl::make_optional; +#endif + +// Please keep in sync with the preprocessing directives above in the include block. +#if ((defined(_MSVC_LANG) && _MSVC_LANG > 202002L) || __cplusplus > 202002L) +using std::expected; +using std::unexpected; +using std::make_unexpected; +#else +using tl::expected; +using tl::unexpected; +using tl::make_unexpected; +#endif + +// Please keep in sync with the preprocessing directives above in the include block. +// Standard library provides std::make_unique in C++14 and above. +#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) || __cplusplus >= 201402L) +using std::make_unique; +#else +// Inspired by: +// https://stackoverflow.com/questions/12547983/is-there-a-way-to-write-make-unique-in-vs2012 +template +std::unique_ptr make_unique() { + return std::unique_ptr( + new T() + ); +} + +template< + typename T, + typename A1 +> +std::unique_ptr make_unique( + A1&& a1 +) { + return std::unique_ptr( + new T( + std::forward(a1) + ) + ); +} + +template< + typename T, + typename A1, + typename A2 +> +std::unique_ptr make_unique( + A1&& a1, + A2&& a2 +) { + return std::unique_ptr( + new T( + std::forward(a1), + std::forward(a2) + ) + ); +} + +template< + typename T, + typename A1, + typename A2, + typename A3 +> +std::unique_ptr make_unique( + A1&& a1, + A2&& a2, + A3&& a3 +) { + return std::unique_ptr( + new T( + std::forward(a1), + std::forward(a2), + std::forward(a3) + ) + ); +} + +template< + typename T, + typename A1, + typename A2, + typename A3, + typename A4 +> +std::unique_ptr make_unique( + A1&& a1, + A2&& a2, + A3&& a3, + A4&& a4 +) { + return std::unique_ptr( + new T( + std::forward(a1), + std::forward(a2), + std::forward(a3), + std::forward(a4) + ) + ); +} + +template< + typename T, + typename A1, + typename A2, + typename A3, + typename A4, + typename A5 +> +std::unique_ptr make_unique( + A1&& a1, + A2&& a2, + A3&& a3, + A4&& a4, + A5&& a5 +) { + return std::unique_ptr( + new T( + std::forward(a1), + std::forward(a2), + std::forward(a3), + std::forward(a4), + std::forward(a5) + ) + ); +} + +template< + typename T, + typename A1, + typename A2, + typename A3, + typename A4, + typename A5, + typename A6 +> +std::unique_ptr make_unique( + A1&& a1, + A2&& a2, + A3&& a3, + A4&& a4, + A5&& a5, + A6&& a6 +) { + return std::unique_ptr( + new T( + std::forward(a1), + std::forward(a2), + std::forward(a3), + std::forward(a4), + std::forward(a5), + std::forward(a6) + ) + ); +} + +template< + typename T, + typename A1, + typename A2, + typename A3, + typename A4, + typename A5, + typename A6, + typename A7 +> +std::unique_ptr make_unique( + A1&& a1, + A2&& a2, + A3&& a3, + A4&& a4, + A5&& a5, + A6&& a6, + A7&& a7 +) { + return std::unique_ptr( + new T( + std::forward(a1), + std::forward(a2), + std::forward(a3), + std::forward(a4), + std::forward(a5), + std::forward(a6), + std::forward(a7) + ) + ); +} + +template< + typename T, + typename A1, + typename A2, + typename A3, + typename A4, + typename A5, + typename A6, + typename A7, + typename A8 +> +std::unique_ptr make_unique( + A1&& a1, + A2&& a2, + A3&& a3, + A4&& a4, + A5&& a5, + A6&& a6, + A7&& a7, + A8&& a8 +) { + return std::unique_ptr( + new T( + std::forward(a1), + std::forward(a2), + std::forward(a3), + std::forward(a4), + std::forward(a5), + std::forward(a6), + std::forward(a7), + std::forward(a8) + ) + ); +} + +template< + typename T, + typename A1, + typename A2, + typename A3, + typename A4, + typename A5, + typename A6, + typename A7, + typename A8, + typename A9 +> +std::unique_ptr make_unique( + A1&& a1, + A2&& a2, + A3&& a3, + A4&& a4, + A5&& a5, + A6&& a6, + A7&& a7, + A8&& a8, + A9&& a9 +) { + return std::unique_ptr( + new T( + std::forward(a1), + std::forward(a2), + std::forward(a3), + std::forward(a4), + std::forward(a5), + std::forward(a6), + std::forward(a7), + std::forward(a8), + std::forward(a9) + ) + ); +} + +template< + typename T, + typename A1, + typename A2, + typename A3, + typename A4, + typename A5, + typename A6, + typename A7, + typename A8, + typename A9, + typename A10 +> +std::unique_ptr make_unique( + A1&& a1, + A2&& a2, + A3&& a3, + A4&& a4, + A5&& a5, + A6&& a6, + A7&& a7, + A8&& a8, + A9&& a9, + A10&& a10 +) { + return std::unique_ptr( + new T( + std::forward(a1), + std::forward(a2), + std::forward(a3), + std::forward(a4), + std::forward(a5), + std::forward(a6), + std::forward(a7), + std::forward(a8), + std::forward(a9), + std::forward(a10) + ) + ); +} + +template< + typename T, + typename A1, + typename A2, + typename A3, + typename A4, + typename A5, + typename A6, + typename A7, + typename A8, + typename A9, + typename A10, + typename A11 +> +std::unique_ptr make_unique( + A1&& a1, + A2&& a2, + A3&& a3, + A4&& a4, + A5&& a5, + A6&& a6, + A7&& a7, + A8&& a8, + A9&& a9, + A10&& a10, + A11&& a11 +) { + return std::unique_ptr( + new T( + std::forward(a1), + std::forward(a2), + std::forward(a3), + std::forward(a4), + std::forward(a5), + std::forward(a6), + std::forward(a7), + std::forward(a8), + std::forward(a9), + std::forward(a10), + std::forward(a11) + ) + ); +} + +template< + typename T, + typename A1, + typename A2, + typename A3, + typename A4, + typename A5, + typename A6, + typename A7, + typename A8, + typename A9, + typename A10, + typename A11, + typename A12 +> +std::unique_ptr make_unique( + A1&& a1, + A2&& a2, + A3&& a3, + A4&& a4, + A5&& a5, + A6&& a6, + A7&& a7, + A8&& a8, + A9&& a9, + A10&& a10, + A11&& a11, + A12&& a12 +) { + return std::unique_ptr( + new T( + std::forward(a1), + std::forward(a2), + std::forward(a3), + std::forward(a4), + std::forward(a5), + std::forward(a6), + std::forward(a7), + std::forward(a8), + std::forward(a9), + std::forward(a10), + std::forward(a11), + std::forward(a12) + ) + ); +} + +template< + typename T, + typename A1, + typename A2, + typename A3, + typename A4, + typename A5, + typename A6, + typename A7, + typename A8, + typename A9, + typename A10, + typename A11, + typename A12, + typename A13 +> +std::unique_ptr make_unique( + A1&& a1, + A2&& a2, + A3&& a3, + A4&& a4, + A5&& a5, + A6&& a6, + A7&& a7, + A8&& a8, + A9&& a9, + A10&& a10, + A11&& a11, + A12&& a12, + A13&& a13 +) { + return std::unique_ptr( + new T( + std::forward(a1), + std::forward(a2), + std::forward(a3), + std::forward(a4), + std::forward(a5), + std::forward(a6), + std::forward(a7), + std::forward(a8), + std::forward(a9), + std::forward(a10), + std::forward(a11), + std::forward(a12), + std::forward(a13) + ) + ); +} + +template< + typename T, + typename A1, + typename A2, + typename A3, + typename A4, + typename A5, + typename A6, + typename A7, + typename A8, + typename A9, + typename A10, + typename A11, + typename A12, + typename A13, + typename A14 +> +std::unique_ptr make_unique( + A1&& a1, + A2&& a2, + A3&& a3, + A4&& a4, + A5&& a5, + A6&& a6, + A7&& a7, + A8&& a8, + A9&& a9, + A10&& a10, + A11&& a11, + A12&& a12, + A13&& a13, + A14&& a14 +) { + return std::unique_ptr( + new T( + std::forward(a1), + std::forward(a2), + std::forward(a3), + std::forward(a4), + std::forward(a5), + std::forward(a6), + std::forward(a7), + std::forward(a8), + std::forward(a9), + std::forward(a10), + std::forward(a11), + std::forward(a12), + std::forward(a13), + std::forward(a14) + ) + ); +} + +template< + typename T, + typename A1, + typename A2, + typename A3, + typename A4, + typename A5, + typename A6, + typename A7, + typename A8, + typename A9, + typename A10, + typename A11, + typename A12, + typename A13, + typename A14, + typename A15 +> +std::unique_ptr make_unique( + A1&& a1, + A2&& a2, + A3&& a3, + A4&& a4, + A5&& a5, + A6&& a6, + A7&& a7, + A8&& a8, + A9&& a9, + A10&& a10, + A11&& a11, + A12&& a12, + A13&& a13, + A14&& a14, + A15&& a15 +) { + return std::unique_ptr( + new T( + std::forward(a1), + std::forward(a2), + std::forward(a3), + std::forward(a4), + std::forward(a5), + std::forward(a6), + std::forward(a7), + std::forward(a8), + std::forward(a9), + std::forward(a10), + std::forward(a11), + std::forward(a12), + std::forward(a13), + std::forward(a14), + std::forward(a15) + ) + ); +} +#endif + +/** + * Concatenate 2 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \return a concatenation of the 2 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1 +); + +/** + * Concatenate 3 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \return a concatenation of the 3 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2 +); + +/** + * Concatenate 4 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \return a concatenation of the 4 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3 +); + +/** + * Concatenate 5 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \return a concatenation of the 5 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4 +); + +/** + * Concatenate 6 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \return a concatenation of the 6 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5 +); + +/** + * Concatenate 7 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \return a concatenation of the 7 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6 +); + +/** + * Concatenate 8 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \return a concatenation of the 8 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7 +); + +/** + * Concatenate 9 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \return a concatenation of the 9 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8 +); + +/** + * Concatenate 10 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \return a concatenation of the 10 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9 +); + +/** + * Concatenate 11 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \return a concatenation of the 11 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10 +); + +/** + * Concatenate 12 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \return a concatenation of the 12 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11 +); + +/** + * Concatenate 13 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \return a concatenation of the 13 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12 +); + +/** + * Concatenate 14 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \return a concatenation of the 14 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13 +); + +/** + * Concatenate 15 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \return a concatenation of the 15 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14 +); + +/** + * Concatenate 16 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \return a concatenation of the 16 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15 +); + +/** + * Concatenate 17 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \return a concatenation of the 17 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16 +); + +/** + * Concatenate 18 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \return a concatenation of the 18 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17 +); + +/** + * Concatenate 19 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \return a concatenation of the 19 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18 +); + +/** + * Concatenate 20 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \return a concatenation of the 20 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19 +); + +/** + * Concatenate 21 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \return a concatenation of the 21 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20 +); + +/** + * Concatenate 22 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \return a concatenation of the 22 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21 +); + +/** + * Concatenate 23 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \return a concatenation of the 23 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22 +); + +/** + * Concatenate 24 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \return a concatenation of the 24 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23 +); + +/** + * Concatenate 25 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \return a concatenation of the 25 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24 +); + +/** + * Concatenate 26 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \return a concatenation of the 26 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25 +); + +/** + * Concatenate 27 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \return a concatenation of the 27 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26 +); + +/** + * Concatenate 28 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \return a concatenation of the 28 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27 +); + +/** + * Concatenate 29 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \return a concatenation of the 29 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28 +); + +/** + * Concatenate 30 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \return a concatenation of the 30 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29 +); + +/** + * Concatenate 31 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \return a concatenation of the 31 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30 +); + +/** + * Concatenate 32 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \return a concatenation of the 32 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31 +); + +/** + * Concatenate 33 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \return a concatenation of the 33 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32 +); + +/** + * Concatenate 34 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \return a concatenation of the 34 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33 +); + +/** + * Concatenate 35 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \return a concatenation of the 35 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34 +); + +/** + * Concatenate 36 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \return a concatenation of the 36 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35 +); + +/** + * Concatenate 37 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \return a concatenation of the 37 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36 +); + +/** + * Concatenate 38 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \return a concatenation of the 38 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37 +); + +/** + * Concatenate 39 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \return a concatenation of the 39 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38 +); + +/** + * Concatenate 40 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \return a concatenation of the 40 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39 +); + +/** + * Concatenate 41 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \return a concatenation of the 41 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40 +); + +/** + * Concatenate 42 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \return a concatenation of the 42 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41 +); + +/** + * Concatenate 43 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \return a concatenation of the 43 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42 +); + +/** + * Concatenate 44 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \return a concatenation of the 44 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43 +); + +/** + * Concatenate 45 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \return a concatenation of the 45 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44 +); + +/** + * Concatenate 46 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \return a concatenation of the 46 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45 +); + +/** + * Concatenate 47 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \return a concatenation of the 47 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46 +); + +/** + * Concatenate 48 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \return a concatenation of the 48 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47 +); + +/** + * Concatenate 49 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \return a concatenation of the 49 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48 +); + +/** + * Concatenate 50 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \return a concatenation of the 50 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49 +); + +/** + * Concatenate 51 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \param part50 51st part of the concatenation + * \return a concatenation of the 51 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49, + const std::string& part50 +); + +/** + * Concatenate 52 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \param part50 51st part of the concatenation + * \param part51 52nd part of the concatenation + * \return a concatenation of the 52 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49, + const std::string& part50, + const std::string& part51 +); + +/** + * Concatenate 53 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \param part50 51st part of the concatenation + * \param part51 52nd part of the concatenation + * \param part52 53rd part of the concatenation + * \return a concatenation of the 53 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49, + const std::string& part50, + const std::string& part51, + const std::string& part52 +); + +/** + * Concatenate 54 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \param part50 51st part of the concatenation + * \param part51 52nd part of the concatenation + * \param part52 53rd part of the concatenation + * \param part53 54th part of the concatenation + * \return a concatenation of the 54 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49, + const std::string& part50, + const std::string& part51, + const std::string& part52, + const std::string& part53 +); + +/** + * Concatenate 55 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \param part50 51st part of the concatenation + * \param part51 52nd part of the concatenation + * \param part52 53rd part of the concatenation + * \param part53 54th part of the concatenation + * \param part54 55th part of the concatenation + * \return a concatenation of the 55 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49, + const std::string& part50, + const std::string& part51, + const std::string& part52, + const std::string& part53, + const std::string& part54 +); + +/** + * Concatenate 56 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \param part50 51st part of the concatenation + * \param part51 52nd part of the concatenation + * \param part52 53rd part of the concatenation + * \param part53 54th part of the concatenation + * \param part54 55th part of the concatenation + * \param part55 56th part of the concatenation + * \return a concatenation of the 56 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49, + const std::string& part50, + const std::string& part51, + const std::string& part52, + const std::string& part53, + const std::string& part54, + const std::string& part55 +); + +/** + * Concatenate 57 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \param part50 51st part of the concatenation + * \param part51 52nd part of the concatenation + * \param part52 53rd part of the concatenation + * \param part53 54th part of the concatenation + * \param part54 55th part of the concatenation + * \param part55 56th part of the concatenation + * \param part56 57th part of the concatenation + * \return a concatenation of the 57 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49, + const std::string& part50, + const std::string& part51, + const std::string& part52, + const std::string& part53, + const std::string& part54, + const std::string& part55, + const std::string& part56 +); + +/** + * Concatenate 58 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \param part50 51st part of the concatenation + * \param part51 52nd part of the concatenation + * \param part52 53rd part of the concatenation + * \param part53 54th part of the concatenation + * \param part54 55th part of the concatenation + * \param part55 56th part of the concatenation + * \param part56 57th part of the concatenation + * \param part57 58th part of the concatenation + * \return a concatenation of the 58 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49, + const std::string& part50, + const std::string& part51, + const std::string& part52, + const std::string& part53, + const std::string& part54, + const std::string& part55, + const std::string& part56, + const std::string& part57 +); + +/** + * Concatenate 59 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \param part50 51st part of the concatenation + * \param part51 52nd part of the concatenation + * \param part52 53rd part of the concatenation + * \param part53 54th part of the concatenation + * \param part54 55th part of the concatenation + * \param part55 56th part of the concatenation + * \param part56 57th part of the concatenation + * \param part57 58th part of the concatenation + * \param part58 59th part of the concatenation + * \return a concatenation of the 59 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49, + const std::string& part50, + const std::string& part51, + const std::string& part52, + const std::string& part53, + const std::string& part54, + const std::string& part55, + const std::string& part56, + const std::string& part57, + const std::string& part58 +); + +/** + * Concatenate 60 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \param part50 51st part of the concatenation + * \param part51 52nd part of the concatenation + * \param part52 53rd part of the concatenation + * \param part53 54th part of the concatenation + * \param part54 55th part of the concatenation + * \param part55 56th part of the concatenation + * \param part56 57th part of the concatenation + * \param part57 58th part of the concatenation + * \param part58 59th part of the concatenation + * \param part59 60th part of the concatenation + * \return a concatenation of the 60 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49, + const std::string& part50, + const std::string& part51, + const std::string& part52, + const std::string& part53, + const std::string& part54, + const std::string& part55, + const std::string& part56, + const std::string& part57, + const std::string& part58, + const std::string& part59 +); + +/** + * Concatenate 61 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \param part50 51st part of the concatenation + * \param part51 52nd part of the concatenation + * \param part52 53rd part of the concatenation + * \param part53 54th part of the concatenation + * \param part54 55th part of the concatenation + * \param part55 56th part of the concatenation + * \param part56 57th part of the concatenation + * \param part57 58th part of the concatenation + * \param part58 59th part of the concatenation + * \param part59 60th part of the concatenation + * \param part60 61st part of the concatenation + * \return a concatenation of the 61 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49, + const std::string& part50, + const std::string& part51, + const std::string& part52, + const std::string& part53, + const std::string& part54, + const std::string& part55, + const std::string& part56, + const std::string& part57, + const std::string& part58, + const std::string& part59, + const std::string& part60 +); + +/** + * Concatenate 62 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \param part50 51st part of the concatenation + * \param part51 52nd part of the concatenation + * \param part52 53rd part of the concatenation + * \param part53 54th part of the concatenation + * \param part54 55th part of the concatenation + * \param part55 56th part of the concatenation + * \param part56 57th part of the concatenation + * \param part57 58th part of the concatenation + * \param part58 59th part of the concatenation + * \param part59 60th part of the concatenation + * \param part60 61st part of the concatenation + * \param part61 62nd part of the concatenation + * \return a concatenation of the 62 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49, + const std::string& part50, + const std::string& part51, + const std::string& part52, + const std::string& part53, + const std::string& part54, + const std::string& part55, + const std::string& part56, + const std::string& part57, + const std::string& part58, + const std::string& part59, + const std::string& part60, + const std::string& part61 +); + +/** + * Concatenate 63 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \param part50 51st part of the concatenation + * \param part51 52nd part of the concatenation + * \param part52 53rd part of the concatenation + * \param part53 54th part of the concatenation + * \param part54 55th part of the concatenation + * \param part55 56th part of the concatenation + * \param part56 57th part of the concatenation + * \param part57 58th part of the concatenation + * \param part58 59th part of the concatenation + * \param part59 60th part of the concatenation + * \param part60 61st part of the concatenation + * \param part61 62nd part of the concatenation + * \param part62 63rd part of the concatenation + * \return a concatenation of the 63 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49, + const std::string& part50, + const std::string& part51, + const std::string& part52, + const std::string& part53, + const std::string& part54, + const std::string& part55, + const std::string& part56, + const std::string& part57, + const std::string& part58, + const std::string& part59, + const std::string& part60, + const std::string& part61, + const std::string& part62 +); + +/** + * Concatenate 64 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \param part50 51st part of the concatenation + * \param part51 52nd part of the concatenation + * \param part52 53rd part of the concatenation + * \param part53 54th part of the concatenation + * \param part54 55th part of the concatenation + * \param part55 56th part of the concatenation + * \param part56 57th part of the concatenation + * \param part57 58th part of the concatenation + * \param part58 59th part of the concatenation + * \param part59 60th part of the concatenation + * \param part60 61st part of the concatenation + * \param part61 62nd part of the concatenation + * \param part62 63rd part of the concatenation + * \param part63 64th part of the concatenation + * \return a concatenation of the 64 parts + */ +std::string Concat( + const std::string& part0, + const std::string& part1, + const std::string& part2, + const std::string& part3, + const std::string& part4, + const std::string& part5, + const std::string& part6, + const std::string& part7, + const std::string& part8, + const std::string& part9, + const std::string& part10, + const std::string& part11, + const std::string& part12, + const std::string& part13, + const std::string& part14, + const std::string& part15, + const std::string& part16, + const std::string& part17, + const std::string& part18, + const std::string& part19, + const std::string& part20, + const std::string& part21, + const std::string& part22, + const std::string& part23, + const std::string& part24, + const std::string& part25, + const std::string& part26, + const std::string& part27, + const std::string& part28, + const std::string& part29, + const std::string& part30, + const std::string& part31, + const std::string& part32, + const std::string& part33, + const std::string& part34, + const std::string& part35, + const std::string& part36, + const std::string& part37, + const std::string& part38, + const std::string& part39, + const std::string& part40, + const std::string& part41, + const std::string& part42, + const std::string& part43, + const std::string& part44, + const std::string& part45, + const std::string& part46, + const std::string& part47, + const std::string& part48, + const std::string& part49, + const std::string& part50, + const std::string& part51, + const std::string& part52, + const std::string& part53, + const std::string& part54, + const std::string& part55, + const std::string& part56, + const std::string& part57, + const std::string& part58, + const std::string& part59, + const std::string& part60, + const std::string& part61, + const std::string& part62, + const std::string& part63 +); + +/** + * Concatenate 2 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \return a concatenation of the 2 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1 +); + +/** + * Concatenate 3 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \return a concatenation of the 3 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2 +); + +/** + * Concatenate 4 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \return a concatenation of the 4 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3 +); + +/** + * Concatenate 5 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \return a concatenation of the 5 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4 +); + +/** + * Concatenate 6 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \return a concatenation of the 6 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5 +); + +/** + * Concatenate 7 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \return a concatenation of the 7 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6 +); + +/** + * Concatenate 8 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \return a concatenation of the 8 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7 +); + +/** + * Concatenate 9 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \return a concatenation of the 9 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8 +); + +/** + * Concatenate 10 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \return a concatenation of the 10 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9 +); + +/** + * Concatenate 11 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \return a concatenation of the 11 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10 +); + +/** + * Concatenate 12 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \return a concatenation of the 12 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11 +); + +/** + * Concatenate 13 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \return a concatenation of the 13 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12 +); + +/** + * Concatenate 14 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \return a concatenation of the 14 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13 +); + +/** + * Concatenate 15 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \return a concatenation of the 15 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14 +); + +/** + * Concatenate 16 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \return a concatenation of the 16 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15 +); + +/** + * Concatenate 17 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \return a concatenation of the 17 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16 +); + +/** + * Concatenate 18 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \return a concatenation of the 18 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17 +); + +/** + * Concatenate 19 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \return a concatenation of the 19 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18 +); + +/** + * Concatenate 20 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \return a concatenation of the 20 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19 +); + +/** + * Concatenate 21 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \return a concatenation of the 21 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20 +); + +/** + * Concatenate 22 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \return a concatenation of the 22 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21 +); + +/** + * Concatenate 23 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \return a concatenation of the 23 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22 +); + +/** + * Concatenate 24 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \return a concatenation of the 24 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23 +); + +/** + * Concatenate 25 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \return a concatenation of the 25 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24 +); + +/** + * Concatenate 26 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \return a concatenation of the 26 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25 +); + +/** + * Concatenate 27 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \return a concatenation of the 27 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26 +); + +/** + * Concatenate 28 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \return a concatenation of the 28 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27 +); + +/** + * Concatenate 29 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \return a concatenation of the 29 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28 +); + +/** + * Concatenate 30 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \return a concatenation of the 30 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29 +); + +/** + * Concatenate 31 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \return a concatenation of the 31 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30 +); + +/** + * Concatenate 32 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \return a concatenation of the 32 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31 +); + +/** + * Concatenate 33 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \return a concatenation of the 33 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32 +); + +/** + * Concatenate 34 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \return a concatenation of the 34 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33 +); + +/** + * Concatenate 35 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \return a concatenation of the 35 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34 +); + +/** + * Concatenate 36 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \return a concatenation of the 36 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35 +); + +/** + * Concatenate 37 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \return a concatenation of the 37 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36 +); + +/** + * Concatenate 38 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \return a concatenation of the 38 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37 +); + +/** + * Concatenate 39 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \return a concatenation of the 39 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38 +); + +/** + * Concatenate 40 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \return a concatenation of the 40 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39 +); + +/** + * Concatenate 41 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \return a concatenation of the 41 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40 +); + +/** + * Concatenate 42 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \return a concatenation of the 42 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41 +); + +/** + * Concatenate 43 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \return a concatenation of the 43 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42 +); + +/** + * Concatenate 44 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \return a concatenation of the 44 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43 +); + +/** + * Concatenate 45 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \return a concatenation of the 45 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44 +); + +/** + * Concatenate 46 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \return a concatenation of the 46 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45 +); + +/** + * Concatenate 47 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \return a concatenation of the 47 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46 +); + +/** + * Concatenate 48 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \return a concatenation of the 48 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47 +); + +/** + * Concatenate 49 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \return a concatenation of the 49 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48 +); + +/** + * Concatenate 50 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \return a concatenation of the 50 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49 +); + +/** + * Concatenate 51 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \param part50 51st part of the concatenation + * \return a concatenation of the 51 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49, + const std::wstring& part50 +); + +/** + * Concatenate 52 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \param part50 51st part of the concatenation + * \param part51 52nd part of the concatenation + * \return a concatenation of the 52 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49, + const std::wstring& part50, + const std::wstring& part51 +); + +/** + * Concatenate 53 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \param part50 51st part of the concatenation + * \param part51 52nd part of the concatenation + * \param part52 53rd part of the concatenation + * \return a concatenation of the 53 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49, + const std::wstring& part50, + const std::wstring& part51, + const std::wstring& part52 +); + +/** + * Concatenate 54 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \param part50 51st part of the concatenation + * \param part51 52nd part of the concatenation + * \param part52 53rd part of the concatenation + * \param part53 54th part of the concatenation + * \return a concatenation of the 54 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49, + const std::wstring& part50, + const std::wstring& part51, + const std::wstring& part52, + const std::wstring& part53 +); + +/** + * Concatenate 55 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \param part50 51st part of the concatenation + * \param part51 52nd part of the concatenation + * \param part52 53rd part of the concatenation + * \param part53 54th part of the concatenation + * \param part54 55th part of the concatenation + * \return a concatenation of the 55 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49, + const std::wstring& part50, + const std::wstring& part51, + const std::wstring& part52, + const std::wstring& part53, + const std::wstring& part54 +); + +/** + * Concatenate 56 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \param part50 51st part of the concatenation + * \param part51 52nd part of the concatenation + * \param part52 53rd part of the concatenation + * \param part53 54th part of the concatenation + * \param part54 55th part of the concatenation + * \param part55 56th part of the concatenation + * \return a concatenation of the 56 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49, + const std::wstring& part50, + const std::wstring& part51, + const std::wstring& part52, + const std::wstring& part53, + const std::wstring& part54, + const std::wstring& part55 +); + +/** + * Concatenate 57 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \param part50 51st part of the concatenation + * \param part51 52nd part of the concatenation + * \param part52 53rd part of the concatenation + * \param part53 54th part of the concatenation + * \param part54 55th part of the concatenation + * \param part55 56th part of the concatenation + * \param part56 57th part of the concatenation + * \return a concatenation of the 57 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49, + const std::wstring& part50, + const std::wstring& part51, + const std::wstring& part52, + const std::wstring& part53, + const std::wstring& part54, + const std::wstring& part55, + const std::wstring& part56 +); + +/** + * Concatenate 58 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \param part50 51st part of the concatenation + * \param part51 52nd part of the concatenation + * \param part52 53rd part of the concatenation + * \param part53 54th part of the concatenation + * \param part54 55th part of the concatenation + * \param part55 56th part of the concatenation + * \param part56 57th part of the concatenation + * \param part57 58th part of the concatenation + * \return a concatenation of the 58 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49, + const std::wstring& part50, + const std::wstring& part51, + const std::wstring& part52, + const std::wstring& part53, + const std::wstring& part54, + const std::wstring& part55, + const std::wstring& part56, + const std::wstring& part57 +); + +/** + * Concatenate 59 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \param part50 51st part of the concatenation + * \param part51 52nd part of the concatenation + * \param part52 53rd part of the concatenation + * \param part53 54th part of the concatenation + * \param part54 55th part of the concatenation + * \param part55 56th part of the concatenation + * \param part56 57th part of the concatenation + * \param part57 58th part of the concatenation + * \param part58 59th part of the concatenation + * \return a concatenation of the 59 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49, + const std::wstring& part50, + const std::wstring& part51, + const std::wstring& part52, + const std::wstring& part53, + const std::wstring& part54, + const std::wstring& part55, + const std::wstring& part56, + const std::wstring& part57, + const std::wstring& part58 +); + +/** + * Concatenate 60 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \param part50 51st part of the concatenation + * \param part51 52nd part of the concatenation + * \param part52 53rd part of the concatenation + * \param part53 54th part of the concatenation + * \param part54 55th part of the concatenation + * \param part55 56th part of the concatenation + * \param part56 57th part of the concatenation + * \param part57 58th part of the concatenation + * \param part58 59th part of the concatenation + * \param part59 60th part of the concatenation + * \return a concatenation of the 60 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49, + const std::wstring& part50, + const std::wstring& part51, + const std::wstring& part52, + const std::wstring& part53, + const std::wstring& part54, + const std::wstring& part55, + const std::wstring& part56, + const std::wstring& part57, + const std::wstring& part58, + const std::wstring& part59 +); + +/** + * Concatenate 61 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \param part50 51st part of the concatenation + * \param part51 52nd part of the concatenation + * \param part52 53rd part of the concatenation + * \param part53 54th part of the concatenation + * \param part54 55th part of the concatenation + * \param part55 56th part of the concatenation + * \param part56 57th part of the concatenation + * \param part57 58th part of the concatenation + * \param part58 59th part of the concatenation + * \param part59 60th part of the concatenation + * \param part60 61st part of the concatenation + * \return a concatenation of the 61 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49, + const std::wstring& part50, + const std::wstring& part51, + const std::wstring& part52, + const std::wstring& part53, + const std::wstring& part54, + const std::wstring& part55, + const std::wstring& part56, + const std::wstring& part57, + const std::wstring& part58, + const std::wstring& part59, + const std::wstring& part60 +); + +/** + * Concatenate 62 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \param part50 51st part of the concatenation + * \param part51 52nd part of the concatenation + * \param part52 53rd part of the concatenation + * \param part53 54th part of the concatenation + * \param part54 55th part of the concatenation + * \param part55 56th part of the concatenation + * \param part56 57th part of the concatenation + * \param part57 58th part of the concatenation + * \param part58 59th part of the concatenation + * \param part59 60th part of the concatenation + * \param part60 61st part of the concatenation + * \param part61 62nd part of the concatenation + * \return a concatenation of the 62 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49, + const std::wstring& part50, + const std::wstring& part51, + const std::wstring& part52, + const std::wstring& part53, + const std::wstring& part54, + const std::wstring& part55, + const std::wstring& part56, + const std::wstring& part57, + const std::wstring& part58, + const std::wstring& part59, + const std::wstring& part60, + const std::wstring& part61 +); + +/** + * Concatenate 63 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \param part50 51st part of the concatenation + * \param part51 52nd part of the concatenation + * \param part52 53rd part of the concatenation + * \param part53 54th part of the concatenation + * \param part54 55th part of the concatenation + * \param part55 56th part of the concatenation + * \param part56 57th part of the concatenation + * \param part57 58th part of the concatenation + * \param part58 59th part of the concatenation + * \param part59 60th part of the concatenation + * \param part60 61st part of the concatenation + * \param part61 62nd part of the concatenation + * \param part62 63rd part of the concatenation + * \return a concatenation of the 63 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49, + const std::wstring& part50, + const std::wstring& part51, + const std::wstring& part52, + const std::wstring& part53, + const std::wstring& part54, + const std::wstring& part55, + const std::wstring& part56, + const std::wstring& part57, + const std::wstring& part58, + const std::wstring& part59, + const std::wstring& part60, + const std::wstring& part61, + const std::wstring& part62 +); + +/** + * Concatenate 64 strings. + * + * \param part0 1st part of the concatenation + * \param part1 2nd part of the concatenation + * \param part2 3rd part of the concatenation + * \param part3 4th part of the concatenation + * \param part4 5th part of the concatenation + * \param part5 6th part of the concatenation + * \param part6 7th part of the concatenation + * \param part7 8th part of the concatenation + * \param part8 9th part of the concatenation + * \param part9 10th part of the concatenation + * \param part10 11st part of the concatenation + * \param part11 12nd part of the concatenation + * \param part12 13rd part of the concatenation + * \param part13 14th part of the concatenation + * \param part14 15th part of the concatenation + * \param part15 16th part of the concatenation + * \param part16 17th part of the concatenation + * \param part17 18th part of the concatenation + * \param part18 19th part of the concatenation + * \param part19 20th part of the concatenation + * \param part20 21st part of the concatenation + * \param part21 22nd part of the concatenation + * \param part22 23rd part of the concatenation + * \param part23 24th part of the concatenation + * \param part24 25th part of the concatenation + * \param part25 26th part of the concatenation + * \param part26 27th part of the concatenation + * \param part27 28th part of the concatenation + * \param part28 29th part of the concatenation + * \param part29 30th part of the concatenation + * \param part30 31st part of the concatenation + * \param part31 32nd part of the concatenation + * \param part32 33rd part of the concatenation + * \param part33 34th part of the concatenation + * \param part34 35th part of the concatenation + * \param part35 36th part of the concatenation + * \param part36 37th part of the concatenation + * \param part37 38th part of the concatenation + * \param part38 39th part of the concatenation + * \param part39 40th part of the concatenation + * \param part40 41st part of the concatenation + * \param part41 42nd part of the concatenation + * \param part42 43rd part of the concatenation + * \param part43 44th part of the concatenation + * \param part44 45th part of the concatenation + * \param part45 46th part of the concatenation + * \param part46 47th part of the concatenation + * \param part47 48th part of the concatenation + * \param part48 49th part of the concatenation + * \param part49 50th part of the concatenation + * \param part50 51st part of the concatenation + * \param part51 52nd part of the concatenation + * \param part52 53rd part of the concatenation + * \param part53 54th part of the concatenation + * \param part54 55th part of the concatenation + * \param part55 56th part of the concatenation + * \param part56 57th part of the concatenation + * \param part57 58th part of the concatenation + * \param part58 59th part of the concatenation + * \param part59 60th part of the concatenation + * \param part60 61st part of the concatenation + * \param part61 62nd part of the concatenation + * \param part62 63rd part of the concatenation + * \param part63 64th part of the concatenation + * \return a concatenation of the 64 parts + */ +std::wstring Concat( + const std::wstring& part0, + const std::wstring& part1, + const std::wstring& part2, + const std::wstring& part3, + const std::wstring& part4, + const std::wstring& part5, + const std::wstring& part6, + const std::wstring& part7, + const std::wstring& part8, + const std::wstring& part9, + const std::wstring& part10, + const std::wstring& part11, + const std::wstring& part12, + const std::wstring& part13, + const std::wstring& part14, + const std::wstring& part15, + const std::wstring& part16, + const std::wstring& part17, + const std::wstring& part18, + const std::wstring& part19, + const std::wstring& part20, + const std::wstring& part21, + const std::wstring& part22, + const std::wstring& part23, + const std::wstring& part24, + const std::wstring& part25, + const std::wstring& part26, + const std::wstring& part27, + const std::wstring& part28, + const std::wstring& part29, + const std::wstring& part30, + const std::wstring& part31, + const std::wstring& part32, + const std::wstring& part33, + const std::wstring& part34, + const std::wstring& part35, + const std::wstring& part36, + const std::wstring& part37, + const std::wstring& part38, + const std::wstring& part39, + const std::wstring& part40, + const std::wstring& part41, + const std::wstring& part42, + const std::wstring& part43, + const std::wstring& part44, + const std::wstring& part45, + const std::wstring& part46, + const std::wstring& part47, + const std::wstring& part48, + const std::wstring& part49, + const std::wstring& part50, + const std::wstring& part51, + const std::wstring& part52, + const std::wstring& part53, + const std::wstring& part54, + const std::wstring& part55, + const std::wstring& part56, + const std::wstring& part57, + const std::wstring& part58, + const std::wstring& part59, + const std::wstring& part60, + const std::wstring& part61, + const std::wstring& part62, + const std::wstring& part63 +); + +/** + * Check if all the elements satisfy the \p condition. + * + * \param condition returning a boolean to be checked for each element + * \param container to be iterated through + * \return `true` if all the elements of \p container satisfy the \p condition + */ +template +bool All( + FunctorT condition, + const ContainerT& container +) { + for (const auto& item : container ) { + if (!condition(item)) { + return false; + } + } + return true; +} + +/** + * Check if any of the elements satisfy the \p condition. + * + * \param condition returning a boolean to be checked for each element + * \param container to be iterated through + * \return `true` if any of the elements of \p container satisfy the \p condition + */ +template +bool Some( + FunctorT condition, + const ContainerT& container +) { + for (const auto& item : container ) { + if (condition(item)) { + return true; + } + } + return false; +} + +/** + * Check if all the numbers in the range `[start, end)` satisfy the \p condition. + * + * \param condition returning a boolean to be checked for each number + * \param start of the range + * \param end of the range + * \return \parblock + * `true` if all the numbers between \p start and \p end (excluded) + * satisfy the \p condition + * \endparblock + */ +template +bool AllRange( + FunctorT condition, + size_t start, + size_t end +) { + for (size_t i = start; i < end; ++i) { + if (!condition(i)) { + return false; + } + } + return true; +} + +/** + * Check if any number in the range `[start, end)` satisfy the \p condition. + * + * \param condition returning a boolean to be checked for each number + * \param start of the range + * \param end of the range + * \return \parblock + * `true` if any number between \p start and + * \p end (excluded) satisfy the \p condition + * \endparblock + */ +template +bool SomeRange( + FunctorT condition, + size_t start, + size_t end +) { + for (size_t i = start; i < end; ++i) { + if (condition(i)) { + return true; + } + } + return false; +} + +/** + * Check if the \p container contains the \p value. + * + * \param container to be searched through + * \param value to be search for + * \return `true` if \p value is in the \p container + */ +template +bool Contains( + const ContainerT& container, + const ValueT& value +) { + const auto container_begin = std::begin(container); + const auto container_end = std::end(container); + return std::find( + container_begin, + container_end, + value + ) != container_end; +} + +/** + * Convert platform-independent the wide string to a UTF-8 string. + * + * \param text to be converted + * \return UTF-8 encoded \p text + */ +std::string WstringToUtf8(const std::wstring& text); + +/** + * Convert platform-independent the UTF-8 encoded string to a wide string. + * + * \param utf8_text UTF-8 encoded text to be converted + * \param utf8_text_size size of the text to be converted. If std::string::npos, + * the \p utf8_text is assumed to be null-terminated and the size is determined + * using `strlen`. + * \return the wide-string representation + */ +std::wstring Utf8ToWstring( + const char* utf8_text, + size_t utf8_text_size = std::string::npos +); + +/** + * Convert platform-independent the UTF-8 encoded string to a wide string. + * + * \param utf8_text UTF-8 encoded text to be converted + * \return wide string + */ +std::wstring Utf8ToWstring(const std::string& utf8_text); + +} // namespace common +/**@}*/ + +} // namespace aas_3_0 +} // namespace aas_core + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#endif // AAS_CORE_AAS_3_0_GUARD_ diff --git a/test_data/cpp/test_main/list_of_primitives/expected_output/constants.cpp b/test_data/cpp/test_main/list_of_primitives/expected_output/constants.cpp new file mode 100644 index 000000000..dd5eaef37 --- /dev/null +++ b/test_data/cpp/test_main/list_of_primitives/expected_output/constants.cpp @@ -0,0 +1,27 @@ +#include "aas_core/aas_3_0/constants.hpp" + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +namespace aas_core { +namespace aas_3_0 { +namespace constants { + +std::size_t HashBytes::operator()( + const std::vector& bytes +) const { + std::size_t result = 0; + const std::size_t prime = 31; + const std::size_t size = bytes.size(); + for (std::size_t i = 0; i < size; ++i) { + result = bytes[i] + (result * prime); + } + return result; +} + +} // namespace constants +} // namespace aas_3_0 +} // namespace aas_core + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. diff --git a/test_data/cpp/test_main/list_of_primitives/expected_output/constants.hpp b/test_data/cpp/test_main/list_of_primitives/expected_output/constants.hpp new file mode 100644 index 000000000..76d34deff --- /dev/null +++ b/test_data/cpp/test_main/list_of_primitives/expected_output/constants.hpp @@ -0,0 +1,40 @@ +#ifndef AAS_CORE_AAS_3_0_CONSTANTS_GUARD_ +#define AAS_CORE_AAS_3_0_CONSTANTS_GUARD_ + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#include "aas_core/aas_3_0/types.hpp" + +#pragma warning(push, 0) +#include +#include +#include +#pragma warning(pop) + +namespace aas_core { +namespace aas_3_0 { + +/** + * \defgroup constants Pre-defined constants of the meta-model + * @{ + */ +namespace constants { + +/** + * Hash a blob of bytes based on the Java's String hash. + */ +struct HashBytes { + std::size_t operator()(const std::vector& bytes) const; +}; + +} // namespace common +/**@}*/ + +} // namespace aas_3_0 +} // namespace aas_core + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#endif // AAS_CORE_AAS_3_0_CONSTANTS_GUARD_ diff --git a/test_data/cpp/test_main/list_of_primitives/expected_output/enhancing.hpp b/test_data/cpp/test_main/list_of_primitives/expected_output/enhancing.hpp new file mode 100644 index 000000000..36f1c1211 --- /dev/null +++ b/test_data/cpp/test_main/list_of_primitives/expected_output/enhancing.hpp @@ -0,0 +1,638 @@ +#ifndef AAS_CORE_AAS_3_0_ENHANCING_GUARD_ +#define AAS_CORE_AAS_3_0_ENHANCING_GUARD_ + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#include "aas_core/aas_3_0/common.hpp" +#include "aas_core/aas_3_0/stringification.hpp" +#include "aas_core/aas_3_0/types.hpp" + +#pragma warning(push, 0) +#include +#include +#pragma warning(pop) + +namespace aas_core { +namespace aas_3_0 { + +/** + * \defgroup enhancing Enhance instances of the model with your custom enhancements. + * @{ + */ +namespace enhancing { + +// region Forward declarations + +template +std::shared_ptr< + types::IMyClass +> Wrap( + const std::shared_ptr< + types::IMyClass + >& that, + const std::function< + std::shared_ptr( + const std::shared_ptr& + ) + >& factory +); + +template +std::shared_ptr< + types::IListOfPrimitives +> Wrap( + const std::shared_ptr< + types::IListOfPrimitives + >& that, + const std::function< + std::shared_ptr( + const std::shared_ptr& + ) + >& factory +); + +// endregion Forward declarations + +/// \cond HIDDEN +namespace impl { + +template +class IEnhanced { + public: + virtual const std::shared_ptr& enhancement() const = 0; + + virtual std::shared_ptr& mutable_enhancement() = 0; + + virtual void set_enhancement( + std::shared_ptr value + ) = 0; + + virtual ~IEnhanced() = default; +}; + +template +class EnhancedMyClass + : virtual public types::IMyClass, + virtual public IEnhanced { + public: + types::ModelType model_type() const override { + return types::ModelType::kMyClass; + } + + const std::shared_ptr& enhancement() const { + return enhancement_; + } + + std::shared_ptr& mutable_enhancement() { + return enhancement_; + } + + void set_enhancement( + std::shared_ptr value + ) { + enhancement_ = std::move(value); + } + + EnhancedMyClass( + std::shared_ptr instance, + std::shared_ptr enhancement + ) : + instance_(instance), + enhancement_(enhancement) { + // Intentionally empty. + } + + virtual ~EnhancedMyClass() = default; + + private: + std::shared_ptr instance_; + std::shared_ptr enhancement_; +}; + +template +class EnhancedListOfPrimitives + : virtual public types::IListOfPrimitives, + virtual public IEnhanced { + public: + types::ModelType model_type() const override { + return types::ModelType::kListOfPrimitives; + } + + const std::vector& strings() const override { + return instance_->strings(); + } + + std::vector& mutable_strings() override { + return instance_->mutable_strings(); + } + + void set_strings( + std::vector value + ) override { + instance_->set_strings(value); + } + + const std::vector& integers() const override { + return instance_->integers(); + } + + std::vector& mutable_integers() override { + return instance_->mutable_integers(); + } + + void set_integers( + std::vector value + ) override { + instance_->set_integers(value); + } + + const std::vector& booleans() const override { + return instance_->booleans(); + } + + std::vector& mutable_booleans() override { + return instance_->mutable_booleans(); + } + + void set_booleans( + std::vector value + ) override { + instance_->set_booleans(value); + } + + const std::vector< + std::shared_ptr + >& classes() const override { + return instance_->classes(); + } + + std::vector< + std::shared_ptr + >& mutable_classes() override { + return instance_->mutable_classes(); + } + + void set_classes( + std::vector< + std::shared_ptr + > value + ) override { + instance_->set_classes(value); + } + + const std::shared_ptr& enhancement() const { + return enhancement_; + } + + std::shared_ptr& mutable_enhancement() { + return enhancement_; + } + + void set_enhancement( + std::shared_ptr value + ) { + enhancement_ = std::move(value); + } + + EnhancedListOfPrimitives( + std::shared_ptr instance, + std::shared_ptr enhancement + ) : + instance_(instance), + enhancement_(enhancement) { + // Intentionally empty. + } + + virtual ~EnhancedListOfPrimitives() = default; + + private: + std::shared_ptr instance_; + std::shared_ptr enhancement_; +}; + +/** + * Wrap \p that with an enhanced instance. + * + * \param that instance to be wrapped and enhanced + * \param factory to produce an enhancement based on an instance + * \return Enhanced instance, or `that` if no enhancement produced + * + * \tparam E type of the enhancement + */ +template +std::shared_ptr WrapMyClass( + const std::shared_ptr& that, + const std::function< + std::shared_ptr( + const std::shared_ptr& + ) + >& factory +) { + // We assume that we already checked whether `that` has been enhanced + // in the caller. + + // No properties to be recursively enhanced. + + std::shared_ptr enh( + factory(that) + ); + return (enh == nullptr) + ? that + : std::shared_ptr( + new EnhancedMyClass( + that, + enh + ) + ); +} + +/** + * Wrap \p that with an enhanced instance. + * + * \param that instance to be wrapped and enhanced + * \param factory to produce an enhancement based on an instance + * \return Enhanced instance, or `that` if no enhancement produced + * + * \tparam E type of the enhancement + */ +template +std::shared_ptr WrapListOfPrimitives( + const std::shared_ptr& that, + const std::function< + std::shared_ptr( + const std::shared_ptr& + ) + >& factory +) { + // We assume that we already checked whether `that` has been enhanced + // in the caller. + + { + const std::vector& value( + that->strings() + ); + const std::size_t size = value.size(); + + std::vector wrapped; + wrapped.reserve(size); + + for ( + const std::wstring& item + : value + ) { + wrapped.emplace_back( + Wrap( + item, + factory + ) + ); + } + + that->set_strings( + std::move(wrapped) + ); + } + + { + const std::vector& value( + that->integers() + ); + const std::size_t size = value.size(); + + std::vector wrapped; + wrapped.reserve(size); + + for ( + int64_t item + : value + ) { + wrapped.emplace_back( + Wrap( + item, + factory + ) + ); + } + + that->set_integers( + std::move(wrapped) + ); + } + + { + const std::vector& value( + that->booleans() + ); + const std::size_t size = value.size(); + + std::vector wrapped; + wrapped.reserve(size); + + for ( + bool item + : value + ) { + wrapped.emplace_back( + Wrap( + item, + factory + ) + ); + } + + that->set_booleans( + std::move(wrapped) + ); + } + + { + const std::vector< + std::shared_ptr + >& value( + that->classes() + ); + const std::size_t size = value.size(); + + std::vector< + std::shared_ptr + > wrapped; + wrapped.reserve(size); + + for ( + const std::shared_ptr& item + : value + ) { + wrapped.emplace_back( + Wrap( + item, + factory + ) + ); + } + + that->set_classes( + std::move(wrapped) + ); + } + + std::shared_ptr enh( + factory(that) + ); + return (enh == nullptr) + ? that + : std::shared_ptr( + new EnhancedListOfPrimitives( + that, + enh + ) + ); +} + +/** + * Assert that the \p that instance has not been already enhanced. + * + * \param that instance to be checked + * \tparam E type of the enhancement + * \tparam T interface type of \p that instance + * \throw std::logic_error if \p that already enhanced + */ +template< + typename E, + typename T, + typename std::enable_if< + std::is_base_of::value + >::type* = nullptr +> +void AssertNotEnhanced( + const std::shared_ptr& that +) { + std::shared_ptr > enhanced( + std::dynamic_pointer_cast< + impl::IEnhanced + >(that) + ); + if (enhanced != nullptr) { + throw std::logic_error( + common::Concat( + "An instance of ", + stringification::to_string(that->model_type()), + " has been already wrapped." + ) + ); + } +} + +} // namespace impl +/// \endcond + +/** + * Wrap \p that instance recursively with the enhancement produced by the \p factory. + * + * The factory decides itself whether it will produce an enhancement for + * \p that instance, or not. Even if no enhancement has been produced for \p that + * instance, we will still continue to enhance the instances referenced + * by \p that instance recursively. + * + * \param that instance to wrap + * \param factory to selectively produce an enhancement + * \return enhanced \p that instance + * \throw std::logic_error if \p that instance has been already wrapped. + * \tparam E type of the enhancement + */ +///@{ + +template +std::shared_ptr< + types::IClass +> Wrap( + const std::shared_ptr< + types::IClass + >& that, + const std::function< + std::shared_ptr( + const std::shared_ptr& + ) + >& factory +) { + impl::AssertNotEnhanced< + E, + types::IClass + >(that); + + switch (that->model_type()) { + case types::ModelType::kMyClass: + return impl::WrapMyClass( + std::dynamic_pointer_cast< + types::IMyClass + >(that), + factory + ); + break; + case types::ModelType::kListOfPrimitives: + return impl::WrapListOfPrimitives( + std::dynamic_pointer_cast< + types::IListOfPrimitives + >(that), + factory + ); + break; + default: + throw std::invalid_argument( + common::Concat( + "Unexpected model type: ", + std::to_string( + static_cast( + that->model_type() + ) + ) + ) + ); + break; + } +} + +template +std::shared_ptr< + types::IMyClass +> Wrap( + const std::shared_ptr< + types::IMyClass + >& that, + const std::function< + std::shared_ptr( + const std::shared_ptr& + ) + >& factory +) { + impl::AssertNotEnhanced< + E, + types::IMyClass + >(that); + + switch (that->model_type()) { + case types::ModelType::kMyClass: + return impl::WrapMyClass( + that, + factory + ); + break; + default: + throw std::invalid_argument( + common::Concat( + "Unexpected model type: ", + std::to_string( + static_cast( + that->model_type() + ) + ) + ) + ); + break; + } +} + +template +std::shared_ptr< + types::IListOfPrimitives +> Wrap( + const std::shared_ptr< + types::IListOfPrimitives + >& that, + const std::function< + std::shared_ptr( + const std::shared_ptr& + ) + >& factory +) { + impl::AssertNotEnhanced< + E, + types::IListOfPrimitives + >(that); + + switch (that->model_type()) { + case types::ModelType::kListOfPrimitives: + return impl::WrapListOfPrimitives( + that, + factory + ); + break; + default: + throw std::invalid_argument( + common::Concat( + "Unexpected model type: ", + std::to_string( + static_cast( + that->model_type() + ) + ) + ) + ); + break; + } +} + +///@}} + +/** + * Try to unwrap the enhancement from \p that instance. + * + * \param that instance possibly wrapped with an enhancement + * \return the enhancement, or `nullptr` if \p that instance has not been wrapped + * \tparam E type of the enhancement + */ +template +std::shared_ptr Unwrap( + const std::shared_ptr& that +) { + const std::shared_ptr >& maybe_enhanced( + std::dynamic_pointer_cast >(that) + ); + + if (!maybe_enhanced) { + return nullptr; + } + + return maybe_enhanced->enhancement(); +} + +/** + * Unwrap the enhancement from \p that instance. + * + * \remark \p that instance must have been wrapped before. + * + * \param that instance expected to be wrapped with an enhancement + * \return the enhancement + * \throw std::invalid_argument if \p that instance has not been wrapped + * \tparam E type of the enhancement + */ +template +std::shared_ptr MustUnwrap( + const std::shared_ptr& that +) { + std::shared_ptr enhancement( + Unwrap(that) + ); + if (!enhancement) { + throw std::invalid_argument( + common::Concat( + "Expected an instance of ", + stringification::to_string(that->model_type()), + " to have been already wrapped with an enhancement, " + "but it has been not." + ) + ); + } + return enhancement; +} + +} // namespace enhancing +/**@}*/ + +} // namespace aas_3_0 +} // namespace aas_core + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#endif // AAS_CORE_AAS_3_0_ENHANCING_GUARD_ diff --git a/test_data/cpp/test_main/list_of_primitives/expected_output/iteration.cpp b/test_data/cpp/test_main/list_of_primitives/expected_output/iteration.cpp new file mode 100644 index 000000000..be373c585 --- /dev/null +++ b/test_data/cpp/test_main/list_of_primitives/expected_output/iteration.cpp @@ -0,0 +1,1229 @@ +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#include "aas_core/aas_3_0/common.hpp" +#include "aas_core/aas_3_0/iteration.hpp" + +namespace aas_core { +namespace aas_3_0 { +namespace iteration { + +// region Pathing + +/** + * Translate the enumeration literal \p property to text. + * + * \param property to be converted into text + * \return text representation of \p property + * \throw std::invalid_argument if \p property invalid + */ +std::wstring PropertyToWstring( + Property property +) { + switch (property) { + case Property::kBooleans: + return L"booleans"; + case Property::kClasses: + return L"classes"; + case Property::kIntegers: + return L"integers"; + case Property::kStrings: + return L"strings"; + default: + throw std::invalid_argument( + common::Concat( + "Unexpected property literal: ", + std::to_string( + static_cast(property) + ) + ) + ); + } +} // function to_wstring + +// region struct PropertySegment + +PropertySegment::PropertySegment(Property a_property) { + property = a_property; +} + +std::wstring PropertySegment::ToWstring() const { + return common::Concat( + L".", + PropertyToWstring(property) + ); +} + +std::unique_ptr PropertySegment::Clone() const { + return common::make_unique(*this); +} + +// endregion struct PropertySegment + +// region struct IndexSegment + +IndexSegment::IndexSegment(size_t an_index) { + index = an_index; +} + +std::wstring IndexSegment::ToWstring() const { + return common::Concat( + L"[", + std::to_wstring(index), + L"]" + ); +} + +std::unique_ptr IndexSegment::Clone() const { + return common::make_unique(*this); +} + +// endregion struct IndexSegment + +// region struct Path + +Path::Path() { + // Intentionally empty. +} + +Path::Path(const Path& other) { + for (const std::unique_ptr& segment : other.segments) { + segments.emplace_back(segment->Clone()); + } +} + +Path::Path(Path&& other) { + segments = std::move(other.segments); +} + +Path& Path::operator=(const Path& other) { + segments.clear(); + for (const std::unique_ptr& segment : other.segments) { + segments.emplace_back(segment->Clone()); + } + return *this; +} + +Path& Path::operator=(Path&& other) { + if (this != &other) { + segments = std::move(other.segments); + } + return *this; +} + +std::wstring Path::ToWstring() const { + std::vector parts; + parts.reserve(segments.size()); + + for (const std::unique_ptr& segment : segments ) { + parts.emplace_back(segment->ToWstring()); + } + + size_t size = 0; + for (const std::wstring& part : parts) { + size += part.size(); + } + + std::wstring result; + result.reserve(size); + for (const std::wstring& part : parts) { + result.append(part); + } + + return result; +} + +// endregion struct Path + +// endregion Pathing + +// region Non-recursive iteration + +/** + * This iterator is always done as IMyClass + * references no other instances. + */ +class IteratorOverMyClass : public impl::IIterator { + public: + IteratorOverMyClass( + const std::shared_ptr& + ) { + // Intentionally empty. + } + + void Start() override { + // Intentionally empty. + } + + void Next() override { + throw std::logic_error( + "You want to move " + "an IteratorOverMyClass, " + "but the iterator is always done as " + "IMyClass " + "references no other instances." + ); + } + + bool Done() const override { + return true; + } + + const std::shared_ptr& Get() const override { + throw std::logic_error( + "You want to get from an IteratorOverMyClass, " + "but the iterator is always done as " + "IMyClass references " + "no other instances." + ); + } + + long Index() const override { + return -1; + } + + std::unique_ptr Clone() const override { + return common::make_unique(*this); + } + + void PrependToPath(Path*) const override { + throw std::logic_error( + "You want to prepend to path from an IteratorOverMyClass, " + "but the iterator is always done as " + "IMyClass references " + "no other instances." + ); + } + + ~IteratorOverMyClass() override = default; +}; // class IteratorOverMyClass + +// region Non-recursive iteration over IListOfPrimitives + +/** + * Iterate non-recursively over the instances referenced from an instance. + */ +class IteratorOverListOfPrimitives : public impl::IIterator { + public: + IteratorOverListOfPrimitives( + const std::shared_ptr& instance + ); + void Start() override; + void Next() override; + bool Done() const override; + const std::shared_ptr& Get() const override; + long Index() const override; + void PrependToPath(Path* path) const override; + std::unique_ptr Clone() const override; + ~IteratorOverListOfPrimitives() override = default; + + private: + // We make instance_ a pointer, so that we can follow the rule-of-zero. + const std::shared_ptr* instance_; + // We make casted_ a pointer, so that we can follow the rule-of-zero. + const types::IListOfPrimitives* casted_; + std::uint32_t state_; + common::optional property_; + common::optional cursor_; // in yield-from loops + std::shared_ptr item_; + long index_; // in total iteration + bool done_; + + void Execute(); +}; // class IteratorOverListOfPrimitives + +IteratorOverListOfPrimitives::IteratorOverListOfPrimitives( + const std::shared_ptr& instance +) : + instance_(&instance), + // NOTE (mristin): + // The dynamic cast is necessary due to virtual inheritance. Otherwise, + // we would have used static cast. + casted_( + dynamic_cast( + instance.get() + ) + ) { + // Intentionally empty. +} + +void IteratorOverListOfPrimitives::Start() { + state_ = 0; + Execute(); +} + +void IteratorOverListOfPrimitives::Next() { + #ifdef DEBUG + if (Done()) { + throw std::logic_error( + "You want to move IteratorOverListOfPrimitives, " + "but it was done." + ); + } + #endif + + Execute(); +} + +bool IteratorOverListOfPrimitives::Done() const { + return done_; +} + +const std::shared_ptr& IteratorOverListOfPrimitives::Get() const { + #ifdef DEBUG + if (Done()) { + throw std::logic_error( + "You want to get from IteratorOverListOfPrimitives, " + "but the iterator was done." + ); + } + #endif + + return item_; +} + +long IteratorOverListOfPrimitives::Index() const { + #ifdef DEBUG + if (Done() && index_ != -1) { + throw std::logic_error( + common::Concat( + "Expected index to be -1 " + "from a done IteratorOverListOfPrimitives, " + "but got: ", + std::to_string(index_) + ) + ); + } + #endif + + return index_; +} + +void IteratorOverListOfPrimitives::PrependToPath( + Path* path +) const { + #ifdef DEBUG + if (Done()) { + throw std::logic_error( + "You want to prepend to path from IteratorOverListOfPrimitives, " + "but the iterator was done." + ); + } + #endif + + if (cursor_.has_value()) { + path->segments.emplace_front( + common::make_unique(*cursor_) + ); + } + + #ifdef DEBUG + if (!property_.has_value()) { + throw std::logic_error( + "You want to prepend to path from IteratorOverListOfPrimitives, " + "but the property_ has not been set to a value." + ); + } + #endif + + path->segments.emplace_front( + common::make_unique(*property_) + ); +} + +std::unique_ptr IteratorOverListOfPrimitives::Clone() const { + return common::make_unique(*this); +} + +void IteratorOverListOfPrimitives::Execute() { + while (true) { + switch (state_) { + case 0: { + property_.reset(); + item_ = nullptr; + index_ = -1; + done_ = false; + + cursor_.reset(); + + property_ = Property::kStrings; + + cursor_ = 0; + } + + case 1: { + if (!(*cursor_ < casted_->strings().size())) { + state_ = 3; + continue; + } + + const std::vector& the_strings( + casted_->strings() + ); + + item_ = std::move( + std::static_pointer_cast( + the_strings[*cursor_] + ) + ); + ++index_; + + state_ = 2; + return; + } + + case 2: { + ++(*cursor_); + + state_ = 1; + continue; + } + + case 3: { + cursor_.reset(); + + property_ = Property::kIntegers; + + cursor_ = 0; + } + + case 4: { + if (!(*cursor_ < casted_->integers().size())) { + state_ = 6; + continue; + } + + const std::vector& the_integers( + casted_->integers() + ); + + item_ = std::move( + std::static_pointer_cast( + the_integers[*cursor_] + ) + ); + ++index_; + + state_ = 5; + return; + } + + case 5: { + ++(*cursor_); + + state_ = 4; + continue; + } + + case 6: { + cursor_.reset(); + + property_ = Property::kBooleans; + + cursor_ = 0; + } + + case 7: { + if (!(*cursor_ < casted_->booleans().size())) { + state_ = 9; + continue; + } + + const std::vector& the_booleans( + casted_->booleans() + ); + + item_ = std::move( + std::static_pointer_cast( + the_booleans[*cursor_] + ) + ); + ++index_; + + state_ = 8; + return; + } + + case 8: { + ++(*cursor_); + + state_ = 7; + continue; + } + + case 9: { + cursor_.reset(); + + property_ = Property::kClasses; + + cursor_ = 0; + } + + case 10: { + if (!(*cursor_ < casted_->classes().size())) { + state_ = 12; + continue; + } + + const std::vector< + std::shared_ptr + >& the_classes( + casted_->classes() + ); + + item_ = std::move( + std::static_pointer_cast( + the_classes[*cursor_] + ) + ); + ++index_; + + state_ = 11; + return; + } + + case 11: { + ++(*cursor_); + + state_ = 10; + continue; + } + + case 12: { + cursor_.reset(); + + done_ = true; + index_ = -1; + + // We invalidate the state since we reached the end of the routine. + state_ = 13; + return; + } + + default: + throw std::logic_error( + common::Concat( + "Invalid state_: ", + std::to_string(state_) + ) + ); + } + } +} + +// endregion + +/** + * This iterator is always done. + * + * It is used for efficient comparisons against end-of-descent. + */ +class AlwaysDoneIterator : public impl::IIterator { + public: + void Start() override { + // Intentionally empty. + } + + void Next() override { + throw std::logic_error( + "You want to move an AlwaysDoneIterator, " + "but the iterator is always done, as its name suggests." + ); + } + + bool Done() const override { + return true; + } + + const std::shared_ptr& Get() const override { + throw std::logic_error( + "You want to get from an AlwaysDoneIterator, " + "but the iterator is always done, as its name suggests." + ); + } + + std::unique_ptr Clone() const override { + return common::make_unique(*this); + }; + + void PrependToPath(Path*) const override { + throw std::logic_error( + "You want to prepend to path from an AlwaysDoneIterator, " + "but the iterator is always done, as its name suggests." + ); + } + + long Index() const override { + return -1; + } + + ~AlwaysDoneIterator() override = default; +}; // class AlwaysDoneIterator + +/** + * Produce a non-recursive iterator over the instance given its runtime model type. + */ +std::unique_ptr NewNonRecursiveIterator( + const std::shared_ptr& instance +) { + switch (instance->model_type()) { + case types::ModelType::kMyClass: + return common::make_unique( + instance + ); + case types::ModelType::kListOfPrimitives: + return common::make_unique( + instance + ); + default: + throw std::logic_error( + common::Concat( + "Unexpected model type: ", + std::to_string( + static_cast(instance->model_type()) + ) + ) + ); + } +} + +// endregion Non-recursive iteration + +// region Recursive iteration + +/** + * Iterate recursively over the instance, including the instance in the iteration. + * + * This is a realisation of the following pseudo-code: + * \code + * stack = new Stack(); + * stack.push(instance); + * while not stack.empty(): + * instance = stack.pop() + * yield instance + * + * it = new_non_recursive_iterator(instance) + * while not it.done(): + * yield recursively from it.get() + * it.next() + * \endcode + */ +class RecursiveInclusiveIterator : public impl::IIterator { + public: + RecursiveInclusiveIterator( + const std::shared_ptr& instance + ); + + RecursiveInclusiveIterator( + const RecursiveInclusiveIterator& other + ); + RecursiveInclusiveIterator( + RecursiveInclusiveIterator&& other + ); + RecursiveInclusiveIterator& operator=( + const RecursiveInclusiveIterator& other + ); + RecursiveInclusiveIterator& operator=( + RecursiveInclusiveIterator&& other + ); + + void Start() override; + void Next() override; + bool Done() const override; + const std::shared_ptr& Get() const override; + long Index() const override; + void PrependToPath(Path* path) const override; + std::unique_ptr Clone() const override; + ~RecursiveInclusiveIterator() override = default; + + private: + // The instance_ needs to be a pointer so that we can re-assign it in + // the constructors and assignment operations. + const std::shared_ptr* instance_; + + // Iterator over the instances referenced from this instance + // in the outer loop + std::unique_ptr non_recursive_iterator_; + + // Iterator for recursion into the reference referenced from this instance + // in the inner loop + std::unique_ptr recursive_iterator_; + + const std::shared_ptr* item_; + + bool done_; + long index_; + size_t state_; + + void Execute(); +}; // class RecursiveInclusiveIterator + +/** + * Iterate recursively over the instance, excluding the instance in the iteration. + * + * This is a realisation of the following pseudo-code: + * \code + * stack = new Stack(); + * stack.push(instance); + * while not stack.empty(): + * some_instance = stack.pop() + * if some_instance is not instance: + * yield some_instance + * + * it = new_non_recursive_iterator(some_instance) + * while not it.done(): + * yield recursively from it.get() + * it.next() + * \endcode + */ +class RecursiveExclusiveIterator : public impl::IIterator { + public: + RecursiveExclusiveIterator( + const std::shared_ptr& instance + ); + + void Start() override; + void Next() override; + bool Done() const override; + const std::shared_ptr& Get() const override; + long Index() const override; + void PrependToPath(Path* path) const override; + std::unique_ptr Clone() const override; + ~RecursiveExclusiveIterator() override = default; + + private: + RecursiveInclusiveIterator inclusive_iterator_; +}; // class RecursiveExclusiveIterator + +// region RecursiveInclusiveIterator implementation + +RecursiveInclusiveIterator::RecursiveInclusiveIterator( + const std::shared_ptr& instance +) : instance_(&instance), item_(nullptr), index_(-1) { + // Intentionally empty. +} + +RecursiveInclusiveIterator::RecursiveInclusiveIterator( + const RecursiveInclusiveIterator& other +) { + instance_ = other.instance_; + non_recursive_iterator_ = (other.non_recursive_iterator_ == nullptr) + ? nullptr + : other.non_recursive_iterator_->Clone(); + recursive_iterator_ = (other.recursive_iterator_ == nullptr) + ? nullptr + : other.recursive_iterator_->Clone(); + item_ = other.item_; + done_ = other.done_; + index_ = other.index_; + state_ = other.state_; +} + +RecursiveInclusiveIterator::RecursiveInclusiveIterator( + RecursiveInclusiveIterator&& other +) { + instance_ = other.instance_; + non_recursive_iterator_ = std::move(other.non_recursive_iterator_); + recursive_iterator_ = std::move(other.recursive_iterator_); + item_ = other.item_; + done_ = other.done_; + index_ = other.index_; + state_ = other.state_; +} + +RecursiveInclusiveIterator& RecursiveInclusiveIterator::operator=( + const RecursiveInclusiveIterator& other +) { + return *this = RecursiveInclusiveIterator(other); +} + +RecursiveInclusiveIterator& RecursiveInclusiveIterator::operator=( + RecursiveInclusiveIterator&& other +) { + if (this != &other) { + instance_ = other.instance_; + non_recursive_iterator_ = std::move(other.non_recursive_iterator_); + recursive_iterator_ = std::move(other.recursive_iterator_); + item_ = other.item_; + done_ = other.done_; + index_ = other.index_; + state_ = other.state_; + } + + return *this; +} + +void RecursiveInclusiveIterator::Start() { + state_ = 0; + Execute(); + + #ifdef DEBUG + if (Done()) { + throw std::logic_error( + "Expected RecursiveInclusiveIterator not to be done at start, but it was." + ); + } + + if (Index() !== 0) { + throw std::logic_error( + common::Concat( + "Expected RecursiveInclusiveIterator::Index() to be 0 on Start()" + ", but got ", + std::to_string(Index()) + ) + ); + } + + const std::shared_ptr& current_item(Get()); + if (current_item == nullptr) { + throw std::logic_error( + "Unexpected null pointer from Get() at the end of " + "RecursiveInclusiveIterator::Start" + ); + } + + if (current_item.get() != instance_.get()) { + throw std::logic_error( + common::Concat( + "Expected the current item to point to the instance " + "at the end of RecursiveInclusiveIterator::Start, " + "but got ", + std::to_string(current_item.get()), + " from Get() instead of ", + std::to_string(instance_.get()) + ) + ); + } + #endif +} + +void RecursiveInclusiveIterator::Next() { + #ifdef DEBUG + if (Done()) { + throw std::logic_error( + "You want to move a RecursiveInclusiveIterator, but it was done." + ); + } + #endif + + Execute(); +} + +bool RecursiveInclusiveIterator::Done() const { + return done_; +} + +const std::shared_ptr& RecursiveInclusiveIterator::Get() const { + #ifdef DEBUG + if (Done()) { + throw std::logic_error( + "You want to get from RecursiveInclusiveIterator, but it was done." + ); + } + + if (item_ == nullptr) { + throw std::logic_error( + "You want to get from a RecursiveInclusiveIterator, " + "but item_ has not been set." + ); + } + #endif + + return *item_; +} + +long RecursiveInclusiveIterator::Index() const { + #ifdef DEBUG + if (Done() && index_ != -1) { + throw std::logic_error( + common::Concat( + "Expected index to be -1 on a done RecursiveInclusiveIterator, " + "but got: ", + std::to_string(index_) + ) + ); + } + #endif + + return index_; +} + +void RecursiveInclusiveIterator::PrependToPath(Path* path) const { + #ifdef DEBUG + if (Done()) { + throw std::logic_error( + "You want to prepend to path from RecursiveInclusiveIterator, " + "but the iterator was done." + ); + } + #endif + + if (Index() == 0) { + // Index set to 0 indicates that the iterator points to the instance itself. + // Therefore, there is nothing to prepend to the path. + return; + } + + if (recursive_iterator_ != nullptr) { + recursive_iterator_->PrependToPath(path); + } + + if (non_recursive_iterator_ != nullptr) { + non_recursive_iterator_->PrependToPath(path); + } +} + +std::unique_ptr RecursiveInclusiveIterator::Clone() const { + return common::make_unique(*this); +} + +void RecursiveInclusiveIterator::Execute() { + while (true) { + switch (state_) { + case 0: { + item_ = instance_; + index_ = 0; + done_ = false; + non_recursive_iterator_.reset(nullptr); + recursive_iterator_.reset(nullptr); + + state_ = 1; + return; + } + + case 1: { + non_recursive_iterator_ = NewNonRecursiveIterator( + *instance_ + ); + + non_recursive_iterator_->Start(); + } + + case 2: { + if (!(!non_recursive_iterator_->Done())) { + state_ = 7; + continue; + } + + item_ = &(non_recursive_iterator_->Get()); + ++index_; + + state_ = 3; + return; + } + + case 3: { + recursive_iterator_ = std::move( + common::make_unique( + *item_ + ) + ); + + recursive_iterator_->Start(); + } + + case 4: { + if (!(!recursive_iterator_->Done())) { + state_ = 6; + continue; + } + + item_ = &(recursive_iterator_->Get()); + ++index_; + + state_ = 5; + return; + } + + case 5: { + recursive_iterator_->Next(); + + state_ = 4; + continue; + } + + case 6: { + recursive_iterator_.reset(nullptr); + + non_recursive_iterator_->Next(); + + state_ = 2; + continue; + } + + case 7: { + non_recursive_iterator_.reset(nullptr); + done_ = true; + index_ = -1; + + // We invalidate the state since we reached the end of the routine. + state_ = 8; + return; + } + + default: + throw std::logic_error( + common::Concat( + "Invalid state_: ", + std::to_string(state_) + ) + ); + } + } +} + +// endregion RecursiveInclusiveIterator implementation + +// region RecursiveExclusiveIterator implementation + +RecursiveExclusiveIterator::RecursiveExclusiveIterator( + const std::shared_ptr& instance +) : inclusive_iterator_(instance) { + // Intentionally empty. +} + +void RecursiveExclusiveIterator::Start() { + inclusive_iterator_.Start(); + + #ifdef DEBUG + if (inclusive_iterator_.Done()) { + throw std::logic_error( + "Expected the inclusive iterator to be not-done immediately after start, " + "as the first item is expected to point to the instance itself, " + "but the inclusive iterator was done." + ); + } + #endif + + // Simply skip the instance in the very first yield. + inclusive_iterator_.Next(); +} + +void RecursiveExclusiveIterator::Next() { + #ifdef DEBUG + if (Done()) { + throw std::logic_error( + "You want to move a RecursiveExclusiveIterator, but it was done." + ); + } + #endif + + inclusive_iterator_.Next(); +} + +bool RecursiveExclusiveIterator::Done() const { + return inclusive_iterator_.Done(); +} + +const std::shared_ptr& RecursiveExclusiveIterator::Get() const { + #ifdef DEBUG + if (Done()) { + throw std::logic_error( + "You want to get from RecursiveExclusiveIterator, but it was done." + ); + } + #endif + + return inclusive_iterator_.Get(); +} + +long RecursiveExclusiveIterator::Index() const { + if (inclusive_iterator_.Done()) { + return -1; + } + + return inclusive_iterator_.Index() - 1; +} + +void RecursiveExclusiveIterator::PrependToPath(Path* path) const { + inclusive_iterator_.PrependToPath(path); +} + +std::unique_ptr RecursiveExclusiveIterator::Clone() const { + return common::make_unique(*this); +} + +// endregion RecursiveExclusiveIterator implementation + +// endregion Recursive iteration + +// region Iterator facade + +Iterator::Iterator( + const Iterator& other +) : implementation_(other.implementation_->Clone()) { + // Intentionally empty. +} + +Iterator::Iterator( + Iterator&& other +) : implementation_(std::move(other.implementation_)) { + // Intentionally empty. +} + +Iterator& Iterator::operator=(const Iterator& other) { + return *this = Iterator(other); +} + +Iterator& Iterator::operator=(Iterator&& other) { + if (this != &other) { + this->implementation_ = std::move(other.implementation_); + } + + return *this; +} + +const std::shared_ptr& Iterator::operator*() const { + if (implementation_->Done()) { + throw std::logic_error( + "You want to dereference a completed iterator." + ); + } + + return implementation_->Get(); +} + +const std::shared_ptr* Iterator::operator->() { + if (implementation_->Done()) { + throw std::logic_error( + "You want to dereference a completed iterator." + ); + } + + return &(implementation_->Get()); +} + +// Prefix increment +Iterator& Iterator::operator++() { + if (implementation_->Done()) { + throw std::logic_error( + "You want to move a completed iterator." + ); + } + + implementation_->Next(); + return *this; +} + +// Postfix increment +Iterator Iterator::operator++(int) { + Iterator result(*this); + ++(*this); + return result; +} + +bool operator==(const Iterator& a, const Iterator& b) { + return a.implementation_->Index() == b.implementation_->Index(); +} + +bool operator!=(const Iterator& a, const Iterator& b) { + return a.implementation_->Index() != b.implementation_->Index(); +} + +Path MaterializePath(const Iterator& iterator) { + if (iterator.implementation_->Done()) { + throw std::logic_error( + "You want to materialize path of a completed iterator." + ); + } + + Path path; + iterator.implementation_->PrependToPath(&path); + return path; +} + +void PrependToPath(const Iterator& iterator, Path* path) { + if (iterator.implementation_->Done()) { + throw std::logic_error( + "You want to prepend a path of a completed iterator." + ); + } + + iterator.implementation_->PrependToPath(path); +} + +// endregion Iterator facade + +// region Descents + +// region Descent + +// NOTE (mristin): +// We have to make a copy of the pointer since we would lose otherwise +// in range-based `for` loops, +// see: https://stackoverflow.com/questions/29990045/temporary-lifetime-in-range-for-expression +Descent::Descent( + std::shared_ptr instance +) : instance_(std::move(instance)) { + // Intentionally empty. +} + +Iterator Descent::begin() const { + std::unique_ptr it_impl( + std::move( + common::make_unique(instance_) + ) + ); + + it_impl->Start(); + + // NOTE(mristin): + // We short-circuit here for memory frugality, + // as we can immediately dispose it_impl. + if (it_impl->Done()) { + return end(); + } + + return Iterator(std::move(it_impl)); +} + +const Iterator& Descent::end() const { + static Iterator iterator(common::make_unique()); + return iterator; +} + +// endregion Descent + +// region DescentOnce + +// NOTE (mristin): +// We have to make a copy of the pointer since we would lose otherwise +// in range-based `for` loops, +// see: https://stackoverflow.com/questions/29990045/temporary-lifetime-in-range-for-expression +DescentOnce::DescentOnce( + std::shared_ptr instance +) : instance_(std::move(instance)) { + // Intentionally empty. +} + +Iterator DescentOnce::begin() const { + std::unique_ptr it_impl( + NewNonRecursiveIterator(instance_) + ); + + it_impl->Start(); + + // NOTE(mristin): + // We short-circuit here for efficiency, as we can immediately dispose it_impl. + if (it_impl->Done()) { + return Iterator(std::move(common::make_unique())); + } + + return Iterator(std::move(it_impl)); +} + +const Iterator& DescentOnce::end() const { + static Iterator iterator(common::make_unique()); + return iterator; +} + +// endregion DescentOnce + +// endregion Descents + +} // namespace iteration +} // namespace aas_3_0 +} // namespace aas_core + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. diff --git a/test_data/cpp/test_main/list_of_primitives/expected_output/iteration.hpp b/test_data/cpp/test_main/list_of_primitives/expected_output/iteration.hpp new file mode 100644 index 000000000..9de87ab7a --- /dev/null +++ b/test_data/cpp/test_main/list_of_primitives/expected_output/iteration.hpp @@ -0,0 +1,338 @@ +#ifndef AAS_CORE_AAS_3_0_ITERATION_GUARD_ +#define AAS_CORE_AAS_3_0_ITERATION_GUARD_ + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#include "aas_core/aas_3_0/types.hpp" + +#pragma warning(push, 0) +#include +#include +#include +#include +#pragma warning(pop) + +namespace aas_core { +namespace aas_3_0 { + +/** + * \defgroup iteration Define functions and structures to iterate over instances. + * @{ +*/ +namespace iteration { + +// region Pathing + +/** + * Define the properties over all the classes to compactly represent the paths. + */ +enum class Property : std::uint32_t { + kBooleans = 0, + kClasses = 1, + kIntegers = 2, + kStrings = 3 +}; + +std::wstring PropertyToWstring( + Property property +); + +/** + * Represent a segment of a path to some value. + */ +class ISegment { + public: + virtual std::wstring ToWstring() const = 0; + virtual std::unique_ptr Clone() const = 0; + virtual ~ISegment() = default; +}; // class ISegment + +/** + * Represent a property access on a path. + */ +struct PropertySegment : public ISegment { + /** + * Enumeration of the property + */ + Property property; + + PropertySegment( + Property a_property + ); + + std::wstring ToWstring() const override; + std::unique_ptr Clone() const override; + + ~PropertySegment() override = default; +}; // struct PropertySegment + +/** + * Represent an index access on a path. + */ +struct IndexSegment : public ISegment { + /** + * Index of the item + */ + size_t index; + + explicit IndexSegment( + size_t an_index + ); + + std::wstring ToWstring() const override; + std::unique_ptr Clone() const override; + + ~IndexSegment() override = default; +}; // struct IndexSegment + +/** + * \brief Represent a path to some value. + * + * This is a path akin to C++ expressions. It is not to be confused with different + * paths used in the specification. This path class is meant to help with reporting. + * For example, we can use this path to let the user know when there is + * a verification error in a model which can concern instances, but also properties + * and items in the lists. + */ +struct Path { + // NOTE (mristin): + // We did not implement the reflection at the moment since we did not have a use + // case for it. If you need reflection, please contact the developers. It should + // be a small step going from paths to dereferencing to getters and setters. + + std::deque > segments; + + Path(); + Path(const Path& other); + Path(Path&& other); + Path& operator=(const Path& other); + Path& operator=(Path&& other); + + std::wstring ToWstring() const; +}; // struct Path + +// endregion Pathing + +// region Iterators and descent + +/// \cond HIDDEN +namespace impl { +class IIterator { + public: + virtual void Start() = 0; + virtual void Next() = 0; + virtual bool Done() const = 0; + virtual const std::shared_ptr& Get() const = 0; + virtual long Index() const = 0; + + /// Prepend the segments to the path reflecting where this iterator points to. + virtual void PrependToPath(Path* path) const = 0; + + virtual std::unique_ptr Clone() const = 0; + + virtual ~IIterator() = default; +}; // class IIterator +} // namespace impl +/// \endcond + +/** + * \brief Iterate over an AAS instance. + * + * Unlike STL, this is not a light-weight iterator. We implement + * a "yielding" iterator by leveraging code generation so that we always keep + * the model stack as well as the properties iterated thus far. + * + * This means that copy-construction and equality comparisons are much more heavy-weight + * than you'd usually expect from an STL iterator. For example, if you want to sort + * model instances, you are most probably faster if you populate a vector, and then + * sort the vector. + * + * Also, given that this iterator is not light-weight, you should in almost all cases + * avoid the postfix increment (it++) and prefer the prefix one (++it) as the postfix + * increment would create an iterator copy every time. + * + * The value of the iterator is intentionally constant reference to a shared pointer. + * This merely means that you can not change the pointer while you are + * iterating. The pointed instances, however, is freely mutable. This way you can make + * further shared pointers, or include the pointed instances in other collections + * different from the original container. On the other hand, the normal case, where + * the pointer is only de-referenced, remains efficient as no copy of + * the shared pointer is created. + * + * We follow the C++ standard, and assume that comparison between the two iterators + * over two different instances results in undefined behavior. See + * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2948.html and + * https://stackoverflow.com/questions/4657513/comparing-iterators-from-different-containers. + * + * Since we use const references to shared pointers here you can also share ownership + * over instances in your own external containers. Making a copy of a shared pointer + * will automatically increase reference count, even though there is a constant + * reference. Since we do not make copies of the shared pointers, it is very important + * that the given shared pointers outlive the iteration, lest cause undefined behavior. + * + * Changing the references during the iteration invalidates the iterators and + * results in undefined behavior. This is similar to many of the containers in the STL, + * see: https://stackoverflow.com/questions/6438086/iterator-invalidation-rules-for-c-containers + * + * See these StackOverflow questions for performance related to shared pointers and + * constant references to shared pointers (copying versus referencing): + * * https://stackoverflow.com/questions/12002480/passing-stdshared-ptr-to-constructors/12002668#12002668 + * * https://stackoverflow.com/questions/3310737/should-we-pass-a-shared-ptr-by-reference-or-by-value + * * https://stackoverflow.com/questions/37610494/passing-const-shared-ptrt-versus-just-shared-ptrt-as-parameter + * + * The following StackOverflow question and answers go into more detail how const-ness + * and shared pointers fit together: + * https://stackoverflow.com/questions/36271663/why-does-copying-a-const-shared-ptr-not-violate-const-ness + */ +class Iterator { + using iterator_category = std::forward_iterator_tag; + /// The difference is meaningless, but has to be defined. + using difference_type = std::ptrdiff_t; + using value_type = std::shared_ptr; + using pointer = const std::shared_ptr*; + using reference = const std::shared_ptr&; + + public: + Iterator(const Iterator& other); + Iterator(Iterator&& other); + + Iterator& operator=(const Iterator& other); + Iterator& operator=(Iterator&& other); + + reference operator*() const; + pointer operator->(); + + // Prefix increment + Iterator& operator++(); + + // Postfix increment + Iterator operator++(int); + + friend bool operator==(const Iterator& a, const Iterator& b); + friend bool operator!=(const Iterator& a, const Iterator& b); + + friend class Descent; + friend class DescentOnce; + friend Path MaterializePath(const Iterator& iterator); + friend void PrependToPath(const Iterator& iterator, Path* path); + + private: + explicit Iterator( + std::unique_ptr implementation + ) : + implementation_(std::move(implementation)) { + // Intentionally empty. + } + + std::unique_ptr implementation_; +}; + +bool operator==(const Iterator& a, const Iterator& b); + +bool operator!=(const Iterator& a, const Iterator& b); + +/** + * \brief Materialize the path that the \p iterator points to. + * + * We assume that you always want a copy of the path, rather than inspect + * the path during the iteration. + * + * \param iterator for which we want to materialize the path + * \return Path referring to the pointed instance + */ +Path MaterializePath(const Iterator& iterator); + +/** + * Build a facade over an instance to iterate over instances referenced from it. + */ +class IDescent { + public: + virtual Iterator begin() const = 0; + virtual const Iterator& end() const = 0; + virtual ~IDescent() = default; +}; // class IDescent + +/** + * \brief Provide a recursive iterable over all the instances referenced from + * an instance. + * + * Please see the notes in the class Iterator regarding the constant reference to + * a shared pointer. In short, the instance should outlive the descent, so make + * sure you do not destroy it during the descent. + * + * Range-based loops should fit the vast majority of the use cases: + * \code + * std::shared_ptr env = ...; + * for ( + * const std::shared_ptr& instance + * : Descent(env) + * ) { + * do_something(instance); + * } + * \endcode + * + * \param that instance to be iterated over recursively + * \return Iterable over referenced instances + */ +class Descent : public IDescent { + public: + Descent( + std::shared_ptr instance + ); + + Iterator begin() const override; + const Iterator& end() const override; + + ~Descent() override = default; + + private: + std::shared_ptr instance_; +}; // class Descent + +/** + * \brief Provide a non-recursive iterable over the instances referenced from + * an instance. + * + * Please see the notes in the class Iterator regarding the constant reference to + * a shared pointer. In short, the instance should outlive the descent, so make + * sure you do not destroy it during the descent. + * + * Range-based loops should fit the vast majority of the use cases: + * \code + * std::shared_ptr env = ...; + * for ( + * const std::shared_ptr& instance + * : DescentOnce(env) + * ) { + * do_something(instance); + * } + * \endcode + */ +class DescentOnce : public IDescent { + public: + DescentOnce( + std::shared_ptr instance + ); + + Iterator begin() const override; + const Iterator& end() const override; + + ~DescentOnce() override = default; + + private: + std::shared_ptr instance_; +}; // class DescentOnce + +// endregion Iterators and descent + +} // namespace iteration +/**@}*/ + +} // namespace aas_3_0 +} // namespace aas_core + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#endif // AAS_CORE_AAS_3_0_ITERATION_GUARD_ diff --git a/test_data/cpp/test_main/list_of_primitives/expected_output/jsonization.cpp b/test_data/cpp/test_main/list_of_primitives/expected_output/jsonization.cpp new file mode 100644 index 000000000..25f1827c2 --- /dev/null +++ b/test_data/cpp/test_main/list_of_primitives/expected_output/jsonization.cpp @@ -0,0 +1,1587 @@ +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#include "aas_core/aas_3_0/jsonization.hpp" +#include "aas_core/aas_3_0/stringification.hpp" +#include "aas_core/aas_3_0/wstringification.hpp" + +#pragma warning(push, 0) +#include +#include +#include +#include +#pragma warning(pop) + +namespace aas_core { +namespace aas_3_0 { +namespace jsonization { + +// region PropertySegment + +PropertySegment::PropertySegment( + std::wstring a_name +) : + name(std::move(a_name)) { + // Intentionally empty. +} + +std::wstring PropertySegment::ToWstring() const { + return common::Concat( + L".", + name + ); +} + +std::unique_ptr PropertySegment::Clone() const { + return common::make_unique(*this); +} + +// endregion PropertySegment + +// region IndexSegment + +IndexSegment::IndexSegment( + size_t an_index +) : + index(an_index) { + // Intentionally empty. +} + +std::wstring IndexSegment::ToWstring() const { + return common::Concat( + L"[", + std::to_wstring(index), + L"]" + ); +} + +std::unique_ptr IndexSegment::Clone() const { + return common::make_unique(*this); +} + +// endregion IndexSegment + +// region struct Path + +Path::Path() { + // Intentionally empty. +} + +Path::Path(const Path& other) { + for (const std::unique_ptr& segment : other.segments) { + segments.emplace_back(segment->Clone()); + } +} + +Path::Path(Path&& other) { + segments = std::move(other.segments); +} + +Path& Path::operator=(const Path& other) { + segments.clear(); + for (const std::unique_ptr& segment : other.segments) { + segments.emplace_back(segment->Clone()); + } + return *this; +} + +Path& Path::operator=(Path&& other) { + if (this != &other) { + segments = std::move(other.segments); + } + return *this; +} + +std::wstring Path::ToWstring() const { + if (segments.empty()) { + return L""; + } + + std::deque parts; + for (const std::unique_ptr& segment : segments ) { + parts.emplace_back(segment->ToWstring()); + } + + size_t out_len = 0; + for (const std::wstring& part : parts) { + out_len += part.size(); + } + + std::wstring out; + out.reserve(out_len); + for (const std::wstring& part : parts) { + out.append(part); + } + + return out; +} + +// endregion struct Path + +// region De-serialization + +// region class DeserializationError + +DeserializationError::DeserializationError( + std::wstring a_cause +) : + cause(a_cause) { + // Intentionally empty. +} + +DeserializationError::DeserializationError( + std::wstring a_cause, + Path a_path +) : + cause(a_cause), + path(a_path) { + // Intentionally empty. +} + +// endregion class DeserializationError + +std::pair< + common::optional, + common::optional +> DeserializeBool( + const nlohmann::json& json +) { + if (!json.is_boolean()) { + std::wstring message = common::Concat( + L"Expected a boolean, but got a value of type: ", + common::Utf8ToWstring(json.type_name()) + ); + + return std::make_pair< + common::optional, + common::optional + >( + common::nullopt, + common::make_optional( + message + ) + ); + } + + return std::make_pair< + common::optional, + common::optional + >( + json.get(), + common::nullopt + ); +} + +std::pair< + common::optional, + common::optional +> DeserializeInt64( + const nlohmann::json& json +) { + if (!json.is_number()) { + std::wstring message = common::Concat( + L"Expected an integer number, but got a value of type: ", + common::Utf8ToWstring(json.type_name()) + ); + + return std::make_pair< + common::optional, + common::optional + >( + common::nullopt, + common::make_optional( + message + ) + ); + } + + static_assert( + std::is_same::value, + "Expected nlohmann::json::number_integer_t to equal int64_t, " + "but it does not." + ); + + if (json.is_number_integer()) { + return std::make_pair< + common::optional, + common::optional + >( + json.get(), + common::nullopt + ); + } + + if (json.is_number_unsigned()) { + std::wstring message = common::Concat( + L"Expected a 64-bit integer number, " + L"but got an unsigned integer number which does not fit in that range: ", + std::to_wstring(json.get()) + ); + + return std::make_pair< + common::optional, + common::optional + >( + common::nullopt, + common::make_optional( + message + ) + ); + } + + // NOTE (mristin): + // We have to check that the number is an integer even though it can + // not be stored in int64_t in order to give an informative message. + + const nlohmann::json::number_float_t number( + json.get() + ); + + nlohmann::json::number_float_t integer_part; + const bool is_integer( + std::modf(number, &integer_part) == 0 + ); + if (is_integer) { + std::wstring message = common::Concat( + L"Expected a 64-bit integer number, " + L"but got an integer number which does not fit in that range: ", + std::to_wstring(number) + ); + + return std::make_pair< + common::optional, + common::optional + >( + common::nullopt, + common::make_optional( + message + ) + ); + } else { + std::wstring message = common::Concat( + L"Expected a 64-bit integer number, " + L"but got a non-integer number: ", + std::to_wstring(number) + ); + + return std::make_pair< + common::optional, + common::optional + >( + common::nullopt, + common::make_optional( + message + ) + ); + } +} + +std::pair< + common::optional, + common::optional +> DeserializeDouble( + const nlohmann::json& json +) { + if (!json.is_number()) { + std::wstring message = common::Concat( + L"Expected a number, but got a value of type: ", + common::Utf8ToWstring(json.type_name()) + ); + + return std::make_pair< + common::optional, + common::optional + >( + common::nullopt, + common::make_optional( + message + ) + ); + } + + static_assert( + std::is_same::value, + "Expected nlohmann::json::number_float_t to equal double, " + "but it does not." + ); + + return std::make_pair< + common::optional, + common::optional + >( + json.get(), + common::nullopt + ); +} + +std::pair< + common::optional, + common::optional +> DeserializeWstring( + const nlohmann::json& json +) { + if (!json.is_string()) { + std::wstring message = common::Concat( + L"Expected a string, but got a value of type: ", + common::Utf8ToWstring(json.type_name()) + ); + + return std::make_pair< + common::optional, + common::optional + >( + common::nullopt, + common::make_optional( + message + ) + ); + } + + return std::make_pair< + common::optional, + common::optional + >( + common::Utf8ToWstring(*(json.get_ptr())), + common::nullopt + ); +} + +std::pair< + common::optional >, + common::optional +> DeserializeByteArray( + const nlohmann::json& json +) { + if (!json.is_string()) { + std::wstring message = common::Concat( + L"Expected a base64-encoded byte array as a string, " + L"but got a value of type: ", + common::Utf8ToWstring(json.type_name()) + );; + + return std::make_pair< + common::optional >, + common::optional + >( + common::nullopt, + common::make_optional( + message + ) + ); + } + + common::expected< + std::vector, + std::string + > bytes = stringification::Base64Decode( + *(json.get_ptr()) + ); + + if (!bytes.has_value()) { + std::wstring message = common::Concat( + L"Failed to base64-decode the bytes from a string: ", + common::Utf8ToWstring(bytes.error()) + ); + + return std::make_pair< + common::optional >, + common::optional + >( + common::nullopt, + common::make_optional( + message + ) + ); + } + + return std::make_pair< + common::optional >, + common::optional + >( + std::move(*bytes), + common::nullopt + ); +} + +/** + * Get the property `modelType` from the JSON value expected as a JSON object. + */ +std::pair< + const std::string*, + common::optional +> GetModelTypeFrom( + const nlohmann::json& json +) { + if (!json.is_object()) { + std::wstring message = common::Concat( + L"Expected an object, but got: ", + common::Utf8ToWstring(json.type_name()) + ); + + return std::make_pair< + const std::string*, + common::optional + >( + nullptr, + common::make_optional( + message + ) + ); + } + + if (!json.contains("modelType")) { + return std::make_pair< + const std::string*, + common::optional + >( + nullptr, + common::make_optional( + L"The required property modelType is missing" + ) + ); + } + + const nlohmann::json& model_type_prop = json["modelType"]; + if (!model_type_prop.is_string()) { + std::wstring message = common::Concat( + L"Expected modelType to be a string, but got: ", + common::Utf8ToWstring(model_type_prop.type_name()) + ); + + common::optional error( + common::make_optional( + message + ) + ); + error->path.segments.emplace_front( + common::make_unique( + L"modelType" + ) + ); + + // NOTE (mristin): + // We have to explicitly use the constructor instead of std::make_pair + // as `const std::string*` can not be automatically converted to a rvalue. + return std::pair< + const std::string*, + common::optional + >( + nullptr, + error + ); + } + + static_assert( + std::is_same::value, + "Expected nlohmann::json::string_t to equal std::string, but it does not." + ); + + const std::string* model_type( + model_type_prop.get_ptr() + ); + + // NOTE (mristin): + // We have to explicitly use the constructor instead of std::make_pair + // as `const std::string*` can not be automatically converted to a rvalue. + return std::pair< + const std::string*, + common::optional + >( + model_type, + common::nullopt + ); +} + +/** + * \brief Deserialize concretely an instance + * of types::IMyClass. + * + * \param json value to be de-serialized + * \param additional_properties if not set, check that \p json contains + * no additional properties + * \return the deserialized instance, or an error, if any + */ +std::pair< + common::optional< + std::shared_ptr + >, + common::optional +> DeserializeMyClass( + const nlohmann::json& json, + bool additional_properties +); + +/** + * \brief Deserialize concretely an instance + * of types::IListOfPrimitives. + * + * \param json value to be de-serialized + * \param additional_properties if not set, check that \p json contains + * no additional properties + * \return the deserialized instance, or an error, if any + */ +std::pair< + common::optional< + std::shared_ptr + >, + common::optional +> DeserializeListOfPrimitives( + const nlohmann::json& json, + bool additional_properties +); + +std::set kPropertiesInMyClass = { + +}; + +std::pair< + common::optional< + std::shared_ptr + >, + common::optional +> DeserializeMyClass( + const nlohmann::json& json, + bool additional_properties +) { + if (!json.is_object()) { + std::wstring message = common::Concat( + L"Expected an object, but got: ", + common::Utf8ToWstring(json.type_name()) + ); + + return std::make_pair< + common::optional >, + common::optional + >( + common::nullopt, + common::make_optional( + message + ) + ); + } + + if (!additional_properties) { + for (const auto& key_val : json.items()) { + auto it( + kPropertiesInMyClass.find(key_val.key()) + ); + if (it == kPropertiesInMyClass.end()) { + std::wstring message = common::Concat( + L"Unexpected additional property: ", + common::Utf8ToWstring(key_val.key()) + ); + + return std::make_pair< + common::optional >, + common::optional + >( + common::nullopt, + common::make_optional( + message + ) + ); + } + } + } + + return std::make_pair( + common::make_optional< + std::shared_ptr + >( + // NOTE (mristin): + // We deliberately do not use std::make_shared here to avoid an unnecessary + // upcast. + new types::MyClass() + ), + common::nullopt + ); +} + +std::set kPropertiesInListOfPrimitives = { + "strings", + "integers", + "booleans", + "classes" +}; + +std::pair< + common::optional< + std::shared_ptr + >, + common::optional +> DeserializeListOfPrimitives( + const nlohmann::json& json, + bool additional_properties +) { + if (!json.is_object()) { + std::wstring message = common::Concat( + L"Expected an object, but got: ", + common::Utf8ToWstring(json.type_name()) + ); + + return std::make_pair< + common::optional >, + common::optional + >( + common::nullopt, + common::make_optional( + message + ) + ); + } + + if (!additional_properties) { + for (const auto& key_val : json.items()) { + auto it( + kPropertiesInListOfPrimitives.find(key_val.key()) + ); + if (it == kPropertiesInListOfPrimitives.end()) { + std::wstring message = common::Concat( + L"Unexpected additional property: ", + common::Utf8ToWstring(key_val.key()) + ); + + return std::make_pair< + common::optional >, + common::optional + >( + common::nullopt, + common::make_optional( + message + ) + ); + } + } + } + + // region Check required properties + + if (!json.contains("strings")) { + return std::make_pair< + common::optional >, + common::optional + >( + common::nullopt, + common::make_optional( + L"The required property strings is missing" + ) + ); + } + + if (!json.contains("integers")) { + return std::make_pair< + common::optional >, + common::optional + >( + common::nullopt, + common::make_optional( + L"The required property integers is missing" + ) + ); + } + + if (!json.contains("booleans")) { + return std::make_pair< + common::optional >, + common::optional + >( + common::nullopt, + common::make_optional( + L"The required property booleans is missing" + ) + ); + } + + if (!json.contains("classes")) { + return std::make_pair< + common::optional >, + common::optional + >( + common::nullopt, + common::make_optional( + L"The required property classes is missing" + ) + ); + } + + // endregion Check required properties + + // region Initialization + + common::optional error; + + common::optional > the_strings; + + common::optional > the_integers; + + common::optional > the_booleans; + + common::optional< + std::vector< + std::shared_ptr + > + > the_classes; + + // endregion Initialization + + // region De-serialize strings + + const nlohmann::json& json_strings( + json["strings"] + ); + if (!json_strings.is_array()) { + error = common::make_optional( + common::Concat( + L"Expected an array, but got: ", + common::Utf8ToWstring( + json_strings.type_name() + ) + ) + ); + + error->path.segments.emplace_front( + common::make_unique( + L"strings" + ) + ); + + return std::make_pair< + common::optional >, + common::optional + >( + common::nullopt, + std::move(error) + ); + } + + the_strings = common::make_optional< + std::vector< + std::shared_ptr + > + >(); + + the_strings->reserve(json_strings.size()); + + size_t index_strings = 0; + + for ( + const nlohmann::json& item + : json_strings + ) { + common::optional< + std::shared_ptr + > deserialized; + + std::tie( + deserialized, + error + ) = DeserializeWstring( + item, + additional_properties + ); + + if (error.has_value()) { + error->path.segments.emplace_front( + common::make_unique( + index_strings + ) + ); + + error->path.segments.emplace_front( + common::make_unique( + L"strings" + ) + ); + + return std::make_pair< + common::optional >, + common::optional + >( + common::nullopt, + std::move(error) + ); + } + + the_strings->emplace_back( + std::move(*deserialized) + ); + + ++index_strings; + } + + // endregion De-serialize strings + + // region De-serialize integers + + const nlohmann::json& json_integers( + json["integers"] + ); + if (!json_integers.is_array()) { + error = common::make_optional( + common::Concat( + L"Expected an array, but got: ", + common::Utf8ToWstring( + json_integers.type_name() + ) + ) + ); + + error->path.segments.emplace_front( + common::make_unique( + L"integers" + ) + ); + + return std::make_pair< + common::optional >, + common::optional + >( + common::nullopt, + std::move(error) + ); + } + + the_integers = common::make_optional< + std::vector< + std::shared_ptr + > + >(); + + the_integers->reserve(json_integers.size()); + + size_t index_integers = 0; + + for ( + const nlohmann::json& item + : json_integers + ) { + common::optional< + std::shared_ptr + > deserialized; + + std::tie( + deserialized, + error + ) = DeserializeInt64( + item, + additional_properties + ); + + if (error.has_value()) { + error->path.segments.emplace_front( + common::make_unique( + index_integers + ) + ); + + error->path.segments.emplace_front( + common::make_unique( + L"integers" + ) + ); + + return std::make_pair< + common::optional >, + common::optional + >( + common::nullopt, + std::move(error) + ); + } + + the_integers->emplace_back( + std::move(*deserialized) + ); + + ++index_integers; + } + + // endregion De-serialize integers + + // region De-serialize booleans + + const nlohmann::json& json_booleans( + json["booleans"] + ); + if (!json_booleans.is_array()) { + error = common::make_optional( + common::Concat( + L"Expected an array, but got: ", + common::Utf8ToWstring( + json_booleans.type_name() + ) + ) + ); + + error->path.segments.emplace_front( + common::make_unique( + L"booleans" + ) + ); + + return std::make_pair< + common::optional >, + common::optional + >( + common::nullopt, + std::move(error) + ); + } + + the_booleans = common::make_optional< + std::vector< + std::shared_ptr + > + >(); + + the_booleans->reserve(json_booleans.size()); + + size_t index_booleans = 0; + + for ( + const nlohmann::json& item + : json_booleans + ) { + common::optional< + std::shared_ptr + > deserialized; + + std::tie( + deserialized, + error + ) = DeserializeBool( + item, + additional_properties + ); + + if (error.has_value()) { + error->path.segments.emplace_front( + common::make_unique( + index_booleans + ) + ); + + error->path.segments.emplace_front( + common::make_unique( + L"booleans" + ) + ); + + return std::make_pair< + common::optional >, + common::optional + >( + common::nullopt, + std::move(error) + ); + } + + the_booleans->emplace_back( + std::move(*deserialized) + ); + + ++index_booleans; + } + + // endregion De-serialize booleans + + // region De-serialize classes + + const nlohmann::json& json_classes( + json["classes"] + ); + if (!json_classes.is_array()) { + error = common::make_optional( + common::Concat( + L"Expected an array, but got: ", + common::Utf8ToWstring( + json_classes.type_name() + ) + ) + ); + + error->path.segments.emplace_front( + common::make_unique( + L"classes" + ) + ); + + return std::make_pair< + common::optional >, + common::optional + >( + common::nullopt, + std::move(error) + ); + } + + the_classes = common::make_optional< + std::vector< + std::shared_ptr + > + >(); + + the_classes->reserve(json_classes.size()); + + size_t index_classes = 0; + + for ( + const nlohmann::json& item + : json_classes + ) { + common::optional< + std::shared_ptr + > deserialized; + + std::tie( + deserialized, + error + ) = DeserializeMyClass( + item, + additional_properties + ); + + if (error.has_value()) { + error->path.segments.emplace_front( + common::make_unique( + index_classes + ) + ); + + error->path.segments.emplace_front( + common::make_unique( + L"classes" + ) + ); + + return std::make_pair< + common::optional >, + common::optional + >( + common::nullopt, + std::move(error) + ); + } + + the_classes->emplace_back( + std::move(*deserialized) + ); + + ++index_classes; + } + + // endregion De-serialize classes + + return std::make_pair( + common::make_optional< + std::shared_ptr + >( + // NOTE (mristin): + // We deliberately do not use std::make_shared here to avoid an unnecessary + // upcast. + new types::ListOfPrimitives( + std::move(*the_strings), + std::move(*the_integers), + std::move(*the_booleans), + std::move(*the_classes) + ) + ), + common::nullopt + ); +} + +common::expected< + std::shared_ptr, + DeserializationError +> MyClassFrom( + const nlohmann::json& json, + bool additional_properties +) { + common::optional< + std::shared_ptr + > instance; + + common::optional error; + + std::tie( + instance, + error + ) = DeserializeMyClass( + json, + additional_properties + ); + + if (instance.has_value()) { + return std::move(*instance); + } + + if (!error.has_value()) { + throw std::logic_error( + "Unexpected null error when null instance." + ); + } + return common::make_unexpected( + std::move(*error) + ); +} + +common::expected< + std::shared_ptr, + DeserializationError +> ListOfPrimitivesFrom( + const nlohmann::json& json, + bool additional_properties +) { + common::optional< + std::shared_ptr + > instance; + + common::optional error; + + std::tie( + instance, + error + ) = DeserializeListOfPrimitives( + json, + additional_properties + ); + + if (instance.has_value()) { + return std::move(*instance); + } + + if (!error.has_value()) { + throw std::logic_error( + "Unexpected null error when null instance." + ); + } + return common::make_unexpected( + std::move(*error) + ); +} + +// endregion De-serialization + +// region Serialization + +/** + * \brief Represent a serialization error. + * + * We use this error internally to avoid unnecessary stack unwinding, + * but throw the \ref SerializationException at the final site of + * the serialization for the user. + */ +struct SerializationError { + /** + * Human-readable description of the error + */ + std::wstring cause; + + /** + * Path to the value that caused the error + */ + iteration::Path path; + + explicit SerializationError( + std::wstring a_cause + ) : cause(std::move(a_cause)) { + // Intentionally empty. + } +}; // struct SerializationError + +// region SerializationException + +std::string RenderSerializationErrorMessage( + const std::wstring& cause, + const iteration::Path& path +) { + return common::WstringToUtf8( + common::Concat( + L"Serialization failed at ", + path.ToWstring(), + L": ", + cause + ) + ); +} + +SerializationException::SerializationException( + std::wstring cause, + iteration::Path path +) : + cause_(std::move(cause)), + path_(std::move(path)), + msg_(RenderSerializationErrorMessage(cause, path)) { + // Intentionally empty. +} + +const char* SerializationException::what() const noexcept { + return msg_.c_str(); +} + +const std::wstring& SerializationException::cause() const noexcept { + return cause_; +} + +const iteration::Path& SerializationException::path() const noexcept { + return path_; +} + +// endregion SerializationException + +/** + * \brief Serialize the given number to a JSON value. + * + * We verify that the integer is within the range representable by 64-bit floats + * for interoperability with other de-serializers. + */ +std::pair< + common::optional, + common::optional +> SerializeInt64(int64_t value) { + if ( + value < -9007199254740991L + || value > 9007199254740991L + ) { + const std::wstring message = common::Concat( + L"The integer ", + std::to_wstring(value), + L" can not be serialized to JSON " + L"as it is outside the range [-2^53 + 1, 2^53 - 1] and can not " + L"be exactly represented as a 64-bit floating point number." + ); + + return std::make_pair< + common::optional, + common::optional + >( + common::nullopt, + common::make_optional( + message + ) + ); + } + + return std::make_pair< + common::optional, + common::optional + >( + common::make_optional(value), + common::nullopt + ); +} + +/** + * Serialize the given text to a JSON value. + */ +nlohmann::json SerializeWstring( + const std::wstring& text +) { + return nlohmann::json( + common::WstringToUtf8(text) + ); +} + +/** + * Serialize the given bytes to a JSON value. + */ +nlohmann::json SerializeByteArray( + const std::vector& bytes +) { + return nlohmann::json( + std::move( + stringification::Base64Encode(bytes) + ) + ); +} + +std::pair< + common::optional, + common::optional +> SerializeIClass( + const types::IClass& that +); + +std::pair< + common::optional, + common::optional +> SerializeMyClass( + const types::IMyClass& that +) { + nlohmann::json result = nlohmann::json::object(); + + return std::make_pair< + common::optional, + common::optional + >( + common::make_optional(std::move(result)), + common::nullopt + ); +} + +std::pair< + common::optional, + common::optional +> SerializeListOfPrimitives( + const types::IListOfPrimitives& that +) { + nlohmann::json result = nlohmann::json::object(); + + common::optional error; + + nlohmann::json json_strings = nlohmann::json::array(); + json_strings.get_ptr()->reserve( + that.strings().size() + ); + size_t index_strings = 0; + for ( + const std::wstring& item + : that.strings() + ) { + common::optional json_item; + std::tie( + json_item, + error + ) = SerializeIClass(*item); + + if (error.has_value()) { + error->path.segments.emplace_front( + common::make_unique( + index_strings + ) + ); + + error->path.segments.emplace_front( + common::make_unique( + iteration::Property::kStrings + ) + ); + + return std::make_pair< + common::optional, + common::optional + >( + common::nullopt, + std::move(error) + ); + } + + json_strings.emplace_back( + std::move(*json_item) + ); + + ++index_strings; + } + result["strings"] = std::move( + json_strings + ); + + nlohmann::json json_integers = nlohmann::json::array(); + json_integers.get_ptr()->reserve( + that.integers().size() + ); + size_t index_integers = 0; + for ( + int64_t item + : that.integers() + ) { + common::optional json_item; + std::tie( + json_item, + error + ) = SerializeIClass(*item); + + if (error.has_value()) { + error->path.segments.emplace_front( + common::make_unique( + index_integers + ) + ); + + error->path.segments.emplace_front( + common::make_unique( + iteration::Property::kIntegers + ) + ); + + return std::make_pair< + common::optional, + common::optional + >( + common::nullopt, + std::move(error) + ); + } + + json_integers.emplace_back( + std::move(*json_item) + ); + + ++index_integers; + } + result["integers"] = std::move( + json_integers + ); + + nlohmann::json json_booleans = nlohmann::json::array(); + json_booleans.get_ptr()->reserve( + that.booleans().size() + ); + size_t index_booleans = 0; + for ( + bool item + : that.booleans() + ) { + common::optional json_item; + std::tie( + json_item, + error + ) = SerializeIClass(*item); + + if (error.has_value()) { + error->path.segments.emplace_front( + common::make_unique( + index_booleans + ) + ); + + error->path.segments.emplace_front( + common::make_unique( + iteration::Property::kBooleans + ) + ); + + return std::make_pair< + common::optional, + common::optional + >( + common::nullopt, + std::move(error) + ); + } + + json_booleans.emplace_back( + std::move(*json_item) + ); + + ++index_booleans; + } + result["booleans"] = std::move( + json_booleans + ); + + nlohmann::json json_classes = nlohmann::json::array(); + json_classes.get_ptr()->reserve( + that.classes().size() + ); + size_t index_classes = 0; + for ( + const std::shared_ptr& item + : that.classes() + ) { + common::optional json_item; + std::tie( + json_item, + error + ) = SerializeIClass(*item); + + if (error.has_value()) { + error->path.segments.emplace_front( + common::make_unique( + index_classes + ) + ); + + error->path.segments.emplace_front( + common::make_unique( + iteration::Property::kClasses + ) + ); + + return std::make_pair< + common::optional, + common::optional + >( + common::nullopt, + std::move(error) + ); + } + + json_classes.emplace_back( + std::move(*json_item) + ); + + ++index_classes; + } + result["classes"] = std::move( + json_classes + ); + + return std::make_pair< + common::optional, + common::optional + >( + common::make_optional(std::move(result)), + common::nullopt + ); +} + +std::pair< + common::optional, + common::optional +> SerializeIClass( + const types::IClass& that +) { + switch (that.model_type()) { + case types::ModelType::kMyClass: + return SerializeMyClass( + dynamic_cast(that) + ); + case types::ModelType::kListOfPrimitives: + return SerializeListOfPrimitives( + dynamic_cast(that) + ); + default: { + std::string message = common::Concat( + "Unexpected model type: ", + std::to_string( + static_cast( + that.model_type() + ) + ) + ); + + throw std::invalid_argument(message); + } + }; +} + +nlohmann::json Serialize( + const types::IClass& that +) { + common::optional result; + common::optional error; + + std::tie( + result, + error + ) = SerializeIClass(that); + + if (error.has_value()) { + throw SerializationException( + std::move(error->cause), + std::move(error->path) + ); + } + + return std::move(*result); +} + +// endregion Serialization + +} // namespace jsonization +} // namespace aas_3_0 +} // namespace aas_core + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. diff --git a/test_data/cpp/test_main/list_of_primitives/expected_output/jsonization.hpp b/test_data/cpp/test_main/list_of_primitives/expected_output/jsonization.hpp new file mode 100644 index 000000000..c989712f0 --- /dev/null +++ b/test_data/cpp/test_main/list_of_primitives/expected_output/jsonization.hpp @@ -0,0 +1,202 @@ +#ifndef AAS_CORE_AAS_3_0_JSONIZATION_GUARD_ +#define AAS_CORE_AAS_3_0_JSONIZATION_GUARD_ + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#include "aas_core/aas_3_0/common.hpp" +#include "aas_core/aas_3_0/iteration.hpp" +#include "aas_core/aas_3_0/types.hpp" + +#pragma warning(push, 0) +#include + +#include +#include +#include +#pragma warning(pop) + +namespace aas_core { +namespace aas_3_0 { + +/** + * \defgroup jsonization De/serialize instances from and to JSON. + * @{ + */ +namespace jsonization { + +/** + * Represent a segment of a JSON path to some value. + */ +class ISegment { + public: + /** + * \brief Convert the segment to a string in a JSON path. + */ + virtual std::wstring ToWstring() const = 0; + + virtual std::unique_ptr Clone() const = 0; + + virtual ~ISegment() = default; +}; // class ISegment + +/** + * Represent a property access on a JSON path. + */ +struct PropertySegment : public ISegment { + /** + * Name of the property in a JSON object + */ + std::wstring name; + + PropertySegment( + std::wstring a_name + ); + + std::wstring ToWstring() const override; + + std::unique_ptr Clone() const override; + + ~PropertySegment() override = default; +}; // struct PropertySegment + +/** + * Represent an index access on a JSON path. + */ +struct IndexSegment : public ISegment { + /** + * Index of the value in an array. + */ + size_t index; + + explicit IndexSegment( + size_t an_index + ); + + std::wstring ToWstring() const override; + + std::unique_ptr Clone() const override; + + ~IndexSegment() override = default; +}; // struct IndexSegment + +/** + * Represent a JSON path to some value. + */ +struct Path { + std::deque > segments; + + Path(); + Path(const Path& other); + Path(Path&& other); + Path& operator=(const Path& other); + Path& operator=(Path&& other); + + std::wstring ToWstring() const; +}; // struct Path + +// region De-serialization + +/** + * Represent a de-serialization error. + */ +struct DeserializationError { + /** + * Human-readable description of the error + */ + std::wstring cause; + + /** + * Path to the erroneous value + */ + Path path; + + explicit DeserializationError(std::wstring a_cause); + DeserializationError(std::wstring a_cause, Path a_path); +}; // struct DeserializationError + +/** + * \brief Deserialize \p json value to an instance + * of types::IMyClass. + * + * \param json value to be de-serialized + * \param additional_properties if not set, check that \p json contains + * no additional properties + * \return The deserialized instance, or a de-serialization error, if any. + */ +common::expected< + std::shared_ptr, + DeserializationError +> MyClassFrom( + const nlohmann::json& json, + bool additional_properties = false +); + +/** + * \brief Deserialize \p json value to an instance + * of types::IListOfPrimitives. + * + * \param json value to be de-serialized + * \param additional_properties if not set, check that \p json contains + * no additional properties + * \return The deserialized instance, or a de-serialization error, if any. + */ +common::expected< + std::shared_ptr, + DeserializationError +> ListOfPrimitivesFrom( + const nlohmann::json& json, + bool additional_properties = false +); + +// endregion Deserialization + +// region Serialization + +/** + * Represent an error in the serialization of an instance to JSON. + */ +class SerializationException : public std::exception { + public: + SerializationException( + std::wstring cause, + iteration::Path path + ); + + const char* what() const noexcept override; + + const std::wstring& cause() const noexcept; + const iteration::Path& path() const noexcept; + + ~SerializationException() noexcept override = default; + + private: + const std::wstring cause_; + const iteration::Path path_; + const std::string msg_; +}; // class SerializationException + +/** + * \brief Serialize \p that instance to a JSON value. + * + * \param that instance to be serialized + * \return The corresponding JSON value + * \throw \ref SerializationException if a value within \p that instance + * could not be serialized + */ +nlohmann::json Serialize( + const types::IClass& that +); + +// endregion Serialization + +} // namespace jsonization +/**@}*/ + +} // namespace aas_3_0 +} // namespace aas_core + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#endif // AAS_CORE_AAS_3_0_JSONIZATION_GUARD_ diff --git a/test_data/cpp/test_main/list_of_primitives/expected_output/pattern.cpp b/test_data/cpp/test_main/list_of_primitives/expected_output/pattern.cpp new file mode 100644 index 000000000..5839a702d --- /dev/null +++ b/test_data/cpp/test_main/list_of_primitives/expected_output/pattern.cpp @@ -0,0 +1,16 @@ +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#include "aas_core/aas_3_0/pattern.hpp" +#include "aas_core/aas_3_0/revm.hpp" + +namespace aas_core { +namespace aas_3_0 { +namespace pattern { + +} // namespace pattern +} // namespace aas_3_0 +} // namespace aas_core + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. diff --git a/test_data/cpp/test_main/list_of_primitives/expected_output/pattern.hpp b/test_data/cpp/test_main/list_of_primitives/expected_output/pattern.hpp new file mode 100644 index 000000000..e3739e47e --- /dev/null +++ b/test_data/cpp/test_main/list_of_primitives/expected_output/pattern.hpp @@ -0,0 +1,36 @@ +#ifndef AAS_CORE_AAS_3_0_PATTERN_GUARD_ +#define AAS_CORE_AAS_3_0_PATTERN_GUARD_ + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#include "aas_core/aas_3_0/revm.hpp" + +#pragma warning(push, 0) +#include +#include +#pragma warning(pop) + +namespace aas_core { +namespace aas_3_0 { + +/** + * \defgroup pattern Provide patterns to be matched using a multi-threaded virtual machine. + * + * The instructions should be supplied to aas_core::aas_3_0::revm::Match. While + * we could have theoretically included this code in verification, we decided to keep + * it separate for readability. You are not expected to use this module directly. + * @{ + */ +namespace pattern { + +} // namespace pattern +/**@}*/ + +} // namespace aas_3_0 +} // namespace aas_core + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#endif // AAS_CORE_AAS_3_0_PATTERN_GUARD_ diff --git a/test_data/cpp/test_main/list_of_primitives/expected_output/revm.cpp b/test_data/cpp/test_main/list_of_primitives/expected_output/revm.cpp new file mode 100644 index 000000000..a90d9d391 --- /dev/null +++ b/test_data/cpp/test_main/list_of_primitives/expected_output/revm.cpp @@ -0,0 +1,863 @@ +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#include "aas_core/aas_3_0/common.hpp" +#include "aas_core/aas_3_0/revm.hpp" + +#pragma warning(push, 0) +#include +#include +#include +#pragma warning(pop) + +namespace aas_core { +namespace aas_3_0 { +namespace revm { + +/** + * Represent the character such that it can be printed in the console. + * + * To that end, we escape the character if it is out of the printable ASCII set. + * + * This function is mostly meant for debugging purposes. + */ +std::string RepresentWCharacter(wchar_t character) { + switch (character) { + case L'\\':return "\\\\"; + case L'"':return "\\\""; + case L'\'':return "\\'"; + case L'\t':return "\\t"; + case L'\n':return "\\n"; + case L'\r':return "\\r"; + default: break; + } + + if (26 <= character && character <= 126) { + return std::string(1, static_cast(character)); + } + + static const char* digits = "0123456789ABCDEF"; + size_t digit_count = sizeof(wchar_t) * 2; + + std::string result; + result.resize(digit_count + 2); + result[0] = L'\\'; + result[1] = L'u'; + + for (size_t i = 0, j = (digit_count - 1) * 4; i < digit_count; ++i, j -= 4) { + const size_t digit_i = (character >> j) & 0x0f; + result[i + 2] = digits[digit_i]; + } + + return result; +} + +/** + * Represent the wide string for debugging purposes where it is printed to the console. + * + * To that end, we escape the individual characters if they are out of printable ASCII + * set. + */ +std::string RepresentWString(const std::wstring& text) { + std::vector parts; + parts.reserve(text.size()); + for (const wchar_t character : text) { + parts.emplace_back(RepresentWCharacter(character)); + } + + size_t size = 0; + for (const std::string& part : parts) { + size += part.size(); + } + + std::string result; + result.reserve(size); + for (const std::string& part : parts) { + result.append(part); + } + return result; +} + +InstructionChar::InstructionChar( + wchar_t a_character +) : + character(a_character) { + // Intentionally empty. +} + +InstructionKind InstructionChar::kind() const { + return InstructionKind::Char; +} + +std::string to_string(const InstructionChar& instruction) { + return common::Concat( + "char '", + RepresentWCharacter(instruction.character), + "'" + ); +} + +Range::Range( + wchar_t a_first, + wchar_t a_last +) : + first(a_first), + last(a_last) { + // NOTE (mristin): + // We are aware that exceptions in constructors should be avoided to prevent + // bug related to uninitialized object state. However, in this case, we do not + // see any risk for such a mistake. + if (a_first > a_last) { + throw std::invalid_argument( + common::Concat( + "The first character in a character range, ", + RepresentWCharacter(a_first), + ", is larger than the last character in the range, ", + RepresentWCharacter(a_last) + ) + ); + } +} + +std::string to_string(const Range& range) { + if (range.first == range.last) { + return RepresentWCharacter(range.first); + } + + return common::Concat( + RepresentWCharacter(range.first), + "-", + RepresentWCharacter(range.last) + ); +} + +InstructionSet::InstructionSet( + std::vector a_ranges +) : + ranges(std::move(a_ranges)) { + // NOTE (mristin): + // We are aware that exceptions in constructors should be avoided to prevent + // bug related to uninitialized object state. However, in this case, we do not + // see any risk for such a mistake. + if (ranges.empty()) { + throw std::invalid_argument( + "Unexpected NotSet instruction with empty ranges" + ); + } + + for (size_t i = 1; i < ranges.size(); ++i) { + if (ranges[i - 1].last >= ranges[i].first) { + throw std::invalid_argument( + common::Concat( + "The ranges for an InstructionSet are unexpectedly either " + "not sorted or overlapping. The range at index ", + std::to_string(i - 1), + " is ", + to_string(ranges[i - 1]), + " and the range at index ", + std::to_string(i), + " is ", + to_string(ranges[i]) + ) + ); + } + } +} + +InstructionKind InstructionSet::kind() const { + return InstructionKind::Set; +} + +std::string to_string(const InstructionSet& instruction) { + std::stringstream ss; + ss << "set '"; + + for (const auto& range : instruction.ranges) { + ss << to_string(range); + } + + ss << "'"; + return ss.str(); +} + +InstructionNotSet::InstructionNotSet( + std::vector a_ranges +) : + ranges(std::move(a_ranges)) { + // NOTE (mristin): + // We are aware that exceptions in constructors should be avoided to prevent + // bug related to uninitialized object state. However, in this case, we do not + // see any risk for such a mistake. + if (ranges.empty()) { + throw std::invalid_argument( + "Unexpected NotSet instruction with empty ranges" + ); + } + + for (size_t i = 1; i < ranges.size(); ++i) { + if (ranges[i - 1].last >= ranges[i].first) { + throw std::invalid_argument( + common::Concat( + "The ranges for an InstructionNotSet are unexpectedly either " + "not sorted or overlapping. The range at index ", + std::to_string(i - 1), + " is ", + to_string(ranges[i - 1]), + " and the range at index ", + std::to_string(i), + " is ", + to_string(ranges[i]) + ) + ); + } + } +} + +InstructionKind InstructionNotSet::kind() const { + return InstructionKind::NotSet; +} + +std::string to_string(const InstructionNotSet& instruction) { + std::stringstream ss; + ss << "not-set '"; + + for (const auto& range : instruction.ranges) { + ss << to_string(range); + } + + ss << "'"; + return ss.str(); +} + +InstructionKind InstructionAny::kind() const { + return InstructionKind::Any; +} + +std::string to_string(const InstructionAny&) { + return "any"; +} + +InstructionKind InstructionMatch::kind() const { + return InstructionKind::Match; +} + +std::string to_string(const InstructionMatch&) { + return "match"; +} + +InstructionJump::InstructionJump( + size_t a_target +) : + target(a_target) { + // Intentionally empty. +} + +InstructionKind InstructionJump::kind() const { + return InstructionKind::Jump; +} + +std::string to_string(const InstructionJump& instruction) { + return common::Concat( + "jump ", + std::to_string(instruction.target) + ); +} + +InstructionSplit::InstructionSplit( + size_t a_first_target, + size_t a_second_target +) : + first_target(a_first_target), + second_target(a_second_target) { + // Intentionally empty. +} + +InstructionKind InstructionSplit::kind() const { + return InstructionKind::Split; +} + +std::string to_string(const InstructionSplit& instruction) { + return common::Concat( + "split ", + std::to_string(instruction.first_target), + ", ", + std::to_string(instruction.second_target) + ); +} + +InstructionKind InstructionEnd::kind() const { + return InstructionKind::End; +} + +std::string to_string(const InstructionEnd&) { + return "end"; +} + +std::string to_string(const Instruction& instruction) { + switch (instruction.kind()) { + case InstructionKind::Char: + return to_string( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const InstructionChar& + >(instruction) + ); + + case InstructionKind::Set: + return to_string( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const InstructionSet& + >(instruction) + ); + + case InstructionKind::NotSet: + return to_string( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const InstructionNotSet& + >(instruction) + ); + + case InstructionKind::Any: + return to_string( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const InstructionAny& + >(instruction) + ); + + case InstructionKind::Match: + return to_string( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const InstructionMatch& + >(instruction) + ); + + case InstructionKind::Jump: + return to_string( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const InstructionJump& + >(instruction) + ); + + case InstructionKind::Split: + return to_string( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const InstructionSplit& + >(instruction) + ); + + case InstructionKind::End: + return to_string( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const InstructionEnd& + >(instruction) + ); + + default: + throw std::logic_error( + common::Concat( + "Unhandled instruction kind: ", + std::to_string( + static_cast(instruction.kind()) + ) + ) + ); + } +} + +std::string to_string( + const std::vector >& instructions +) { + std::stringstream ss; + for (size_t i = 0; i < instructions.size(); ++i) { + ss + << std::setw(4) << i << ": " + << to_string(*instructions[i]) << std::endl; + } + + return ss.str(); +} + +bool CharacterInRanges( + const std::vector& ranges, + wchar_t character +) { + if (ranges.empty()) { + return false; + } + + if (ranges.size() == 1) { + return (ranges[0].first <= character && character <= ranges[0].last); + } + + // Binary search + size_t begin = 0; + size_t end = ranges.size(); + + while (true) { + if (begin == end) { + return false; + } + + // NOTE (mristin): + // Most implementations of the binary search are buggy, see: + // https://en.wikipedia.org/wiki/Binary_search_algorithm#Implementation_issues. + // + // We try to avert some of the bugs by explicitly handling the case where there + // are at most 3 elements in the segment, so we stop here instead of proceeding + // recursively. + if (end - begin <= 3) { + for (size_t i = begin; i < end; ++i) { + const Range& range = ranges[i]; + if (range.first <= character && character <= range.last) { + return true; + } + } + return false; + } + + const size_t middle = (begin + end) / 2; + const Range& range = ranges[middle]; + if (character < range.first) { + end = middle; + } else if (character > range.last) { + begin = middle; + } else { + return true; + } + } +} + +/** + * Keep track of the threads currently being executed. + */ +class ThreadList { + public: + explicit ThreadList(size_t program_size) { + has_.resize(program_size, false); + items_.reserve(program_size); + } + + /** + * Add a new thread for the given program counter if it is not already in the list. + */ + void Spawn(size_t program_counter) { + #ifdef DEBUG + if (program_counter >= program_size_) { + throw std::invalid_argument( + common::Concat( + "Unexpected spawning of a thread at the program counter ", + std::to_string(program_counter), + " since the program size was indicated to be ", + std::to_string(program_size_) + ) + ); + } + #endif + + if (has_[program_counter]) { + return; + } + + has_[program_counter] = true; + items_.push_back(program_counter); + } + + bool Empty() const { + return items_.empty(); + } + + /** + * Pop the thread from the back, returning its program counter. + * + * The order of the threads is not guaranteed. + */ + size_t Pop() { + #ifdef DEBUG + if (items_.empty()) { + throw std::logic_error( + "You tried to pop from an empty thread list." + ); + } + #endif + + const size_t program_counter = items_.back(); + items_.pop_back(); + has_[program_counter] = false; + return program_counter; + } + + /** + * Clear the thread list, keeping its memory capacity. + */ + void Clear() { + std::fill(has_.begin(), has_.end(), false); + items_.clear(); + } + + /** + * Return the program counters corresponding to the spawned threads. + */ + const std::vector& Items() const { + return items_; + }; + + private: + /** + * Keep track of the program counters corresponding to the threads so that we can + * avoid the duplicate threads. + */ + std::vector has_; + + /** + * Keep track of the active threads. + */ + std::vector items_; +}; + +std::string to_string(const ThreadList& thread_list) { + if (thread_list.Empty()) { + return "[]"; + } + + std::vector items(thread_list.Items()); + std::sort(items.begin(), items.end()); + + std::stringstream ss; + ss << "["; + ss << std::to_string(items[0]); + + for (size_t i = 1; i < items.size(); ++i) { + ss << ", " << items[i]; + } + ss << "]"; + + return ss.str(); +} + +/** + * Try to match the program against the text. + * + * @return true if the text matches + */ +bool Match( + const std::vector >& program, + const std::wstring& text +) { + if (program.empty()) { + return false; + } + + // NOTE (mristin): + // We validate at the beginning so that we can avoid checks in + // the instruction loops. + for (size_t i = 0; i < program.size(); ++i) { + const Instruction& instruction = *program[i]; + + switch (instruction.kind()) { + case InstructionKind::Jump: { + const auto& instruction_jump( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const InstructionJump& + >( + instruction + ) + ); + + if (instruction_jump.target >= program.size()) { + throw std::invalid_argument( + common::Concat( + "Unexpected jump beyond the end of the program. Program has ", + std::to_string(program.size()), + " instruction(s), but the instruction ", + std::to_string(i), + " wants to jump to ", + std::to_string(instruction_jump.target) + ) + ); + } + break; + } + + case InstructionKind::Split: { + const auto& instruction_split( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const InstructionSplit& + >( + instruction + ) + ); + + if (instruction_split.first_target >= program.size()) { + throw std::invalid_argument( + common::Concat( + "Unexpected split & jump beyond the end of the program. Program has ", + std::to_string(program.size()), + " instruction(s), but the instruction ", + std::to_string(i), + " wants to split and make the first jump to ", + std::to_string(instruction_split.first_target) + ) + ); + } + + if (instruction_split.second_target >= program.size()) { + throw std::invalid_argument( + common::Concat( + "Unexpected split & jump beyond the end of the program. Program has ", + std::to_string(program.size()), + " instruction(s), but the instruction ", + std::to_string(i), + " wants to split and make the second jump to ", + std::to_string(instruction_split.second_target) + ) + ); + } + + break; + } + + default: + continue; + } + } + + // NOTE (mristin): + // See: https://swtch.com/~rsc/regexp/regexp2.html, + // Section "Thompson's Implementation". + + std::unique_ptr clist(std::make_unique(program.size())); + std::unique_ptr nlist(std::make_unique(program.size())); + + clist->Spawn(0); + + for (const wchar_t character : text) { + #ifdef DEBUG + if (!nlist->Empty()) { + throw std::logic_error( + "Expected the list of next-to-be-executed threads to be empty, " + "but it was not." + ); + } + #endif + + while (!clist->Empty()) { + const size_t program_counter = clist->Pop(); + + #ifdef DEBUG + if (program_counter >= program.size()) { + throw std::logic_error( + common::Concat( + "Unexpected program counter beyond the program. The program size was ", + std::to_string(program.size()), + ", while the program counter of a thread was ", + std::to_string(program_counter) + ) + ); + } + #endif + + const Instruction& instruction = *program[program_counter]; + + switch (instruction.kind()) { + case InstructionKind::Char: { + const auto& instruction_char( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const InstructionChar& + >(instruction) + ); + + if (character != instruction_char.character) { + // The matching failed for this thread. + break; + } + + nlist->Spawn(program_counter + 1); + break; + } + + case InstructionKind::Set: { + const auto& instruction_set( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const InstructionSet& + >(instruction) + ); + + if (!CharacterInRanges(instruction_set.ranges, character)) { + // The matching failed for this thread. + break; + } + + nlist->Spawn(program_counter + 1); + break; + } + + case InstructionKind::NotSet: { + const auto& instruction_not_set( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const InstructionNotSet& + >(instruction) + ); + + if (CharacterInRanges(instruction_not_set.ranges, character)) { + // The matching failed for this thread. + break; + } + + nlist->Spawn(program_counter + 1); + break; + } + + case InstructionKind::Any: { + // NOTE (mristin): + // We simply proceed to the next instruction at the next character without + // any checks. + nlist->Spawn(program_counter + 1); + break; + } + + case InstructionKind::Match: + return true; + + case InstructionKind::Jump: { + const auto& instruction_jump( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const InstructionJump& + >(instruction) + ); + + clist->Spawn(instruction_jump.target); + break; + } + + case InstructionKind::Split: { + const auto& instruction_split( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const InstructionSplit& + >(instruction) + ); + + clist->Spawn(instruction_split.first_target); + clist->Spawn(instruction_split.second_target); + break; + } + + case InstructionKind::End: { + // The matching failed for this thread as we have just consumed + // a character. + break; + } + + default: + throw std::logic_error( + common::Concat( + "Unhandled instruction kind: ", + std::to_string( + static_cast(instruction.kind()) + ) + ) + ); + } + } + + std::swap(clist, nlist); + nlist->Clear(); + } + + // NOTE (mristin): + // We need to process any pending jumps, splits and matches even tough there are + // no more characters to consume. + while (!clist->Empty()) { + const size_t program_counter = clist->Pop(); + + #ifdef DEBUG + if (program_counter >= program.size()) { + throw std::logic_error( + common::Concat( + "Unexpected program counter beyond the program. The program size was ", + std::to_string(program.size()), + ", while the program counter of a thread was ", + std::to_string(program_counter) + ) + ); + } + #endif + + const Instruction& instruction = *program[program_counter]; + + switch (instruction.kind()) { + case InstructionKind::Char: { // NOLINT(bugprone-branch-clone) + // We reached the end-of-input so there are no characters to be matched. + // This thread needs therefore to die. + break; + } + + case InstructionKind::Set: { + // We reached the end-of-input so there are no character sets to be matched. + // This thread needs therefore to die. + break; + } + + case InstructionKind::NotSet: { + // We reached the end-of-input so there are no character sets to be matched. + // This thread needs therefore to die. + break; + } + + case InstructionKind::Any: { + // We reached the end-of-input so there are no characters to be matched. + // This thread needs therefore to die. + break; + } + + case InstructionKind::Match: + return true; + + case InstructionKind::Jump: { + const auto& instruction_jump( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const InstructionJump& + >(instruction) + ); + + clist->Spawn(instruction_jump.target); + break; + } + + case InstructionKind::Split: { + const auto& instruction_split( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const InstructionSplit& + >(instruction) + ); + + clist->Spawn(instruction_split.first_target); + clist->Spawn(instruction_split.second_target); + break; + } + + case InstructionKind::End: { + // We reached the end-of-input so we match and move to the next instruction. + clist->Spawn(program_counter + 1); + break; + } + + default: + throw std::logic_error( + common::Concat( + "Unhandled instruction kind: ", + std::to_string( + static_cast(instruction.kind()) + ) + ) + ); + } + } + + return false; +} + +} // namespace revm +} // namespace aas_3_0 +} // namespace aas_core + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. diff --git a/test_data/cpp/test_main/list_of_primitives/expected_output/revm.hpp b/test_data/cpp/test_main/list_of_primitives/expected_output/revm.hpp new file mode 100644 index 000000000..fa54533ee --- /dev/null +++ b/test_data/cpp/test_main/list_of_primitives/expected_output/revm.hpp @@ -0,0 +1,215 @@ +#ifndef AAS_CORE_AAS_3_0_REVM_GUARD_ +#define AAS_CORE_AAS_3_0_REVM_GUARD_ + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#pragma warning(push, 0) +#include +#include +#include +#include +#pragma warning(pop) + +namespace aas_core { +namespace aas_3_0 { + +/** + * \defgroup revm Match regular expressions using a multi-threaded virtual machine. + * + * The implementation in the standard library has exponential time complexity, so it was + * a major blocker for most of the practical inputs. For example, see this bug report: + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93502 + * + * This implementation is based on Ken Thompson's approach which uses a virtual + * machine to match regular expressions. The original technique has been + * published in: + * Thompson, K., "Regular expression search algorithm", ACM 11(6) (June 1968) + * + * We followed a very clear and concise blog post which described in detail: + * https://swtch.com/~rsc/regexp/regexp2.html + * + * The ideas for additional instructions were taken from: + * https://www.codeproject.com/Articles/5256833/Regex-as-a-Tiny-Threaded-Virtual-Machine + * @{ + */ +namespace revm { + +enum class InstructionKind : std::uint8_t { + Char, + Set, + NotSet, + Any, + Match, + Jump, + Split, + End +}; + +/** + * Represent an instruction of the virtual machine. + */ +struct Instruction { + // NOTE (mristin): + // We avoid RTTI for performance reasons, and use our own enumerator instead. + virtual InstructionKind kind() const = 0; + + virtual ~Instruction() = default; +}; + +/** + * Match a single character. + * + * If the character on the String Pointer does not match the `character`, stop this + * thread as it failed. Otherwise, move the String Pointer to the next character, + * and the Program Counter to the next instruction. + */ +struct InstructionChar : Instruction { + wchar_t character; + + explicit InstructionChar(wchar_t a_character); + InstructionKind kind() const override; + ~InstructionChar() override = default; +}; + +std::string to_string(const InstructionChar& instruction); + +/** + * Define a character range. + */ +struct Range { + wchar_t first; + wchar_t last; + + Range(wchar_t a_first, wchar_t a_last); +}; + +std::string to_string(const Range& range); + +/** + * Check whether the character is in any of the given character ranges. + * + * @return true if the character is in any of the ranges + */ +bool CharacterInRanges( + const std::vector& ranges, + wchar_t character +); + +/** + * Match a set of characters. + * + * If the character on the String Pointer *is not* in the given set, stop this + * thread as it failed. Otherwise, move the String Pointer to the next character, + * and the Program Counter to the next instruction. + */ +struct InstructionSet : Instruction { + std::vector ranges; + + explicit InstructionSet(std::vector a_ranges); + InstructionKind kind() const override; + ~InstructionSet() override = default; +}; + +std::string to_string(const InstructionSet& instruction); + +/** + * Match an out-of-set character. + * + * If the character on the String Pointer *is* in the given set, stop this + * thread as it failed. Otherwise, move the String Pointer to the next character, + * and the Program Counter to the next instruction. + */ +struct InstructionNotSet : Instruction { + std::vector ranges; + + explicit InstructionNotSet(std::vector a_ranges); + InstructionKind kind() const override; + ~InstructionNotSet() override = default; +}; + +std::string to_string(const InstructionNotSet& instruction); + +/** + * Match any character. + */ +struct InstructionAny : Instruction { + InstructionKind kind() const override; + ~InstructionAny() override = default; +}; + +std::string to_string(const InstructionAny&); + +/** + * Stop this thread and signal that we found a match. + */ +struct InstructionMatch : Instruction { + InstructionKind kind() const override; + ~InstructionMatch() override = default; +}; + +std::string to_string(const InstructionMatch&); + +/** + * Jump to the indicated position in the program. + */ +struct InstructionJump : Instruction { + size_t target; + + explicit InstructionJump(size_t a_target); + InstructionKind kind() const override; + ~InstructionJump() override = default; +}; + +std::string to_string(const InstructionJump& instruction); + +/** + * Split the program in two threads, both jumping to different locations. The string + * pointer is kept as-is. + */ +struct InstructionSplit : Instruction { + size_t first_target; + size_t second_target; + + explicit InstructionSplit(size_t a_first_target, size_t a_second_target); + InstructionKind kind() const override; + ~InstructionSplit() override = default; +}; + +std::string to_string(const InstructionSplit& instruction); + +/** + * Match the end-of-input. + */ +struct InstructionEnd : Instruction { + InstructionKind kind() const override; + ~InstructionEnd() override = default; +}; + +std::string to_string(const InstructionEnd&); + +std::string to_string(const Instruction& instruction); + +std::string to_string( + const std::vector >& instructions +); + +/** + * Try to match the program against the text. + * @return true if the text matches + */ +bool Match( + const std::vector >& program, + const std::wstring& text +); + +} // namespace revm +/**@}*/ + +} // namespace aas_3_0 +} // namespace aas_core + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#endif // AAS_CORE_AAS_3_0_REVM_GUARD_ diff --git a/test_data/cpp/test_main/list_of_primitives/expected_output/stdout.txt b/test_data/cpp/test_main/list_of_primitives/expected_output/stdout.txt new file mode 100644 index 000000000..2d755fc5a --- /dev/null +++ b/test_data/cpp/test_main/list_of_primitives/expected_output/stdout.txt @@ -0,0 +1 @@ +Code generated to: diff --git a/test_data/cpp/test_main/list_of_primitives/expected_output/stringification.cpp b/test_data/cpp/test_main/list_of_primitives/expected_output/stringification.cpp new file mode 100644 index 000000000..53bb0d402 --- /dev/null +++ b/test_data/cpp/test_main/list_of_primitives/expected_output/stringification.cpp @@ -0,0 +1,365 @@ +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#include "aas_core/aas_3_0/stringification.hpp" + +#pragma warning(push, 0) +#include +#pragma warning(pop) + +namespace aas_core { +namespace aas_3_0 { +namespace stringification { + +const std::unordered_map< + std::string, + types::ModelType +> kModelTypeFromStringMap = { + { + "MyClass", + types::ModelType::kMyClass + }, + { + "ListOfPrimitives", + types::ModelType::kListOfPrimitives + } +}; + +common::optional ModelTypeFromString( + const std::string& text +) { + const auto it = kModelTypeFromStringMap.find( + text + ); + if (it == kModelTypeFromStringMap.end()) { + return {}; + } + return it->second; +} + +types::ModelType MustModelTypeFromString( + const std::string& text +) { + const auto it = kModelTypeFromStringMap.find( + text + ); + if (it == kModelTypeFromStringMap.end()) { + throw std::invalid_argument( + common::Concat( + "Unexpected ModelType literal: ", + text + ) + ); + } + return it->second; +} + +std::string to_string( + types::ModelType model_type +) { + switch (model_type) { + case types::ModelType::kMyClass: + return "MyClass"; + case types::ModelType::kListOfPrimitives: + return "ListOfPrimitives"; + default: + throw std::invalid_argument( + common::Concat( + "Unexpected model type: ", + std::to_string( + static_cast( + model_type + ) + ) + ) + ); + } +} + +// The following encoder has been adapted from Jouni Malinen to work with +// std::string. The original source code is available at: +// https://web.mit.edu/freebsd/head/contrib/wpa/src/utils/base64.c +// +// See also the following StackOverflow question for a benchmark: +// https://stackoverflow.com/questions/342409/how-do-i-base64-encode-decode-in-c/41094722#41094722 + +constexpr std::size_t kCharBase64TableLen = 65; +static const unsigned char kCharBase64Table[kCharBase64TableLen]( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" +); + +std::string Base64Encode( + const std::vector& bytes +) { + // See: https://cplusplus.com/reference/vector/vector/data/. + // The data is guaranteed to be a continuous block in memory. + const unsigned char* const src( + bytes.data() + ); + + const std::size_t len = bytes.size(); + + // 3-byte blocks to 4-byte + const std::size_t olen = 4 * ((len + 2) / 3); + + // Integer overflow? + if (olen < len) { + throw std::invalid_argument( + common::Concat( + "The calculation of the output length overflowed. " + "The length was: ", + std::to_string(len), + ", but the output length was calculated as: ", + std::to_string(olen) + ) + ); + } + + std::string out_string; + out_string.resize(olen); + + unsigned char* out( + reinterpret_cast( + &out_string[0] + ) + ); + + const unsigned char* const end = src + len; + + const unsigned char* in = src; + unsigned char* pos = out; + + while (end - in >= 3) { + *pos++ = kCharBase64Table[in[0] >> 2]; + *pos++ = kCharBase64Table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; + *pos++ = kCharBase64Table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; + *pos++ = kCharBase64Table[in[2] & 0x3f]; + in += 3; + } + + if (end - in) { + *pos++ = kCharBase64Table[in[0] >> 2]; + + if (end - in == 1) { + *pos++ = kCharBase64Table[(in[0] & 0x03) << 4]; + *pos++ = '='; + } else { + *pos++ = kCharBase64Table[ + ((in[0] & 0x03) << 4) | (in[1] >> 4) + ]; + *pos++ = kCharBase64Table[(in[1] & 0x0f) << 2]; + } + *pos++ = '='; + } + + return out_string; +} + +// The following decoder is vaguely based on: +// https://github.com/danguer/blog-examples/blob/master/js/base64-binary.js, +// https://github.com/niklasvh/base64-arraybuffer/blob/master/src/index.ts and +// https://github.com/beatgammit/base64-js/blob/master/index.js. + +std::vector ConstructBase64Lookup() { + std::vector lookup(256, 255); + for (std::uint8_t i = 0; i < kCharBase64TableLen; ++i) { + lookup.at(kCharBase64Table[i]) = i; + } + return lookup; +} +const std::vector kBase64Lookup = ConstructBase64Lookup(); + +common::expected< + std::vector, + std::string +> Base64Decode( + const std::string& text +) { + if (text.empty()) { + return std::vector(); + } + + const std::size_t len = text.size(); + std::size_t len_wo_pad = len; + + // NOTE (mristin): + // Some implementations forget the padding, so we try to be robust and check + // for the padding manually. + std::size_t bytes_length = (len * 3) / 4; + if (text[len - 1] == '=') { + bytes_length--; + len_wo_pad--; + + if (text[len - 2] == '=') { + bytes_length--; + len_wo_pad--; + } + } + + std::vector bytes(bytes_length); + + const std::size_t base64_lookup_len = kBase64Lookup.size(); + + std::size_t pointer = 0; + + for (std::size_t i = 0; i < len; i += 4) { + // NOTE (mristin): + // Admittedly, this is very verbose code, but we want to be efficient, so we + // opted for performance over readability here. + + const unsigned char code0 = text[i]; + if (code0 >= base64_lookup_len) { + std::string message = common::Concat( + "Expected a valid character from base64-encoded string, " + "but got at index ", + std::to_string(i), + ": ", + std::to_string(code0), + " (code: ", + std::to_string(static_cast(code0)), + ")" + ); + + return common::make_unexpected(message); + } + const std::uint8_t encoded0 = kBase64Lookup[code0]; + if (encoded0 == 255) { + std::string message = common::Concat( + "Expected a valid character from base64-encoded string, " + "but got at index ", + std::to_string(i), + ": ", + std::to_string(code0), + " (code: ", + std::to_string(static_cast(code0)), + ")" + ); + + return common::make_unexpected(message); + } + + const unsigned char code1 = text[i + 1]; + if (code1 >= base64_lookup_len) { + std::string message = common::Concat( + "Expected a valid character from base64-encoded string, " + "but got at index ", + std::to_string(i + 1), + ": ", + std::to_string(code1), + " (code: ", + std::to_string(static_cast(code1)), + ")" + ); + + return common::make_unexpected(message); + } + const std::uint8_t encoded1 = kBase64Lookup[code1]; + if (encoded1 == 255) { + std::string message = common::Concat( + "Expected a valid character from base64-encoded string, " + "but got at index ", + std::to_string(i + 1), + ": ", + std::to_string(code1), + " (code: ", + std::to_string(static_cast(code1)), + ")" + ); + + return common::make_unexpected(message); + } + + // We map padding to 65, which is the value of "A". + const unsigned char code2 = i + 2 < len_wo_pad ? text[i + 2] : 65; + if (code2 >= base64_lookup_len) { + std::string message = common::Concat( + "Expected a valid character from base64-encoded string, " + "but got at index ", + std::to_string(i + 2), + ": ", + std::to_string(code2), + " (code: ", + std::to_string(static_cast(code2)), + ")" + ); + + return common::make_unexpected(message); + } + const std::uint8_t encoded2 = kBase64Lookup[code2]; + if (encoded2 == 255) { + std::string message = common::Concat( + "Expected a valid character from base64-encoded string, " + "but got at index ", + std::to_string(i + 2), + ": ", + std::to_string(code2), + " (code: ", + std::to_string(static_cast(code2)), + ")" + ); + + return common::make_unexpected(message); + } + + // We map padding to 65, which is the value of 'A'. + const unsigned char code3 = i + 3 < len_wo_pad ? text[i + 3] : 65; + if (code3 >= base64_lookup_len) { + std::string message = common::Concat( + "Expected a valid character from base64-encoded string, " + "but got at index ", + std::to_string(i + 3), + ": ", + std::to_string(code3), + " (code: ", + std::to_string(static_cast(code3)), + ")" + ); + + return common::make_unexpected(message); + } + const std::uint8_t encoded3 = kBase64Lookup[code3]; + if (encoded3 == 255) { + std::string message = common::Concat( + "Expected a valid character from base64-encoded string, " + "but got at index ", + std::to_string(i + 3), + ": ", + std::to_string(code3), + " (code: ", + std::to_string(static_cast(code3)), + ")" + ); + + return common::make_unexpected(message); + } + + if (pointer >= bytes_length) { + break; + } + bytes[pointer] = (encoded0 << 2) | (encoded1 >> 4); + pointer++; + + if (pointer >= bytes_length) { + break; + } + bytes[pointer] = ((encoded1 & 15) << 4) | (encoded2 >> 2); + pointer++; + + if (pointer >= bytes_length) { + break; + } + bytes[pointer] = ((encoded2 & 3) << 6) | (encoded3 & 63); + pointer++; + } + + return bytes; +} + +} // namespace stringification +/**@}*/ + +} // namespace aas_3_0 +} // namespace aas_core + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. diff --git a/test_data/cpp/test_main/list_of_primitives/expected_output/stringification.hpp b/test_data/cpp/test_main/list_of_primitives/expected_output/stringification.hpp new file mode 100644 index 000000000..ed4f86b19 --- /dev/null +++ b/test_data/cpp/test_main/list_of_primitives/expected_output/stringification.hpp @@ -0,0 +1,93 @@ +#ifndef AAS_CORE_AAS_3_0_STRINGIFICATION_GUARD_ +#define AAS_CORE_AAS_3_0_STRINGIFICATION_GUARD_ + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#include "aas_core/aas_3_0/common.hpp" +#include "aas_core/aas_3_0/types.hpp" + +#pragma warning(push, 0) +#include +#include +#pragma warning(pop) + +namespace aas_core { +namespace aas_3_0 { + +/** + * \defgroup stringification Translate to strings, and, where applicable, from strings. + * @{ + */ +namespace stringification { + +/** + * Try to parse the \p text as a model type literal. + * + * \param text to be parsed + * \return literal, or nothing, if \p text invalid + */ +common::optional ModelTypeFromString( + const std::string& text +); + +/** + * Parse the \p text as a model type literal. + * + * \param text to be parsed + * \return literal + * \throw std::invalid_argument if \p text invalid + */ +types::ModelType MustModelTypeFromString( + const std::string& text +); + +/** + * Translate the enumeration literal \p model_type to text. + * + * \param model_type to be converted into text + * \return text representation of \p model_type + * \throw std::invalid_argument if \p model_type invalid + */ +std::string to_string( + types::ModelType model_type +); + +/** + * Encode the \p bytes with base64 to a std::string. + * + * \param bytes to be encoded + * \return base64-encoding of \p bytes + */ +std::string Base64Encode( + const std::vector& bytes +); + +/** + * Decode the \p the text with base64 to bytes. + * + * \remark \parblock + * We intentionally decode from std::string and *not* from std::wstring as + * the de/serialization libraries currently work only with UTF-8 encoded strings. + * \endparblock + * + * \param text to be decoded + * \return decoded bytes, or error message, if any. + */ +common::expected< + std::vector, + std::string +> Base64Decode( + const std::string& text +); + +} // namespace stringification +} // namespace aas_3_0 +} // namespace aas_core + +/**@}*/ + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#endif // AAS_CORE_AAS_3_0_STRINGIFICATION_GUARD_ diff --git a/test_data/cpp/test_main/list_of_primitives/expected_output/types.cpp b/test_data/cpp/test_main/list_of_primitives/expected_output/types.cpp new file mode 100644 index 000000000..e5428649f --- /dev/null +++ b/test_data/cpp/test_main/list_of_primitives/expected_output/types.cpp @@ -0,0 +1,158 @@ +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#include "aas_core/aas_3_0/types.hpp" + +namespace aas_core { +namespace aas_3_0 { +namespace types { + +// region MyClass + +MyClass::MyClass() { + // Intentionally empty. +} + +ModelType MyClass::model_type() const { + return ModelType::kMyClass; +} + +// endregion MyClass + +// region ListOfPrimitives + +ListOfPrimitives::ListOfPrimitives( + std::vector strings, + std::vector integers, + std::vector booleans, + std::vector< + std::shared_ptr + > classes +) { + strings_ = std::move(strings); + + integers_ = std::move(integers); + + booleans_ = std::move(booleans); + + classes_ = std::move(classes); +} + +ModelType ListOfPrimitives::model_type() const { + return ModelType::kListOfPrimitives; +} + +const std::vector& ListOfPrimitives::strings() const { + return strings_; +} + +std::vector& ListOfPrimitives::mutable_strings() { + return strings_; +} + +void ListOfPrimitives::set_strings( + std::vector value +) { + strings_ = value; +} + +const std::vector& ListOfPrimitives::integers() const { + return integers_; +} + +std::vector& ListOfPrimitives::mutable_integers() { + return integers_; +} + +void ListOfPrimitives::set_integers( + std::vector value +) { + integers_ = value; +} + +const std::vector& ListOfPrimitives::booleans() const { + return booleans_; +} + +std::vector& ListOfPrimitives::mutable_booleans() { + return booleans_; +} + +void ListOfPrimitives::set_booleans( + std::vector value +) { + booleans_ = value; +} + +const std::vector< + std::shared_ptr +>& ListOfPrimitives::classes() const { + return classes_; +} + +std::vector< + std::shared_ptr +>& ListOfPrimitives::mutable_classes() { + return classes_; +} + +void ListOfPrimitives::set_classes( + std::vector< + std::shared_ptr + > value +) { + classes_ = value; +} + +// endregion ListOfPrimitives + +// region Is-a functions + +bool IsMyClass( + const IClass& that +) { + switch (that.model_type()) { + case ModelType::kMyClass: + return true; + case ModelType::kListOfPrimitives: + return false; + default: + throw std::invalid_argument( + common::Concat( + "Unexpected model type: ", + std::to_string( + static_cast(that.model_type()) + ) + ) + ); + } +} + +bool IsListOfPrimitives( + const IClass& that +) { + switch (that.model_type()) { + case ModelType::kMyClass: + return false; + case ModelType::kListOfPrimitives: + return true; + default: + throw std::invalid_argument( + common::Concat( + "Unexpected model type: ", + std::to_string( + static_cast(that.model_type()) + ) + ) + ); + } +} + +// endregion Is-a functions + +} // namespace types +} // namespace aas_3_0 +} // namespace aas_core + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. diff --git a/test_data/cpp/test_main/list_of_primitives/expected_output/types.hpp b/test_data/cpp/test_main/list_of_primitives/expected_output/types.hpp new file mode 100644 index 000000000..1b66e3b48 --- /dev/null +++ b/test_data/cpp/test_main/list_of_primitives/expected_output/types.hpp @@ -0,0 +1,253 @@ +#ifndef AAS_CORE_AAS_3_0_TYPES_GUARD_ +#define AAS_CORE_AAS_3_0_TYPES_GUARD_ + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#include "aas_core/aas_3_0/common.hpp" + +#pragma warning(push, 0) +#include +#include +#include +#include +#include +#pragma warning(pop) + +namespace aas_core { +namespace aas_3_0 { + +/** + * \defgroup types Define data structures corresponding to the meta-model. + * @{ + */ +namespace types { + +// region Enumerations + +/** + * Enumerate the model types for faster type switches. + * + * For example, switch statements can be implemented as jump tables. + */ +enum class ModelType : std::uint32_t { + kMyClass = 0, + kListOfPrimitives = 1 +}; + +// endregion Enumerations + +// region Forward declaration of interfaces + +// endregion Forward declaration of interfaces + +class IMyClass; + +class IListOfPrimitives; + +// region Class interfaces + +/** + * Model the most general instance of the model. + */ +class IClass { + public: + /** + * Indicate the runtime model type. + */ + virtual ModelType model_type() const = 0; + virtual ~IClass() = default; +}; + +class IMyClass + : virtual public IClass { + public: + virtual ~IMyClass() = default; +}; + +class IListOfPrimitives + : virtual public IClass { + public: + virtual const std::vector& strings() const = 0; + + virtual std::vector& mutable_strings() = 0; + + virtual void set_strings( + std::vector value + ) = 0; + + virtual const std::vector& integers() const = 0; + + virtual std::vector& mutable_integers() = 0; + + virtual void set_integers( + std::vector value + ) = 0; + + virtual const std::vector& booleans() const = 0; + + virtual std::vector& mutable_booleans() = 0; + + virtual void set_booleans( + std::vector value + ) = 0; + + virtual const std::vector< + std::shared_ptr + >& classes() const = 0; + + virtual std::vector< + std::shared_ptr + >& mutable_classes() = 0; + + virtual void set_classes( + std::vector< + std::shared_ptr + > value + ) = 0; + + virtual ~IListOfPrimitives() = default; +}; + +// endregion + +// region Definitions of concrete classes + +class MyClass + : public IMyClass { + public: + MyClass() {} + + ModelType model_type() const override; + + ~MyClass() override = default; +}; + +class ListOfPrimitives + : public IListOfPrimitives { + public: + ListOfPrimitives( + std::vector strings, + std::vector integers, + std::vector booleans, + std::vector< + std::shared_ptr + > classes + ); + + ModelType model_type() const override; + + // region Get and set strings_ + + const std::vector& strings() const override; + + std::vector& mutable_strings() override; + + void set_strings( + std::vector value + ) override; + + // endregion + + // region Get and set integers_ + + const std::vector& integers() const override; + + std::vector& mutable_integers() override; + + void set_integers( + std::vector value + ) override; + + // endregion + + // region Get and set booleans_ + + const std::vector& booleans() const override; + + std::vector& mutable_booleans() override; + + void set_booleans( + std::vector value + ) override; + + // endregion + + // region Get and set classes_ + + const std::vector< + std::shared_ptr + >& classes() const override; + + std::vector< + std::shared_ptr + >& mutable_classes() override; + + void set_classes( + std::vector< + std::shared_ptr + > value + ) override; + + // endregion + + ~ListOfPrimitives() override = default; + + private: + std::vector strings_; + + std::vector integers_; + + std::vector booleans_; + + std::vector< + std::shared_ptr + > classes_; +}; + +// endregion + +// region Is-a functions + +/** + * \brief Check whether \p that instance is of runtime type + * \ref IMyClass. + * + * We use `IClass::model_type` to determine the runtime type, which is + * a bit faster than native C++'s RTTI. + * + * \param that instance to check for runtime type + * \return `true` if \p that instance is indeed + * an instance of \ref IMyClass + */ +bool IsMyClass( + const IClass& that +); + +/** + * \brief Check whether \p that instance is of runtime type + * \ref IListOfPrimitives. + * + * We use `IClass::model_type` to determine the runtime type, which is + * a bit faster than native C++'s RTTI. + * + * \param that instance to check for runtime type + * \return `true` if \p that instance is indeed + * an instance of \ref IListOfPrimitives + */ +bool IsListOfPrimitives( + const IClass& that +); + +// endregion Is-a functions + +} // namespace types +/**@}*/ + +} // namespace aas_3_0 +} // namespace aas_core + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#endif // AAS_CORE_AAS_3_0_TYPES_GUARD_ diff --git a/test_data/cpp/test_main/list_of_primitives/expected_output/verification.cpp b/test_data/cpp/test_main/list_of_primitives/expected_output/verification.cpp new file mode 100644 index 000000000..b2233917d --- /dev/null +++ b/test_data/cpp/test_main/list_of_primitives/expected_output/verification.cpp @@ -0,0 +1,727 @@ +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#include "aas_core/aas_3_0/common.hpp" +#include "aas_core/aas_3_0/constants.hpp" +#include "aas_core/aas_3_0/pattern.hpp" +#include "aas_core/aas_3_0/revm.hpp" +#include "aas_core/aas_3_0/verification.hpp" + +#pragma warning(push, 0) +#include +#include +#pragma warning(pop) + +namespace aas_core { +namespace aas_3_0 { +namespace verification { + +// region struct Error + +Error::Error( + std::wstring a_cause +) : + cause(std::move(a_cause)) { + // Intentionally empty. +} + +Error::Error( + std::wstring a_cause, + iteration::Path a_path +) : + cause(std::move(a_cause)), + path(std::move(a_path)) { + // Intentionally empty. +} + +// endregion struct Error + +// region class AlwaysDoneVerificator + +class AlwaysDoneVerificator : public impl::IVerificator { + public: + void Start() override; + void Next() override; + bool Done() const override; + const Error& Get() const override; + Error& GetMutable() override; + long Index() const override; + std::unique_ptr Clone() const override; + + virtual ~AlwaysDoneVerificator() = default; +}; // class AlwaysDoneVerificator + +void AlwaysDoneVerificator::Start() { + // Intentionally empty. +} + +void AlwaysDoneVerificator::Next() { + throw std::logic_error( + "You want to move an AlwaysDoneVerificator, " + "but the verificator is always done, as its name suggests." + ); +} + +bool AlwaysDoneVerificator::Done() const { + return true; +} + +const Error& AlwaysDoneVerificator::Get() const { + throw std::logic_error( + "You want to get from an AlwaysDoneVerificator, " + "but the verificator is always done, as its name suggests." + ); +} + +Error& AlwaysDoneVerificator::GetMutable() { + throw std::logic_error( + "You want to get mutable from an AlwaysDoneVerificator, " + "but the verificator is always done, as its name suggests." + ); +} + +long AlwaysDoneVerificator::Index() const { + return -1; +} + +std::unique_ptr AlwaysDoneVerificator::Clone() const { + return common::make_unique(*this); +} + +// endregion class AlwaysDoneVerificator + +/** + * Produce a non-recursive verificator of the instance given its runtime model type. + */ +std::unique_ptr NewNonRecursiveVerificator( + const std::shared_ptr& instance +); + +// region Non-recursive verificators + +namespace non_recursive_verificator { + +class OfMyClass : public impl::IVerificator { + public: + OfMyClass( + const std::shared_ptr& instance + ); + + void Start() override; + void Next() override; + bool Done() const override; + const Error& Get() const override; + Error& GetMutable() override; + long Index() const override; + + std::unique_ptr Clone() const override; + + ~OfMyClass() override = default; +}; // class OfMyClass + +OfMyClass::OfMyClass( + const std::shared_ptr& +) { + // Intentionally empty. +} + +void OfMyClass::Start() { + // Intentionally empty. +} + +void OfMyClass::Next() { + throw std::logic_error( + "You want to move " + "a verificator OfMyClass, " + "but the verificator is always done as " + "IMyClass " + "has no invariants defined." + ); +} + +bool OfMyClass::Done() const { + return true; +} + +const Error& OfMyClass::Get() const { + throw std::logic_error( + "You want to get from " + "a verificator OfMyClass, " + "but the verificator is always done as " + "IMyClass " + "has no invariants defined." + ); +} + +Error& OfMyClass::GetMutable() { + throw std::logic_error( + "You want to get mutable from " + "a verificator OfMyClass, " + "but the verificator is always done as " + "IMyClass " + "has no invariants defined." + ); +} + +long OfMyClass::Index() const { + return -1; +} + +std::unique_ptr OfMyClass::Clone() const { + return common::make_unique< + OfMyClass + >(*this); +} + +class OfListOfPrimitives : public impl::IVerificator { + public: + OfListOfPrimitives( + const std::shared_ptr& instance + ); + + void Start() override; + void Next() override; + bool Done() const override; + const Error& Get() const override; + Error& GetMutable() override; + long Index() const override; + + std::unique_ptr Clone() const override; + + ~OfListOfPrimitives() override = default; +}; // class OfListOfPrimitives + +OfListOfPrimitives::OfListOfPrimitives( + const std::shared_ptr& +) { + // Intentionally empty. +} + +void OfListOfPrimitives::Start() { + // Intentionally empty. +} + +void OfListOfPrimitives::Next() { + throw std::logic_error( + "You want to move " + "a verificator OfListOfPrimitives, " + "but the verificator is always done as " + "IListOfPrimitives " + "has no invariants defined." + ); +} + +bool OfListOfPrimitives::Done() const { + return true; +} + +const Error& OfListOfPrimitives::Get() const { + throw std::logic_error( + "You want to get from " + "a verificator OfListOfPrimitives, " + "but the verificator is always done as " + "IListOfPrimitives " + "has no invariants defined." + ); +} + +Error& OfListOfPrimitives::GetMutable() { + throw std::logic_error( + "You want to get mutable from " + "a verificator OfListOfPrimitives, " + "but the verificator is always done as " + "IListOfPrimitives " + "has no invariants defined." + ); +} + +long OfListOfPrimitives::Index() const { + return -1; +} + +std::unique_ptr OfListOfPrimitives::Clone() const { + return common::make_unique< + OfListOfPrimitives + >(*this); +} + +} // namespace non_recursive_verificator + +std::unique_ptr NewNonRecursiveVerificator( + const std::shared_ptr& instance +) { + switch (instance->model_type()) { + case types::ModelType::kMyClass: + return common::make_unique< + non_recursive_verificator::OfMyClass + >( + instance + ); + case types::ModelType::kListOfPrimitives: + return common::make_unique< + non_recursive_verificator::OfListOfPrimitives + >( + instance + ); + default: + throw std::logic_error( + common::Concat( + "Unexpected model type: ", + std::to_string( + static_cast(instance->model_type()) + ) + ) + ); + } +} + +// endregion Non-recursive verificators + +// region Recursive verificators + +class RecursiveVerificator : public impl::IVerificator { + public: + RecursiveVerificator( + const std::shared_ptr& instance + ); + + RecursiveVerificator(const RecursiveVerificator& other); + RecursiveVerificator(RecursiveVerificator&& other); + RecursiveVerificator& operator=(const RecursiveVerificator& other); + RecursiveVerificator& operator=(RecursiveVerificator&& other); + + void Start() override; + void Next() override; + bool Done() const override; + const Error& Get() const override; + Error& GetMutable() override; + long Index() const override; + + std::unique_ptr Clone() const override; + + ~RecursiveVerificator() override = default; + + private: + // NOTE(mristin): + // We use a pointer to a shared pointer here so that we can implement + // copy-assignment and move-assignment. Otherwise, if we used a constant + // reference here, the assignments could not be implemented as C++ does not + // allow re-binding of constant references. + const std::shared_ptr* instance_; + + std::uint32_t state_; + std::unique_ptr verificator_; + bool done_; + long index_; + std::unique_ptr error_; + common::optional iterator_; + common::optional iterator_end_; + + void Execute(); +}; // class RecursiveVerificator + +RecursiveVerificator::RecursiveVerificator( + const std::shared_ptr& instance +) : instance_(&instance) { + // Intentionally empty. +} + +RecursiveVerificator::RecursiveVerificator(const RecursiveVerificator& other) { + instance_ = other.instance_; + state_ = other.state_; + verificator_ = other.verificator_->Clone(); + done_ = other.done_; + index_ = other.index_; + error_ = common::make_unique(*(other.error_)); + iterator_ = other.iterator_; + iterator_end_ = other.iterator_end_; +} + +RecursiveVerificator::RecursiveVerificator(RecursiveVerificator&& other) { + instance_ = other.instance_; + state_ = other.state_; + verificator_ = std::move(other.verificator_); + done_ = other.done_; + index_ = other.index_; + error_ = std::move(other.error_); + iterator_ = std::move(other.iterator_); + iterator_end_ = std::move(other.iterator_end_); +} + +RecursiveVerificator& RecursiveVerificator::operator=( + const RecursiveVerificator& other +) { + return *this = RecursiveVerificator(other); +} + +RecursiveVerificator& RecursiveVerificator::operator=(RecursiveVerificator&& other) { + if (this != &other) { + instance_ = other.instance_; + state_ = other.state_; + verificator_ = std::move(other.verificator_); + done_ = other.done_; + index_ = other.index_; + error_ = std::move(other.error_); + iterator_ = std::move(other.iterator_); + iterator_end_ = std::move(other.iterator_end_); + } + + return *this; +} + +void RecursiveVerificator::Start() { + state_ = 0; + Execute(); +} + +void RecursiveVerificator::Next() { + #ifdef DEBUG + if (Done()) { + throw std::logic_error( + "You want to get from a RecursiveVerificator, " + "but the verificator was done." + ); + } + #endif + + Execute(); +} + +bool RecursiveVerificator::Done() const { + return done_; +} + +const Error& RecursiveVerificator::Get() const { + #ifdef DEBUG + if (Done()) { + throw std::logic_error( + "You want to get from a RecursiveVerificator, " + "but the verificator is done." + ); + } + #endif + + return *error_; +} + +Error& RecursiveVerificator::GetMutable() { + #ifdef DEBUG + if (Done()) { + throw std::logic_error( + "You want to get mutable from a RecursiveVerificator, " + "but the verificator is done." + ); + } + #endif + + return *error_; +} + +long RecursiveVerificator::Index() const { + #ifdef DEBUG + if (Done() && index_ != -1) { + throw std::logic_error( + common::Concat( + "Expected index to be -1 " + "from a done RecursiveVerificator, " + "but got: ", + std::to_string(index_) + ) + ); + } + #endif + + return index_; +} + +std::unique_ptr RecursiveVerificator::Clone() const { + return common::make_unique(*this); +} + +void RecursiveVerificator::Execute() { + while (true) { + switch (state_) { + case 0: { + error_ = nullptr; + index_ = -1; + done_ = false; + + verificator_ = NewNonRecursiveVerificator(*instance_); + verificator_->Start(); + } + + case 1: { + if (!(!verificator_->Done())) { + state_ = 3; + continue; + } + + // We intentionally take over the ownership of the errors' data members, + // as we know the implementation in all the detail, and want to avoid a costly + // copy. + error_ = common::make_unique( + std::move( + verificator_->GetMutable() + ) + ); + // No path is prepended as the error refers to the instance itself. + ++index_; + + state_ = 2; + return; + } + + case 2: { + verificator_->Next(); + + state_ = 1; + continue; + } + + case 3: { + verificator_ = nullptr; + + { + // NOTE (mristin): + // We will not need descent, so we introduce it in the scope. + iteration::Descent descent( + *instance_ + ); + iterator_ = std::move(descent.begin()); + + // NOTE (mristin): + // descent.end() is a constant reference, so we make an explicit + // copy here. + iterator_end_ = descent.end(); + } + } + + case 4: { + if (!(*iterator_ != *iterator_end_)) { + state_ = 8; + continue; + } + + verificator_ = NewNonRecursiveVerificator( + *(*iterator_) + ); + verificator_->Start(); + } + + case 5: { + if (!(!verificator_->Done())) { + state_ = 7; + continue; + } + + // We intentionally take over the ownership of the errors' data members, + // as we know the implementation in all the detail, and want to avoid a costly + // copy. + error_ = common::make_unique( + std::move( + verificator_->GetMutable() + ) + ); + + error_->path = std::move( + iteration::MaterializePath( + *iterator_ + ) + ); + + ++index_; + + state_ = 6; + return; + } + + case 6: { + verificator_->Next(); + + state_ = 5; + continue; + } + + case 7: { + verificator_ = nullptr; + + ++(*iterator_); + + state_ = 4; + continue; + } + + case 8: { + iterator_.reset(); + iterator_end_.reset(); + done_ = true; + index_ = -1; + + // We invalidate the state since we reached the end of the routine. + state_ = 9; + return; + } + + default: + throw std::logic_error( + common::Concat( + "Invalid state_: ", + std::to_string(state_) + ) + ); + } + } +} + +// endregion Recursive verificators + +// region NonRecursiveVerification + +NonRecursiveVerification::NonRecursiveVerification( + const std::shared_ptr& instance +) : instance_(instance) { + // Intentionally empty. +} + +Iterator NonRecursiveVerification::begin() const { + std::unique_ptr verificator( + NewNonRecursiveVerificator(instance_) + ); + + verificator->Start(); + + // NOTE(mristin): + // We short-circuit here for efficiency, as we can immediately dispose + // of the verificator. + if (verificator->Done()) { + return Iterator(common::make_unique()); + } + + return Iterator(std::move(verificator)); +} + +const Iterator& NonRecursiveVerification::end() const { + static Iterator iterator(common::make_unique()); + return iterator; +} + +// endregion NonRecursiveVerification + +// region RecursiveVerification + +RecursiveVerification::RecursiveVerification( + const std::shared_ptr& instance +) : instance_(instance) { + // Intentionally empty. +} + +Iterator RecursiveVerification::begin() const { + std::unique_ptr verificator( + common::make_unique(instance_) + ); + + verificator->Start(); + + // NOTE(mristin): + // We short-circuit here for efficiency, as we can immediately dispose + // of the verificator. + if (verificator->Done()) { + return Iterator(common::make_unique()); + } + + return Iterator(std::move(verificator)); +} + +const Iterator& RecursiveVerification::end() const { + static Iterator iterator(common::make_unique()); + return iterator; +} + +// endregion RecursiveVerification + +// region struct Iterator + +Iterator::Iterator( + const Iterator& other +) : + verificator_(other.verificator_->Clone()) { + // Intentionally empty. +} + +Iterator::Iterator( + Iterator&& other +) : + verificator_(std::move(other.verificator_)) { + // Intentionally empty. +} + +Iterator& Iterator::operator=(const Iterator& other) { + return *this = Iterator(other); +} + +Iterator& Iterator::operator=(Iterator&& other) { + if (this != &other) { + verificator_ = std::move(other.verificator_); + } + + return *this; +} + +const Error& Iterator::operator*() const { + if (verificator_->Done()) { + throw std::logic_error( + "You want to de-reference from a completed iterator " + "over verification errors." + ); + } + + return verificator_->Get(); +} + +const Error* Iterator::operator->() const { + if (verificator_->Done()) { + throw std::logic_error( + "You want to de-reference from a completed iterator " + "over verification errors." + ); + } + + return &(verificator_->Get()); +} + +// Prefix increment +Iterator& Iterator::operator++() { + if (verificator_->Done()) { + throw std::logic_error( + "You want to move a completed iterator " + "over verification errors." + ); + } + + verificator_->Next(); + return *this; +} + +// Postfix increment +Iterator Iterator::operator++(int) { + Iterator result(*this); + ++(*this); + return result; +} + +bool operator==(const Iterator& a, const Iterator& b) { + return a.verificator_->Index() == b.verificator_->Index(); +} + +bool operator!=(const Iterator& a, const Iterator& b) { + return a.verificator_->Index() != b.verificator_->Index(); +} + +// endregion struct Iterator + +} // namespace verification +} // namespace aas_3_0 +} // namespace aas_core + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. diff --git a/test_data/cpp/test_main/list_of_primitives/expected_output/verification.hpp b/test_data/cpp/test_main/list_of_primitives/expected_output/verification.hpp new file mode 100644 index 000000000..1e51a3abf --- /dev/null +++ b/test_data/cpp/test_main/list_of_primitives/expected_output/verification.hpp @@ -0,0 +1,225 @@ +#ifndef AAS_CORE_AAS_3_0_VERIFICATION_GUARD_ +#define AAS_CORE_AAS_3_0_VERIFICATION_GUARD_ + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#include "aas_core/aas_3_0/common.hpp" +#include "aas_core/aas_3_0/iteration.hpp" +#include "aas_core/aas_3_0/pattern.hpp" +#include "aas_core/aas_3_0/types.hpp" + +#pragma warning(push, 0) +#include +#pragma warning(pop) + +namespace aas_core { +namespace aas_3_0 { + +/** + * \defgroup verification Verify that instances conform to the meta-model constraints. + * @{ + */ +namespace verification { + +// region Forward declarations +class Iterator; +class IVerification; + +namespace impl { +class IVerificator; +} // namespace impl +// endregion Forward declarations + +/** + * Represent a verification error in an instance. + */ +struct Error { + /** + * Human-readable description of the error + */ + std::wstring cause; + + /** + * Path to the erroneous value + */ + iteration::Path path; + + explicit Error(std::wstring a_cause); + Error(std::wstring a_cause, iteration::Path a_path); +}; // struct Error + +/** + * \brief Iterate over the verification errors. + * + * The user is expected to take ownership of the errors if they need to be further + * processed. + * + * Unlike STL, this is not a light-weight iterator. We implement + * a "yielding" iterator by leveraging code generation so that we always keep + * the model stack as well as the properties verified thus far. + * + * This means that copy-construction and equality comparisons are much more heavy-weight + * than you'd usually expect from an STL iterator. For example, if you want to sort + * the errors by some criterion, you are most probably faster if you populate a vector, + * and then sort the vector. + * + * Also, given that this iterator is not light-weight, you should in almost all cases + * avoid the postfix increment (it++) and prefer the prefix one (++it) as the postfix + * increment would create an iterator copy every time. + * + * We follow the C++ standard, and assume that comparison between the two iterators + * over two different collections results in undefined behavior. See + * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2948.html and + * https://stackoverflow.com/questions/4657513/comparing-iterators-from-different-containers. + */ +class Iterator { + using iterator_category = std::forward_iterator_tag; + /// The difference is meaningless, but has to be defined. + using difference_type = std::ptrdiff_t; + using value_type = Error; + using pointer = const Error*; + using reference = const Error&; + + public: + explicit Iterator( + std::unique_ptr verificator + ) : + verificator_(std::move(verificator)) { + // Intentionally empty. + } + + Iterator(const Iterator& other); + Iterator(Iterator&& other); + + Iterator& operator=(const Iterator& other); + Iterator& operator=(Iterator&& other); + + reference operator*() const; + pointer operator->() const; + + // Prefix increment + Iterator& operator++(); + + // Postfix increment + Iterator operator++(int); + + friend bool operator==(const Iterator& a, const Iterator& b); + friend bool operator!=(const Iterator& a, const Iterator& b); + + private: + std::unique_ptr verificator_; +}; + +bool operator==(const Iterator& a, const Iterator& b); + +bool operator!=(const Iterator& a, const Iterator& b); + +/// \cond HIDDEN +namespace impl { +class IVerificator { + public: + virtual void Start() = 0; + virtual void Next() = 0; + virtual bool Done() const = 0; + + virtual const Error& Get() const = 0; + virtual Error& GetMutable() = 0; + virtual long Index() const = 0; + + virtual std::unique_ptr Clone() const = 0; + + virtual ~IVerificator() = default; +}; // class IVerificator +} // namespace impl +/// \endcond + +class IVerification { + public: + virtual Iterator begin() const = 0; + virtual const Iterator& end() const = 0; + virtual ~IVerification() = default; +}; // class IVerification + +/** + * \brief Verify that the instance conforms to the meta-model constraints. + * + * Do not proceed to verify the instances referenced from + * the given instance. + * + * Range-based loops should fit the vast majority of the use cases: + * \code + * std::shared_ptr env = ...; + * for (const Error& error : NonRecursiveVerification(env)) { + * report_somehow(error); + * } + * \endcode + * + * We use const references to shared pointers here for efficiency. Since + * we do not make a copy of \p that shared pointer, it is very important that + * the given shared pointer outlives the verification, lest cause undefined behavior. + * See these StackOverflow questions: + * * https://stackoverflow.com/questions/12002480/passing-stdshared-ptr-to-constructors/12002668#12002668 + * * https://stackoverflow.com/questions/3310737/should-we-pass-a-shared-ptr-by-reference-or-by-value + * * https://stackoverflow.com/questions/37610494/passing-const-shared-ptrt-versus-just-shared-ptrt-as-parameter + */ +class NonRecursiveVerification : public IVerification { + public: + NonRecursiveVerification( + const std::shared_ptr& instance + ); + + Iterator begin() const override; + const Iterator& end() const override; + + ~NonRecursiveVerification() override = default; + private: + const std::shared_ptr& instance_; +}; // class NonRecursiveVerification + +/** + * \brief Verify that the instance conforms to the meta-model constraints. + * + * Also verify recursively all the instances referenced from + * the given instance. + * + * Range-based loops should fit the vast majority of the use cases: + * \code + * std::shared_ptr env = ...; + * for (const Error& error : RecursiveVerification(env)) { + * report_somehow(error); + * } + * \endcode + * + * We use const references to shared pointers here for efficiency. Since + * we do not make a copy of \p that shared pointer, it is very important that + * the given shared pointer outlives the verification, lest cause undefined behavior. + * See these StackOverflow questions: + * * https://stackoverflow.com/questions/12002480/passing-stdshared-ptr-to-constructors/12002668#12002668 + * * https://stackoverflow.com/questions/3310737/should-we-pass-a-shared-ptr-by-reference-or-by-value + * * https://stackoverflow.com/questions/37610494/passing-const-shared-ptrt-versus-just-shared-ptrt-as-parameter + */ +class RecursiveVerification : public IVerification { + public: + RecursiveVerification( + const std::shared_ptr& instance + ); + + Iterator begin() const override; + const Iterator& end() const override; + + ~RecursiveVerification() override = default; + private: + const std::shared_ptr& instance_; +}; // class RecursiveVerification + +} // namespace verification +/**@}*/ + +} // namespace aas_3_0 +} // namespace aas_core + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#endif // AAS_CORE_AAS_3_0_VERIFICATION_GUARD_ diff --git a/test_data/cpp/test_main/list_of_primitives/expected_output/visitation.cpp b/test_data/cpp/test_main/list_of_primitives/expected_output/visitation.cpp new file mode 100644 index 000000000..2d89c340a --- /dev/null +++ b/test_data/cpp/test_main/list_of_primitives/expected_output/visitation.cpp @@ -0,0 +1,109 @@ +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#include "aas_core/aas_3_0/types.hpp" +#include "aas_core/aas_3_0/stringification.hpp" +#include "aas_core/aas_3_0/visitation.hpp" + +#pragma warning(push, 0) +#include +#pragma warning(pop) + +namespace aas_core { +namespace aas_3_0 { +namespace visitation { + +// region AbstractVisitor + +void AbstractVisitor::Visit( + const std::shared_ptr& that +) { + // NOTE (mristin): + // We have to dynamically cast the pointers due to the virtual multiple + // inheritance, and also because we used shared pointers for references. + // If we used constant references instead of shared pointers, we could use + // a pattern such as double dispatch. However, this has the limitation that + // it would prevent us from collecting the instances in the visitor, such that + // they outlive the original structures. + + switch (that->model_type()) { + case types::ModelType::kMyClass: + VisitMyClass( + std::dynamic_pointer_cast< + types::IMyClass + >(that) + ); + break; + case types::ModelType::kListOfPrimitives: + VisitListOfPrimitives( + std::dynamic_pointer_cast< + types::IListOfPrimitives + >(that) + ); + break; + default: + throw std::logic_error( + common::Concat( + "Unexpected model type: ", + std::to_string( + static_cast(that->model_type()) + ) + ) + ); + } +} + +// endregion + +// region PassThroughVisitor + +void PassThroughVisitor::VisitMyClass( + const std::shared_ptr& +) { + // No properties to be passed through. +} + +void PassThroughVisitor::VisitListOfPrimitives( + const std::shared_ptr& that +) { + // mutable_strings + for ( + const std::wstring& item : + that->mutable_strings() + ) { + Visit(item); + } + + // mutable_integers + for ( + int64_t item : + that->mutable_integers() + ) { + Visit(item); + } + + // mutable_booleans + for ( + bool item : + that->mutable_booleans() + ) { + Visit(item); + } + + // mutable_classes + for ( + const std::shared_ptr& item : + that->mutable_classes() + ) { + Visit(item); + } +} + +// endregion + +} // namespace visitation +} // namespace aas_3_0 +} // namespace aas_core + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. diff --git a/test_data/cpp/test_main/list_of_primitives/expected_output/visitation.hpp b/test_data/cpp/test_main/list_of_primitives/expected_output/visitation.hpp new file mode 100644 index 000000000..69441667c --- /dev/null +++ b/test_data/cpp/test_main/list_of_primitives/expected_output/visitation.hpp @@ -0,0 +1,93 @@ +#ifndef AAS_CORE_AAS_3_0_VISITATION_GUARD_ +#define AAS_CORE_AAS_3_0_VISITATION_GUARD_ + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#include "aas_core/aas_3_0/types.hpp" + +namespace aas_core { +namespace aas_3_0 { + +/** + * \defgroup visitation Iterate and modify instances through visitors. + * @{ + */ +namespace visitation { + +/** + * Provide an interface for a recursive mutating visitor on an instance. + */ +class IVisitor { + public: + /** + * Visit \p that instance and recursively visit all the instances + * referenced from \p that instance. + * + * We use const references to shared pointers here for efficiency in case you want, + * say, to share ownership over instances in your own external containers. Since + * we do not make copies of the shared pointers, it is very important that + * the given shared pointers outlive the visitor, lest cause undefined behavior. + * See these StackOverflow questions: + * * https://stackoverflow.com/questions/12002480/passing-stdshared-ptr-to-constructors/12002668#12002668 + * * https://stackoverflow.com/questions/3310737/should-we-pass-a-shared-ptr-by-reference-or-by-value + * * https://stackoverflow.com/questions/37610494/passing-const-shared-ptrt-versus-just-shared-ptrt-as-parameter + * + * Changing the references during the visitation results in undefined + * behavior. This follows how STL deals with modifications to containers, see: + * https://stackoverflow.com/questions/6438086/iterator-invalidation-rules-for-c-containers + * + * \param that instance to be visited recursively + */ + virtual void Visit(const std::shared_ptr& that) = 0; + virtual ~IVisitor() = default; + + protected: + virtual void VisitMyClass( + const std::shared_ptr& that + ) = 0; + virtual void VisitListOfPrimitives( + const std::shared_ptr& that + ) = 0; +}; // class IVisitor + +/** + * Provide an abstract recursive mutating visitor on an instance. + */ +class AbstractVisitor + : public IVisitor { + public: + void Visit(const std::shared_ptr& that) override; + ~AbstractVisitor() override = default; +}; // class AbstractVisitor + +/** + * \brief Provide a mutating, recursive and no-op visitor on an instance. + * + * Usually, you want to inherit from this visitor and override one or more of its + * visitation methods. + */ +class PassThroughVisitor + : public AbstractVisitor { + public: + ~PassThroughVisitor() override = default; + + protected: + void VisitMyClass( + const std::shared_ptr& that + ) override; + void VisitListOfPrimitives( + const std::shared_ptr& that + ) override; +}; // class PassThroughVisitor + +} // namespace visitation +/**@*/ + +} // namespace aas_3_0 +} // namespace aas_core + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#endif // AAS_CORE_AAS_3_0_VISITATION_GUARD_ diff --git a/test_data/cpp/test_main/list_of_primitives/expected_output/wstringification.cpp b/test_data/cpp/test_main/list_of_primitives/expected_output/wstringification.cpp new file mode 100644 index 000000000..0f876b94f --- /dev/null +++ b/test_data/cpp/test_main/list_of_primitives/expected_output/wstringification.cpp @@ -0,0 +1,84 @@ +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#include "aas_core/aas_3_0/wstringification.hpp" + +#pragma warning(push, 0) +#include +#pragma warning(pop) + +namespace aas_core { +namespace aas_3_0 { +namespace wstringification { + +const std::unordered_map< + std::wstring, + types::ModelType +> kModelTypeFromWstringMap = { + { + L"MyClass", + types::ModelType::kMyClass + }, + { + L"ListOfPrimitives", + types::ModelType::kListOfPrimitives + } +}; + +common::optional ModelTypeFromWstring( + const std::wstring& text +) { + const auto it = kModelTypeFromWstringMap.find( + text + ); + if (it == kModelTypeFromWstringMap.end()) { + return {}; + } + return it->second; +} + +types::ModelType MustModelTypeFromWstring( + const std::wstring& text +) { + const auto it = kModelTypeFromWstringMap.find( + text + ); + if (it == kModelTypeFromWstringMap.end()) { + throw std::invalid_argument( + common::WstringToUtf8( + common::Concat( + L"Unexpected ModelType literal: ", + text + ) + ) + ); + } + return it->second; +} + +std::wstring to_wstring( + types::ModelType model_type +) { + switch (model_type) { + case types::ModelType::kMyClass: + return L"MyClass"; + case types::ModelType::kListOfPrimitives: + return L"ListOfPrimitives"; + default: + throw std::invalid_argument( + common::Concat( + "Unexpected ModelType literal: ", + std::to_string( + static_cast(model_type) + ) + ) + ); + } +} + +} // namespace wstringification +} // namespace aas_3_0 +} // namespace aas_core + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. diff --git a/test_data/cpp/test_main/list_of_primitives/expected_output/wstringification.hpp b/test_data/cpp/test_main/list_of_primitives/expected_output/wstringification.hpp new file mode 100644 index 000000000..161bb7245 --- /dev/null +++ b/test_data/cpp/test_main/list_of_primitives/expected_output/wstringification.hpp @@ -0,0 +1,65 @@ +#ifndef AAS_CORE_AAS_3_0_WSTRINGIFICATION_GUARD_ +#define AAS_CORE_AAS_3_0_WSTRINGIFICATION_GUARD_ + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#include "aas_core/aas_3_0/common.hpp" +#include "aas_core/aas_3_0/types.hpp" + +#pragma warning(push, 0) +#include +#include +#pragma warning(pop) + +namespace aas_core { +namespace aas_3_0 { + +/** + * \defgroup wstringification De/wstringify to and from wstrings (where applicable). + * @{ + */ +namespace wstringification { + +/** + * Try to parse the \p text as a model type literal. + * + * \param text to be parsed + * \return literal, or nothing, if \p text invalid + */ +common::optional ModelTypeFromWstring( + const std::wstring& text +); + +/** + * Parse the \p text as a model type literal. + * + * \param text to be parsed + * \return literal + * \throw std::invalid_argument if \p text invalid + */ +types::ModelType MustModelTypeFromWstring( + const std::wstring& text +); + +/** + * Translate the enumeration literal \p model_type to text. + * + * \param model_type to be converted into text + * \return text representation of \p model_type + * \throw std::invalid_argument if \p model_type invalid + */ +std::wstring to_wstring( + types::ModelType model_type +); + +} // namespace wstringification +/**@}*/ + +} // namespace aas_3_0 +} // namespace aas_core + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#endif // AAS_CORE_AAS_3_0_WSTRINGIFICATION_GUARD_ diff --git a/test_data/cpp/test_main/list_of_primitives/expected_output/xmlization.cpp b/test_data/cpp/test_main/list_of_primitives/expected_output/xmlization.cpp new file mode 100644 index 000000000..890d01e30 --- /dev/null +++ b/test_data/cpp/test_main/list_of_primitives/expected_output/xmlization.cpp @@ -0,0 +1,4718 @@ +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#include "aas_core/aas_3_0/stringification.hpp" +#include "aas_core/aas_3_0/wstringification.hpp" +#include "aas_core/aas_3_0/xmlization.hpp" + +#pragma warning(push, 0) +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#pragma warning(pop) + +static_assert( + !std::is_same::value, + "Expected Expat to be compiled with UTF-8 support, i.e., that character is " + "stored as char internally, " + "but Expat was compiled to store characters internally as UTF-16." +); + +static_assert( + std::is_same::value, + "Expected Expat to be compiled with UTF-8 support, i.e., that " + "character is stored as char internally, " + "but it was not." +); + +namespace aas_core { +namespace aas_3_0 { +namespace xmlization { + +const std::string kNamespace( // NOLINT(cert-err58-cpp) + "https://admin-shell.io/aas/3/0" +); + +// region De-serialization + +// region struct ElementSegment + +ElementSegment::ElementSegment( + std::wstring a_name +) : + name(std::move(a_name)) { + // Intentionally empty. +} + +std::wstring ElementSegment::ToWstring() const { + size_t out_len = 0; + for (const wchar_t character : name) { + switch (character) { + // NOTE (mristin): + // We use sizeof on *strings* instead of *wide strings* to get + // the number of *characters*. Otherwise, if we used wide strings, + // we would obtain the wrong number of characters with `sizeof` + // as we would count bytes instead of characters, which differ + // in wide strings due to encoding. + + case L'&': { + out_len += sizeof("&"); + break; + } + case L'/': { + out_len += sizeof("/"); + break; + } + case L'<': { + out_len += sizeof("<"); + break; + } + case L'>': { + out_len += sizeof(">"); + break; + } + case L'"': { + out_len += sizeof("""); + break; + } + case L'\'': { + out_len += sizeof("'"); + break; + } + default: + ++out_len; + break; + } + } + + // NOTE (mristin): + // We assume here that XML encoding is always *longer* than + // the original text. + if (out_len == name.size()) { + return name; + } + + std::wstring out; + out.reserve(out_len); + + for (const wchar_t character : name) { + switch (character) { + case L'&': + out.append(L"&"); + break; + case L'/': + out.append(L"/"); + break; + case L'<': + out.append(L"<"); + break; + case L'>': + out.append(L">"); + break; + case L'"': + out.append(L"""); + break; + case L'\'': + out.append(L"'"); + break; + default: + out.push_back(character); + break; + } + } + + return out; +} + +std::unique_ptr ElementSegment::Clone() const { + return common::make_unique(*this); +} + +// endregion struct ElementSegment + +// region struct IndexSegment + +IndexSegment::IndexSegment( + size_t an_index +) : + index(an_index) { + // Intentionally empty. +} + +std::wstring IndexSegment::ToWstring() const { + return common::Concat( + L"*[", + std::to_wstring(index), + L"]" + ); +} + +std::unique_ptr IndexSegment::Clone() const { + return common::make_unique(*this); +} + +// endregion struct IndexSegment + +// region struct Path + +Path::Path() { + // Intentionally empty. +} + +Path::Path(const Path& other) { + for (const std::unique_ptr& segment : other.segments) { + segments.emplace_back(segment->Clone()); + } +} + +Path::Path(Path&& other) { + segments = std::move(other.segments); +} + +Path& Path::operator=(const Path& other) { + segments.clear(); + for (const std::unique_ptr& segment : other.segments) { + segments.emplace_back(segment->Clone()); + } + return *this; +} + +Path& Path::operator=(Path&& other) { + if (this != &other) { + segments = std::move(other.segments); + } + return *this; +} + +std::wstring Path::ToWstring() const { + if (segments.empty()) { + return L""; + } + + std::vector parts; + parts.reserve(segments.size() * 2 - 1); + + auto it = segments.begin(); + + parts.emplace_back((*it)->ToWstring()); + ++it; + + for (; it != segments.end(); ++it) { + parts.emplace_back(L"/"); + parts.emplace_back((*it)->ToWstring()); + } + + size_t out_len = 0; + for (const std::wstring& part : parts) { + out_len += part.size(); + } + + std::wstring out; + out.reserve(out_len); + for (const std::wstring& part : parts) { + out.append(part); + } + + return out; +} + +// region DeserializationError + +DeserializationError::DeserializationError( + std::wstring a_cause +) : + cause(a_cause) { + // Intentionally empty. +} + +DeserializationError::DeserializationError( + std::wstring a_cause, + Path a_path +) : + cause(a_cause), + path(a_path) { + // Intentionally empty. +} + +// endregion DeserializationError + +enum class NodeKind : std::uint32_t { + // Nodes of the kind `Bof` represent the beginning-of-input, before any read. + Bof = 0, + Start = 1, + Stop = 2, + Text = 3, + // Nodes of the kind `Eof` represent the end-of-input. + Eof = 4, + // Nodes of the kind `Error` represent low-level errors in the XML parsing. + Error = 5 +}; // enum class NodeKind + +const std::unordered_map< + NodeKind, + std::string +> kNodeKindToHumanReadableString = { + {NodeKind::Bof, "a beginning-of-input"}, + {NodeKind::Start, "a start element"}, + {NodeKind::Stop, "a stop element"}, + {NodeKind::Text, "a text"}, + {NodeKind::Eof, "an end-of-input"}, + {NodeKind::Error, "an error"}, +}; + +const std::string& NodeKindToHumanReadableString(NodeKind kind) { + auto it = kNodeKindToHumanReadableString.find(kind); + if (it == kNodeKindToHumanReadableString.end()) { + throw std::invalid_argument( + common::Concat( + "Unexpected node kind: ", + std::to_string( + static_cast(kind) + ) + ) + ); + } + + return it->second; +} + +// region Nodes + +/** + * Model a node in an XML document. + */ +class INode { + public: + /** + * @return the kind of the node, used instead of much slower RTTI. + */ + virtual NodeKind kind() const = 0; + virtual ~INode() = default; +}; // class INode + +/** + * Model the beginning of the input, before anything was read. + */ +class BofNode : public INode { + public: + NodeKind kind() const override { return NodeKind::Bof; } + + ~BofNode() override = default; +}; // class StartNode + +/** + * Model a start of an XML element. + */ +class StartNode : public INode { + public: + explicit StartNode( + std::string a_name + ) : + name(std::move(a_name)) { + // Intentionally empty. + } + + NodeKind kind() const override { return NodeKind::Start; } + + /** + * Name of the start element, stripped of the expected XML namespace + */ + const std::string name; + + ~StartNode() override = default; +}; // class StartNode + +/** + * Model a stop of an XML element. + */ +class StopNode : public INode { + public: + explicit StopNode( + std::string a_name + ) : + name(std::move(a_name)) { + // Intentionally empty. + } + + NodeKind kind() const override { return NodeKind::Stop; } + + /** + * Name of the stop element, stripped of the expected XML namespace + */ + const std::string name; + + ~StopNode() override = default; +}; // class StopNode + +/** + * Model a text node. + */ +class TextNode : public INode { + public: + explicit TextNode( + std::string a_text + ) : + text(std::move(a_text)) { + // Intentionally empty. + } + + NodeKind kind() const override { return NodeKind::Text; } + + /** + * UTF-8 encoded XML text somewhere within an XML element + */ + const std::string text; + + ~TextNode() override = default; +}; // class TextNode + +/** + * Model an end-of-input. + */ +class EofNode : public INode { + public: + NodeKind kind() const override { return NodeKind::Eof; } + + ~EofNode() override = default; +}; // class EofNode + +/** + * Model a low-level XML parsing error. + */ +class ErrorNode : public INode { + public: + ErrorNode( + size_t a_line, + size_t a_column, + std::string a_cause + ) : + line(a_line), + column(a_column), + cause(std::move(a_cause)) { + // Intentionally empty. + } + + NodeKind kind() const override { return NodeKind::Error; } + + const size_t line; + const size_t column; + + // Cause of the error as UTF-8 encoded string + const std::string cause; + + ~ErrorNode() override = default; +}; // class ErrorNode + +// endregion Nodes + +// region Reading + +// region class Reader + +/** + * Structure the data passed over to Expat XML reader. + */ +struct OurData { + bool additional_attributes; + size_t buffer_size; + XML_Parser parser; + + std::deque >& node_buffer; + + bool stopped = false; + + OurData( + bool the_additional_attributes, + size_t a_buffer_size, + XML_Parser a_parser, + std::deque >& a_node_buffer + ) : + additional_attributes(the_additional_attributes), + buffer_size(a_buffer_size), parser(a_parser), + node_buffer(a_node_buffer) { + // Intentionally empty. + } +}; // struct OurData + +/** + * \brief Read XML in form of nodes, whereas text nodes are fragmented. + * + * We need a more abstract approach since the Expat library is too low-level + * to parse complex models. + * + * Expat does not read the whole content of a text node in memory, but + * we need to process the whole text during the XML de-serialization. Hence, + * we keep on reading until we read the complete text. This has repercussions + * on memory usage, as the the text will be held in three copies(one copy in + * the Expat buffer, second copy in our internal buffer in which we + * incrementally feed in the fragments, and the third copy is the final merged + * text). + */ +class Reader { + public: + Reader( + std::istream& is, + const ReadingOptions& options + ); + + /** + * Set up the reader for the XML parsing and read the first node. + */ + void Initialize(); + + /** + * Read the next node in the document. + */ + void Read(); + + /** + * @return the node which has been read last + */ + const INode& node() const; + + /** + * @return the node which has been read last moved out of this reader + */ + std::unique_ptr moved_node(); + + ~Reader(); + + private: + const bool additional_attributes_; + const size_t buffer_size_; + std::istream& is_; + + XML_Parser parser_; + std::unique_ptr our_data_; + + // Node buffer does not include the current node. + std::deque> node_buffer_; + + // Current node is never null. + std::unique_ptr current_; + + // Set if the current node is end-of-input + bool eof_; + + // Set if the current node is an error + bool error_; + + void SetCurrentAndEofAndError(std::unique_ptr node); + + // Re-usable buffer to keep a chunk of the data read from the input + std::vector chunk_; +}; // class Reader + +Reader::Reader( + std::istream& is, + const ReadingOptions& options +) : + additional_attributes_(options.additional_attributes), + buffer_size_(options.buffer_size), + is_(is), + parser_(nullptr), + current_(common::make_unique()), + eof_(false), + error_(false) { + // Intentionally empty. +} + +const char kNamespaceSeparator = '|'; + +void XMLCALL OnStartElement( + void* user_data, + const char* name, + const char* attributes[] +) { + auto our_data = static_cast(user_data); + + // NOTE (mristin): + // Since Expat continues parsing and adding nodes even if the parsing is + // suspended (see the documentation of `XML_StopParser`), we have to ignore + // any further events. + if (our_data->stopped) { + return; + } + + const std::string name_str(name); + + size_t separator_i = name_str.find(kNamespaceSeparator); + if (separator_i == std::string::npos || separator_i == 0) { + std::string message = common::Concat( + "The namespace is missing in the start element <", + name_str, + ">" + ); + + our_data->node_buffer.emplace_back( + common::make_unique( + XML_GetCurrentLineNumber(our_data->parser), + XML_GetCurrentColumnNumber(our_data->parser), + message + ) + ); + + XML_StopParser(our_data->parser, false); + our_data->stopped = true; + return; + } + + if (name_str.compare(0, separator_i, kNamespace) != 0) { + std::string message = common::Concat( + "We expected the XML namespace ", + kNamespace, + ", but we got the namespace ", + name_str.substr(0, separator_i), + " in the start element <", + name_str.substr(separator_i + 1), + ">" + ); + + our_data->node_buffer.emplace_back( + common::make_unique( + XML_GetCurrentLineNumber(our_data->parser), + XML_GetCurrentColumnNumber(our_data->parser), + message + ) + ); + + XML_StopParser(our_data->parser, false); + our_data->stopped = true; + return; + } + + if ( + attributes[0] != nullptr + && !(our_data->additional_attributes) + ) { + std::string message = common::Concat( + "Additional attributes are not allowed, " + "but the attribute ", + attributes[0], + " was read in the start element <", + name_str.substr(separator_i + 1), + ">" + ); + + our_data->node_buffer.emplace_back( + common::make_unique( + XML_GetCurrentLineNumber(our_data->parser), + XML_GetCurrentColumnNumber(our_data->parser), + message + ) + ); + + XML_StopParser(our_data->parser, false); + our_data->stopped = true; + return; + } + + our_data->node_buffer.emplace_back( + common::make_unique( + name_str.substr(separator_i + 1) + ) + ); +} + +void XMLCALL OnStopElement( + void* user_data, + const char* name +) { + auto* our_data = static_cast(user_data); + + // NOTE (mristin): + // Since Expat continues parsing and adding nodes even if the parsing is + // suspended (see the documentation of `XML_StopParser`), we have to ignore + // any further events. + if (our_data->stopped) { + return; + } + + const std::string name_str(name); + + size_t separator_i = name_str.find(kNamespaceSeparator); + if (separator_i == std::string::npos || separator_i == 0) { + std::string message = common::Concat( + "The namespace is missing in the stop element " + ); + + our_data->node_buffer.emplace_back( + common::make_unique( + XML_GetCurrentLineNumber(our_data->parser), + XML_GetCurrentColumnNumber(our_data->parser), + message + ) + ); + + XML_StopParser(our_data->parser, false); + our_data->stopped = true; + return; + } + + if (name_str.compare(0, separator_i, kNamespace) != 0) { + std::string message = common::Concat( + "We expected the XML namespace ", + kNamespace, + ", but we got the namespace ", + name_str.substr(0, separator_i), + " in the stop element " + ); + + our_data->node_buffer.emplace_back( + common::make_unique( + XML_GetCurrentLineNumber(our_data->parser), + XML_GetCurrentColumnNumber(our_data->parser), + message + ) + ); + + XML_StopParser(our_data->parser, false); + our_data->stopped = true; + return; + } + + our_data->node_buffer.emplace_back( + common::make_unique( + name_str.substr(separator_i + 1) + ) + ); +} + +void XMLCALL OnText( + void* user_data, + const char* val, + int len +) { + auto our_data = static_cast(user_data); + + // NOTE (mristin): + // Since Expat continues parsing and adding nodes even if the parsing is + // suspended (see the documentation of `XML_StopParser`), we have to ignore + // any further events. + if (our_data->stopped) { + return; + } + + our_data->node_buffer.emplace_back( + common::make_unique( + std::string(val, len) + ) + ); +} + +void Reader::Initialize() { + // NOTE (mristin): + // We set up the underlying parser here instead of the constructor + // to avoid throwing exceptions in the constructor. + + if (parser_ != nullptr) { + throw std::logic_error( + "You are trying to re-initialize an initialized XML reader." + ); + } + + if ( + buffer_size_ + > static_cast( + (std::numeric_limits::max)() + ) + ) { + throw std::invalid_argument( + common::Concat( + "Expat library expects the buffer size as int, " + "but the given buffer size ", + std::to_string(buffer_size_), + " does not fit in an int as it is larger than the maximum int ", + std::to_string(std::numeric_limits::max()) + ) + ); + } + + parser_ = XML_ParserCreateNS(nullptr, kNamespaceSeparator); + our_data_ = common::make_unique( + additional_attributes_, + buffer_size_, + parser_, + node_buffer_ + ); + + XML_SetUserData(parser_, our_data_.get()); + XML_SetElementHandler( + parser_, + OnStartElement, + OnStopElement + ); + XML_SetCharacterDataHandler(parser_, OnText); + + chunk_.resize(buffer_size_); + + Read(); +} + +void Reader::Read() { + if (parser_ == nullptr) { + throw std::logic_error( + "You are trying to read from an uninitialized XML reader" + ); + } + + if (eof_) { + throw std::logic_error( + "The XML reader reached the end-of-input, " + "but you called Read()" + ); + } + + if (error_) { + throw std::logic_error( + "There was an error while reading XML, " + "but you called Read() again" + ); + } + + while (node_buffer_.empty()) { + // NOTE (mristin): + // We read and parse the next chunk of input, until we parsed a whole node. + // The text, however, will be fragmented by Expat's design. + + is_.read(&(chunk_[0]), buffer_size_); + + const std::streamsize actual_bytes_read = is_.gcount(); + + if (is_.bad()) { + SetCurrentAndEofAndError( + common::make_unique( + 0, + 0, + "Failed to read from the input" + ) + ); + return; + } + + if (actual_bytes_read == 0) { + if (is_.eof()) { + SetCurrentAndEofAndError(common::make_unique()); + return; + } else { + SetCurrentAndEofAndError( + common::make_unique( + 0, + 0, + "Read zero bytes from the input, " + "but the input is neither eof() nor bad()" + ) + ); + return; + } + } else { + const bool done = is_.eof(); + + if (actual_bytes_read > std::numeric_limits::max()) { + std::string message = common::Concat( + "Expat library expects the buffer size as int, ", + "but the actual number of bytes read ", + std::to_string(actual_bytes_read), + " does not fit in an int as it is larger than the maximum int ", + std::to_string(std::numeric_limits::max()) + ); + + throw std::runtime_error(message); + } + + const auto actual_bytes_read_int = static_cast(actual_bytes_read); + + XML_Status status = XML_Parse( + parser_, + &(chunk_[0]), + actual_bytes_read_int, + done + ); + + if (status == XML_STATUS_ERROR) { + XML_Error error_code = XML_GetErrorCode(parser_); + + if (error_code == XML_ERROR_ABORTED) { + if (node_buffer_.empty()) { + throw std::logic_error( + "The XML parsing was aborted, " + "so we expected an error node on the buffer, " + "but the buffer was empty" + ); + } + + if (node_buffer_.back()->kind() != NodeKind::Error) { + std::string message = common::Concat( + "The XML parsing was aborted, " + "so we expected an error node on the buffer, " + "but we got ", + NodeKindToHumanReadableString(node_buffer_.back()->kind()) + ); + + throw std::logic_error(message); + } + } else { + const XML_LChar* error_str = XML_ErrorString(error_code); + + node_buffer_.emplace_back( + common::make_unique( + XML_GetCurrentLineNumber(parser_), + XML_GetCurrentColumnNumber(parser_), + std::string(error_str) + ) + ); + } + } else { + if (done) { + node_buffer_.emplace_back(common::make_unique()); + } + } + } + } + + SetCurrentAndEofAndError(std::move(node_buffer_.front())); + node_buffer_.pop_front(); +} + +const INode& Reader::node() const { + return *current_; +} + +std::unique_ptr Reader::moved_node() { + return std::move(current_); +} + +Reader::~Reader() { + if (parser_ != nullptr) { + XML_ParserFree(parser_); + } +} + +void Reader::SetCurrentAndEofAndError( + std::unique_ptr node +) { + current_ = std::move(node); + + #ifdef __clang__ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wswitch" + #endif + switch (current_->kind()) { + case NodeKind::Eof: + eof_ = true; + break; + case NodeKind::Error: + error_ = true; + break; + } + #ifdef __clang__ + #pragma clang diagnostic pop + #endif +} + +// endregion class Reader + +// region class ReaderMergingText + +/** + * \brief Read XML in forms of nodes, with text nodes read in whole. + * + * This is a reader on top of the \ref Reader which keeps the text fragments + * in the buffer. We need to process the text in whole during the XML + * de-serialization, so this buffering is necessary. However, this means that + * the text is kept in four copies (one partial copy in Expat buffer, + * another partial copy as fragmented text nodes in the underlying \ref Reader + * instance, yet another copy in the internal buffer of this instance, and + * finally the fourth copy as the merged complete text). + */ +class ReaderMergingText { + public: + ReaderMergingText( + std::istream& is, + const ReadingOptions& options + ); + + /** + * Set up the reader for the XML parsing and read the first node. + */ + void Initialize(); + + /** + * Read the next node in the document. + */ + void Read(); + + /** + * @return the node which has been read last + */ + const INode& node() const; + + /** + * @return set if the current node represents an error + */ + bool error() const; + + /** + * @return set if the current node represents an end-of-input + */ + bool eof() const; + + private: + bool initialized_; + Reader reader_; + + std::unique_ptr current_; + std::unique_ptr look_ahead_; + + // Assuming that the underlying reader points to a text node, + // read all the consecutive text nodes and set the look-ahead node + void ReadAndMergeAllTextAndSetLookahead(); + + bool error_; + bool eof_; + void SetCurrentAndEofAndError( + std::unique_ptr node + ); +}; // class ReaderMergingText + +ReaderMergingText::ReaderMergingText( + std::istream& is, + const ReadingOptions& options +) : + initialized_(false), + reader_(is, options), + current_(common::make_unique()), + error_(false), + eof_(false) { + // Intentionally empty. +} + +void ReaderMergingText::Initialize() { + if (initialized_) { + throw std::logic_error( + "You are trying to initialize " + "an already initialized ReaderMergingText" + ); + } + + reader_.Initialize(); + + // NOTE (mristin): + // The `reader_` has already read a node. Hence, we need to parse it here + // separately from `ReaderMergingText::Read` method. + + if (reader_.node().kind() != NodeKind::Text) { + SetCurrentAndEofAndError(reader_.moved_node()); + } else { + ReadAndMergeAllTextAndSetLookahead(); + } + + initialized_ = true; +} + +void ReaderMergingText::Read() { + if (!initialized_) { + throw std::logic_error( + "You are reading from an uninitialized ReaderMergingText" + ); + } + + if (eof()) { + throw std::logic_error( + "You are trying to read from a ReaderMergingText, " + "but it reached the end-of-input" + ); + } + + if (error()) { + throw std::logic_error( + "You are trying to read from a ReaderMergingText, " + "but an error already occurred" + ); + } + + if (look_ahead_ != nullptr) { + SetCurrentAndEofAndError(std::move(look_ahead_)); + return; + } + + reader_.Read(); + if (reader_.node().kind() != NodeKind::Text) { + SetCurrentAndEofAndError(reader_.moved_node()); + } else { + ReadAndMergeAllTextAndSetLookahead(); + } +} + +const INode& ReaderMergingText::node() const { + return *current_; +} + +bool ReaderMergingText::error() const { + return error_; +} + +bool ReaderMergingText::eof() const { + return eof_; +} + +void ReaderMergingText::ReadAndMergeAllTextAndSetLookahead() { + if (reader_.node().kind() != NodeKind::Text) { + std::string message = common::Concat( + "Expected the current node in the reader " + "underlying ReaderMergingText to be a text, " + "but it was ", + NodeKindToHumanReadableString(reader_.node().kind()) + ); + + throw std::logic_error(message); + } + + std::deque text_buffer; + + while (reader_.node().kind() == NodeKind::Text) { + const TextNode& fragment_text_node( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const TextNode& + >( + reader_.node() + ) + ); + + text_buffer.emplace_back(fragment_text_node.text); + + reader_.Read(); + } + look_ahead_ = reader_.moved_node(); + + size_t size = 0; + for (const std::string& fragment : text_buffer) { + size += fragment.size(); + } + + std::string text; + text.reserve(size); + while (!text_buffer.empty()) { + text.append(text_buffer.front()); + text_buffer.pop_front(); + } + + SetCurrentAndEofAndError(common::make_unique(text)); +} + +void ReaderMergingText::SetCurrentAndEofAndError(std::unique_ptr node) { + current_ = std::move(node); + + #ifdef __clang__ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wswitch" + #endif + switch (current_->kind()) { + case NodeKind::Eof:eof_ = true; + break; + case NodeKind::Error:error_ = true; + break; + } + #ifdef __clang__ + #pragma clang diagnostic pop + #endif +} + +// endregion class ReaderMergingText + +// endregion Reading + +// region Forward declarations of de-serialization functions + +// NOTE (mristin): +// We make forward declarations of de-serialization functions so that they can be +// called in any order. + +std::pair< + common::optional< + std::shared_ptr + >, + common::optional +> MyClassFromElement( + ReaderMergingText& reader +); + +template < + typename T, + typename std::enable_if< + std::is_base_of::value + >::type* = nullptr +> +std::pair< + common::optional >, + common::optional +> MyClassFromSequence( + ReaderMergingText& reader +); + +std::pair< + common::optional< + std::shared_ptr + >, + common::optional +> ListOfPrimitivesFromElement( + ReaderMergingText& reader +); + +template < + typename T, + typename std::enable_if< + std::is_base_of::value + >::type* = nullptr +> +std::pair< + common::optional >, + common::optional +> ListOfPrimitivesFromSequence( + ReaderMergingText& reader +); + +// endregion Forward declarations of de-serialization functions + +/** + * Map XML class names to model types. + */ +const std::unordered_map< + std::string, + types::ModelType +> kElementNameToModelType = { + { + "myClass", + types::ModelType::kMyClass + }, + { + "listOfPrimitives", + types::ModelType::kListOfPrimitives + } +}; + +common::optional ModelTypeFromElementName( + const std::string& element_name +) { + auto it = kElementNameToModelType.find(element_name); + if (it == kElementNameToModelType.end()) { + return common::nullopt; + } + + return it->second; +} + +std::string NodeToHumanReadableString( + const INode& node +) { + switch (node.kind()) { + case NodeKind::Bof: + return "beginning-of-input"; + + case NodeKind::Start: { + const StartNode& start_node( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const StartNode& + >(node) + ); + + return common::Concat( + "a start node <", + start_node.name, + ">" + ); + } + + case NodeKind::Stop: { + const StopNode& stop_node( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const StopNode& + >(node) + ); + + return common::Concat( + "a stop node " + ); + } + + case NodeKind::Text: + return "an XML text"; + + case NodeKind::Eof: + return "end-of-input"; + + case NodeKind::Error: + return "an XML error"; + + default: + throw std::invalid_argument( + common::Concat( + "Unexpected node kind: ", + std::to_string( + static_cast(node.kind()) + ) + ) + ); + } +} + +std::wstring NodeToHumanReadableWstring( + const INode& node +) { + switch (node.kind()) { + case NodeKind::Bof: + return L"beginning-of-input"; + + case NodeKind::Start: { + const StartNode& start_node( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const StartNode& + >(node) + ); + + return common::Concat( + L"a start node <", + common::Utf8ToWstring(start_node.name), + L">" + ); + } + + case NodeKind::Stop: { + const StopNode& stop_node( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const StopNode& + >(node) + ); + + return common::Concat( + L"a stop node " + ); + } + + case NodeKind::Text: + return L"an XML text"; + + case NodeKind::Eof: + return L"end-of-input"; + + case NodeKind::Error: + return L"an XML error"; + + default: + throw std::invalid_argument( + common::Concat( + "Unexpected node kind: ", + std::to_string( + static_cast(node.kind()) + ) + ) + ); + } +} + +/** + * Check that the given node is a stop node and that its name corresponds to + * the expected name. + */ +bool IsStopNodeWithName( + const INode& node, + const std::string& expected_name +) { + if (node.kind() != NodeKind::Stop) { + return false; + } + + const std::string& name( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const StopNode& + >(node).name + ); + if (name != expected_name) { + return false; + } + + return true; +} + +template < + typename T +> +std::pair< + common::optional, + common::optional +> InstanceAndNoDeserializationError( + T&& instance +) { + return std::make_pair< + common::optional, + common::optional + >( + std::move(instance), + common::nullopt + ); +} + +template < + typename T +> std::pair< + common::optional, + common::optional +> NoInstanceAndDeserializationErrorWithCause( + std::wstring cause +) { + return std::make_pair< + common::optional, + common::optional + >( + common::nullopt, + common::make_optional( + std::move(cause) + ) + ); +} + +DeserializationError DeserializationErrorFromReader( + ReaderMergingText& reader +) { + if (reader.node().kind() != NodeKind::Error) { + throw std::logic_error( + common::Concat( + "Expected an error node at the reader cursor, but got ", + NodeToHumanReadableString(reader.node()) + ) + ); + } + + const auto error_node( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const ErrorNode& + >(reader.node()) + ); + + return DeserializationError( + common::Utf8ToWstring( + error_node.cause + ) + ); +} + +template < + typename T +> +std::pair< + common::optional, + common::optional +> NoInstanceAndDeserializationErrorFromReader( + ReaderMergingText& reader +) { + if (reader.node().kind() != NodeKind::Error) { + throw std::logic_error( + common::Concat( + "Expected an error node at the reader cursor, but got ", + NodeToHumanReadableString(reader.node()) + ) + ); + } + + DeserializationError error = DeserializationErrorFromReader( + reader + ); + + return std::make_pair( + common::nullopt, + common::make_optional( + std::move(error) + ) + ); +} + +template < + typename T +> +std::pair< + common::optional, + common::optional +> NoInstanceAndDeserializationError( + DeserializationError error +) { + return std::make_pair( + common::nullopt, + common::make_optional( + std::move(error) + ) + ); +} + +void PrependElementSegmentToDeserializationError( + const std::string& name, + DeserializationError& deserialization_error +) { + deserialization_error.path.segments.emplace_front( + common::make_unique( + common::Utf8ToWstring(name) + ) + ); +} + +common::optional CheckReaderAtEof( + const ReaderMergingText& reader +) { + #ifdef DEBUG + if (reader.node().kind() == NodeKind::Error) { + throw std::logic_error( + "Unexpected unhandled XML error in CheckReaderAtEof. " + "CheckReaderAtEof expects no reader error at entry." + ); + } + #endif + + if (reader.node().kind() != NodeKind::Eof) { + return common::make_optional( + common::Concat( + L"Expected end-of-input, but got ", + NodeToHumanReadableWstring(reader.node()) + ) + ); + } + + return common::nullopt; +} + +/** + * \brief Skip the beginning-of-file (BoF) and read a node. + * + * Do nothing if the cursor points to a non-BoF node. + * + * Return an error if the reader produced an error. + */ +common::optional SkipBof( + ReaderMergingText& reader +) { + if (reader.node().kind() != NodeKind::Bof) { + return common::nullopt; + } + + reader.Read(); + if (reader.node().kind() == NodeKind::Error) { + return DeserializationErrorFromReader(reader); + } + + return common::nullopt; +} + +/** + * Return `true` if all characters are whitespace in the UTF-8-encoded text. + */ +bool IsWhitespace(const std::string& utf8_text) { + for (const char character : utf8_text) { + switch (character) { + // NOTE (mristin): + // The characters are ordered by their ASCII codes so that + // we allow compilers to optimize. + + // NOTE (mristin): + // Text nodes contain text in UTF-8 which is compatible with ASCII. + // In particular, all characters above ASCII (>127) are encoded with + // all the leading bits set. Hence, it is safe to check for whitespace + // characters in an UTF-8-encoded string using one-byte characters. + // + // See: https://stackoverflow.com/questions/15965811/why-utf8-is-compatible-with-ascii + + case '\t': + case '\n': + case '\r': + case ' ': + // Pass + break; + default: + return false; + } + } + + return true; +} + +/** + * \brief Skip all whitespace text nodes. + * + * Do nothing if the cursor points to a non-text node. + * + * The whitespace includes space, tab, carriage return and newline. + * + * Return an error if the reader produced an error. + */ +common::optional SkipWhitespace( + ReaderMergingText& reader +) { + while (reader.node().kind() == NodeKind::Text) { + const TextNode& text_node( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const TextNode& + >( + reader.node() + ) + ); + + if (!IsWhitespace(text_node.text)) { + break; + } + + reader.Read(); + } + + if (reader.node().kind() == NodeKind::Error) { + return DeserializationErrorFromReader(reader); + } + + return common::nullopt; +} + +std::pair< + common::optional< + std::shared_ptr + >, + common::optional +> ClassFromElement( + ReaderMergingText& reader +) { + #ifdef DEBUG + if (reader.node().kind() == NodeKind::Error) { + throw std::logic_error( + "Unexpected unhandled XML error in ClassFromElement. " + "ClassFromElement expects no reader error at entry." + ); + } + #endif + + common::optional error; + + error = SkipBof(reader); + if (error.has_value()) { + return NoInstanceAndDeserializationError< + std::shared_ptr + >(std::move(*error)); + } + + error = SkipWhitespace(reader); + if (error.has_value()) { + return NoInstanceAndDeserializationError< + std::shared_ptr + >(std::move(*error)); + } + + if (reader.node().kind() != NodeKind::Start) { + return NoInstanceAndDeserializationErrorWithCause< + std::shared_ptr + >( + common::Concat( + L"Expected a start element opening an instance " + L"of IClass, but got ", + NodeToHumanReadableWstring(reader.node()) + ) + ); + } + + const std::string name( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const StartNode& + >(reader.node()).name + ); + + common::optional model_type( + ModelTypeFromElementName(name) + ); + if (!model_type.has_value()) { + return NoInstanceAndDeserializationErrorWithCause< + std::shared_ptr + >( + common::Concat( + L"Unexpected start element as its name does not correspond " + L"to any model type: ", + common::Utf8ToWstring(name) + ) + ); + } + + // NOTE (mristin): + // We consume the start element. + reader.Read(); + + if (reader.node().kind() == NodeKind::Error) { + auto noInstanceAndError = NoInstanceAndDeserializationErrorFromReader< + std::shared_ptr + >( + reader + ); + + PrependElementSegmentToDeserializationError( + name, + *(noInstanceAndError.second) + ); + + return noInstanceAndError; + } + + common::optional< + std::shared_ptr + > instance; + + switch (*model_type) { + case types::ModelType::kMyClass: + std::tie(instance, error) = MyClassFromSequence< + types::IClass + >(reader); + break; + case types::ModelType::kListOfPrimitives: + std::tie(instance, error) = ListOfPrimitivesFromSequence< + types::IClass + >(reader); + break; + default: + return NoInstanceAndDeserializationErrorWithCause< + std::shared_ptr + >( + common::Concat( + L"Impossible to de-serialize an instance " + L"of IClass from <", + common::Utf8ToWstring(name), + L">" + ) + ); + } + + if (error.has_value()) { + PrependElementSegmentToDeserializationError( + name, + *error + ); + + return NoInstanceAndDeserializationError< + std::shared_ptr + >(std::move(*error)); + } + + error = SkipWhitespace(reader); + if (error.has_value()) { + PrependElementSegmentToDeserializationError( + name, + *error + ); + + return NoInstanceAndDeserializationError< + std::shared_ptr + >(std::move(*error)); + } + + if (!IsStopNodeWithName(reader.node(), name)) { + error = DeserializationError( + common::Concat( + L"Expected a stop element closing an instance " + L"of IClass, but got ", + NodeToHumanReadableWstring(reader.node()) + ) + ); + + PrependElementSegmentToDeserializationError( + name, + *error + ); + + return NoInstanceAndDeserializationError< + std::shared_ptr + >(std::move(*error)); + } + + const StopNode& stop_node( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const StopNode& + >(reader.node()) + ); + if (stop_node.name != name) { + error = DeserializationError( + common::Concat( + L"Expected a stop element closing an instance " + L"of IClass, but got ", + NodeToHumanReadableWstring(reader.node()) + ) + ); + + PrependElementSegmentToDeserializationError( + name, + *error + ); + + return NoInstanceAndDeserializationError< + std::shared_ptr + >(std::move(*error)); + } + + // NOTE (mristin): + // We consume the stop element. + reader.Read(); + if (reader.node().kind() == NodeKind::Error) { + error = DeserializationErrorFromReader(reader); + + PrependElementSegmentToDeserializationError( + name, + *error + ); + + return NoInstanceAndDeserializationError< + std::shared_ptr + >(std::move(*error)); + } + + return InstanceAndNoDeserializationError( + std::move(*instance) + ); +} + +std::pair< + common::optional< + std::shared_ptr + >, + common::optional +> MyClassFromElement( + ReaderMergingText& reader +) { + #ifdef DEBUG + if (reader.node().kind() == NodeKind::Error) { + throw std::logic_error( + "Unexpected unhandled XML error in MyClassFromElement. " + "MyClassFromElement expects no reader error at entry." + ); + } + #endif + + common::optional error; + + error = SkipBof(reader); + if (error.has_value()) { + return NoInstanceAndDeserializationError< + std::shared_ptr + >(std::move(*error)); + } + + error = SkipWhitespace(reader); + if (error.has_value()) { + return NoInstanceAndDeserializationError< + std::shared_ptr + >(std::move(*error)); + } + + if (reader.node().kind() != NodeKind::Start) { + return NoInstanceAndDeserializationErrorWithCause< + std::shared_ptr + >( + common::Concat( + L"Expected a start element opening an instance " + L"of IMyClass, but got ", + NodeToHumanReadableWstring(reader.node()) + ) + ); + } + + const std::string name( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const StartNode& + >(reader.node()).name + ); + + common::optional model_type( + ModelTypeFromElementName(name) + ); + if (!model_type.has_value()) { + return NoInstanceAndDeserializationErrorWithCause< + std::shared_ptr + >( + common::Concat( + L"Unexpected start element as its name does not correspond " + L"to any model type: ", + common::Utf8ToWstring(name) + ) + ); + } + + // NOTE (mristin): + // We consume the start element. + reader.Read(); + + if (reader.node().kind() == NodeKind::Error) { + auto noInstanceAndError = NoInstanceAndDeserializationErrorFromReader< + std::shared_ptr + >( + reader + ); + + PrependElementSegmentToDeserializationError( + name, + *(noInstanceAndError.second) + ); + + return noInstanceAndError; + } + + common::optional< + std::shared_ptr + > instance; + + switch (*model_type) { + case types::ModelType::kMyClass: + std::tie(instance, error) = MyClassFromSequence< + types::IMyClass + >(reader); + break; + default: + return NoInstanceAndDeserializationErrorWithCause< + std::shared_ptr + >( + common::Concat( + L"Impossible to de-serialize an instance " + L"of IMyClass from <", + common::Utf8ToWstring(name), + L">" + ) + ); + } + + if (error.has_value()) { + PrependElementSegmentToDeserializationError( + name, + *error + ); + + return NoInstanceAndDeserializationError< + std::shared_ptr + >(std::move(*error)); + } + + error = SkipWhitespace(reader); + if (error.has_value()) { + PrependElementSegmentToDeserializationError( + name, + *error + ); + + return NoInstanceAndDeserializationError< + std::shared_ptr + >(std::move(*error)); + } + + if (!IsStopNodeWithName(reader.node(), name)) { + error = DeserializationError( + common::Concat( + L"Expected a stop element closing an instance " + L"of IMyClass, but got ", + NodeToHumanReadableWstring(reader.node()) + ) + ); + + PrependElementSegmentToDeserializationError( + name, + *error + ); + + return NoInstanceAndDeserializationError< + std::shared_ptr + >(std::move(*error)); + } + + const StopNode& stop_node( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const StopNode& + >(reader.node()) + ); + if (stop_node.name != name) { + error = DeserializationError( + common::Concat( + L"Expected a stop element closing an instance " + L"of IMyClass, but got ", + NodeToHumanReadableWstring(reader.node()) + ) + ); + + PrependElementSegmentToDeserializationError( + name, + *error + ); + + return NoInstanceAndDeserializationError< + std::shared_ptr + >(std::move(*error)); + } + + // NOTE (mristin): + // We consume the stop element. + reader.Read(); + if (reader.node().kind() == NodeKind::Error) { + error = DeserializationErrorFromReader(reader); + + PrependElementSegmentToDeserializationError( + name, + *error + ); + + return NoInstanceAndDeserializationError< + std::shared_ptr + >(std::move(*error)); + } + + return InstanceAndNoDeserializationError( + std::move(*instance) + ); +} + +std::pair< + common::optional< + std::shared_ptr + >, + common::optional +> ListOfPrimitivesFromElement( + ReaderMergingText& reader +) { + #ifdef DEBUG + if (reader.node().kind() == NodeKind::Error) { + throw std::logic_error( + "Unexpected unhandled XML error in ListOfPrimitivesFromElement. " + "ListOfPrimitivesFromElement expects no reader error at entry." + ); + } + #endif + + common::optional error; + + error = SkipBof(reader); + if (error.has_value()) { + return NoInstanceAndDeserializationError< + std::shared_ptr + >(std::move(*error)); + } + + error = SkipWhitespace(reader); + if (error.has_value()) { + return NoInstanceAndDeserializationError< + std::shared_ptr + >(std::move(*error)); + } + + if (reader.node().kind() != NodeKind::Start) { + return NoInstanceAndDeserializationErrorWithCause< + std::shared_ptr + >( + common::Concat( + L"Expected a start element opening an instance " + L"of IListOfPrimitives, but got ", + NodeToHumanReadableWstring(reader.node()) + ) + ); + } + + const std::string name( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const StartNode& + >(reader.node()).name + ); + + common::optional model_type( + ModelTypeFromElementName(name) + ); + if (!model_type.has_value()) { + return NoInstanceAndDeserializationErrorWithCause< + std::shared_ptr + >( + common::Concat( + L"Unexpected start element as its name does not correspond " + L"to any model type: ", + common::Utf8ToWstring(name) + ) + ); + } + + // NOTE (mristin): + // We consume the start element. + reader.Read(); + + if (reader.node().kind() == NodeKind::Error) { + auto noInstanceAndError = NoInstanceAndDeserializationErrorFromReader< + std::shared_ptr + >( + reader + ); + + PrependElementSegmentToDeserializationError( + name, + *(noInstanceAndError.second) + ); + + return noInstanceAndError; + } + + common::optional< + std::shared_ptr + > instance; + + switch (*model_type) { + case types::ModelType::kListOfPrimitives: + std::tie(instance, error) = ListOfPrimitivesFromSequence< + types::IListOfPrimitives + >(reader); + break; + default: + return NoInstanceAndDeserializationErrorWithCause< + std::shared_ptr + >( + common::Concat( + L"Impossible to de-serialize an instance " + L"of IListOfPrimitives from <", + common::Utf8ToWstring(name), + L">" + ) + ); + } + + if (error.has_value()) { + PrependElementSegmentToDeserializationError( + name, + *error + ); + + return NoInstanceAndDeserializationError< + std::shared_ptr + >(std::move(*error)); + } + + error = SkipWhitespace(reader); + if (error.has_value()) { + PrependElementSegmentToDeserializationError( + name, + *error + ); + + return NoInstanceAndDeserializationError< + std::shared_ptr + >(std::move(*error)); + } + + if (!IsStopNodeWithName(reader.node(), name)) { + error = DeserializationError( + common::Concat( + L"Expected a stop element closing an instance " + L"of IListOfPrimitives, but got ", + NodeToHumanReadableWstring(reader.node()) + ) + ); + + PrependElementSegmentToDeserializationError( + name, + *error + ); + + return NoInstanceAndDeserializationError< + std::shared_ptr + >(std::move(*error)); + } + + const StopNode& stop_node( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const StopNode& + >(reader.node()) + ); + if (stop_node.name != name) { + error = DeserializationError( + common::Concat( + L"Expected a stop element closing an instance " + L"of IListOfPrimitives, but got ", + NodeToHumanReadableWstring(reader.node()) + ) + ); + + PrependElementSegmentToDeserializationError( + name, + *error + ); + + return NoInstanceAndDeserializationError< + std::shared_ptr + >(std::move(*error)); + } + + // NOTE (mristin): + // We consume the stop element. + reader.Read(); + if (reader.node().kind() == NodeKind::Error) { + error = DeserializationErrorFromReader(reader); + + PrependElementSegmentToDeserializationError( + name, + *error + ); + + return NoInstanceAndDeserializationError< + std::shared_ptr + >(std::move(*error)); + } + + return InstanceAndNoDeserializationError( + std::move(*instance) + ); +} + +// region De-serialize primitives + +const std::unordered_map< + std::string, + bool +> kTextToBool = { + {"true", true}, + {"false", false}, + {"1", true}, + {"0", false} +}; + +std::pair< + common::optional, + common::optional +> DeserializeBool( + ReaderMergingText& reader +) { + #ifdef DEBUG + if (reader.node().kind() == NodeKind::Error) { + throw std::logic_error( + "Unexpected unhandled XML error in DeserializeBool. " + "DeserializeBool expects no error node." + ); + } + #endif + + if (reader.node().kind() != NodeKind::Text) { + return NoInstanceAndDeserializationErrorWithCause( + common::Concat( + L"Expected to parse an xs:boolean from XML text, but got ", + NodeToHumanReadableWstring(reader.node()) + ) + ); + } + + const std::string& text( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const TextNode& + >(reader.node()).text + ); + + auto it = kTextToBool.find(text); + if (it == kTextToBool.end()) { + return NoInstanceAndDeserializationErrorWithCause( + common::Concat( + L"Expected to parse an xs:boolean from text, " + L"but got an invalid value: ", + common::Utf8ToWstring(text) + ) + ); + } + + // NOTE (mristin): + // We consume the text node. + reader.Read(); + + if (reader.node().kind() == NodeKind::Error) { + return NoInstanceAndDeserializationErrorFromReader(reader); + } + + return std::make_pair( + it->second, + common::nullopt + ); +} + +std::pair< + common::optional, + common::optional +> DeserializeInt64( + ReaderMergingText& reader +) { + #ifdef DEBUG + if (reader.node().kind() == NodeKind::Error) { + throw std::logic_error( + "Unexpected unhandled XML error in DeserializeInt64. " + "DeserializeInt64 expects no error node." + ); + } + #endif + + if (reader.node().kind() != NodeKind::Text) { + return NoInstanceAndDeserializationErrorWithCause( + common::Concat( + L"Expected to parse an xs:long from XML text, but got ", + NodeToHumanReadableWstring(reader.node()) + ) + ); + } + + const std::string& text( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const TextNode& + >(reader.node()).text + ); + + common::optional deserialized; + + static_assert( + sizeof(int) == 8 + || sizeof(long) == 8 + || sizeof(long long) == 8, + "Neither int nor long nor long long are 8 bytes long, " + "so we do not know how to parse an xs:long." + ); + + try { + // NOTE (mristin): + // We remove the warning C4101 in MSVC with constants. + // See: https://stackoverflow.com/questions/25573996/c4127-conditional-expression-is-constant + const bool sizeof_int_is_8 = sizeof(int) == 8; + const bool sizeof_long_is_8 = sizeof(long) == 8; + const bool sizeof_long_long_is_8 = sizeof(long long) == 8; + + if (sizeof_int_is_8) { + deserialized = std::stoi(text); + } else if (sizeof_long_is_8) { + deserialized = std::stol(text); + } else if (sizeof_long_long_is_8) { + deserialized = std::stoll(text); + } + } catch (std::invalid_argument&) { + return NoInstanceAndDeserializationErrorWithCause( + common::Concat( + L"Expected to parse an xs:long from text, " + L"but got an invalid value: ", + common::Utf8ToWstring(text) + ) + ); + } catch (std::out_of_range&) { + return NoInstanceAndDeserializationErrorWithCause( + common::Concat( + L"Expected to parse an xs:long from text, " + L"but got a value out of the xs:long range: ", + common::Utf8ToWstring(text) + ) + ); + } + + if (!deserialized.has_value()) { + throw std::logic_error( + "Neither int nor long nor long long are 8 bytes long, " + "but this should have been caught earlier in the static assert" + ); + } + + // NOTE (mristin): + // We consume the text node. + reader.Read(); + + if (reader.node().kind() == NodeKind::Error) { + return NoInstanceAndDeserializationErrorFromReader(reader); + } + + return std::make_pair( + deserialized, + common::nullopt + ); +} + +std::pair< + common::optional, + common::optional +> DeserializeDouble( + ReaderMergingText& reader +) { + static_assert( + sizeof(double) == 8, + "DeserializeDouble expects double to be 8 bytes, " + "but the size of the double is not 8 bytes" + ); + + #ifdef DEBUG + if (node.kind() == NodeKind::Error) { + throw std::logic_error( + "Unexpected unhandled XML error in DeserializeDouble. " + "DeserializeDouble expects no error node." + ); + } + #endif + + if (reader.node().kind() != NodeKind::Text) { + return NoInstanceAndDeserializationErrorWithCause( + common::Concat( + L"Expected to parse an xs:double from XML text, but got ", + NodeToHumanReadableWstring(reader.node()) + ) + ); + } + + const std::string& text( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const TextNode& + >(reader.node()).text + ); + + double deserialized; + + try { + deserialized = std::stod(text); + } catch (std::invalid_argument&) { + return NoInstanceAndDeserializationErrorWithCause( + common::Concat( + L"Expected to parse an xs:double from text, " + L"but got an invalid value: ", + common::Utf8ToWstring(text) + ) + ); + } catch (std::out_of_range&) { + return NoInstanceAndDeserializationErrorWithCause( + common::Concat( + L"Expected to parse an xs:double from text, " + L"but got a value out of the xs:double range: ", + common::Utf8ToWstring(text) + ) + ); + } + + // NOTE (mristin): + // XSD basic types are not case insensitive and quite strict. + // We follow this strictness in the parsing as well. + // + // See: https://www.w3.org/TR/xmlschema11-2/#double + + const bool invalid_xml( + ( + deserialized == std::numeric_limits::infinity() + && text != "INF" + ) || ( + deserialized == -std::numeric_limits::infinity() + && text != "-INF" + ) || ( + std::isnan(deserialized) + && text != "NaN" + ) + ); + + if (invalid_xml) { + return NoInstanceAndDeserializationErrorWithCause( + common::Concat( + L"Expected to parse an xs:double from text, " + L"but got an invalid value: ", + common::Utf8ToWstring(text) + ) + ); + } + + // NOTE (mristin): + // We consume the text node. + reader.Read(); + + if (reader.node().kind() == NodeKind::Error) { + return NoInstanceAndDeserializationErrorFromReader(reader); + } + + return std::make_pair( + deserialized, + common::nullopt + ); +} + +std::pair< + common::optional, + common::optional +> DeserializeWstring( + ReaderMergingText& reader +) { + #ifdef DEBUG + if (reader.node().kind() == NodeKind::Error) { + throw std::logic_error( + "Unexpected unhandled XML error in DeserializeWstring. " + "DeserializeWstring expects no error node." + ); + } + #endif + + switch (reader.node().kind()) { + case NodeKind::Stop: + // Encountering a stop node means that the string is empty. + return std::make_pair(std::wstring(), common::nullopt); + case NodeKind::Text: + // We pass and continue decoding the text. + break; + default: + return NoInstanceAndDeserializationErrorWithCause( + common::Concat( + L"Expected to parse an xs:string from XML text, but got ", + NodeToHumanReadableWstring(reader.node()) + ) + ); + } + + const std::string& text( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const TextNode& + >(reader.node()).text + ); + + std::wstring deserialized = common::Utf8ToWstring(text); + + // NOTE (mristin): + // We consume the text node. + reader.Read(); + + if (reader.node().kind() == NodeKind::Error) { + return NoInstanceAndDeserializationErrorFromReader(reader); + } + + return std::make_pair(std::move(deserialized), common::nullopt); +} + +std::pair< + common::optional >, + common::optional +> DeserializeByteArray( + ReaderMergingText& reader +) { + #ifdef DEBUG + if (reader.node().kind() == NodeKind::Error) { + throw std::logic_error( + "Unexpected unhandled XML error in DeserializeByteArray. " + "DeserializeByteArray expects no error node." + ); + } + #endif + + switch (reader.node().kind()) { + case NodeKind::Stop: + // Encountering a stop node means empty byte array. + return std::make_pair( + std::vector(), + common::nullopt + ); + case NodeKind::Text: + // We pass and continue decoding the byte array. + break; + default: + return NoInstanceAndDeserializationErrorWithCause< + std::vector + >( + common::Concat( + L"Expected to parse an xs:base64Binary from XML text, but got ", + NodeToHumanReadableWstring(reader.node()) + ) + ); + } + + const std::string& text( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const TextNode& + >(reader.node()).text + ); + + common::expected< + std::vector, + std::string + > deserialized = stringification::Base64Decode(text); + + if (!deserialized.has_value()) { + return NoInstanceAndDeserializationErrorWithCause< + std::vector + >( + common::Concat( + L"Expected to parse an xs:base64Binary from text, " + L"but the value was invalid: ", + common::Utf8ToWstring(deserialized.error()) + ) + ); + } + + // NOTE (mristin): + // We consume the text node. + reader.Read(); + + if (reader.node().kind() == NodeKind::Error) { + return NoInstanceAndDeserializationErrorFromReader< + std::vector + >(reader); + } + + return std::make_pair( + std::move(*deserialized), + common::nullopt + ); +} + +// endregion De-serialize primitives + +namespace properties { + +enum class OfMyClass : std::uint32_t { + +}; // enum class OfMyClass + +enum class OfListOfPrimitives : std::uint32_t { + kStrings = 0, + kIntegers = 1, + kBooleans = 2, + kClasses = 3 +}; // enum class OfListOfPrimitives + +const std::unordered_map< + std::string, + OfMyClass +> kMapOfMyClass = { + +}; + +const std::unordered_map< + std::string, + OfListOfPrimitives +> kMapOfListOfPrimitives = { + { + "strings", + OfListOfPrimitives::kStrings + }, + { + "integers", + OfListOfPrimitives::kIntegers + }, + { + "booleans", + OfListOfPrimitives::kBooleans + }, + { + "classes", + OfListOfPrimitives::kClasses + } +}; + +} // namespace properties + +template < + typename T, + typename std::enable_if< + std::is_base_of::value + >::type* +> +std::pair< + common::optional >, + common::optional +> MyClassFromSequence( + ReaderMergingText& reader +) { + #ifdef DEBUG + if (reader.node().kind() == NodeKind::Error) { + throw std::logic_error( + "Unexpected unhandled XML error in MyClassFromSequence. " + "MyClassFromSequence expects no reader error at entry." + ); + } + #endif + + common::optional error; + + error = SkipBof(reader); + if (error.has_value()) { + return NoInstanceAndDeserializationError< + std::shared_ptr + >( + std::move(*error) + ); + } + + while (true) { + error = SkipWhitespace(reader); + if (error.has_value()) { + return NoInstanceAndDeserializationError< + std::shared_ptr + >( + std::move(*error) + ); + } + + if (reader.node().kind() == NodeKind::Stop) { + // NOTE (mristin): + // We reached a closing element of an instance, so we know that + // the sequence ended. + break; + } else if (reader.node().kind() != NodeKind::Start) { + return NoInstanceAndDeserializationErrorWithCause< + std::shared_ptr + >( + common::Concat( + L"Expected a start element opening a property " + L"of IMyClass, but got ", + NodeToHumanReadableWstring(reader.node()) + ) + ); + } + + const std::string name( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const StartNode& + >(reader.node()).name + ); + + // NOTE (mristin): + // We consume the start element. + reader.Read(); + + if (reader.node().kind() == NodeKind::Error) { + error = DeserializationErrorFromReader(reader); + + PrependElementSegmentToDeserializationError( + name, + *error + ); + + return NoInstanceAndDeserializationError< + std::shared_ptr + >( + std::move(*error) + ); + } + + auto it = properties::kMapOfMyClass.find( + name + ); + if (it == properties::kMapOfMyClass.end()) { + return NoInstanceAndDeserializationErrorWithCause< + std::shared_ptr + >( + common::Concat( + L"Expected a start element opening a property " + L"of IMyClass, " + L"but got a start element " + L"which does not correspond to any of its properties: <", + common::Utf8ToWstring(name), + L">" + ) + ); + } + + const properties::OfMyClass property( + it->second + ); + + switch (property) { + default: + throw std::logic_error( + common::Concat( + "Unexpected properties literal of " + "properties::OfMyClass: ", + std::to_string( + static_cast(property) + ) + ) + ); + } + + if (error.has_value()) { + PrependElementSegmentToDeserializationError( + name, + *error + ); + + return NoInstanceAndDeserializationError< + std::shared_ptr + >( + std::move(*error) + ); + } + + error = SkipWhitespace(reader); + if (error.has_value()) { + PrependElementSegmentToDeserializationError( + name, + *error + ); + + return NoInstanceAndDeserializationError< + std::shared_ptr + >( + std::move(*error) + ); + } + + if (!IsStopNodeWithName(reader.node(), name)) { + error = DeserializationError( + common::Concat( + L"Expected a stop element closing the property " + L"of IMyClass, but got ", + NodeToHumanReadableWstring(reader.node()) + ) + ); + + PrependElementSegmentToDeserializationError( + name, + *error + ); + + return NoInstanceAndDeserializationError< + std::shared_ptr + >( + std::move(*error) + ); + } + + // NOTE (mristin): + // We consume the stop element. + reader.Read(); + + if (reader.node().kind() == NodeKind::Error) { + error = DeserializationErrorFromReader(reader); + + PrependElementSegmentToDeserializationError( + name, + *error + ); + + return NoInstanceAndDeserializationError< + std::shared_ptr + >( + std::move(*error) + ); + } + } + + return std::make_pair( + common::make_optional< + std::shared_ptr + >( + // NOTE (mristin): + // We deliberately do not use std::make_shared here to avoid an unnecessary + // upcast. + new types::MyClass() + ), + common::nullopt + ); +} + +template < + typename T, + typename std::enable_if< + std::is_base_of::value + >::type* +> +std::pair< + common::optional >, + common::optional +> ListOfPrimitivesFromSequence( + ReaderMergingText& reader +) { + #ifdef DEBUG + if (reader.node().kind() == NodeKind::Error) { + throw std::logic_error( + "Unexpected unhandled XML error in ListOfPrimitivesFromSequence. " + "ListOfPrimitivesFromSequence expects no reader error at entry." + ); + } + #endif + + common::optional error; + + error = SkipBof(reader); + if (error.has_value()) { + return NoInstanceAndDeserializationError< + std::shared_ptr + >( + std::move(*error) + ); + } + + // region Initialization + + common::optional > the_strings; + + common::optional > the_integers; + + common::optional > the_booleans; + + common::optional< + std::vector< + std::shared_ptr + > + > the_classes; + + // endregion Initialization + + while (true) { + error = SkipWhitespace(reader); + if (error.has_value()) { + return NoInstanceAndDeserializationError< + std::shared_ptr + >( + std::move(*error) + ); + } + + if (reader.node().kind() == NodeKind::Stop) { + // NOTE (mristin): + // We reached a closing element of an instance, so we know that + // the sequence ended. + break; + } else if (reader.node().kind() != NodeKind::Start) { + return NoInstanceAndDeserializationErrorWithCause< + std::shared_ptr + >( + common::Concat( + L"Expected a start element opening a property " + L"of IListOfPrimitives, but got ", + NodeToHumanReadableWstring(reader.node()) + ) + ); + } + + const std::string name( + static_cast< // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + const StartNode& + >(reader.node()).name + ); + + // NOTE (mristin): + // We consume the start element. + reader.Read(); + + if (reader.node().kind() == NodeKind::Error) { + error = DeserializationErrorFromReader(reader); + + PrependElementSegmentToDeserializationError( + name, + *error + ); + + return NoInstanceAndDeserializationError< + std::shared_ptr + >( + std::move(*error) + ); + } + + auto it = properties::kMapOfListOfPrimitives.find( + name + ); + if (it == properties::kMapOfListOfPrimitives.end()) { + return NoInstanceAndDeserializationErrorWithCause< + std::shared_ptr + >( + common::Concat( + L"Expected a start element opening a property " + L"of IListOfPrimitives, " + L"but got a start element " + L"which does not correspond to any of its properties: <", + common::Utf8ToWstring(name), + L">" + ) + ); + } + + const properties::OfListOfPrimitives property( + it->second + ); + + switch (property) { + case properties::OfListOfPrimitives::kStrings: { + if (reader.node().kind() == NodeKind::Stop) { + the_strings = std::vector< + std::wstring + >(); + } else { + std::deque< + std::wstring + > items; + size_t i = 0; + + while (true) { + common::optional< + std::wstring + > item; + + std::tie( + item, + error + ) = DeserializeWstring(reader); + + if (error.has_value()) { + error->path.segments.emplace_front( + common::make_unique(i) + ); + break; + } + + error = SkipWhitespace(reader); + if (error.has_value()) { + break; + } + + items.emplace_back(*item); + + if (reader.node().kind() == NodeKind::Stop) { + break; + } + + ++i; + } + + if (!error.has_value()) { + the_strings = std::vector< + std::wstring + >(); + the_strings->reserve(items.size()); + + for (auto& item : items) { + the_strings->emplace_back( + std::move(item) + ); + } + } + } + break; + } + case properties::OfListOfPrimitives::kIntegers: { + if (reader.node().kind() == NodeKind::Stop) { + the_integers = std::vector< + int64_t + >(); + } else { + std::deque< + int64_t + > items; + size_t i = 0; + + while (true) { + common::optional< + int64_t + > item; + + std::tie( + item, + error + ) = DeserializeInt64(reader); + + if (error.has_value()) { + error->path.segments.emplace_front( + common::make_unique(i) + ); + break; + } + + error = SkipWhitespace(reader); + if (error.has_value()) { + break; + } + + items.emplace_back(*item); + + if (reader.node().kind() == NodeKind::Stop) { + break; + } + + ++i; + } + + if (!error.has_value()) { + the_integers = std::vector< + int64_t + >(); + the_integers->reserve(items.size()); + + for (auto& item : items) { + the_integers->emplace_back( + std::move(item) + ); + } + } + } + break; + } + case properties::OfListOfPrimitives::kBooleans: { + if (reader.node().kind() == NodeKind::Stop) { + the_booleans = std::vector< + bool + >(); + } else { + std::deque< + bool + > items; + size_t i = 0; + + while (true) { + common::optional< + bool + > item; + + std::tie( + item, + error + ) = DeserializeBool(reader); + + if (error.has_value()) { + error->path.segments.emplace_front( + common::make_unique(i) + ); + break; + } + + error = SkipWhitespace(reader); + if (error.has_value()) { + break; + } + + items.emplace_back(*item); + + if (reader.node().kind() == NodeKind::Stop) { + break; + } + + ++i; + } + + if (!error.has_value()) { + the_booleans = std::vector< + bool + >(); + the_booleans->reserve(items.size()); + + for (auto& item : items) { + the_booleans->emplace_back( + std::move(item) + ); + } + } + } + break; + } + case properties::OfListOfPrimitives::kClasses: { + if (reader.node().kind() == NodeKind::Stop) { + the_classes = std::vector< + std::shared_ptr + >(); + } else { + std::deque< + std::shared_ptr + > items; + size_t i = 0; + + while (true) { + common::optional< + std::shared_ptr + > item; + + std::tie( + item, + error + ) = MyClassFromElement(reader); + + if (error.has_value()) { + error->path.segments.emplace_front( + common::make_unique(i) + ); + break; + } + + error = SkipWhitespace(reader); + if (error.has_value()) { + break; + } + + items.emplace_back(*item); + + if (reader.node().kind() == NodeKind::Stop) { + break; + } + + ++i; + } + + if (!error.has_value()) { + the_classes = std::vector< + std::shared_ptr + >(); + the_classes->reserve(items.size()); + + for (auto& item : items) { + the_classes->emplace_back( + std::move(item) + ); + } + } + } + break; + } + default: + throw std::logic_error( + common::Concat( + "Unexpected properties literal of " + "properties::OfListOfPrimitives: ", + std::to_string( + static_cast(property) + ) + ) + ); + } + + if (error.has_value()) { + PrependElementSegmentToDeserializationError( + name, + *error + ); + + return NoInstanceAndDeserializationError< + std::shared_ptr + >( + std::move(*error) + ); + } + + error = SkipWhitespace(reader); + if (error.has_value()) { + PrependElementSegmentToDeserializationError( + name, + *error + ); + + return NoInstanceAndDeserializationError< + std::shared_ptr + >( + std::move(*error) + ); + } + + if (!IsStopNodeWithName(reader.node(), name)) { + error = DeserializationError( + common::Concat( + L"Expected a stop element closing the property " + L"of IListOfPrimitives, but got ", + NodeToHumanReadableWstring(reader.node()) + ) + ); + + PrependElementSegmentToDeserializationError( + name, + *error + ); + + return NoInstanceAndDeserializationError< + std::shared_ptr + >( + std::move(*error) + ); + } + + // NOTE (mristin): + // We consume the stop element. + reader.Read(); + + if (reader.node().kind() == NodeKind::Error) { + error = DeserializationErrorFromReader(reader); + + PrependElementSegmentToDeserializationError( + name, + *error + ); + + return NoInstanceAndDeserializationError< + std::shared_ptr + >( + std::move(*error) + ); + } + } + + // region Check required properties + + if (!the_strings.has_value()) { + return NoInstanceAndDeserializationErrorWithCause< + std::shared_ptr + >( + L"The required property strings is missing" + ); + } + + if (!the_integers.has_value()) { + return NoInstanceAndDeserializationErrorWithCause< + std::shared_ptr + >( + L"The required property integers is missing" + ); + } + + if (!the_booleans.has_value()) { + return NoInstanceAndDeserializationErrorWithCause< + std::shared_ptr + >( + L"The required property booleans is missing" + ); + } + + if (!the_classes.has_value()) { + return NoInstanceAndDeserializationErrorWithCause< + std::shared_ptr + >( + L"The required property classes is missing" + ); + } + + // endregion Check required properties + + return std::make_pair( + common::make_optional< + std::shared_ptr + >( + // NOTE (mristin): + // We deliberately do not use std::make_shared here to avoid an unnecessary + // upcast. + new types::ListOfPrimitives( + std::move(*the_strings), + std::move(*the_integers), + std::move(*the_booleans), + std::move(*the_classes) + ) + ), + common::nullopt + ); +} + +common::expected< + std::shared_ptr, + DeserializationError +> From( + std::istream& is, + const ReadingOptions& options +) { + ReaderMergingText reader(is, options); + + reader.Initialize(); + if (reader.node().kind() == NodeKind::Error) { + return common::make_unexpected( + DeserializationErrorFromReader(reader) + ); + } + + common::optional< + std::shared_ptr + > instance; + + common::optional error; + + std::tie( + instance, + error + ) = ClassFromElement(reader); + + if (error.has_value()) { + return common::make_unexpected( + std::move(*error) + ); + } + + error = SkipWhitespace(reader); + if (error.has_value()) { + return common::make_unexpected( + std::move(*error) + ); + } + + error = CheckReaderAtEof(reader); + if (error.has_value()) { + return common::make_unexpected( + std::move(*error) + ); + } + + return std::move(*instance); +} + +common::expected< + std::shared_ptr, + DeserializationError +> MyClassFrom( + std::istream& is, + const ReadingOptions& options +) { + ReaderMergingText reader(is, options); + + reader.Initialize(); + if (reader.node().kind() == NodeKind::Error) { + return common::make_unexpected( + DeserializationErrorFromReader(reader) + ); + } + + common::optional< + std::shared_ptr + > instance; + + common::optional error; + + std::tie( + instance, + error + ) = MyClassFromElement(reader); + + if (error.has_value()) { + return common::make_unexpected( + std::move(*error) + ); + } + + error = SkipWhitespace(reader); + if (error.has_value()) { + return common::make_unexpected( + std::move(*error) + ); + } + + error = CheckReaderAtEof(reader); + if (error.has_value()) { + return common::make_unexpected( + std::move(*error) + ); + } + + return std::move(*instance); +} + +common::expected< + std::shared_ptr, + DeserializationError +> ListOfPrimitivesFrom( + std::istream& is, + const ReadingOptions& options +) { + ReaderMergingText reader(is, options); + + reader.Initialize(); + if (reader.node().kind() == NodeKind::Error) { + return common::make_unexpected( + DeserializationErrorFromReader(reader) + ); + } + + common::optional< + std::shared_ptr + > instance; + + common::optional error; + + std::tie( + instance, + error + ) = ListOfPrimitivesFromElement(reader); + + if (error.has_value()) { + return common::make_unexpected( + std::move(*error) + ); + } + + error = SkipWhitespace(reader); + if (error.has_value()) { + return common::make_unexpected( + std::move(*error) + ); + } + + error = CheckReaderAtEof(reader); + if (error.has_value()) { + return common::make_unexpected( + std::move(*error) + ); + } + + return std::move(*instance); +} + +// endregion De-serialization + +// region Serialization + +/** + * Represent a serialization error. + * + * We use this error internally to avoid unnecessary stack unwinding, + * but throw the \ref SerializationException at the final site of + * the serialization for the user. + */ +struct SerializationError { + /** + * Human-readable description of the error + */ + std::wstring cause; + + /** + * Path to the value that caused the error + */ + iteration::Path path; + + explicit SerializationError( + std::wstring a_cause + ) : + cause(std::move(a_cause)) { + // Intentionally empty. + } +}; // struct SerializationError + +const std::wstring kTheOutputStreamIsInABadState( + L"The output stream is in a bad state." + ); + +/** + * Check that the output stream is not in a bad state. If so, create an error. + */ +common::optional CheckOstreamState( + const std::ostream& os +) { + if (os.bad()) { + return common::make_optional( + kTheOutputStreamIsInABadState + ); + } + + return common::nullopt; +} + +// region SerializationException + +std::string RenderSerializationErrorMessage( + const std::wstring& cause, + const iteration::Path& path +) { + return common::WstringToUtf8( + common::Concat( + L"Serialization failed at ", + path.ToWstring(), + L": ", + cause + ) + ); +} + +SerializationException::SerializationException( + std::wstring cause +) : + cause_(std::move(cause)), + path_(), + msg_(RenderSerializationErrorMessage(cause, path_)) { + // Intentionally empty. +} + +SerializationException::SerializationException( + std::wstring cause, + iteration::Path path +) : + cause_(std::move(cause)), + path_(std::move(path)), + msg_(RenderSerializationErrorMessage(cause, path)) { + // Intentionally empty. +} + +const char* SerializationException::what() const noexcept { + return msg_.c_str(); +} + +const std::wstring& SerializationException::cause() const noexcept { + return cause_; +} + +const iteration::Path& SerializationException::path() const noexcept { + return path_; +} + +// endregion SerializationException + +// region SelfClosingWriter + +/** + * \brief Write XML nodes to the UTF-8-encoded output stream. + * + * The start elements are put on hold until we observe a text, a stop element or + * end-of-input. This allows us to continuously shorten the XML elements to self-closing + * tags. + * + * The prefix is appended to each element name. If you do not need the prefix, + * specify it as empty string. In most cases, you put a colon, `:` at the end of + * the prefix. + * + * Each writing method captures any errors and obvious exceptions as + * serialization errors. + * + * Use \ref error() to check if there is any error. + */ +class SelfClosingWriter { + public: + SelfClosingWriter( + std::ostream& os, + std::string prefix + ); + + /** + * Queue a start element for an eventual write. + */ + void StartElement( + std::string name + ); + + /** + * Write a stop element. + * + * If there is a pending start element with no content, shorten it to + * a self-closing XML element. + */ + void StopElement( + const std::string& name + ); + + /** + * \brief Serialize the given boolean to an xs:bool value. + * + * We explicitly write longer text, `true` and `false`, to make the values explicit, + * and not potentially confusing with numbers, in the XML. + */ + void SerializeBool( + bool value + ); + + /** + * \brief Serialize the given number to an xs:long value. + * + * We do not check that the number is within a range representable as 64-bit + * floats, as the value can be de-serialized correctly from XML. However, this + * means that XML and JSON serializations are not interoperable. If you need + * interoperability, you have to ensure that range yourself (e.g., through + * \ref validation, see also + * https://github.com/aas-core-works/aas-core-meta/issues/298). + */ + void SerializeInt64( + int64_t value + ); + + /** + * \brief Serialize the given number to an xs:double value. + */ + void SerializeDouble( + double value + ); + + /** + * \brief Write the text while escaping special characters for XML. + */ + void SerializeWstring( + const std::wstring& text + ); + + /** + * \brief Write the text while escaping special characters for XML. + */ + void SerializeString( + const std::string& text + ); + + /** + * \brief Encode bytes to Base64 and write them. + */ + void SerializeByteArray( + const std::vector& byte_array + ); + + /** + * Finish and flush any pending start nodes. + */ + void Finish(); + + /** + * Get an error, if any, caught during the serialization. + */ + const common::optional& error() const; + + /** + * Transfer the ownership of the error. + */ + common::optional&& move_error(); + + private: + std::ostream& os_; + std::string prefix_; + common::optional error_; + common::optional pending_start_wo_text_; + + /** + * \brief Escape the given text to XML. + * + * Return nothing if no escaping was needed. + */ + static common::optional EscapeForXml( + const std::wstring& text + ); + + /** + * \brief Escape the given text to XML. + * + * Return nothing if no escaping was needed. + */ + static common::optional EscapeForXml( + const std::string& text + ); + + void WritePendingStartElementIfAvailable(); + + /** + * Write the text without any XML escaping or flushing of pending start elements. + */ + void WriteStringWithoutEscapingNorFlushing( + const std::string& text + ); +}; // class SelfClosingWriter + +SelfClosingWriter::SelfClosingWriter( + std::ostream& os, + std::string prefix +) : + os_(os), + prefix_(std::move(prefix)) { + // Intentionally empty. +} + +void SelfClosingWriter::StartElement( + std::string name +) { + #ifdef DEBUG + if (error_.has_value()) { + throw std::logic_error( + "You are trying to queue a start element with a SelfClosingWriter " + "which caught an error." + ); + #endif + + WritePendingStartElementIfAvailable(); + if (error_.has_value()) { + return; + } + + pending_start_wo_text_ = std::move(name); +} + +void SelfClosingWriter::StopElement( + const std::string& name +) { + #ifdef DEBUG + if (error_.has_value()) { + throw std::logic_error( + "You are trying to write a stop element with a SelfClosingWriter " + "which caught an error before." + ); + #endif + + if (pending_start_wo_text_.has_value()) { + #ifdef DEBUG + if (*pending_start_wo_text_ != name) { + throw std::logic_error( + common::Concat( + "The start element <", + *pending_start_wo_text_, + "> is pending for writing, " + "but you are trying to write a stop element " + ) + ); + } + #endif + + pending_start_wo_text_ = common::nullopt; + + WriteStringWithoutEscapingNorFlushing( + common::Concat( + "<", + prefix_, + name, + " />" + ) + ); + } else { + WritePendingStartElementIfAvailable(); + if (error_.has_value()) { + return; + } + + WriteStringWithoutEscapingNorFlushing( + common::Concat( + "" + ) + ); + } +} + +void SelfClosingWriter::SerializeBool( + bool value +) { + WritePendingStartElementIfAvailable(); + if (error_.has_value()) { + return; + } + + WriteStringWithoutEscapingNorFlushing( + value ? "true" : "false" + ); +} + +void SelfClosingWriter::SerializeInt64( + int64_t value +) { + WritePendingStartElementIfAvailable(); + if (error_.has_value()) { + return; + } + + WriteStringWithoutEscapingNorFlushing( + std::to_string(value) + ); +} + +void SelfClosingWriter::SerializeDouble( + double value +) { + WritePendingStartElementIfAvailable(); + if (error_.has_value()) { + return; + } + + // NOTE (mristin): + // We handle edge values infinity and not-a-number explicitly here + // as some C/C++ implementations might not convert them to XML-conformant + // strings. + + if (std::isinf(value)) { + if (value < 0) { + WriteStringWithoutEscapingNorFlushing("-INF"); + } else { + WriteStringWithoutEscapingNorFlushing("INF"); + } + } else if(std::isnan(value)) { + WriteStringWithoutEscapingNorFlushing("NaN"); + } else { + WriteStringWithoutEscapingNorFlushing( + std::to_string(value) + ); + } +} + +void SelfClosingWriter::SerializeString( + const std::string& text +) { + WritePendingStartElementIfAvailable(); + if (error_.has_value()) { + return; + } + + // NOTE (mristin): + // We optimize here for short and long texts, respectively. + // The main assumption is that the short texts can be escaped and converted + // in one go, while the longer texts need to be converted in chunks. + + if (text.size() < 1024) { + common::optional escaped = EscapeForXml(text); + + if (escaped.has_value()) { + WriteStringWithoutEscapingNorFlushing( + *escaped + ); + return; + } else { + WriteStringWithoutEscapingNorFlushing( + text + ); + return; + } + } + + size_t start = 0; + while (start < text.size()) { + const size_t end = std::min(start + 1024, text.size()); + const size_t chunk_size = end - start; + + // NOTE (mristin): + // We assume that making short copies of text substrings does not hurt + // the performance here, but makes the code more readable. + + const std::string chunk = text.substr(start, chunk_size); + + common::optional escaped = EscapeForXml(chunk); + + if (escaped.has_value()) { + WriteStringWithoutEscapingNorFlushing( + *escaped + ); + } else { + WriteStringWithoutEscapingNorFlushing( + chunk + ); + } + + if (error_.has_value()) { + return; + } + + start += chunk_size; + } +} + +void SelfClosingWriter::SerializeWstring( + const std::wstring& text +) { + WritePendingStartElementIfAvailable(); + if (error_.has_value()) { + return; + } + + // NOTE (mristin): + // We optimize here for short and long texts, respectively. + // The main assumption is that the short texts can be escaped and converted + // in one go, while the longer texts need to be converted in chunks. + + if (text.size() < 1024) { + common::optional escaped = EscapeForXml(text); + + if (escaped.has_value()) { + WriteStringWithoutEscapingNorFlushing( + common::WstringToUtf8(*escaped) + ); + return; + } else { + WriteStringWithoutEscapingNorFlushing( + common::WstringToUtf8(text) + ); + return; + } + } + + size_t start = 0; + while (start < text.size()) { + const size_t end = std::min(start + 1024, text.size()); + const size_t chunk_size = end - start; + + // NOTE (mristin): + // We assume that making short copies of text substrings does not hurt + // the performance here, but makes the code more readable. + + const std::wstring chunk = text.substr(start, chunk_size); + + common::optional escaped = EscapeForXml(chunk); + + if (escaped.has_value()) { + WriteStringWithoutEscapingNorFlushing( + common::WstringToUtf8(*escaped) + ); + } else { + WriteStringWithoutEscapingNorFlushing( + common::WstringToUtf8(chunk) + ); + } + + if (error_.has_value()) { + return; + } + + start += chunk_size; + } +} + +void SelfClosingWriter::SerializeByteArray( + const std::vector& byte_array +) { + WritePendingStartElementIfAvailable(); + if (error_.has_value()) { + return; + } + + // NOTE (mristin): + // We optimize here for short and long byte arrays, respectively. + // The main assumption is that the short texts can be escaped and converted + // in one go, while the longer texts need to be converted in chunks. + // + // Optimally, we would write an encoding function such that it encodes directly + // to the output stream. As we lack the time resources for that at the moment, + // we go for the compromise with one pass and chunking, respectively. + + if (byte_array.size() <= 1536) { + WriteStringWithoutEscapingNorFlushing( + stringification::Base64Encode(byte_array) + ); + return; + } + + // NOTE (mristin): + // We assume here that making copies of small sub-arrays does not hurt + // the performance, but makes the code substantially more readable. + + size_t start = 0; + while (start < byte_array.size()) { + // NOTE (mristin): + // We pick a multiple of 3 for the chunk size in order to make the encoding + // of chunking identical to the output as we encoded all bytes at the same time. + // + // See: https://stackoverflow.com/questions/7920780/is-it-possible-to-base64-encode-a-file-in-chunks + + const size_t end = std::min(start + 1536, byte_array.size()); + + const std::vector chunk( + byte_array.begin() + start, + byte_array.begin() + end + ); + + WriteStringWithoutEscapingNorFlushing( + stringification::Base64Encode(chunk) + ); + if (error_.has_value()) { + return; + } + } +} + +void SelfClosingWriter::Finish() { + WritePendingStartElementIfAvailable(); +} + +const common::optional& SelfClosingWriter::error() const { + return error_; +} + +common::optional&& SelfClosingWriter::move_error() { + return std::move(error_); +} + +common::optional SelfClosingWriter::EscapeForXml( + const std::wstring& text +) { + size_t out_len = 0; + + // NOTE (mristin): + // We use sizeof on *strings* instead of *wide strings* to get + // the number of *characters*. Otherwise, if we used wide strings, + // we would obtain the wrong number of characters as we would count + // bytes instead of characters with `sizeof`, which differ in wide strings + // due to encoding. + + for (wchar_t character : text ) { + switch (character) { + case L'&': { + out_len += sizeof("&"); + break; + } + case L'<': { + out_len += sizeof("<"); + break; + } + case L'>': { + out_len += sizeof(">"); + break; + } + case L'"': { + out_len += sizeof("""); + break; + } + case L'\'': { + out_len += sizeof("'"); + break; + } + default: + ++out_len; + break; + } + } + + // NOTE (mristin): + // We assume here that XML encoding is always *longer* than + // the original text. + + if (out_len == text.size()) { + return common::nullopt; + } + + std::wstring out; + out.reserve(out_len); + + for (wchar_t character : text ) { + switch (character) { + case L'&': + out.append(L"&"); + break; + case L'<': + out.append(L"<"); + break; + case L'>': + out.append(L">"); + break; + case L'"': + out.append(L"""); + break; + case L'\'': + out.append(L"'"); + break; + default: + out.push_back(character); + break; + } + } + + return common::make_optional( + std::move(out) + ); +} + +common::optional SelfClosingWriter::EscapeForXml( + const std::string& text +) { + size_t out_len = 0; + + for (char character : text ) { + switch (character) { + case '&': { + out_len += sizeof("&"); + break; + } + case '<': { + out_len += sizeof("<"); + break; + } + case '>': { + out_len += sizeof(">"); + break; + } + case '"': { + out_len += sizeof("""); + break; + } + case '\'': { + out_len += sizeof("'"); + break; + } + default: + ++out_len; + break; + } + } + + // NOTE (mristin): + // We assume here that XML encoding is always *longer* than + // the original text. + + if (out_len == text.size()) { + return common::nullopt; + } + + std::string out; + out.reserve(out_len); + + for (char character : text ) { + switch (character) { + case '&': + out.append("&"); + break; + case '<': + out.append("<"); + break; + case '>': + out.append(">"); + break; + case '"': + out.append("""); + break; + case '\'': + out.append("'"); + break; + default: + out.push_back(character); + break; + } + } + + return common::make_optional( + std::move(out) + ); +} + +void SelfClosingWriter::WritePendingStartElementIfAvailable() { + if (!pending_start_wo_text_.has_value()) { + return; + } + + WriteStringWithoutEscapingNorFlushing( + common::Concat( + "<", + prefix_, + *pending_start_wo_text_, + ">" + ) + ); + + pending_start_wo_text_ = common::nullopt; +} + +void SelfClosingWriter::WriteStringWithoutEscapingNorFlushing( + const std::string& text +) { + #ifdef DEBUG + if (error_.has_value()) { + throw std::logic_error( + "You are trying to write to a SelfClosingWriter which " + "caught an error" + ); + } + #endif + + if (os_.bad()) { + error_ = common::make_optional( + kTheOutputStreamIsInABadState + ); + return; + } + + os_ << text; + + if (os_.bad()) { + error_ = common::make_optional( + kTheOutputStreamIsInABadState + ); + return; + } +} + +// endregion SelfClosingWriter + +/** + * \brief Serialize \p that instance as a sequence of XML elements. + * + * Each XML element corresponds to a property. + * + * \param that instance to be serialized + * \param writer to write to + * \return error, if any + */ +common::optional SerializeMyClassAsSequence( + const types::IMyClass& that, + SelfClosingWriter& writer +); + +/** + * Serialize \p that instance to an XML element + * ``. + * + * \param that instance to be serialized + * \return an error, if any + */ +common::optional SerializeMyClassAsElement( + const types::IMyClass& that, + SelfClosingWriter& writer +); + +/** + * \brief Serialize \p that instance as a sequence of XML elements. + * + * Each XML element corresponds to a property. + * + * \param that instance to be serialized + * \param writer to write to + * \return error, if any + */ +common::optional SerializeListOfPrimitivesAsSequence( + const types::IListOfPrimitives& that, + SelfClosingWriter& writer +); + +/** + * Serialize \p that instance to an XML element + * ``. + * + * \param that instance to be serialized + * \return an error, if any + */ +common::optional SerializeListOfPrimitivesAsElement( + const types::IListOfPrimitives& that, + SelfClosingWriter& writer +); + +/** + * \brief Serialize \p that instance as a sequence of XML elements. + * + * Each XML element corresponds to a property. + * + * \param that instance to be serialized + * \param writer to write to + * \return error, if any + */ +common::optional SerializeMyClassAsSequence( + const types::IMyClass& that, + SelfClosingWriter& writer +) { + return common::nullopt; +} + +common::optional SerializeMyClassAsElement( + const types::IMyClass& that, + SelfClosingWriter& writer +) { + common::optional error; + + writer.StartElement( + "myClass" + ); + if (writer.error().has_value()) { + return writer.move_error(); + } + + error = SerializeMyClassAsSequence( + that, + writer + ); + if (error.has_value()) { + return error; + } + + writer.StopElement( + "myClass" + ); + if (writer.error().has_value()) { + return writer.move_error(); + } + + writer.Finish(); + if (writer.error().has_value()) { + return writer.move_error(); + } + + return common::nullopt; +} + +/** + * \brief Serialize \p that instance as a sequence of XML elements. + * + * Each XML element corresponds to a property. + * + * \param that instance to be serialized + * \param writer to write to + * \return error, if any + */ +common::optional SerializeListOfPrimitivesAsSequence( + const types::IListOfPrimitives& that, + SelfClosingWriter& writer +) { + common::optional error; + + const std::vector& the_strings( + that.strings() + ); + writer.StartElement( + "strings" + ); + if (writer.error().has_value()) { + return writer.move_error(); + } + for (size_t i = 0; i < the_strings.size(); ++i) { + std::wstring item( + the_strings[i] + ); + + error = DeserializeWstring( + *item, + writer + ); + + if (error.has_value()) { + error->path.segments.emplace_front( + common::make_unique( + i + ) + ); + + break; + } + } + if (error.has_value()) { + error->path.segments.emplace_front( + common::make_unique( + iteration::Property::kStrings + ) + ); + + return error; + } + writer.StopElement( + "strings" + ); + if (writer.error().has_value()) { + error = writer.move_error(); + + error->path.segments.emplace_front( + common::make_unique( + iteration::Property::kStrings + ) + ); + + return error; + } + + const std::vector& the_integers( + that.integers() + ); + writer.StartElement( + "integers" + ); + if (writer.error().has_value()) { + return writer.move_error(); + } + for (size_t i = 0; i < the_integers.size(); ++i) { + int64_t item( + the_integers[i] + ); + + error = DeserializeInt64( + *item, + writer + ); + + if (error.has_value()) { + error->path.segments.emplace_front( + common::make_unique( + i + ) + ); + + break; + } + } + if (error.has_value()) { + error->path.segments.emplace_front( + common::make_unique( + iteration::Property::kIntegers + ) + ); + + return error; + } + writer.StopElement( + "integers" + ); + if (writer.error().has_value()) { + error = writer.move_error(); + + error->path.segments.emplace_front( + common::make_unique( + iteration::Property::kIntegers + ) + ); + + return error; + } + + const std::vector& the_booleans( + that.booleans() + ); + writer.StartElement( + "booleans" + ); + if (writer.error().has_value()) { + return writer.move_error(); + } + for (size_t i = 0; i < the_booleans.size(); ++i) { + bool item( + the_booleans[i] + ); + + error = DeserializeBool( + *item, + writer + ); + + if (error.has_value()) { + error->path.segments.emplace_front( + common::make_unique( + i + ) + ); + + break; + } + } + if (error.has_value()) { + error->path.segments.emplace_front( + common::make_unique( + iteration::Property::kBooleans + ) + ); + + return error; + } + writer.StopElement( + "booleans" + ); + if (writer.error().has_value()) { + error = writer.move_error(); + + error->path.segments.emplace_front( + common::make_unique( + iteration::Property::kBooleans + ) + ); + + return error; + } + + const std::vector< + std::shared_ptr + >& the_classes( + that.classes() + ); + writer.StartElement( + "classes" + ); + if (writer.error().has_value()) { + return writer.move_error(); + } + for (size_t i = 0; i < the_classes.size(); ++i) { + const std::shared_ptr& item( + the_classes[i] + ); + + error = SerializeMyClassAsElement( + *item, + writer + ); + + if (error.has_value()) { + error->path.segments.emplace_front( + common::make_unique( + i + ) + ); + + break; + } + } + if (error.has_value()) { + error->path.segments.emplace_front( + common::make_unique( + iteration::Property::kClasses + ) + ); + + return error; + } + writer.StopElement( + "classes" + ); + if (writer.error().has_value()) { + error = writer.move_error(); + + error->path.segments.emplace_front( + common::make_unique( + iteration::Property::kClasses + ) + ); + + return error; + } + + writer.Finish(); + if (writer.error().has_value()) { + return writer.move_error(); + } + + return common::nullopt; +} + +common::optional SerializeListOfPrimitivesAsElement( + const types::IListOfPrimitives& that, + SelfClosingWriter& writer +) { + common::optional error; + + writer.StartElement( + "listOfPrimitives" + ); + if (writer.error().has_value()) { + return writer.move_error(); + } + + error = SerializeListOfPrimitivesAsSequence( + that, + writer + ); + if (error.has_value()) { + return error; + } + + writer.StopElement( + "listOfPrimitives" + ); + if (writer.error().has_value()) { + return writer.move_error(); + } + + writer.Finish(); + if (writer.error().has_value()) { + return writer.move_error(); + } + + return common::nullopt; +} + +void Serialize( + const types::IClass& that, + const WritingOptions& options, + std::ostream& os +) { + if (options.write_declaration) { + os << "\n"; + if (os.bad()) { + throw SerializationException( + kTheOutputStreamIsInABadState + ); + } + } + + SelfClosingWriter writer( + os, + options.prefix + ); + + common::optional error; + + // NOTE (mristin): + // Instead of using `Serialize*AsElement`, we write the root XML element + // in this functions so that we check for the XML namespace only once, namely + // here. Otherwise, we would have a condition check in every nested + // `Serialize*AsElement` which could cause a significant efficiency hit. + + // NOTE (mristin): + // The dynamic casts are necessary due to virtual inheritance. Otherwise, + // we would have used static casts. + + switch (that.model_type()) { + case types::ModelType::kMyClass: + if (options.write_namespace) { + os << ( + "" + ); + } else { + os << ""; + } + + error = CheckOstreamState(os); + if (error.has_value()) { + break; + } + + error = SerializeMyClassAsSequence( + dynamic_cast< + const types::IMyClass& + >(that), + writer + ); + if (error.has_value()) { + break; + } + + os << ""; + + error = CheckOstreamState(os); + if (error.has_value()) { + break; + } + + break; + case types::ModelType::kListOfPrimitives: + if (options.write_namespace) { + os << ( + "" + ); + } else { + os << ""; + } + + error = CheckOstreamState(os); + if (error.has_value()) { + break; + } + + error = SerializeListOfPrimitivesAsSequence( + dynamic_cast< + const types::IListOfPrimitives& + >(that), + writer + ); + if (error.has_value()) { + break; + } + + os << ""; + + error = CheckOstreamState(os); + if (error.has_value()) { + break; + } + + break; + default: + throw std::invalid_argument( + common::Concat( + "Invalid model type: ", + stringification::to_string(that.model_type()) + ) + ); + } + + if (error.has_value()) { + throw SerializationException( + std::move(error->cause), + std::move(error->path) + ); + } +} + +// endregion Serialization + +} // namespace xmlization +} // namespace aas_3_0 +} // namespace aas_core + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. diff --git a/test_data/cpp/test_main/list_of_primitives/expected_output/xmlization.hpp b/test_data/cpp/test_main/list_of_primitives/expected_output/xmlization.hpp new file mode 100644 index 000000000..c508fc181 --- /dev/null +++ b/test_data/cpp/test_main/list_of_primitives/expected_output/xmlization.hpp @@ -0,0 +1,290 @@ +#ifndef AAS_CORE_AAS_3_0_XMLIZATION_GUARD_ +#define AAS_CORE_AAS_3_0_XMLIZATION_GUARD_ + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#include "aas_core/aas_3_0/common.hpp" +#include "aas_core/aas_3_0/iteration.hpp" +#include "aas_core/aas_3_0/types.hpp" + +#pragma warning(push, 0) +#include +#include +#include +#pragma warning(pop) + +namespace aas_core { +namespace aas_3_0 { + +/** + * \defgroup xmlization De/serialize instances from and to XML. + * @{ + */ +namespace xmlization { + +/** + * Specify the expected XML namespace of all the XML elements. + */ +extern const std::string kNamespace; + +/** + * Represent a segment of an XPath to an erroneous value. + */ +class ISegment { + public: + /** + * \brief Convert the segment to a string in an XPath. + * + * The result is escaped such that it can be directly inserted + * into an XPath. + */ + virtual std::wstring ToWstring() const = 0; + + virtual std::unique_ptr Clone() const = 0; + + virtual ~ISegment() = default; +}; // class ISegment + +/** + * Represent an element on an XPath to the erroneous value. + */ +struct ElementSegment : public ISegment { + /** + * \brief Name of the XML element, without the namespace + * + * We deliberately omit the namespace in the tag names. If you want to actually + * query with the resulting XPath, you have to insert the namespaces manually. + * We did not know how to include the namespace in a meaningful way, as XPath + * assumes namespace prefixes to be defined outside of the document. + * At least the path thus rendered is informative, and you should be able to + * descend it manually. + */ + std::wstring name; + + ElementSegment( + std::wstring a_name + ); + + std::wstring ToWstring() const override; + + std::unique_ptr Clone() const override; + + ~ElementSegment() override = default; +}; // struct ElementSegment + +/** + * Represent an element in a sequence on an XPath to the erroneous value. + */ +struct IndexSegment : public ISegment { + /** + * Index of the element in the sequence + */ + size_t index; + + explicit IndexSegment( + size_t an_index + ); + + std::wstring ToWstring() const override; + + std::unique_ptr Clone() const override; + + ~IndexSegment() override = default; +}; // struct IndexSegment + +/** + * Represent the relative XPath to the erroneous element. + */ +struct Path { + std::deque > segments; + + Path(); + Path(const Path& other); + Path(Path&& other); + Path& operator=(const Path& other); + Path& operator=(Path&& other); + + std::wstring ToWstring() const; +}; // struct Path + +// region De-serialization + +/** + * Represent a de-serialization error. + */ +struct DeserializationError { + /** + * Human-readable description of the error + */ + std::wstring cause; + + /** + * Path to the erroneous value + */ + Path path; + + explicit DeserializationError(std::wstring a_cause); + DeserializationError(std::wstring a_cause, Path a_path); +}; // struct DeserializationError + +struct ReadingOptions { + /** + * No XML attributes are expected in XML elements. + * Usually, attributes are considered errors and reported as such. However, + * some implementations add their own custom attributes, and we sometimes + * still want to parse such XML. If `additional_attributes` is set, + * the unexpected XML attributes will be ignored during parsing, and not + * reported. + */ + bool additional_attributes = false; + + /** + * Size of the chunk to be read from the input stream and passed to + * the XML parser. + */ + size_t buffer_size = 1024; +}; // struct ReadingOptions + +/** + * Deserialize the instance from an XML read from the stream \p is. + * + * \param is stream of ASCII, ISO-8859-1 or UTF-8-encoded characters to read XML from + * \param options reading options to be tweaked for special cases. The defaults should + * work in most cases. + * \return the parsed instance, or an error if any + */ +common::expected< + std::shared_ptr, + DeserializationError +> From( + std::istream& is, + const ReadingOptions& options = {} +); + +/** + * Deserialize an instance of types::IMyClass from an XML + * read from the stream \p is. + * + * \param is stream to read XML from + * \param options reading options to be tweaked for special cases. The defaults should + * work in most cases. + * \return the parsed types::IMyClass, or an error if any + */ +common::expected< + std::shared_ptr, + DeserializationError +> MyClassFrom( + std::istream& is, + const ReadingOptions& options = {} +); + +/** + * Deserialize an instance of types::IListOfPrimitives from an XML + * read from the stream \p is. + * + * \param is stream to read XML from + * \param options reading options to be tweaked for special cases. The defaults should + * work in most cases. + * \return the parsed types::IListOfPrimitives, or an error if any + */ +common::expected< + std::shared_ptr, + DeserializationError +> ListOfPrimitivesFrom( + std::istream& is, + const ReadingOptions& options = {} +); + +// endregion Deserialization + +// region Serialization + +/** + * Represent an error in the serialization of an instance to XML. + */ +class SerializationException : public std::exception { + public: + SerializationException( + std::wstring cause + ); + + SerializationException( + std::wstring cause, + iteration::Path path + ); + + const char* what() const noexcept override; + + const std::wstring& cause() const noexcept; + const iteration::Path& path() const noexcept; + + ~SerializationException() noexcept override = default; + + private: + const std::wstring cause_; + const iteration::Path path_; + const std::string msg_; +}; // class SerializationException + +/** + * \brief Customize how instances should be serialized to XML. + * + * We selected the defaults so that they can be used when you serialize to + * a file. + * + * Usually, you want to write the namespace at the root element, and no + * prefixes are written in the XML names. However, if you are embedding + * the XML in a larger XML structure, you specify the namespace + * aliases and then use them as XML name prefixes. The prefix usually ends + * with a full colon (`:`). + * + * We can not imagine in what situation you would want to write both + * the namespace and the prefix. Nevertheless, we allow for that + * possibility and do not throw any exception if you specify the both. + */ +struct WritingOptions { + /** + * If set, the XML declaration is written at the beginning. + */ + bool write_declaration = true; + + /** + * If set, the root XML element is written with the XML namespace + * set as the XML attribute `xmlns`. + */ + bool write_namespace = true; + + /** + * The prefix is prepended to the name of each XML element. + */ + std::string prefix = ""; +}; // struct WritingOptions + +/** + * \brief Serialize \p that instance to XML. + * + * \param that instance to be serialized + * \param options to be tweaked for special cases. The defaults should + * work in most cases. + * \param os The UTF8-encoded output stream where XML will be written + * \throw \ref SerializationException if \p that instance could not be serialized + */ +void Serialize( + const types::IClass& that, + const WritingOptions& options, + std::ostream& os +); + +// endregion Serialization + +} // namespace xmlization +/**@}*/ + +} // namespace aas_3_0 +} // namespace aas_core + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +#endif // AAS_CORE_AAS_3_0_XMLIZATION_GUARD_ diff --git a/test_data/cpp/test_main/list_of_primitives/input/snippets/namespace.txt b/test_data/cpp/test_main/list_of_primitives/input/snippets/namespace.txt new file mode 100644 index 000000000..8a3f28b9a --- /dev/null +++ b/test_data/cpp/test_main/list_of_primitives/input/snippets/namespace.txt @@ -0,0 +1 @@ +aas_core::aas_3_0 diff --git a/test_data/cpp/test_main/list_of_primitives/meta_model.py b/test_data/cpp/test_main/list_of_primitives/meta_model.py new file mode 100644 index 000000000..ed2060bd5 --- /dev/null +++ b/test_data/cpp/test_main/list_of_primitives/meta_model.py @@ -0,0 +1,28 @@ +from typing import List + + +class My_class: + pass + + +class List_of_primitives: + strings: List[str] + integers: List[int] + booleans: List[bool] + classes: List[My_class] + + def __init__( + self, + strings: List[str], + integers: List[int], + booleans: List[bool], + classes: List[My_class], + ) -> None: + self.strings = strings + self.integers = integers + self.booleans = booleans + self.classes = classes + + +__version__ = "dummy" +__xml_namespace__ = "https://dummy.com" diff --git a/tests/cpp/test_main.py b/tests/cpp/test_main.py index d05f72680..7004f6cb7 100644 --- a/tests/cpp/test_main.py +++ b/tests/cpp/test_main.py @@ -15,26 +15,29 @@ class Test_against_recorded(unittest.TestCase): - def test_cases(self) -> None: - repo_dir = pathlib.Path(os.path.realpath(__file__)).parent.parent.parent - - parent_case_dir = repo_dir / "test_data" / "cpp" / "test_main" - assert parent_case_dir.exists() and parent_case_dir.is_dir(), parent_case_dir - - for module in [aas_core_meta.v3]: - case_dir = parent_case_dir / module.__name__ - assert case_dir.is_dir(), case_dir - - assert ( - module.__file__ is not None - ), f"Expected the module {module!r} to have a __file__, but it has None" - model_pth = pathlib.Path(module.__file__) - assert model_pth.exists() and model_pth.is_file(), model_pth + _REPO_DIR = pathlib.Path(os.path.realpath(__file__)).parent.parent.parent + PARENT_CASE_DIR = _REPO_DIR / "test_data" / "cpp" / "test_main" - snippets_dir = case_dir / "input/snippets" + def test_cases(self) -> None: + assert ( + Test_against_recorded.PARENT_CASE_DIR.exists() + and Test_against_recorded.PARENT_CASE_DIR.is_dir() + ), f"{Test_against_recorded.PARENT_CASE_DIR=}" + + # fmt: off + test_cases = ( + tests.common.find_meta_models_in_parent_directory_of_test_cases_and_modules( + parent_case_dir=Test_against_recorded.PARENT_CASE_DIR, + aas_core_meta_modules=[aas_core_meta.v3] + ) + ) + # fmt: on + + for test_case in test_cases: + snippets_dir = test_case.case_dir / "input/snippets" assert snippets_dir.exists() and snippets_dir.is_dir(), snippets_dir - expected_output_dir = case_dir / "expected_output" + expected_output_dir = test_case.case_dir / "expected_output" with contextlib.ExitStack() as exit_stack: if tests.common.RERECORD: @@ -51,7 +54,7 @@ def test_cases(self) -> None: output_dir = pathlib.Path(tmp_dir.name) params = aas_core_codegen.main.Parameters( - model_path=model_pth, + model_path=test_case.model_path, target=aas_core_codegen.main.Target.CPP, snippets_dir=snippets_dir, output_dir=output_dir, @@ -123,27 +126,14 @@ def test_cases(self) -> None: f"The output file is missing: {output_pth}" ) - try: - output = output_pth.read_text(encoding="utf-8") - except Exception as exception: - raise RuntimeError( - f"Failed to read the output from {output_pth}" - ) from exception - if tests.common.RERECORD: - expected_pth.write_text(output, encoding="utf-8") + expected_pth.write_text( + output_pth.read_text(encoding="utf-8"), encoding="utf-8" + ) else: - try: - expected_output = expected_pth.read_text(encoding="utf-8") - except Exception as exception: - raise RuntimeError( - f"Failed to read the expected output " - f"from {expected_pth}" - ) from exception - self.assertEqual( - expected_output, - output, + expected_pth.read_text(encoding="utf-8"), + output_pth.read_text(encoding="utf-8"), f"The files {expected_pth} and {output_pth} do not match.", ) From 5363655e7710df8ceceed5f6634a4d259a3c2056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Otto?= Date: Tue, 4 Feb 2025 14:54:24 +0100 Subject: [PATCH 07/14] Add XSD generation --- aas_core_codegen/xsd/main.py | 20 +++++++ .../expected_output/schema.xsd | 53 +++++++++++++++++++ .../expected_output/stdout.txt | 1 + .../input/snippets/root_element.xml | 8 +++ .../list_of_primitives/meta_model.py | 45 ++++++++++++++++ tests/xsd/test_main.py | 26 ++++----- 6 files changed, 140 insertions(+), 13 deletions(-) create mode 100644 test_data/xsd/test_main/list_of_primitives/expected_output/schema.xsd create mode 100644 test_data/xsd/test_main/list_of_primitives/expected_output/stdout.txt create mode 100644 test_data/xsd/test_main/list_of_primitives/input/snippets/root_element.xml create mode 100644 test_data/xsd/test_main/list_of_primitives/meta_model.py diff --git a/aas_core_codegen/xsd/main.py b/aas_core_codegen/xsd/main.py index 67a49f09c..596eeefca 100644 --- a/aas_core_codegen/xsd/main.py +++ b/aas_core_codegen/xsd/main.py @@ -472,6 +472,26 @@ def _generate_xs_element_for_a_list_property( ) else: assert_never(our_type) + elif isinstance(type_anno.items, intermediate.PrimitiveTypeAnnotation): + xs_element_inner = ET.Element( + "xs:element", + { + "name": "v", + "type": _PRIMITIVE_MAP[type_anno.items.a_type], + "minOccurs": min_occurs, + "maxOccurs": max_occurs, + }, + ) + xs_sequence = ET.Element("xs:sequence") + xs_sequence.append(xs_element_inner) + + xs_complex_type = ET.Element("xs:complexType") + xs_complex_type.append(xs_sequence) + + xs_element = ET.Element( + "xs:element", {"name": naming.xml_property(prop.name)} + ) + xs_element.append(xs_complex_type) else: return None, Error( prop.parsed.node, diff --git a/test_data/xsd/test_main/list_of_primitives/expected_output/schema.xsd b/test_data/xsd/test_main/list_of_primitives/expected_output/schema.xsd new file mode 100644 index 000000000..b05c607d9 --- /dev/null +++ b/test_data/xsd/test_main/list_of_primitives/expected_output/schema.xsd @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test_data/xsd/test_main/list_of_primitives/expected_output/stdout.txt b/test_data/xsd/test_main/list_of_primitives/expected_output/stdout.txt new file mode 100644 index 000000000..2d755fc5a --- /dev/null +++ b/test_data/xsd/test_main/list_of_primitives/expected_output/stdout.txt @@ -0,0 +1 @@ +Code generated to: diff --git a/test_data/xsd/test_main/list_of_primitives/input/snippets/root_element.xml b/test_data/xsd/test_main/list_of_primitives/input/snippets/root_element.xml new file mode 100644 index 000000000..ee0bfd97d --- /dev/null +++ b/test_data/xsd/test_main/list_of_primitives/input/snippets/root_element.xml @@ -0,0 +1,8 @@ + + + diff --git a/test_data/xsd/test_main/list_of_primitives/meta_model.py b/test_data/xsd/test_main/list_of_primitives/meta_model.py new file mode 100644 index 000000000..7de018dd8 --- /dev/null +++ b/test_data/xsd/test_main/list_of_primitives/meta_model.py @@ -0,0 +1,45 @@ +from typing import List +from icontract import DBC + +class Value_data_type(str, DBC): + """ + any XSD simple type as specified via :class:`Data_type_def_XSD` + """ + +class Data_type_def_XSD(Enum): + """ + Enumeration listing all XSD anySimpleTypes + """ + Boolean = "xs:boolean" + Date = "xs:date" + Integer = "xs:integer" + String = "xs:string" + +class My_class: + pass + + +class List_of_primitives: + foo: str + strings: List[str] + integers: List[int] + booleans: List[bool] + classes: List[My_class] + + def __init__( + self, + foo: str, + strings: List[str], + integers: List[int], + booleans: List[bool], + classes: List[My_class], + ) -> None: + self.foo = foo + self.strings = strings + self.integers = integers + self.booleans = booleans + self.classes = classes + + +__version__ = "dummy" +__xml_namespace__ = "https://dummy.com" diff --git a/tests/xsd/test_main.py b/tests/xsd/test_main.py index b2e6513bb..cd4a547a1 100644 --- a/tests/xsd/test_main.py +++ b/tests/xsd/test_main.py @@ -109,26 +109,26 @@ class Test_against_recorded(unittest.TestCase): _REPO_DIR = pathlib.Path(os.path.realpath(__file__)).parent.parent.parent PARENT_CASE_DIR = _REPO_DIR / "test_data" / "xsd" / "test_main" - def test_against_aas_core_meta(self) -> None: + def test_against_meta_models(self) -> None: assert ( Test_against_recorded.PARENT_CASE_DIR.exists() and Test_against_recorded.PARENT_CASE_DIR.is_dir() ), f"{Test_against_recorded.PARENT_CASE_DIR=}" - for module in [aas_core_meta.v3]: - case_dir = Test_against_recorded.PARENT_CASE_DIR / module.__name__ - assert case_dir.is_dir(), case_dir - - assert ( - module.__file__ is not None - ), f"Expected the module {module!r} to have a __file__, but it has None" - model_pth = pathlib.Path(module.__file__) - assert model_pth.exists() and model_pth.is_file(), model_pth + # fmt: off + test_cases = ( + tests.common.find_meta_models_in_parent_directory_of_test_cases_and_modules( + parent_case_dir=Test_against_recorded.PARENT_CASE_DIR, + aas_core_meta_modules=[aas_core_meta.v3] + ) + ) + # fmt: on - snippets_dir = case_dir / "input/snippets" + for test_case in test_cases: + snippets_dir = test_case.case_dir / "input/snippets" assert snippets_dir.exists() and snippets_dir.is_dir(), snippets_dir - expected_output_dir = case_dir / "expected_output" + expected_output_dir = test_case.case_dir / "expected_output" with contextlib.ExitStack() as exit_stack: if tests.common.RERECORD: @@ -145,7 +145,7 @@ def test_against_aas_core_meta(self) -> None: output_dir = pathlib.Path(tmp_dir.name) params = aas_core_codegen.main.Parameters( - model_path=model_pth, + model_path=test_case.model_path, target=aas_core_codegen.main.Target.XSD, snippets_dir=snippets_dir, output_dir=output_dir, From 9db3bac71e74de5bcc8c91c830c98bd99d7dc07b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Otto?= Date: Thu, 20 Feb 2025 13:59:31 +0100 Subject: [PATCH 08/14] Python support --- .../python/jsonization/_generate.py | 2 +- .../python/xmlization/_generate.py | 46 +- .../expected_output/common.py | 24 + .../expected_output/constants.py | 11 + .../expected_output/jsonization.py | 577 ++++++ .../expected_output/stdout.txt | 1 + .../expected_output/stringification.py | 17 + .../expected_output/types.py | 359 ++++ .../expected_output/verification.py | 171 ++ .../expected_output/xmlization.py | 1761 +++++++++++++++++ .../input/snippets/qualified_module_name.txt | 1 + .../list_of_primitives/meta_model.py | 18 + tests/python/test_main.py | 64 +- 13 files changed, 2990 insertions(+), 62 deletions(-) create mode 100644 test_data/python/test_main/list_of_primitives/expected_output/common.py create mode 100644 test_data/python/test_main/list_of_primitives/expected_output/constants.py create mode 100644 test_data/python/test_main/list_of_primitives/expected_output/jsonization.py create mode 100644 test_data/python/test_main/list_of_primitives/expected_output/stdout.txt create mode 100644 test_data/python/test_main/list_of_primitives/expected_output/stringification.py create mode 100644 test_data/python/test_main/list_of_primitives/expected_output/types.py create mode 100644 test_data/python/test_main/list_of_primitives/expected_output/verification.py create mode 100644 test_data/python/test_main/list_of_primitives/expected_output/xmlization.py create mode 100644 test_data/python/test_main/list_of_primitives/input/snippets/qualified_module_name.txt create mode 100644 test_data/python/test_main/list_of_primitives/meta_model.py diff --git a/aas_core_codegen/python/jsonization/_generate.py b/aas_core_codegen/python/jsonization/_generate.py index 9f8a741ac..683ac8976 100644 --- a/aas_core_codegen/python/jsonization/_generate.py +++ b/aas_core_codegen/python/jsonization/_generate.py @@ -993,7 +993,7 @@ def _generate_transform(cls: intermediate.ConcreteClass) -> Stripped: elif isinstance(type_anno, intermediate.ListTypeAnnotation): assert isinstance( type_anno.items, - (intermediate.PrimitiveType, intermediate.OurTypeAnnotation), + (intermediate.PrimitiveTypeAnnotation, intermediate.OurTypeAnnotation), ), ( "We expect only lists of primitive and our types. Lists of optionals " "and nested lists are not handled yet. Please contact the developers." diff --git a/aas_core_codegen/python/xmlization/_generate.py b/aas_core_codegen/python/xmlization/_generate.py index 4372f5f33..f3dd1f1f0 100644 --- a/aas_core_codegen/python/xmlization/_generate.py +++ b/aas_core_codegen/python/xmlization/_generate.py @@ -943,28 +943,27 @@ def __init__(self) -> None: ) elif isinstance(type_anno, intermediate.ListTypeAnnotation): - if not ( - isinstance(type_anno.items, intermediate.OurTypeAnnotation) - and isinstance( - type_anno.items.our_type, - (intermediate.AbstractClass, intermediate.ConcreteClass), - ) + if isinstance( + type_anno.items, intermediate.OurTypeAnnotation + ) and isinstance( + type_anno.items.our_type, + (intermediate.AbstractClass, intermediate.ConcreteClass), ): - raise AssertionError( - "(mristin, 2022-10-09) We handle only lists of classes in the XML " - "de-serialization at the moment. The meta-model does not contain " - "any other lists, so we wanted to keep the code as simple as " - "possible, and avoid unrolling. Please contact the developers " - "if you need this feature." + read_item_cls_as_element = python_naming.function_name( + Identifier(f"_read_{type_anno.items.our_type.name}_as_element") ) - read_item_cls_as_element = python_naming.function_name( - Identifier(f"_read_{type_anno.items.our_type.name}_as_element") - ) - - items_type = python_common.generate_type( - type_anno.items, types_module=Identifier("aas_types") - ) + items_type = python_common.generate_type( + type_anno.items, types_module=Identifier("aas_types") + ) + elif isinstance(type_anno.items, intermediate.PrimitiveTypeAnnotation): + read_item_cls_as_element = _READ_FUNCTION_BY_PRIMITIVE_TYPE[ + type_anno.items.a_type + ] + items_type = type_anno.items.a_type + else: + assert_never(type_anno) + raise AssertionError("Unexpected execution path") method_body = Stripped( f"""\ @@ -1669,16 +1668,15 @@ def _generate_write_cls_as_sequence(cls: intermediate.ConcreteClass) -> Stripped assert_never(our_type) elif isinstance(type_anno, intermediate.ListTypeAnnotation): - # fmt: off assert ( - isinstance(type_anno, intermediate.ListTypeAnnotation) - and isinstance(type_anno.items, intermediate.OurTypeAnnotation) + isinstance(type_anno.items, intermediate.OurTypeAnnotation) and isinstance( type_anno.items.our_type, - (intermediate.AbstractClass, intermediate.ConcreteClass) + (intermediate.AbstractClass, intermediate.ConcreteClass), ) + ) or isinstance( + type_anno.items, intermediate.PrimitiveTypeAnnotation ), "See intermediate._translate._verify_only_simple_type_patterns" - # fmt: on variable = next(generator_for_loop_variables) diff --git a/test_data/python/test_main/list_of_primitives/expected_output/common.py b/test_data/python/test_main/list_of_primitives/expected_output/common.py new file mode 100644 index 000000000..ed4617ccf --- /dev/null +++ b/test_data/python/test_main/list_of_primitives/expected_output/common.py @@ -0,0 +1,24 @@ +"""Provide common functions shared among the modules.""" + + +# This code has been automatically generated by aas-core-codegen. +# Do NOT edit or append. + + +from typing import ( + NoReturn +) + + +def assert_never(value: NoReturn) -> NoReturn: + """ + Signal to mypy to perform an exhaustive matching. + + Please see the following page for more details: + https://hakibenita.com/python-mypy-exhaustive-checking + """ + assert False, f"Unhandled value: {value} ({type(value).__name__})" + + +# This code has been automatically generated by aas-core-codegen. +# Do NOT edit or append. diff --git a/test_data/python/test_main/list_of_primitives/expected_output/constants.py b/test_data/python/test_main/list_of_primitives/expected_output/constants.py new file mode 100644 index 000000000..cf7b85abb --- /dev/null +++ b/test_data/python/test_main/list_of_primitives/expected_output/constants.py @@ -0,0 +1,11 @@ +"""Provide constant values of the meta-model.""" + +# This code has been automatically generated by aas-core-codegen. +# Do NOT edit or append. + +from typing import Set + +import test.types as aas_types + +# This code has been automatically generated by aas-core-codegen. +# Do NOT edit or append. diff --git a/test_data/python/test_main/list_of_primitives/expected_output/jsonization.py b/test_data/python/test_main/list_of_primitives/expected_output/jsonization.py new file mode 100644 index 000000000..89ab57540 --- /dev/null +++ b/test_data/python/test_main/list_of_primitives/expected_output/jsonization.py @@ -0,0 +1,577 @@ +""" +Provide de/serialization of AAS classes to/from JSON. + +We can not use one-pass deserialization for JSON since the object +properties do not have fixed order, and hence we can not read +``modelType`` property ahead of the remaining properties. +""" + + +# This code has been automatically generated by aas-core-codegen. +# Do NOT edit or append. + + +import base64 +import collections.abc +import sys +from typing import ( + cast, + Any, + Callable, + Iterable, + List, + Mapping, + MutableMapping, + Optional, + Sequence, + Union, +) + +if sys.version_info >= (3, 8): + from typing import Final +else: + from typing_extensions import Final + +import test.common as aas_common +import test.stringification as aas_stringification +import test.types as aas_types + + +class PropertySegment: + """Represent a property on a path to the erroneous value.""" + + #: Instance that contains the property + instance: Final[Mapping[str, Any]] + + #: Name of the property + name: Final[str] + + def __init__( + self, + instance: Mapping[str, Any], + name: str + ) -> None: + """Initialize with the given values.""" + self.instance = instance + self.name = name + + +class IndexSegment: + """Represent an index access on a path to the erroneous value.""" + + #: Container that contains the item + container: Final[Iterable[Any]] + + #: Index of the item + index: Final[int] + + def __init__( + self, + container: Iterable[Any], + index: int + ) -> None: + """Initialize with the given values.""" + self.container = container + self.index = index + + +Segment = Union[PropertySegment, IndexSegment] + + +class Path: + """Represent the relative path to the erroneous value.""" + + def __init__(self) -> None: + """Initialize as an empty path.""" + self._segments = [] # type: List[Segment] + + @property + def segments(self) -> Sequence[Segment]: + """Get the segments of the path.""" + return self._segments + + def _prepend(self, segment: Segment) -> None: + """Insert the :paramref:`segment` in front of other segments.""" + self._segments.insert(0, segment) + + def __str__(self) -> str: + if len(self._segments) == 0: + return "" + + parts = [] # type: List[str] + + iterator = iter(self._segments) + first = next(iterator) + if isinstance(first, PropertySegment): + parts.append(f"{first.name}") + elif isinstance(first, IndexSegment): + parts.append(f"[{first.index}]") + else: + aas_common.assert_never(first) + + for segment in iterator: + if isinstance(segment, PropertySegment): + parts.append(f".{segment.name}") + elif isinstance(segment, IndexSegment): + parts.append(f"[{segment.index}]") + else: + aas_common.assert_never(segment) + + return "".join(parts) + + +class DeserializationException(Exception): + """Signal that the JSON de-serialization could not be performed.""" + + #: Human-readable explanation of the exception's cause + cause: Final[str] + + #: Relative path to the erroneous value + path: Final[Path] + + def __init__( + self, + cause: str + ) -> None: + """Initialize with the given :paramref:`cause` and an empty path.""" + self.cause = cause + self.path = Path() + + +# NOTE (mristin, 2022-10-03): +# Recursive definitions are not yet available in mypy +# (see https://github.com/python/mypy/issues/731). We have to use ``Any`` +# here, instead of recursive type annotations. +Jsonable = Union[ + bool, + int, + float, + str, + Sequence[Any], + Mapping[str, Any] +] + + +MutableJsonable = Union[ + bool, + int, + float, + str, + List[Any], + MutableMapping[str, Any] +] + + +# region De-serialization + + +def _bool_from_jsonable( + jsonable: Jsonable +) -> bool: + """ + Parse :paramref:`jsonable` as a boolean. + + :param jsonable: JSON-able structure to be parsed + :return: parsed boolean + :raise: :py:class:`DeserializationException` if unexpected :paramref:`jsonable` + """ + if not isinstance(jsonable, bool): + raise DeserializationException( + f"Expected a bool, but got: {type(jsonable)}" + ) + return jsonable + + +def _int_from_jsonable( + jsonable: Jsonable +) -> int: + """ + Parse :paramref:`jsonable` as an integer. + + :param jsonable: JSON-able structure to be parsed + :return: parsed integer + :raise: :py:class:`DeserializationException` if unexpected :paramref:`jsonable` + """ + if not isinstance(jsonable, int): + raise DeserializationException( + f"Expected an int, but got: {type(jsonable)}" + ) + return jsonable + + +def _float_from_jsonable( + jsonable: Jsonable +) -> float: + """ + Parse :paramref:`jsonable` as a floating-point number. + + :param jsonable: JSON-able structure to be parsed + :return: parsed floating-point number + :raise: :py:class:`DeserializationException` if unexpected :paramref:`jsonable` + """ + if not isinstance(jsonable, float): + raise DeserializationException( + f"Expected a float, but got: {type(jsonable)}" + ) + return jsonable + + +def _str_from_jsonable( + jsonable: Jsonable +) -> str: + """ + Parse :paramref:`jsonable` as a string. + + :param jsonable: JSON-able structure to be parsed + :return: parsed string + :raise: :py:class:`DeserializationException` if unexpected :paramref:`jsonable` + """ + if not isinstance(jsonable, str): + raise DeserializationException( + f"Expected a str, but got: {type(jsonable)}" + ) + return jsonable + + +def _bytes_from_jsonable( + jsonable: Jsonable +) -> bytes: + """ + Decode :paramref:`jsonable` as base64 string to a ``bytearray``. + + :param jsonable: JSON-able structure to be decoded + :return: decoded bytearray + :raise: :py:class:`DeserializationException` if unexpected :paramref:`jsonable` + """ + if not isinstance(jsonable, str): + raise DeserializationException( + f"Expected a str, but got: {type(jsonable)}" + ) + + return base64.b64decode( + jsonable.encode('ascii') + ) + + +def _try_to_cast_to_array_like( + jsonable: Jsonable +) -> Optional[Iterable[Any]]: + """ + Try to cast the ``jsonable`` to something like a JSON array. + + In particular, we explicitly check that the ``jsonable`` is not a mapping, as we + do not want to mistake dictionaries (*i.e.* de-serialized JSON objects) for lists. + + >>> assert _try_to_cast_to_array_like(True) is None + + >>> assert _try_to_cast_to_array_like(0) is None + + >>> assert _try_to_cast_to_array_like(2.2) is None + + >>> assert _try_to_cast_to_array_like("hello") is None + + >>> assert _try_to_cast_to_array_like(b"hello") is None + + >>> _try_to_cast_to_array_like([1, 2]) + [1, 2] + + >>> assert _try_to_cast_to_array_like({"a": 3}) is None + + >>> assert _try_to_cast_to_array_like(collections.OrderedDict()) is None + + >>> _try_to_cast_to_array_like(range(1, 2)) + range(1, 2) + + >>> _try_to_cast_to_array_like((1, 2)) + (1, 2) + + >>> assert _try_to_cast_to_array_like({1, 2, 3}) is None + """ + if ( + + not isinstance(jsonable, (str, bytearray, bytes)) + and hasattr(jsonable, "__iter__") + and not hasattr(jsonable, "keys") + # NOTE (mristin): + # There is no easy way to check for sets as opposed to sequence except + # for checking for direct inheritance. A sequence also inherits from + # a collection, so both sequences and sets provide ``__contains__`` method. + # + # See: https://docs.python.org/3/library/collections.abc.html + and not isinstance(jsonable, collections.abc.Set) + ): + return cast(Iterable[Any], jsonable) + + return None + + +class _SetterForListOfPrimitives: + """Provide de-serialization-setters for properties.""" + + def __init__(self) -> None: + """Initialize with all the properties unset.""" + self.strings: Optional[List[str]] = None + self.integers: Optional[List[int]] = None + self.booleans: Optional[List[bool]] = None + + def ignore(self, jsonable: Jsonable) -> None: + """Ignore :paramref:`jsonable` and do not set anything.""" + pass + + def set_strings_from_jsonable( + self, + jsonable: Jsonable + ) -> None: + """ + Parse :paramref:`jsonable` as the value of :py:attr:`~strings`. + + :param jsonable: input to be parsed + """ + array_like = _try_to_cast_to_array_like(jsonable) + if array_like is None: + raise DeserializationException( + f"Expected something array-like, but got: {type(jsonable)}" + ) + + items: List[ + str + ] = [] + for i, jsonable_item in enumerate(array_like): + try: + item = _str_from_jsonable( + jsonable_item + ) + except DeserializationException as exception: + exception.path._prepend( + IndexSegment( + array_like, + i + ) + ) + raise + + items.append(item) + + self.strings = items + + def set_integers_from_jsonable( + self, + jsonable: Jsonable + ) -> None: + """ + Parse :paramref:`jsonable` as the value of :py:attr:`~integers`. + + :param jsonable: input to be parsed + """ + array_like = _try_to_cast_to_array_like(jsonable) + if array_like is None: + raise DeserializationException( + f"Expected something array-like, but got: {type(jsonable)}" + ) + + items: List[ + int + ] = [] + for i, jsonable_item in enumerate(array_like): + try: + item = _int_from_jsonable( + jsonable_item + ) + except DeserializationException as exception: + exception.path._prepend( + IndexSegment( + array_like, + i + ) + ) + raise + + items.append(item) + + self.integers = items + + def set_booleans_from_jsonable( + self, + jsonable: Jsonable + ) -> None: + """ + Parse :paramref:`jsonable` as the value of :py:attr:`~booleans`. + + :param jsonable: input to be parsed + """ + array_like = _try_to_cast_to_array_like(jsonable) + if array_like is None: + raise DeserializationException( + f"Expected something array-like, but got: {type(jsonable)}" + ) + + items: List[ + bool + ] = [] + for i, jsonable_item in enumerate(array_like): + try: + item = _bool_from_jsonable( + jsonable_item + ) + except DeserializationException as exception: + exception.path._prepend( + IndexSegment( + array_like, + i + ) + ) + raise + + items.append(item) + + self.booleans = items + + +def list_of_primitives_from_jsonable( + jsonable: Jsonable +) -> aas_types.ListOfPrimitives: + """ + Parse an instance of :py:class:`.types.ListOfPrimitives` from the JSON-able + structure :paramref:`jsonable`. + + :param jsonable: structure to be parsed + :return: Parsed instance of :py:class:`.types.ListOfPrimitives` + :raise: :py:class:`DeserializationException` if unexpected :paramref:`jsonable` + """ + if not isinstance(jsonable, collections.abc.Mapping): + raise DeserializationException( + f"Expected a mapping, but got: {type(jsonable)}" + ) + + setter = _SetterForListOfPrimitives() + + for key, jsonable_value in jsonable.items(): + setter_method = ( + _SETTER_MAP_FOR_LIST_OF_PRIMITIVES.get(key) + ) + if setter_method is None: + raise DeserializationException( + f"Unexpected property: {key}" + ) + + try: + setter_method(setter, jsonable_value) + except DeserializationException as exception: + exception.path._prepend( + PropertySegment( + jsonable_value, + key + ) + ) + raise exception + + if setter.strings is None: + raise DeserializationException( + "The required property 'strings' is missing" + ) + + if setter.integers is None: + raise DeserializationException( + "The required property 'integers' is missing" + ) + + if setter.booleans is None: + raise DeserializationException( + "The required property 'booleans' is missing" + ) + + return aas_types.ListOfPrimitives( + setter.strings, + setter.integers, + setter.booleans + ) + + +_SETTER_MAP_FOR_LIST_OF_PRIMITIVES: Mapping[ + str, + Callable[ + [_SetterForListOfPrimitives, Jsonable], + None + ] +] = { + 'strings': + _SetterForListOfPrimitives.set_strings_from_jsonable, + 'integers': + _SetterForListOfPrimitives.set_integers_from_jsonable, + 'booleans': + _SetterForListOfPrimitives.set_booleans_from_jsonable, + 'modelType': + _SetterForListOfPrimitives.ignore +} + + +# endregion + + +# region Serialization + + +def _bytes_to_base64_str( + value: bytes +) -> str: + """ + Encode :paramref:`value` as a base64 string. + + :param value: to be encoded + :return: encoded :paramref:`value` in base64 + """ + # We need to decode as ascii as ``base64.b64encode`` returns bytes, + # not a string! + return base64.b64encode(value).decode('ascii') + + +class _Serializer( + aas_types.AbstractTransformer[MutableJsonable] +): + """Transform the instance to its JSON-able representation.""" + + def transform_list_of_primitives( + self, + that: aas_types.ListOfPrimitives + ) -> MutableJsonable: + """Serialize :paramref:`that` to a JSON-able representation.""" + jsonable: MutableMapping[str, MutableJsonable] = dict() + + jsonable['strings'] = [ + item + for item in that.strings + ] + + jsonable['integers'] = [ + item + for item in that.integers + ] + + jsonable['booleans'] = [ + item + for item in that.booleans + ] + + return jsonable + + +_SERIALIZER = _Serializer() + + +def to_jsonable(that: aas_types.Class) -> MutableJsonable: + """ + Convert :paramref:`that` to a JSON-able structure. + + :param that: + AAS data to be recursively converted to a JSON-able structure + :return: + JSON-able structure which can be further encoded with, *e.g.*, :py:mod:`json` + """ + return _SERIALIZER.transform(that) + + +# endregion + + +# This code has been automatically generated by aas-core-codegen. +# Do NOT edit or append. diff --git a/test_data/python/test_main/list_of_primitives/expected_output/stdout.txt b/test_data/python/test_main/list_of_primitives/expected_output/stdout.txt new file mode 100644 index 000000000..2d755fc5a --- /dev/null +++ b/test_data/python/test_main/list_of_primitives/expected_output/stdout.txt @@ -0,0 +1 @@ +Code generated to: diff --git a/test_data/python/test_main/list_of_primitives/expected_output/stringification.py b/test_data/python/test_main/list_of_primitives/expected_output/stringification.py new file mode 100644 index 000000000..471133925 --- /dev/null +++ b/test_data/python/test_main/list_of_primitives/expected_output/stringification.py @@ -0,0 +1,17 @@ +"""De-serialize enumerations from string representations.""" + + +# This code has been automatically generated by aas-core-codegen. +# Do NOT edit or append. + + +from typing import ( + Mapping, + Optional, +) + +import test.types as aas_types + + +# This code has been automatically generated by aas-core-codegen. +# Do NOT edit or append. diff --git a/test_data/python/test_main/list_of_primitives/expected_output/types.py b/test_data/python/test_main/list_of_primitives/expected_output/types.py new file mode 100644 index 000000000..dbaa87db7 --- /dev/null +++ b/test_data/python/test_main/list_of_primitives/expected_output/types.py @@ -0,0 +1,359 @@ +# This code has been automatically generated by aas-core-codegen. +# Do NOT edit or append. + + +import abc +import enum +from typing import ( + Generic, + Iterator, + Optional, + TypeVar, + List +) + + +T = TypeVar("T") +ContextT = TypeVar("ContextT") + + +class Class(abc.ABC): + """Represent the most general class of an AAS model.""" + @abc.abstractmethod + def descend_once(self) -> Iterator["Class"]: + """Iterate over all the instances referenced from this one.""" + raise NotImplementedError() + + @abc.abstractmethod + def descend(self) -> Iterator["Class"]: + """Iterate recursively over all the instances referenced from this one.""" + raise NotImplementedError() + + @abc.abstractmethod + def accept( + self, + visitor: "AbstractVisitor" + ) -> None: + """ + Dispatch the :paramref:`visitor` on this instance. + + :param visitor: to be dispatched + """ + raise NotImplementedError() + + @abc.abstractmethod + def accept_with_context( + self, + visitor: "AbstractVisitorWithContext[ContextT]", + context: ContextT + ) -> None: + """ + Dispatch the :paramref:`visitor` on this instance with :paramref:`context`. + + :param visitor: to be dispatched + :param context: of the visitation + """ + raise NotImplementedError() + + @abc.abstractmethod + def transform( + self, + transformer: "AbstractTransformer[T]" + ) -> T: + """ + Dispatch the :paramref:`transformer` on this instance. + + :param transformer: to be dispatched + :return: transformed self + """ + raise NotImplementedError() + + @abc.abstractmethod + def transform_with_context( + self, + transformer: "AbstractTransformerWithContext[ContextT, T]", + context: ContextT + ) -> T: + """ + Dispatch the :paramref:`transformer` on this instance with :paramref:`context`. + + :param transformer: to be dispatched + :return: transformed self + """ + raise NotImplementedError() + + +# pylint: disable=redefined-builtin + + +class ListOfPrimitives(Class): + # pylint: disable=missing-class-docstring + + strings: List[str] + + integers: List[int] + + booleans: List[bool] + + def descend_once(self) -> Iterator[Class]: + """ + Iterate over the instances referenced from this instance. + + We do not recurse into the referenced instance. + + :yield: instances directly referenced from this instance + """ + # No descendable properties + return + # For this uncommon return-yield construction, see: + # https://stackoverflow.com/questions/13243766/how-to-define-an-empty-generator-function + # noinspection PyUnreachableCode + yield + + def descend(self) -> Iterator[Class]: + """ + Iterate recursively over the instances referenced from this one. + + :yield: instances recursively referenced from this instance + """ + # No descendable properties + return + # For this uncommon return-yield construction, see: + # https://stackoverflow.com/questions/13243766/how-to-define-an-empty-generator-function + # noinspection PyUnreachableCode + yield + + def accept(self, visitor: "AbstractVisitor") -> None: + """Dispatch the :paramref:`visitor` on this instance.""" + visitor.visit_list_of_primitives(self) + + def accept_with_context( + self, + visitor: "AbstractVisitorWithContext[ContextT]", + context: ContextT + ) -> None: + """Dispatch the :paramref:`visitor` on this instance in :paramref:`context`.""" + visitor.visit_list_of_primitives_with_context(self, context) + + def transform( + self, + transformer: "AbstractTransformer[T]" + ) -> T: + """Dispatch the :paramref:`transformer` on this instance.""" + return transformer.transform_list_of_primitives(self) + + def transform_with_context( + self, + transformer: "AbstractTransformerWithContext[ContextT, T]", + context: ContextT + ) -> T: + """ + Dispatch the :paramref:`transformer` on this instance in :paramref:`context`. + """ + return transformer.transform_list_of_primitives_with_context( + self, context) + + def __init__( + self, + strings: List[str], + integers: List[int], + booleans: List[bool] + ) -> None: + """Initialize with the given values.""" + self.strings = strings + self.integers = integers + self.booleans = booleans + + +class AbstractVisitor: + """Visit the instances of the model.""" + def visit( + self, + that: Class + ) -> None: + """Double-dispatch on :paramref:`that`.""" + that.accept(self) + + @abc.abstractmethod + def visit_list_of_primitives( + self, + that: ListOfPrimitives + ) -> None: + """Visit :paramref:`that`.""" + raise NotImplementedError() + + +class AbstractVisitorWithContext(Generic[ContextT]): + """Visit the instances of the model with context.""" + def visit_with_context( + self, + that: Class, + context: ContextT + ) -> None: + """Double-dispatch on :paramref:`that`.""" + that.accept_with_context(self, context) + + @abc.abstractmethod + def visit_list_of_primitives_with_context( + self, + that: ListOfPrimitives, + context: ContextT + ) -> None: + """Visit :paramref:`that` in :paramref:`context`.""" + raise NotImplementedError() + + +class PassThroughVisitor(AbstractVisitor): + """ + Visit the instances of the model without action. + + This visitor is not meant to be directly used. Instead, you usually + inherit from it, and implement only the relevant visit methods. + """ + def visit( + self, + that: Class + ) -> None: + """Double-dispatch on :paramref:`that`.""" + that.accept(self) + + def visit_list_of_primitives( + self, + that: ListOfPrimitives + ) -> None: + """Visit :paramref:`that`.""" + for another in that.descend_once(): + self.visit(another) + + +class PassThroughVisitorWithContext( + AbstractVisitorWithContext[ContextT] +): + """ + Visit the instances of the model without action and in context. + + This visitor is not meant to be directly used. Instead, you usually + inherit from it, and implement only the relevant visit methods. + """ + def visit_with_context( + self, + that: Class, + context: ContextT + ) -> None: + """Double-dispatch on :paramref:`that`.""" + that.accept_with_context(self, context) + + def visit_list_of_primitives_with_context( + self, + that: ListOfPrimitives, + context: ContextT + ) -> None: + """Visit :paramref:`that` in :paramref:`context`.""" + for another in that.descend_once(): + self.visit_with_context(another, context) + + +class AbstractTransformer(Generic[T]): + """Transform the instances of the model.""" + def transform( + self, + that: Class + ) -> T: + """Double-dispatch on :paramref:`that`.""" + return that.transform(self) + + @abc.abstractmethod + def transform_list_of_primitives( + self, + that: ListOfPrimitives + ) -> T: + """Transform :paramref:`that`.""" + raise NotImplementedError() + + +class AbstractTransformerWithContext( + Generic[ContextT, T] +): + """Transform the instances of the model in context.""" + def transform_with_context( + self, + that: Class, + context: ContextT + ) -> T: + """Double-dispatch on :paramref:`that`.""" + return that.transform_with_context(self, context) + + @abc.abstractmethod + def transform_list_of_primitives_with_context( + self, + that: ListOfPrimitives, + context: ContextT + ) -> T: + """Transform :paramref:`that` in :paramref:`context`.""" + raise NotImplementedError() + + +class TransformerWithDefault(AbstractTransformer[T]): + """ + Transform the instances of the model. + + If you do not override the transformation methods, they simply + return :py:attr:`.default`. + """ + #: Default value which is returned if no override of the transformation + default: T + + def __init__(self, default: T) -> None: + """Initialize with the given :paramref:`default` value.""" + self.default = default + + def transform( + self, + that: Class + ) -> T: + """Double-dispatch on :paramref:`that`.""" + return that.transform(self) + + def transform_list_of_primitives( + self, + that: ListOfPrimitives + ) -> T: + """Transform :paramref:`that`.""" + return self.default + + +class TransformerWithDefaultAndContext( + AbstractTransformerWithContext[ContextT, T] +): + """ + Transform the instances of the model in context. + + If you do not override the transformation methods, they simply + return :py:attr:`.default`. + """ + #: Default value which is returned if no override of the transformation + default: T + + def __init__(self, default: T) -> None: + """Initialize with the given :paramref:`default` value.""" + self.default = default + + def transform_with_context( + self, + that: Class, + context: ContextT + ) -> T: + """Double-dispatch on :paramref:`that`.""" + return that.transform_with_context(self, context) + + def transform_list_of_primitives_with_context( + self, + that: ListOfPrimitives, + context: ContextT + ) -> T: + """Transform :paramref:`that` in :paramref:`context`.""" + return self.default + + +# This code has been automatically generated by aas-core-codegen. +# Do NOT edit or append. diff --git a/test_data/python/test_main/list_of_primitives/expected_output/verification.py b/test_data/python/test_main/list_of_primitives/expected_output/verification.py new file mode 100644 index 000000000..9e4a5f6a9 --- /dev/null +++ b/test_data/python/test_main/list_of_primitives/expected_output/verification.py @@ -0,0 +1,171 @@ +""" +Verify that the instances of the meta-model satisfy the invariants. + +Here is an example how to verify an instance of :py:class:`test.types.ListOfPrimitives`: + +.. code-block:: + + import test.types as aas_types + import test.verification as aas_verification + + an_instance = aas_types.ListOfPrimitives( + # ... some constructor arguments ... + ) + + for error in aas_verification.verify(an_instance): + print(f"{error.cause} at: {error.path}") +""" + + +# This code has been automatically generated by aas-core-codegen. +# Do NOT edit or append. + + +import math +import re +import struct +import sys +from typing import ( + Callable, + Iterable, + Iterator, + List, + Mapping, + Optional, + Pattern, + Sequence, + Set, + Union +) + +if sys.version_info >= (3, 8): + from typing import Final +else: + from typing_extensions import Final + +from test import ( + constants as aas_constants, + types as aas_types, +) + + +class PropertySegment: + """Represent a property access on a path to an erroneous value.""" + + #: Instance containing the property + instance: Final[aas_types.Class] + + #: Name of the property + name: Final[str] + + def __init__( + self, + instance: aas_types.Class, + name: str + ) -> None: + """Initialize with the given values.""" + self.instance = instance + self.name = name + + def __str__(self) -> str: + return f'.{self.name}' + + +class IndexSegment: + """Represent an index access on a path to an erroneous value.""" + + #: Sequence containing the item at :py:attr:`~index` + sequence: Final[Sequence[aas_types.Class]] + + #: Index of the item + index: Final[int] + + def __init__( + self, + sequence: Sequence[aas_types.Class], + index: int + ) -> None: + """Initialize with the given values.""" + self.sequence = sequence + self.index = index + + def __str__(self) -> str: + return f'[{self.index}]' + + +Segment = Union[PropertySegment, IndexSegment] + + +class Path: + """Represent the relative path to the erroneous value.""" + + def __init__(self) -> None: + """Initialize as an empty path.""" + self._segments = [] # type: List[Segment] + + @property + def segments(self) -> Sequence[Segment]: + """Get the segments of the path.""" + return self._segments + + def _prepend(self, segment: Segment) -> None: + """Insert the :paramref:`segment` in front of other segments.""" + self._segments.insert(0, segment) + + def __str__(self) -> str: + return "".join(str(segment) for segment in self._segments) + + +class Error: + """Represent a verification error in the data.""" + + #: Human-readable description of the error + cause: Final[str] + + #: Path to the erroneous value + path: Final[Path] + + def __init__(self, cause: str) -> None: + """Initialize as an error with an empty path.""" + self.cause = cause + self.path = Path() + + def __repr__(self) -> str: + return f"Error(path={self.path}, cause={self.cause})" + + +class _Transformer( + aas_types.AbstractTransformer[ + Iterator[Error] + ] +): + # noinspection PyMethodMayBeStatic + def transform_list_of_primitives( + self, + that: aas_types.ListOfPrimitives + ) -> Iterator[Error]: + # No verification has been defined for ListOfPrimitives. + return + # For this uncommon return-yield construction, see: + # https://stackoverflow.com/questions/13243766/how-to-define-an-empty-generator-function + # noinspection PyUnreachableCode + yield + + +_TRANSFORMER = _Transformer() + + +def verify( + that: aas_types.Class +) -> Iterator[Error]: + """ + Verify the constraints of :paramref:`that` recursively. + + :param that: instance whose constraints we want to verify + :yield: constraint violations + """ + yield from _TRANSFORMER.transform(that) + + +# This code has been automatically generated by aas-core-codegen. +# Do NOT edit or append. diff --git a/test_data/python/test_main/list_of_primitives/expected_output/xmlization.py b/test_data/python/test_main/list_of_primitives/expected_output/xmlization.py new file mode 100644 index 000000000..41f645dfe --- /dev/null +++ b/test_data/python/test_main/list_of_primitives/expected_output/xmlization.py @@ -0,0 +1,1761 @@ +""" +Read and write AAS models as XML. + +For reading, we provide different reading functions, each handling a different kind +of input. All the reading functions operate in one pass, *i.e.*, the source is read +incrementally and the complete XML is not held in memory. + +We provide the following four reading functions (where ``X`` represents the name of +the class): + +1) ``X_from_iterparse`` reads from a stream of ``(event, element)`` tuples coming from + :py:func:`xml.etree.ElementTree.iterparse` with the argument + ``events=["start", "end"]``. If you do not trust the source, please consider + using `defusedxml.ElementTree`_. +2) ``X_from_stream`` reads from the given text stream. +3) ``X_from_file`` reads from a file on disk. +4) ``X_from_str`` reads from the given string. + +The functions ``X_from_stream``, ``X_from_file`` and ``X_from_str`` provide +an extra parameter, ``has_iterparse``, which allows you to use a parsing library +different from :py:mod:`xml.etree.ElementTree`. For example, you can pass in +`defusedxml.ElementTree`_. + +.. _defusedxml.ElementTree: https://pypi.org/project/defusedxml/#defusedxml-elementtree + +All XML elements are expected to live in the :py:attr:`~NAMESPACE`. + +For writing, use the function :py:func:`test.xmlization.write` which +translates the instance of the model into an XML document and writes it in one pass +to the stream. + +Here is an example usage how to de-serialize from a file: + +.. code-block:: + + import pathlib + import xml.etree.ElementTree as ET + + import test.xmlization as aas_xmlization + + path = pathlib.Path(...) + instance = aas_xmlization.read_list_of_primitives_from_file( + path + ) + + # Do something with the ``instance`` + +Here is another code example where we serialize the instance: + +.. code-block:: + + import pathlib + + import test.types as aas_types + import test.xmlization as aas_xmlization + + instance = ListOfPrimitives( + ... # some constructor arguments + ) + + pth = pathlib.Path(...) + with pth.open("wt") as fid: + aas_xmlization.write(instance, fid) +""" + + +# This code has been automatically generated by aas-core-codegen. +# Do NOT edit or append. + + +import base64 +import io +import math +import os +import sys +from typing import ( + Any, + Callable, + Iterator, + List, + Mapping, + Optional, + Sequence, + TextIO, + Tuple, + Union, + TYPE_CHECKING +) +import xml.etree.ElementTree + +if sys.version_info >= (3, 8): + from typing import ( + Final, + Protocol + ) +else: + from typing_extensions import ( + Final, + Protocol + ) + +import test.stringification as aas_stringification +import test.types as aas_types + +# See: https://stackoverflow.com/questions/55076778/why-isnt-this-function-type-annotated-correctly-error-missing-type-parameters +if TYPE_CHECKING: + PathLike = os.PathLike[Any] +else: + PathLike = os.PathLike + + +#: XML namespace in which all the elements are expected to reside +NAMESPACE = 'https://dummy.com' + + +# region De-serialization + + +#: XML namespace as a prefix specially tailored for +#: :py:mod:`xml.etree.ElementTree` +_NAMESPACE_IN_CURLY_BRACKETS = f'{{{NAMESPACE}}}' + + +class Element(Protocol): + """Behave like :py:meth:`xml.etree.ElementTree.Element`.""" + + @property + def attrib(self) -> Optional[Mapping[str, str]]: + """Attributes of the element""" + raise NotImplementedError() + + @property + def text(self) -> Optional[str]: + """Text content of the element""" + raise NotImplementedError() + + @property + def tail(self) -> Optional[str]: + """Tail text of the element""" + raise NotImplementedError() + + @property + def tag(self) -> str: + """Tag of the element; with a namespace provided as a ``{...}`` prefix""" + raise NotImplementedError() + + def clear(self) -> None: + """Behave like :py:meth:`xml.etree.ElementTree.Element.clear`.""" + raise NotImplementedError() + + +class HasIterparse(Protocol): + """Parse an XML document incrementally.""" + + # NOTE (mristin, 2022-10-26): + # ``self`` is not used in this context, but is necessary for Mypy, + # see: https://github.com/python/mypy/issues/5018 and + # https://github.com/python/mypy/commit/3efbc5c5e910296a60ed5b9e0e7eb11dd912c3ed#diff-e165eb7aed9dca0a5ebd93985c8cd263a6462d36ac185f9461348dc5a1396d76R9937 + + def iterparse( + self, + source: TextIO, + events: Optional[Sequence[str]] = None + ) -> Iterator[Tuple[str, Element]]: + """Behave like :py:func:`xml.etree.ElementTree.iterparse`.""" + + +class ElementSegment: + """Represent an element on a path to the erroneous value.""" + #: Erroneous element + element: Final[Element] + + def __init__( + self, + element: Element + ) -> None: + """Initialize with the given values.""" + self.element = element + + def __str__(self) -> str: + """ + Render the segment as a tag without the namespace. + + We deliberately omit the namespace in the tag names. If you want to actually + query with the resulting XPath, you have to insert the namespaces manually. + We did not know how to include the namespace in a meaningful way, as XPath + assumes namespace prefixes to be defined *outside* of the document. At least + the path thus rendered is informative, and you should be able to descend it + manually. + """ + _, has_namespace, tag_wo_ns = self.element.tag.rpartition('}') + if not has_namespace: + return self.element.tag + else: + return tag_wo_ns + + +class IndexSegment: + """Represent an element in a sequence on a path to the erroneous value.""" + #: Erroneous element + element: Final[Element] + + #: Index of the element in the sequence + index: Final[int] + + def __init__( + self, + element: Element, + index: int + ) -> None: + """Initialize with the given values.""" + self.element = element + self.index = index + + def __str__(self) -> str: + """Render the segment as an element wildcard with the index.""" + return f'*[{self.index}]' + + +Segment = Union[ElementSegment, IndexSegment] + + +class Path: + """Represent the relative path to the erroneous element.""" + + def __init__(self) -> None: + """Initialize as an empty path.""" + self._segments = [] # type: List[Segment] + + @property + def segments(self) -> Sequence[Segment]: + """Get the segments of the path.""" + return self._segments + + def _prepend(self, segment: Segment) -> None: + """Insert the :paramref:`segment` in front of other segments.""" + self._segments.insert(0, segment) + + def __str__(self) -> str: + """Render the path as a relative XPath. + + We omit the leading ``/`` so that you can easily prefix it as you need. + """ + return "/".join(str(segment) for segment in self._segments) + + +class DeserializationException(Exception): + """Signal that the XML de-serialization could not be performed.""" + + #: Human-readable explanation of the exception's cause + cause: Final[str] + + #: Relative path to the erroneous value + path: Final[Path] + + def __init__( + self, + cause: str + ) -> None: + """Initialize with the given :paramref:`cause` and an empty path.""" + self.cause = cause + self.path = Path() + + +def _with_elements_cleared_after_yield( + iterator: Iterator[Tuple[str, Element]] +) -> Iterator[Tuple[str, Element]]: + """ + Map the :paramref:`iterator` such that the element is ``clear()``'ed + *after* every ``yield``. + + :param iterator: to be mapped + :yield: event and element from :paramref:`iterator` + """ + for event, element in iterator: + yield event, element + element.clear() + + +def list_of_primitives_from_iterparse( + iterator: Iterator[Tuple[str, Element]] +) -> aas_types.ListOfPrimitives: + """ + Read an instance of :py:class:`.types.ListOfPrimitives` from + the :paramref:`iterator`. + + Example usage: + + .. code-block:: + + import pathlib + import xml.etree.ElementTree as ET + + import test.xmlization as aas_xmlization + + path = pathlib.Path(...) + with path.open("rt") as fid: + iterator = ET.iterparse( + source=fid, + events=['start', 'end'] + ) + instance = aas_xmlization.list_of_primitives_from_iterparse( + iterator + ) + + # Do something with the ``instance`` + + :param iterator: + Input stream of ``(event, element)`` coming from + :py:func:`xml.etree.ElementTree.iterparse` with the argument + ``events=["start", "end"]`` + :raise: :py:class:`DeserializationException` if unexpected input + :return: + Instance of :py:class:`.types.ListOfPrimitives` read from + :paramref:`iterator` + """ + next_event_element = next(iterator, None) + if next_event_element is None: + raise DeserializationException( + # fmt: off + "Expected the start element for ListOfPrimitives, " + "but got the end-of-input" + # fmt: on + ) + + next_event, next_element = next_event_element + if next_event != 'start': + raise DeserializationException( + f"Expected the start element for ListOfPrimitives, " + f"but got event {next_event!r} and element {next_element.tag!r}" + ) + + try: + return _read_list_of_primitives_as_element( + next_element, + iterator + ) + except DeserializationException as exception: + exception.path._prepend(ElementSegment(next_element)) + raise exception + + +def list_of_primitives_from_stream( + stream: TextIO, + has_iterparse: HasIterparse = xml.etree.ElementTree +) -> aas_types.ListOfPrimitives: + """ + Read an instance of :py:class:`.types.ListOfPrimitives` from + the :paramref:`stream`. + + Example usage: + + .. code-block:: + + import test.xmlization as aas_xmlization + + with open_some_stream_over_network(...) as stream: + instance = aas_xmlization.list_of_primitives_from_stream( + stream + ) + + # Do something with the ``instance`` + + :param stream: + representing an instance of + :py:class:`.types.ListOfPrimitives` in XML + :param has_iterparse: + Module containing ``iterparse`` function. + + Default is to use :py:mod:`xml.etree.ElementTree` from the standard + library. If you have to deal with malicious input, consider using + a library such as `defusedxml.ElementTree`_. + :raise: :py:class:`DeserializationException` if unexpected input + :return: + Instance of :py:class:`.types.ListOfPrimitives` read from + :paramref:`stream` + """ + iterator = has_iterparse.iterparse( + stream, + ['start', 'end'] + ) + return list_of_primitives_from_iterparse( + _with_elements_cleared_after_yield(iterator) + ) + + +def list_of_primitives_from_file( + path: PathLike, + has_iterparse: HasIterparse = xml.etree.ElementTree +) -> aas_types.ListOfPrimitives: + """ + Read an instance of :py:class:`.types.ListOfPrimitives` from + the :paramref:`path`. + + Example usage: + + .. code-block:: + + import pathlib + import test.xmlization as aas_xmlization + + path = pathlib.Path(...) + instance = aas_xmlization.list_of_primitives_from_file( + path + ) + + # Do something with the ``instance`` + + :param path: + to the file representing an instance of + :py:class:`.types.ListOfPrimitives` in XML + :param has_iterparse: + Module containing ``iterparse`` function. + + Default is to use :py:mod:`xml.etree.ElementTree` from the standard + library. If you have to deal with malicious input, consider using + a library such as `defusedxml.ElementTree`_. + :raise: :py:class:`DeserializationException` if unexpected input + :return: + Instance of :py:class:`.types.ListOfPrimitives` read from + :paramref:`path` + """ + with open(os.fspath(path), "rt", encoding='utf-8') as fid: + iterator = has_iterparse.iterparse( + fid, + ['start', 'end'] + ) + return list_of_primitives_from_iterparse( + _with_elements_cleared_after_yield(iterator) + ) + + +def list_of_primitives_from_str( + text: str, + has_iterparse: HasIterparse = xml.etree.ElementTree +) -> aas_types.ListOfPrimitives: + """ + Read an instance of :py:class:`.types.ListOfPrimitives` from + the :paramref:`text`. + + Example usage: + + .. code-block:: + + import pathlib + import test.xmlization as aas_xmlization + + text = "<...>..." + instance = aas_xmlization.list_of_primitives_from_str( + text + ) + + # Do something with the ``instance`` + + :param text: + representing an instance of + :py:class:`.types.ListOfPrimitives` in XML + :param has_iterparse: + Module containing ``iterparse`` function. + + Default is to use :py:mod:`xml.etree.ElementTree` from the standard + library. If you have to deal with malicious input, consider using + a library such as `defusedxml.ElementTree`_. + :raise: :py:class:`DeserializationException` if unexpected input + :return: + Instance of :py:class:`.types.ListOfPrimitives` read from + :paramref:`text` + """ + iterator = has_iterparse.iterparse( + io.StringIO(text), + ['start', 'end'] + ) + return list_of_primitives_from_iterparse( + _with_elements_cleared_after_yield(iterator) + ) + + +def from_iterparse( + iterator: Iterator[Tuple[str, Element]] +) -> aas_types.Class: + """ + Read an instance from the :paramref:`iterator`. + + The type of the instance is determined by the very first start element. + + Example usage: + + .. code-block:: + + import pathlib + import xml.etree.ElementTree as ET + + import test.xmlization as aas_xmlization + + path = pathlib.Path(...) + with path.open("rt") as fid: + iterator = ET.iterparse( + source=fid, + events=['start', 'end'] + ) + instance = aas_xmlization.from_iterparse( + iterator + ) + + # Do something with the ``instance`` + + :param iterator: + Input stream of ``(event, element)`` coming from + :py:func:`xml.etree.ElementTree.iterparse` with the argument + ``events=["start", "end"]`` + :raise: :py:class:`DeserializationException` if unexpected input + :return: + Instance of :py:class:`.types.Class` read from the :paramref:`iterator` + """ + next_event_element = next(iterator, None) + if next_event_element is None: + raise DeserializationException( + # fmt: off + "Expected the start element of an instance, " + "but got the end-of-input" + # fmt: on + ) + + next_event, next_element = next_event_element + if next_event != 'start': + raise DeserializationException( + f"Expected the start element of an instance, " + f"but got event {next_event!r} and element {next_element.tag!r}" + ) + + try: + return _read_as_element( + next_element, + iterator + ) + except DeserializationException as exception: + exception.path._prepend(ElementSegment(next_element)) + raise exception + + +def from_stream( + stream: TextIO, + has_iterparse: HasIterparse = xml.etree.ElementTree +) -> aas_types.Class: + """ + Read an instance from the :paramref:`stream`. + + The type of the instance is determined by the very first start element. + + Example usage: + + .. code-block:: + + import test.xmlization as aas_xmlization + + with open_some_stream_over_network(...) as stream: + instance = aas_xmlization.from_stream( + stream + ) + + # Do something with the ``instance`` + + :param stream: + representing an instance in XML + :param has_iterparse: + Module containing ``iterparse`` function. + + Default is to use :py:mod:`xml.etree.ElementTree` from the standard + library. If you have to deal with malicious input, consider using + a library such as `defusedxml.ElementTree`_. + :raise: :py:class:`DeserializationException` if unexpected input + :return: + Instance read from :paramref:`stream` + """ + iterator = has_iterparse.iterparse( + stream, + ['start', 'end'] + ) + return from_iterparse( + _with_elements_cleared_after_yield(iterator) + ) + + +def from_file( + path: PathLike, + has_iterparse: HasIterparse = xml.etree.ElementTree +) -> aas_types.Class: + """ + Read an instance from the file at the :paramref:`path`. + + Example usage: + + .. code-block:: + + import pathlib + import test.xmlization as aas_xmlization + + path = pathlib.Path(...) + instance = aas_xmlization.from_file( + path + ) + + # Do something with the ``instance`` + + :param path: + to the file representing an instance in XML + :param has_iterparse: + Module containing ``iterparse`` function. + + Default is to use :py:mod:`xml.etree.ElementTree` from the standard + library. If you have to deal with malicious input, consider using + a library such as `defusedxml.ElementTree`_. + :raise: :py:class:`DeserializationException` if unexpected input + :return: + Instance read from the file at :paramref:`path` + """ + with open(os.fspath(path), "rt", encoding='utf-8') as fid: + iterator = has_iterparse.iterparse( + fid, + ['start', 'end'] + ) + return from_iterparse( + _with_elements_cleared_after_yield(iterator) + ) + + +def from_str( + text: str, + has_iterparse: HasIterparse = xml.etree.ElementTree +) -> aas_types.Class: + """ + Read an instance from the :paramref:`text`. + + Example usage: + + .. code-block:: + + import pathlib + import test.xmlization as aas_xmlization + + text = "<...>..." + instance = aas_xmlization.from_str( + text + ) + + # Do something with the ``instance`` + + :param text: + representing an instance in XML + :param has_iterparse: + Module containing ``iterparse`` function. + + Default is to use :py:mod:`xml.etree.ElementTree` from the standard + library. If you have to deal with malicious input, consider using + a library such as `defusedxml.ElementTree`_. + :raise: :py:class:`DeserializationException` if unexpected input + :return: + Instance read from :paramref:`text` + """ + iterator = has_iterparse.iterparse( + io.StringIO(text), + ['start', 'end'] + ) + return from_iterparse( + _with_elements_cleared_after_yield(iterator) + ) + + +# NOTE (mristin, 2022-10-08): +# Directly using the iterator turned out to result in very complex function +# designs. The design became much simpler as soon as we considered one look-ahead +# element. We came up finally with the following pattern which all the protected +# reading functions below roughly follow: +# +# ..code-block:: +# +# _read_*( +# look-ahead element, +# iterator +# ) -> result +# +# The reading functions all read from the ``iterator`` coming from +# :py:func:`xml.etree.ElementTree.iterparse` with the argument +# ``events=["start", "end"]``. The exception :py:class:`.DeserializationException` +# is raised in case of unexpected input. +# +# The reading functions are responsible to read the end element corresponding to the +# start look-ahead element. +# +# When it comes to error reporting, we use exceptions. The exceptions are raised in +# the *callee*, as usual. However, the context of the exception, such as the error path, +# is added in the *caller*, as only the caller knows the context of +# the lookahead-element. In particular, prepending the path segment corresponding to +# the lookahead-element is the responsibility of the *caller*, and not of +# the *callee*. + + +def _parse_element_tag(element: Element) -> str: + """ + Extract the tag name without the namespace prefix from :paramref:`element`. + + :param element: whose tag without namespace we want to extract + :return: tag name without the namespace prefix + :raise: :py:class:`DeserializationException` if unexpected :paramref:`element` + """ + if not element.tag.startswith(_NAMESPACE_IN_CURLY_BRACKETS): + namespace, got_namespace, tag_wo_ns = ( + element.tag.rpartition('}') + ) + if got_namespace: + if namespace.startswith('{'): + namespace = namespace[1:] + + raise DeserializationException( + f"Expected the element in the namespace {NAMESPACE!r}, " + f"but got the element {tag_wo_ns!r} in the namespace {namespace!r}" + ) + else: + raise DeserializationException( + f"Expected the element in the namespace {NAMESPACE!r}, " + f"but got the element {tag_wo_ns!r} without the namespace prefix" + ) + + return element.tag[len(_NAMESPACE_IN_CURLY_BRACKETS):] + + +def _raise_if_has_tail_or_attrib( + element: Element +) -> None: + """ + Check that :paramref:`element` has no trailing text and no attributes. + + :param element: to be verified + :raise: + :py:class:`.DeserializationException` if trailing text or attributes; + conforming to the convention about handling error paths, + the exception path is left empty. + """ + if element.tail is not None and len(element.tail.strip()) != 0: + raise DeserializationException( + f"Expected no trailing text, but got: {element.tail!r}" + ) + + if element.attrib is not None and len(element.attrib) > 0: + raise DeserializationException( + f"Expected no attributes, but got: {element.attrib}" + ) + + +def _read_end_element( + element: Element, + iterator: Iterator[Tuple[str, Element]] +) -> Element: + """ + Read the end element corresponding to the start :paramref:`element` + from :paramref:`iterator`. + + :param element: corresponding start element + :param iterator: + Input stream of ``(event, element)`` coming from + :py:func:`xml.etree.ElementTree.iterparse` with the argument + ``events=["start", "end"]`` + :raise: :py:class:`DeserializationException` if unexpected input + """ + next_event_element = next(iterator, None) + if next_event_element is None: + raise DeserializationException( + f"Expected the end element for {element.tag}, " + f"but got the end-of-input" + ) + + next_event, next_element = next_event_element + if next_event != "end" or next_element.tag != element.tag: + raise DeserializationException( + f"Expected the end element for {element.tag!r}, " + f"but got the event {next_event!r} and element {next_element.tag!r}" + ) + + _raise_if_has_tail_or_attrib(next_element) + + return next_element + + +def _read_text_from_element( + element: Element, + iterator: Iterator[Tuple[str, Element]] +) -> str: + """ + Extract the text from the :paramref:`element`, and read + the end element from :paramref:`iterator`. + + The :paramref:`element` is expected to contain text. Otherwise, + it is considered as unexpected input. + + :param element: start element enclosing the text + :param iterator: + Input stream of ``(event, element)`` coming from + :py:func:`xml.etree.ElementTree.iterparse` with the argument + ``events=["start", "end"]`` + :raise: :py:class:`DeserializationException` if unexpected input + """ + _raise_if_has_tail_or_attrib(element) + + text = element.text + + end_element = _read_end_element( + element, + iterator, + ) + + if text is None: + if end_element.text is None: + raise DeserializationException( + "Expected an element with text, but got an element with no text." + ) + + text = end_element.text + + return text + + +_XS_BOOLEAN_LITERAL_SET = { + "1", + "true", + "0", + "false", +} + + +def _read_bool_from_element_text( + element: Element, + iterator: Iterator[Tuple[str, Element]] +) -> bool: + """ + Parse the text of :paramref:`element` as a boolean, and + read the corresponding end element from :paramref:`iterator`. + + :param element: start element + :param iterator: + Input stream of ``(event, element)`` coming from + :py:func:`xml.etree.ElementTree.iterparse` with the argument + ``events=["start", "end"]`` + :raise: :py:class:`DeserializationException` if unexpected input + :return: parsed value + """ + text = _read_text_from_element( + element, + iterator + ) + + if text not in _XS_BOOLEAN_LITERAL_SET: + raise DeserializationException( + f"Expected a boolean, " + f"but got an element with text: {text!r}" + ) + + return text in ('1', 'true') + + +def _read_int_from_element_text( + element: Element, + iterator: Iterator[Tuple[str, Element]] +) -> int: + """ + Parse the text of :paramref:`element` as an integer, and + read the corresponding end element from :paramref:`iterator`. + + :param element: start element + :param iterator: + Input stream of ``(event, element)`` coming from + :py:func:`xml.etree.ElementTree.iterparse` with the argument + ``events=["start", "end"]`` + :raise: :py:class:`DeserializationException` if unexpected input + :return: parsed value + """ + text = _read_text_from_element( + element, + iterator + ) + + try: + value = int(text) + except ValueError: + # pylint: disable=raise-missing-from + raise DeserializationException( + f"Expected an integer, " + f"but got an element with text: {text!r}" + ) + + return value + + +_TEXT_TO_XS_DOUBLE_LITERALS = { + "NaN": math.nan, + "INF": math.inf, + "-INF": -math.inf, +} + + +def _read_float_from_element_text( + element: Element, + iterator: Iterator[Tuple[str, Element]] +) -> float: + """ + Parse the text of :paramref:`element` as a floating-point number, and + read the corresponding end element from :paramref:`iterator`. + + :param element: start element + :param iterator: + Input stream of ``(event, element)`` coming from + :py:func:`xml.etree.ElementTree.iterparse` with the argument + ``events=["start", "end"]`` + :raise: :py:class:`DeserializationException` if unexpected input + :return: parsed value + """ + text = _read_text_from_element( + element, + iterator + ) + + value = _TEXT_TO_XS_DOUBLE_LITERALS.get(text, None) + if value is None: + try: + value = float(text) + except ValueError: + # pylint: disable=raise-missing-from + raise DeserializationException( + f"Expected a floating-point number, " + f"but got an element with text: {text!r}" + ) + + return value + + +def _read_str_from_element_text( + element: Element, + iterator: Iterator[Tuple[str, Element]] +) -> str: + """ + Parse the text of :paramref:`element` as a string, and + read the corresponding end element from :paramref:`iterator`. + + If there is no text, empty string is returned. + + :param element: start element + :param iterator: + Input stream of ``(event, element)`` coming from + :py:func:`xml.etree.ElementTree.iterparse` with the argument + ``events=["start", "end"]`` + :raise: :py:class:`DeserializationException` if unexpected input + :return: parsed value + """ + # NOTE (mristin, 2022-10-26): + # We do not use ``_read_text_from_element`` as that function expects + # the ``element`` to contain *some* text. In contrast, this function + # can also deal with empty text, in which case it returns an empty string. + + text = element.text + + end_element = _read_end_element( + element, + iterator + ) + + if text is None: + text = end_element.text + + _raise_if_has_tail_or_attrib(element) + result = ( + text + if text is not None + else "" + ) + + return result + + +def _read_bytes_from_element_text( + element: Element, + iterator: Iterator[Tuple[str, Element]] +) -> bytes: + """ + Parse the text of :paramref:`element` as base64-encoded bytes, and + read the corresponding end element from :paramref:`iterator`. + + :param element: look-ahead element + :param iterator: + Input stream of ``(event, element)`` coming from + :py:func:`xml.etree.ElementTree.iterparse` with the argument + ``events=["start", "end"]`` + :raise: :py:class:`DeserializationException` if unexpected input + :return: parsed value + """ + text = _read_text_from_element( + element, + iterator + ) + + try: + value = base64.b64decode(text) + except Exception: + # pylint: disable=raise-missing-from + raise DeserializationException( + f"Expected a text as base64-encoded bytes, " + f"but got an element with text: {text!r}" + ) + + return value + + +class _ReaderAndSetterForListOfPrimitives: + """ + Provide a buffer for reading and setting the properties for the class + :py:class:`ListOfPrimitives`. + + The properties correspond to the constructor arguments of + :py:class:`ListOfPrimitives`. We use this buffer to facilitate dispatching when + parsing the properties in a streaming fashion. + """ + + def __init__(self) -> None: + """Initialize with all the properties unset.""" + self.strings: Optional[List[str]] = None + self.integers: Optional[List[int]] = None + self.booleans: Optional[List[bool]] = None + + def read_and_set_strings( + self, + element: Element, + iterator: Iterator[Tuple[str, Element]] + ) -> None: + """ + Read :paramref:`element` as the property + :py:attr:`.types.ListOfPrimitives.strings` and set it. + """ + if element.text is not None and len(element.text.strip()) != 0: + raise DeserializationException( + f"Expected only item elements and whitespace text, " + f"but got text: {element.text!r}" + ) + + result: List[ + PrimitiveType.STR + ] = [] + + item_i = 0 + + while True: + next_event_element = next(iterator, None) + if next_event_element is None: + raise DeserializationException( + "Expected one or more items from a list or the end element, " + "but got end-of-input" + ) + + next_event, next_element = next_event_element + if next_event == 'end' and next_element.tag == element.tag: + # We reached the end of the list. + break + + if next_event != 'start': + raise DeserializationException( + "Expected a start element corresponding to an item, " + f"but got event {next_event!r} and element {next_element.tag!r}" + ) + + try: + item = _read_str_from_element_text( + next_element, + iterator + ) + except DeserializationException as exception: + exception.path._prepend(IndexSegment(next_element, item_i)) + raise + + result.append(item) + item_i += 1 + + self.strings = result + + def read_and_set_integers( + self, + element: Element, + iterator: Iterator[Tuple[str, Element]] + ) -> None: + """ + Read :paramref:`element` as the property + :py:attr:`.types.ListOfPrimitives.integers` and set it. + """ + if element.text is not None and len(element.text.strip()) != 0: + raise DeserializationException( + f"Expected only item elements and whitespace text, " + f"but got text: {element.text!r}" + ) + + result: List[ + PrimitiveType.INT + ] = [] + + item_i = 0 + + while True: + next_event_element = next(iterator, None) + if next_event_element is None: + raise DeserializationException( + "Expected one or more items from a list or the end element, " + "but got end-of-input" + ) + + next_event, next_element = next_event_element + if next_event == 'end' and next_element.tag == element.tag: + # We reached the end of the list. + break + + if next_event != 'start': + raise DeserializationException( + "Expected a start element corresponding to an item, " + f"but got event {next_event!r} and element {next_element.tag!r}" + ) + + try: + item = _read_int_from_element_text( + next_element, + iterator + ) + except DeserializationException as exception: + exception.path._prepend(IndexSegment(next_element, item_i)) + raise + + result.append(item) + item_i += 1 + + self.integers = result + + def read_and_set_booleans( + self, + element: Element, + iterator: Iterator[Tuple[str, Element]] + ) -> None: + """ + Read :paramref:`element` as the property + :py:attr:`.types.ListOfPrimitives.booleans` and set it. + """ + if element.text is not None and len(element.text.strip()) != 0: + raise DeserializationException( + f"Expected only item elements and whitespace text, " + f"but got text: {element.text!r}" + ) + + result: List[ + PrimitiveType.BOOL + ] = [] + + item_i = 0 + + while True: + next_event_element = next(iterator, None) + if next_event_element is None: + raise DeserializationException( + "Expected one or more items from a list or the end element, " + "but got end-of-input" + ) + + next_event, next_element = next_event_element + if next_event == 'end' and next_element.tag == element.tag: + # We reached the end of the list. + break + + if next_event != 'start': + raise DeserializationException( + "Expected a start element corresponding to an item, " + f"but got event {next_event!r} and element {next_element.tag!r}" + ) + + try: + item = _read_bool_from_element_text( + next_element, + iterator + ) + except DeserializationException as exception: + exception.path._prepend(IndexSegment(next_element, item_i)) + raise + + result.append(item) + item_i += 1 + + self.booleans = result + + +def _read_list_of_primitives_as_sequence( + element: Element, + iterator: Iterator[Tuple[str, Element]] +) -> aas_types.ListOfPrimitives: + """ + Read an instance of :py:class:`.types.ListOfPrimitives` + as a sequence of XML-encoded properties. + + The end element corresponding to the :paramref:`element` will be + read as well. + + :param element: start element, parent of the sequence + :param iterator: + Input stream of ``(event, element)`` coming from + :py:func:`xml.etree.ElementTree.iterparse` with the argument + ``events=["start", "end"]`` + :raise: :py:class:`DeserializationException` if unexpected input + :return: parsed instance + """ + if element.text is not None and len(element.text.strip()) != 0: + raise DeserializationException( + f"Expected only XML elements representing the properties and whitespace text, " + f"but got text: {element.text!r}" + ) + + _raise_if_has_tail_or_attrib(element) + + reader_and_setter = ( + _ReaderAndSetterForListOfPrimitives() + ) + + while True: + next_event_element = next(iterator, None) + if next_event_element is None: + raise DeserializationException( + "Expected one or more XML-encoded properties or the end element, " + "but got the end-of-input" + ) + + next_event, next_element = next_event_element + if next_event == 'end' and next_element.tag == element.tag: + # We reached the end element enclosing the sequence. + break + + if next_event != 'start': + raise DeserializationException( + "Expected a start element corresponding to a property, " + f"but got event {next_event!r} and element {next_element.tag!r}" + ) + + try: + tag_wo_ns = _parse_element_tag(next_element) + except DeserializationException as exception: + exception.path._prepend(ElementSegment(next_element)) + raise + + read_and_set_method = _READ_AND_SET_DISPATCH_FOR_LIST_OF_PRIMITIVES.get( + tag_wo_ns, + None + ) + if read_and_set_method is None: + an_exception = DeserializationException( + f"Expected an element representing a property, " + f"but got an element with unexpected tag: {tag_wo_ns!r}" + ) + an_exception.path._prepend(ElementSegment(next_element)) + raise an_exception + + try: + read_and_set_method( + reader_and_setter, + next_element, + iterator + ) + except DeserializationException as exception: + exception.path._prepend(ElementSegment(next_element)) + raise + + if reader_and_setter.strings is None: + raise DeserializationException( + "The required property 'strings' is missing" + ) + + if reader_and_setter.integers is None: + raise DeserializationException( + "The required property 'integers' is missing" + ) + + if reader_and_setter.booleans is None: + raise DeserializationException( + "The required property 'booleans' is missing" + ) + + return aas_types.ListOfPrimitives( + reader_and_setter.strings, + reader_and_setter.integers, + reader_and_setter.booleans + ) + + +def _read_list_of_primitives_as_element( + element: Element, + iterator: Iterator[Tuple[str, Element]] +) -> aas_types.ListOfPrimitives: + """ + Read an instance of :py:class:`.types.ListOfPrimitives` from + :paramref:`iterator`, including the end element. + + :param element: start element + :param iterator: + Input stream of ``(event, element)`` coming from + :py:func:`xml.etree.ElementTree.iterparse` with the argument + ``events=["start", "end"]`` + :raise: :py:class:`DeserializationException` if unexpected input + :return: parsed instance + """ + tag_wo_ns = _parse_element_tag(element) + + if tag_wo_ns != 'listOfPrimitives': + raise DeserializationException( + f"Expected the element with the tag 'listOfPrimitives', " + f"but got tag: {tag_wo_ns}" + ) + + return _read_list_of_primitives_as_sequence( + element, + iterator + ) + + +def _read_as_element( + element: Element, + iterator: Iterator[Tuple[str, Element]] +) -> aas_types.Class: + """ + Read an instance from :paramref:`iterator`, including the end element. + + :param element: start element + :param iterator: + Input stream of ``(event, element)`` coming from + :py:func:`xml.etree.ElementTree.iterparse` with the argument + ``events=["start", "end"]`` + :raise: :py:class:`DeserializationException` if unexpected input + :return: parsed instance + """ + tag_wo_ns = _parse_element_tag(element) + read_as_sequence = _GENERAL_DISPATCH.get( + tag_wo_ns, + None + ) + + if read_as_sequence is None: + raise DeserializationException( + f"Expected the element tag to be a valid model type " + f"of a concrete instance, " + f"but got tag {tag_wo_ns!r}" + ) + + return read_as_sequence( + element, + iterator + ) + + +#: Dispatch XML property name to read & set method in +#: :py:class:`_ReaderAndSetterForListOfPrimitives` +_READ_AND_SET_DISPATCH_FOR_LIST_OF_PRIMITIVES: Mapping[ + str, + Callable[ + [ + _ReaderAndSetterForListOfPrimitives, + Element, + Iterator[Tuple[str, Element]] + ], + None + ] +] = { + 'strings': + _ReaderAndSetterForListOfPrimitives.read_and_set_strings, + 'integers': + _ReaderAndSetterForListOfPrimitives.read_and_set_integers, + 'booleans': + _ReaderAndSetterForListOfPrimitives.read_and_set_booleans, +} + + +#: Dispatch XML class names to read-as-sequence functions +#: corresponding to the concrete classes +_GENERAL_DISPATCH: Mapping[ + str, + Callable[ + [ + Element, + Iterator[Tuple[str, Element]] + ], + aas_types.Class + ] +] = { + 'listOfPrimitives': _read_list_of_primitives_as_sequence, +} + + +# endregion + + +# region Serialization + + +class _Serializer(aas_types.AbstractVisitor): + """Encode instances as XML and write them to :py:attr:`~stream`.""" + + #: Stream to be written to when we visit the instances + stream: Final[TextIO] + + #: Method pointer to be invoked for writing the start element with or without + #: specifying a namespace (depending on the state of the serializer) + _write_start_element: Callable[ + [str], + None + ] + + #: Method pointer to be invoked for writing an empty element with or without + #: specifying a namespace (depending on the state of the serializer) + _write_empty_element: Callable[ + [str], + None + ] + + # NOTE (mristin, 2022-10-14): + # The serialization procedure is quite rigid. We leverage the specifics of + # the serialization procedure to optimize the code a bit. + # + # Namely, we model the writing of the XML elements as a state machine. + # The namespace is only specified for the very first element. All the subsequent + # elements will *not* have the namespace specified. We implement that behavior by + # using pointers to methods, as Python treats the methods as first-class citizens. + # + # The ``_write_start_element`` will point to + # ``_write_first_start_element_with_namespace`` on the *first* invocation. + # Afterwards, it will be redirected to ``_write_start_element_without_namespace``. + # + # Analogously for ``_write_empty_element``. + # + # Please see the implementation for the details, but this should give you at least + # a rough overview. + + def _write_first_start_element_with_namespace( + self, + name: str + ) -> None: + """ + Write the start element with the tag name :paramref:`name` and specify + its namespace. + + The :py:attr:`~_write_start_element` is set to + :py:meth:`~_write_start_element_without_namespace` after the first invocation + of this method. + + :param name: of the element tag. Expected to contain no XML special characters. + """ + self.stream.write(f'<{name} xmlns="{NAMESPACE}">') + + # NOTE (mristin, 2022-10-14): + # Any subsequence call to `_write_start_element` or `_write_empty_element` + # should not specify the namespace of the element as we specified now already + # specified it. + self._write_start_element = self._write_start_element_without_namespace + self._write_empty_element = self._write_empty_element_without_namespace + + def _write_start_element_without_namespace( + self, + name: str + ) -> None: + """ + Write the start element with the tag name :paramref:`name`. + + The first element, written *before* this one, is expected to have been + already written with the namespace specified. + + :param name: of the element tag. Expected to contain no XML special characters. + """ + self.stream.write(f'<{name}>') + + def _escape_and_write_text( + self, + text: str + ) -> None: + """ + Escape :paramref:`text` for XML and write it. + + :param text: to be escaped and written + """ + # NOTE (mristin, 2022-10-14): + # We ran ``timeit`` on manual code which escaped XML special characters with + # a dictionary, and on another snippet which called three ``.replace()``. + # The code with ``.replace()`` was an order of magnitude faster on our computers. + self.stream.write( + text.replace('&', '&').replace('<', '<').replace('>', '>') + ) + + def _write_end_element( + self, + name: str + ) -> None: + """ + Write the end element with the tag name :paramref:`name`. + + :param name: of the element tag. Expected to contain no XML special characters. + """ + self.stream.write(f'') + + def _write_first_empty_element_with_namespace( + self, + name: str + ) -> None: + """ + Write the first (and only) empty element with the tag name :paramref:`name`. + + No elements are expected to be written to the stream afterwards. The element + includes the namespace specification. + + :param name: of the element tag. Expected to contain no XML special characters. + """ + self.stream.write(f'<{name} xmlns="{NAMESPACE}"/>') + self._write_empty_element = self._rase_if_write_element_called_again + self._write_start_element = self._rase_if_write_element_called_again + + def _rase_if_write_element_called_again( + self, + name: str + ) -> None: + raise AssertionError( + f"We expected to call ``_write_first_empty_element_with_namespace`` " + f"only once. This is an unexpected second call for writing " + f"an (empty or non-empty) element with the tag name: {name!r}" + ) + + def _write_empty_element_without_namespace( + self, + name: str + ) -> None: + """ + Write the empty element with the tag name :paramref:`name`. + + The call to this method is expected to occur *after* the enclosing element with + a specified namespace has been written. + + :param name: of the element tag. Expected to contain no XML special characters. + """ + self.stream.write(f'<{name}/>') + + def _write_bool_property( + self, + name: str, + value: bool + ) -> None: + """ + Write the :paramref:`value` of a boolean property enclosed in + the :paramref:`name` element. + + :param name: of the corresponding element tag + :param value: of the property + """ + self._write_start_element(name) + self.stream.write('true' if value else 'false') + self._write_end_element(name) + + def _write_int_property( + self, + name: str, + value: int + ) -> None: + """ + Write the :paramref:`value` of an integer property enclosed in + the :paramref:`name` element. + + :param name: of the corresponding element tag + :param value: of the property + """ + self._write_start_element(name) + self.stream.write(str(value)) + self._write_end_element(name) + + def _write_float_property( + self, + name: str, + value: float + ) -> None: + """ + Write the :paramref:`value` of a floating-point property enclosed in + the :paramref:`name` element. + + :param name: of the corresponding element tag + :param value: of the property + """ + self._write_start_element(name) + + if value == math.inf: + self.stream.write('INF') + elif value == -math.inf: + self.stream.write('-INF') + elif math.isnan(value): + self.stream.write('NaN') + elif value == 0: + if math.copysign(1.0, value) < 0.0: + self.stream.write('-0.0') + else: + self.stream.write('0.0') + else: + self.stream.write(str(value)) + + def _write_str_property( + self, + name: str, + value: str + ) -> None: + """ + Write the :paramref:`value` of a string property enclosed in + the :paramref:`name` element. + + :param name: of the corresponding element tag + :param value: of the property + """ + self._write_start_element(name) + self._escape_and_write_text(value) + self._write_end_element(name) + + def _write_bytes_property( + self, + name: str, + value: bytes + ) -> None: + """ + Write the :paramref:`value` of a binary-content property enclosed in + the :paramref:`name` element. + + :param name: of the corresponding element tag + :param value: of the property + """ + self._write_start_element(name) + + # NOTE (mristin, 2022-10-14): + # We need to decode the result of the base64-encoding to ASCII since we are + # writing to an XML *text* stream. ``base64.b64encode(.)`` gives us bytes, + # not a string. + encoded = base64.b64encode(value).decode('ascii') + + # NOTE (mristin, 2022-10-14): + # Base64 alphabet excludes ``<``, ``>`` and ``&``, so we can directly + # write the ``encoded`` content to the stream as XML text. + # + # See: https://datatracker.ietf.org/doc/html/rfc4648#section-4 + self.stream.write(encoded) + self._write_end_element(name) + + def __init__( + self, + stream: TextIO + ) -> None: + """ + Initialize the visitor to write to :paramref:`stream`. + + The first element will include the :py:attr:`~.NAMESPACE`. Every other + element will not have the namespace specified. + + :param stream: where to write to + """ + self.stream = stream + self._write_start_element = ( + self._write_first_start_element_with_namespace + ) + self._write_empty_element = ( + self._write_first_empty_element_with_namespace + ) + + def _write_list_of_primitives_as_sequence( + self, + that: aas_types.ListOfPrimitives + ) -> None: + """ + Serialize :paramref:`that` to :py:attr:`~stream` as a sequence of + XML elements. + + Each element in the sequence corresponds to a property. If no properties + are set, nothing is written to the :py:attr:`~stream`. + + :param that: instance to be serialized + """ + if len(that.strings) == 0: + self._write_empty_element('strings') + else: + self._write_start_element('strings') + for an_item in that.strings: + self.visit(an_item) + self._write_end_element('strings') + + if len(that.integers) == 0: + self._write_empty_element('integers') + else: + self._write_start_element('integers') + for another_item in that.integers: + self.visit(another_item) + self._write_end_element('integers') + + if len(that.booleans) == 0: + self._write_empty_element('booleans') + else: + self._write_start_element('booleans') + for yet_another_item in that.booleans: + self.visit(yet_another_item) + self._write_end_element('booleans') + + def visit_list_of_primitives( + self, + that: aas_types.ListOfPrimitives + ) -> None: + """ + Serialize :paramref:`that` to :py:attr:`~stream` as an XML element. + + The enclosing XML element designates the class of the instance, where its + children correspond to the properties of the instance. + + :param that: instance to be serialized + """ + self._write_start_element('listOfPrimitives') + self._write_list_of_primitives_as_sequence( + that + ) + self._write_end_element('listOfPrimitives') + + +def write(instance: aas_types.Class, stream: TextIO) -> None: + """ + Write the XML representation of :paramref:`instance` to :paramref:`stream`. + + Example usage: + + .. code-block:: + + import pathlib + + import test.types as aas_types + import test.xmlization as aas_xmlization + + instance = ListOfPrimitives( + ... # some constructor arguments + ) + + pth = pathlib.Path(...) + with pth.open("wt") as fid: + aas_xmlization.write(instance, fid) + + :param instance: to be serialized + :param stream: to write to + """ + serializer = _Serializer(stream) + serializer.visit(instance) + + +def to_str(that: aas_types.Class) -> str: + """ + Serialize :paramref:`that` to an XML-encoded text. + + :param that: instance to be serialized + :return: :paramref:`that` serialized to XML serialized to text + """ + writer = io.StringIO() + write(that, writer) + return writer.getvalue() + + +# endregion diff --git a/test_data/python/test_main/list_of_primitives/input/snippets/qualified_module_name.txt b/test_data/python/test_main/list_of_primitives/input/snippets/qualified_module_name.txt new file mode 100644 index 000000000..9daeafb98 --- /dev/null +++ b/test_data/python/test_main/list_of_primitives/input/snippets/qualified_module_name.txt @@ -0,0 +1 @@ +test diff --git a/test_data/python/test_main/list_of_primitives/meta_model.py b/test_data/python/test_main/list_of_primitives/meta_model.py new file mode 100644 index 000000000..531303f43 --- /dev/null +++ b/test_data/python/test_main/list_of_primitives/meta_model.py @@ -0,0 +1,18 @@ +from typing import List + + +class List_of_primitives: + strings: List[str] + integers: List[int] + booleans: List[bool] + + def __init__( + self, strings: List[str], integers: List[int], booleans: List[bool] + ) -> None: + self.strings = strings + self.integers = integers + self.booleans = booleans + + +__version__ = "dummy" +__xml_namespace__ = "https://dummy.com" diff --git a/tests/python/test_main.py b/tests/python/test_main.py index 6030f7a6b..07bc80ee1 100644 --- a/tests/python/test_main.py +++ b/tests/python/test_main.py @@ -15,26 +15,29 @@ class Test_against_recorded(unittest.TestCase): - def test_cases(self) -> None: - repo_dir = pathlib.Path(os.path.realpath(__file__)).parent.parent.parent - - parent_case_dir = repo_dir / "test_data" / "python" / "test_main" - assert parent_case_dir.exists() and parent_case_dir.is_dir(), parent_case_dir - - for module in [aas_core_meta.v3]: - case_dir = parent_case_dir / module.__name__ - assert case_dir.is_dir(), case_dir - - assert ( - module.__file__ is not None - ), f"Expected the module {module!r} to have a __file__, but it has None" - model_pth = pathlib.Path(module.__file__) - assert model_pth.exists() and model_pth.is_file(), model_pth - - snippets_dir = case_dir / "input/snippets" + _REPO_DIR = pathlib.Path(os.path.realpath(__file__)).parent.parent.parent + PARENT_CASE_DIR = _REPO_DIR / "test_data" / "python" / "test_main" + + def test_against_meta_models(self) -> None: + assert ( + Test_against_recorded.PARENT_CASE_DIR.exists() + and Test_against_recorded.PARENT_CASE_DIR.is_dir() + ), f"{Test_against_recorded.PARENT_CASE_DIR=}" + + # fmt: off + test_cases = ( + tests.common.find_meta_models_in_parent_directory_of_test_cases_and_modules( + parent_case_dir=Test_against_recorded.PARENT_CASE_DIR, + aas_core_meta_modules=[aas_core_meta.v3] + ) + ) + # fmt: on + + for test_case in test_cases: + snippets_dir = test_case.case_dir / "input/snippets" assert snippets_dir.exists() and snippets_dir.is_dir(), snippets_dir - expected_output_dir = case_dir / "expected_output" + expected_output_dir = test_case.case_dir / "expected_output" with contextlib.ExitStack() as exit_stack: if tests.common.RERECORD: @@ -51,7 +54,7 @@ def test_cases(self) -> None: output_dir = pathlib.Path(tmp_dir.name) params = aas_core_codegen.main.Parameters( - model_path=model_pth, + model_path=test_case.model_path, target=aas_core_codegen.main.Target.PYTHON, snippets_dir=snippets_dir, output_dir=output_dir, @@ -105,27 +108,14 @@ def test_cases(self) -> None: f"The output file is missing: {output_pth}" ) - try: - output = output_pth.read_text(encoding="utf-8") - except Exception as exception: - raise RuntimeError( - f"Failed to read the output from {output_pth}" - ) from exception - if tests.common.RERECORD: - expected_pth.write_text(output, encoding="utf-8") + expected_pth.write_text( + output_pth.read_text(encoding="utf-8"), encoding="utf-8" + ) else: - try: - expected_output = expected_pth.read_text(encoding="utf-8") - except Exception as exception: - raise RuntimeError( - f"Failed to read the expected output " - f"from {expected_pth}" - ) from exception - self.assertEqual( - expected_output, - output, + expected_pth.read_text(encoding="utf-8"), + output_pth.read_text(encoding="utf-8"), f"The files {expected_pth} and {output_pth} do not match.", ) From 2285a6613756d47e914e6b341410912ce58b1c68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Otto?= Date: Thu, 20 Feb 2025 14:01:12 +0100 Subject: [PATCH 09/14] Code formatting --- aas_core_codegen/cpp/xmlization/_generate.py | 16 ++++++++-------- aas_core_codegen/xsd/main.py | 6 ++---- .../test_main/list_of_primitives/meta_model.py | 4 ++++ 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/aas_core_codegen/cpp/xmlization/_generate.py b/aas_core_codegen/cpp/xmlization/_generate.py index 09adf6160..06c3aae74 100644 --- a/aas_core_codegen/cpp/xmlization/_generate.py +++ b/aas_core_codegen/cpp/xmlization/_generate.py @@ -3009,6 +3009,14 @@ def _generate_deserialize_instance_property( False, ) +_PRIMITIVE_TYPE_TO_NATIVE_TYPE = { + intermediate.PrimitiveType.BOOL: "bool", + intermediate.PrimitiveType.INT: "int64_t", + intermediate.PrimitiveType.FLOAT: "double", + intermediate.PrimitiveType.STR: "std::wstring", + intermediate.PrimitiveType.BYTEARRAY: "std::vector", +} + def _generate_deserialize_list_property( prop: intermediate.Property, @@ -4424,14 +4432,6 @@ class SelfClosingWriter {{ primitive_type in _PRIMITIVE_TYPE_TO_SERIALIZE for primitive_type in intermediate.PrimitiveType ) - -_PRIMITIVE_TYPE_TO_NATIVE_TYPE = { - intermediate.PrimitiveType.BOOL: "bool", - intermediate.PrimitiveType.INT: "int64_t", - intermediate.PrimitiveType.FLOAT: "double", - intermediate.PrimitiveType.STR: "std::wstring", - intermediate.PrimitiveType.BYTEARRAY: "std::vector", -} assert all( primitive_type in _PRIMITIVE_TYPE_TO_NATIVE_TYPE for primitive_type in intermediate.PrimitiveType diff --git a/aas_core_codegen/xsd/main.py b/aas_core_codegen/xsd/main.py index 596eeefca..31f4c84dc 100644 --- a/aas_core_codegen/xsd/main.py +++ b/aas_core_codegen/xsd/main.py @@ -477,7 +477,7 @@ def _generate_xs_element_for_a_list_property( "xs:element", { "name": "v", - "type": _PRIMITIVE_MAP[type_anno.items.a_type], + "type": _PRIMITIVE_MAP[type_anno.items.a_type], "minOccurs": min_occurs, "maxOccurs": max_occurs, }, @@ -488,9 +488,7 @@ def _generate_xs_element_for_a_list_property( xs_complex_type = ET.Element("xs:complexType") xs_complex_type.append(xs_sequence) - xs_element = ET.Element( - "xs:element", {"name": naming.xml_property(prop.name)} - ) + xs_element = ET.Element("xs:element", {"name": naming.xml_property(prop.name)}) xs_element.append(xs_complex_type) else: return None, Error( diff --git a/test_data/xsd/test_main/list_of_primitives/meta_model.py b/test_data/xsd/test_main/list_of_primitives/meta_model.py index 7de018dd8..fcb55f653 100644 --- a/test_data/xsd/test_main/list_of_primitives/meta_model.py +++ b/test_data/xsd/test_main/list_of_primitives/meta_model.py @@ -1,20 +1,24 @@ from typing import List from icontract import DBC + class Value_data_type(str, DBC): """ any XSD simple type as specified via :class:`Data_type_def_XSD` """ + class Data_type_def_XSD(Enum): """ Enumeration listing all XSD anySimpleTypes """ + Boolean = "xs:boolean" Date = "xs:date" Integer = "xs:integer" String = "xs:string" + class My_class: pass From 5f0e27962e5c6f928fed9ca32ab8dd9195f15243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Otto?= Date: Thu, 20 Feb 2025 14:01:12 +0100 Subject: [PATCH 10/14] Code formatting --- aas_core_codegen/cpp/xmlization/_generate.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/aas_core_codegen/cpp/xmlization/_generate.py b/aas_core_codegen/cpp/xmlization/_generate.py index 06c3aae74..738dc85b9 100644 --- a/aas_core_codegen/cpp/xmlization/_generate.py +++ b/aas_core_codegen/cpp/xmlization/_generate.py @@ -3018,6 +3018,15 @@ def _generate_deserialize_instance_property( } +_PRIMITIVE_TYPE_TO_NATIVE_TYPE = { + intermediate.PrimitiveType.BOOL: "bool", + intermediate.PrimitiveType.INT: "int64_t", + intermediate.PrimitiveType.FLOAT: "double", + intermediate.PrimitiveType.STR: "std::wstring", + intermediate.PrimitiveType.BYTEARRAY: "std::vector", +} + + def _generate_deserialize_list_property( prop: intermediate.Property, ) -> Tuple[Stripped, bool]: From cd317a4dc2e040527e36f9b9111f0bb8efcc4f21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Otto?= Date: Thu, 20 Feb 2025 14:30:13 +0100 Subject: [PATCH 11/14] Support typescript --- .../typescript/jsonization/_generate.py | 22 +- .../typescript/verification/_generate.py | 5 +- .../expected_output/jsonization.ts | 248 +++--- .../expected_output/common.ts | 374 +++++++++ .../expected_output/constants.ts | 15 + .../expected_output/jsonization.ts | 757 ++++++++++++++++++ .../expected_output/stdout.txt | 1 + .../expected_output/stringification.ts | 81 ++ .../expected_output/types.ts | 724 +++++++++++++++++ .../expected_output/verification.ts | 231 ++++++ .../input/snippets/package_identifier.txt | 1 + .../list_of_primitives/meta_model.py | 22 + tests/typescript/test_main.py | 64 +- 13 files changed, 2371 insertions(+), 174 deletions(-) create mode 100644 test_data/typescript/test_main/list_of_primitives/expected_output/common.ts create mode 100644 test_data/typescript/test_main/list_of_primitives/expected_output/constants.ts create mode 100644 test_data/typescript/test_main/list_of_primitives/expected_output/jsonization.ts create mode 100644 test_data/typescript/test_main/list_of_primitives/expected_output/stdout.txt create mode 100644 test_data/typescript/test_main/list_of_primitives/expected_output/stringification.ts create mode 100644 test_data/typescript/test_main/list_of_primitives/expected_output/types.ts create mode 100644 test_data/typescript/test_main/list_of_primitives/expected_output/verification.ts create mode 100644 test_data/typescript/test_main/list_of_primitives/input/snippets/package_identifier.txt create mode 100644 test_data/typescript/test_main/list_of_primitives/meta_model.py diff --git a/aas_core_codegen/typescript/jsonization/_generate.py b/aas_core_codegen/typescript/jsonization/_generate.py index 4c50edb43..a55be668b 100644 --- a/aas_core_codegen/typescript/jsonization/_generate.py +++ b/aas_core_codegen/typescript/jsonization/_generate.py @@ -1102,23 +1102,21 @@ def _generate_transform(cls: intermediate.ConcreteClass) -> Stripped: ) elif isinstance(type_anno, intermediate.ListTypeAnnotation): - assert isinstance( - type_anno.items, - (intermediate.PrimitiveType, intermediate.OurTypeAnnotation), - ), ( - "We expect only lists of primitive and our types. Lists of optionals " - "and nested lists are not handled yet. Please contact the developers." - ) - - transformation_expression = _generate_transform_atomic_value( - access_expression=Stripped("item"), type_anno=type_anno.items - ) + if isinstance(type_anno.items, intermediate.PrimitiveTypeAnnotation): + transformation_expression = f"{_PARSE_FUNCTION_BY_PRIMITIVE_TYPE[type_anno.items.a_type]}(item).mustValue()" + elif isinstance(type_anno.items, intermediate.OurTypeAnnotation): + transformation_expression = _generate_transform_atomic_value( + access_expression=Stripped("item"), type_anno=type_anno.items + ) + else: + assert_never(type_anno) + raise AssertionError("Unexpected code path") var_name = typescript_naming.variable_name(Identifier(f"{prop.name}_array")) block = Stripped( f"""\ -const {var_name} = new Array(); +const {var_name} = new Array(); for (const item of that.{prop_name}) {{ {I}{var_name}.push( {II}{indent_but_first_line(transformation_expression, II)} diff --git a/aas_core_codegen/typescript/verification/_generate.py b/aas_core_codegen/typescript/verification/_generate.py index c55442e41..92b782680 100644 --- a/aas_core_codegen/typescript/verification/_generate.py +++ b/aas_core_codegen/typescript/verification/_generate.py @@ -856,7 +856,10 @@ def _generate_verify_property_snippet( assert_never(type_anno.our_type) elif isinstance(type_anno, intermediate.ListTypeAnnotation): - assert isinstance(type_anno.items, intermediate.OurTypeAnnotation), ( + assert isinstance( + type_anno.items, + (intermediate.OurTypeAnnotation, intermediate.PrimitiveTypeAnnotation), + ), ( "We chose to implement only a very limited pattern matching; " "see the note above in the code." ) diff --git a/test_data/typescript/test_main/aas_core_meta.v3/expected_output/jsonization.ts b/test_data/typescript/test_main/aas_core_meta.v3/expected_output/jsonization.ts index d83810d09..8632038d7 100644 --- a/test_data/typescript/test_main/aas_core_meta.v3/expected_output/jsonization.ts +++ b/test_data/typescript/test_main/aas_core_meta.v3/expected_output/jsonization.ts @@ -18281,7 +18281,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.supplementalSemanticIds !== null) { - const supplementalSemanticIdsArray = new Array(); + const supplementalSemanticIdsArray = new Array(); for (const item of that.supplementalSemanticIds) { supplementalSemanticIdsArray.push( this.transform(item) @@ -18306,7 +18306,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.refersTo !== null) { - const refersToArray = new Array(); + const refersToArray = new Array(); for (const item of that.refersTo) { refersToArray.push( this.transform(item) @@ -18330,7 +18330,7 @@ class Serializer extends AasTypes.AbstractTransformer { const jsonable: JsonObject = {}; if (that.embeddedDataSpecifications !== null) { - const embeddedDataSpecificationsArray = new Array(); + const embeddedDataSpecificationsArray = new Array(); for (const item of that.embeddedDataSpecifications) { embeddedDataSpecificationsArray.push( this.transform(item) @@ -18379,7 +18379,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.supplementalSemanticIds !== null) { - const supplementalSemanticIdsArray = new Array(); + const supplementalSemanticIdsArray = new Array(); for (const item of that.supplementalSemanticIds) { supplementalSemanticIdsArray.push( this.transform(item) @@ -18428,7 +18428,7 @@ class Serializer extends AasTypes.AbstractTransformer { const jsonable: JsonObject = {}; if (that.extensions !== null) { - const extensionsArray = new Array(); + const extensionsArray = new Array(); for (const item of that.extensions) { extensionsArray.push( this.transform(item) @@ -18448,7 +18448,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.displayName !== null) { - const displayNameArray = new Array(); + const displayNameArray = new Array(); for (const item of that.displayName) { displayNameArray.push( this.transform(item) @@ -18458,7 +18458,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.description !== null) { - const descriptionArray = new Array(); + const descriptionArray = new Array(); for (const item of that.description) { descriptionArray.push( this.transform(item) @@ -18476,7 +18476,7 @@ class Serializer extends AasTypes.AbstractTransformer { that.id; if (that.embeddedDataSpecifications !== null) { - const embeddedDataSpecificationsArray = new Array(); + const embeddedDataSpecificationsArray = new Array(); for (const item of that.embeddedDataSpecifications) { embeddedDataSpecificationsArray.push( this.transform(item) @@ -18494,7 +18494,7 @@ class Serializer extends AasTypes.AbstractTransformer { this.transform(that.assetInformation); if (that.submodels !== null) { - const submodelsArray = new Array(); + const submodelsArray = new Array(); for (const item of that.submodels) { submodelsArray.push( this.transform(item) @@ -18530,7 +18530,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.specificAssetIds !== null) { - const specificAssetIdsArray = new Array(); + const specificAssetIdsArray = new Array(); for (const item of that.specificAssetIds) { specificAssetIdsArray.push( this.transform(item) @@ -18591,7 +18591,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.supplementalSemanticIds !== null) { - const supplementalSemanticIdsArray = new Array(); + const supplementalSemanticIdsArray = new Array(); for (const item of that.supplementalSemanticIds) { supplementalSemanticIdsArray.push( this.transform(item) @@ -18626,7 +18626,7 @@ class Serializer extends AasTypes.AbstractTransformer { const jsonable: JsonObject = {}; if (that.extensions !== null) { - const extensionsArray = new Array(); + const extensionsArray = new Array(); for (const item of that.extensions) { extensionsArray.push( this.transform(item) @@ -18646,7 +18646,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.displayName !== null) { - const displayNameArray = new Array(); + const displayNameArray = new Array(); for (const item of that.displayName) { displayNameArray.push( this.transform(item) @@ -18656,7 +18656,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.description !== null) { - const descriptionArray = new Array(); + const descriptionArray = new Array(); for (const item of that.description) { descriptionArray.push( this.transform(item) @@ -18686,7 +18686,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.supplementalSemanticIds !== null) { - const supplementalSemanticIdsArray = new Array(); + const supplementalSemanticIdsArray = new Array(); for (const item of that.supplementalSemanticIds) { supplementalSemanticIdsArray.push( this.transform(item) @@ -18696,7 +18696,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.qualifiers !== null) { - const qualifiersArray = new Array(); + const qualifiersArray = new Array(); for (const item of that.qualifiers) { qualifiersArray.push( this.transform(item) @@ -18706,7 +18706,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.embeddedDataSpecifications !== null) { - const embeddedDataSpecificationsArray = new Array(); + const embeddedDataSpecificationsArray = new Array(); for (const item of that.embeddedDataSpecifications) { embeddedDataSpecificationsArray.push( this.transform(item) @@ -18716,7 +18716,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.submodelElements !== null) { - const submodelElementsArray = new Array(); + const submodelElementsArray = new Array(); for (const item of that.submodelElements) { submodelElementsArray.push( this.transform(item) @@ -18742,7 +18742,7 @@ class Serializer extends AasTypes.AbstractTransformer { const jsonable: JsonObject = {}; if (that.extensions !== null) { - const extensionsArray = new Array(); + const extensionsArray = new Array(); for (const item of that.extensions) { extensionsArray.push( this.transform(item) @@ -18762,7 +18762,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.displayName !== null) { - const displayNameArray = new Array(); + const displayNameArray = new Array(); for (const item of that.displayName) { displayNameArray.push( this.transform(item) @@ -18772,7 +18772,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.description !== null) { - const descriptionArray = new Array(); + const descriptionArray = new Array(); for (const item of that.description) { descriptionArray.push( this.transform(item) @@ -18787,7 +18787,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.supplementalSemanticIds !== null) { - const supplementalSemanticIdsArray = new Array(); + const supplementalSemanticIdsArray = new Array(); for (const item of that.supplementalSemanticIds) { supplementalSemanticIdsArray.push( this.transform(item) @@ -18797,7 +18797,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.qualifiers !== null) { - const qualifiersArray = new Array(); + const qualifiersArray = new Array(); for (const item of that.qualifiers) { qualifiersArray.push( this.transform(item) @@ -18807,7 +18807,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.embeddedDataSpecifications !== null) { - const embeddedDataSpecificationsArray = new Array(); + const embeddedDataSpecificationsArray = new Array(); for (const item of that.embeddedDataSpecifications) { embeddedDataSpecificationsArray.push( this.transform(item) @@ -18839,7 +18839,7 @@ class Serializer extends AasTypes.AbstractTransformer { const jsonable: JsonObject = {}; if (that.extensions !== null) { - const extensionsArray = new Array(); + const extensionsArray = new Array(); for (const item of that.extensions) { extensionsArray.push( this.transform(item) @@ -18859,7 +18859,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.displayName !== null) { - const displayNameArray = new Array(); + const displayNameArray = new Array(); for (const item of that.displayName) { displayNameArray.push( this.transform(item) @@ -18869,7 +18869,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.description !== null) { - const descriptionArray = new Array(); + const descriptionArray = new Array(); for (const item of that.description) { descriptionArray.push( this.transform(item) @@ -18884,7 +18884,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.supplementalSemanticIds !== null) { - const supplementalSemanticIdsArray = new Array(); + const supplementalSemanticIdsArray = new Array(); for (const item of that.supplementalSemanticIds) { supplementalSemanticIdsArray.push( this.transform(item) @@ -18894,7 +18894,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.qualifiers !== null) { - const qualifiersArray = new Array(); + const qualifiersArray = new Array(); for (const item of that.qualifiers) { qualifiersArray.push( this.transform(item) @@ -18904,7 +18904,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.embeddedDataSpecifications !== null) { - const embeddedDataSpecificationsArray = new Array(); + const embeddedDataSpecificationsArray = new Array(); for (const item of that.embeddedDataSpecifications) { embeddedDataSpecificationsArray.push( this.transform(item) @@ -18936,7 +18936,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.value !== null) { - const valueArray = new Array(); + const valueArray = new Array(); for (const item of that.value) { valueArray.push( this.transform(item) @@ -18962,7 +18962,7 @@ class Serializer extends AasTypes.AbstractTransformer { const jsonable: JsonObject = {}; if (that.extensions !== null) { - const extensionsArray = new Array(); + const extensionsArray = new Array(); for (const item of that.extensions) { extensionsArray.push( this.transform(item) @@ -18982,7 +18982,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.displayName !== null) { - const displayNameArray = new Array(); + const displayNameArray = new Array(); for (const item of that.displayName) { displayNameArray.push( this.transform(item) @@ -18992,7 +18992,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.description !== null) { - const descriptionArray = new Array(); + const descriptionArray = new Array(); for (const item of that.description) { descriptionArray.push( this.transform(item) @@ -19007,7 +19007,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.supplementalSemanticIds !== null) { - const supplementalSemanticIdsArray = new Array(); + const supplementalSemanticIdsArray = new Array(); for (const item of that.supplementalSemanticIds) { supplementalSemanticIdsArray.push( this.transform(item) @@ -19017,7 +19017,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.qualifiers !== null) { - const qualifiersArray = new Array(); + const qualifiersArray = new Array(); for (const item of that.qualifiers) { qualifiersArray.push( this.transform(item) @@ -19027,7 +19027,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.embeddedDataSpecifications !== null) { - const embeddedDataSpecificationsArray = new Array(); + const embeddedDataSpecificationsArray = new Array(); for (const item of that.embeddedDataSpecifications) { embeddedDataSpecificationsArray.push( this.transform(item) @@ -19037,7 +19037,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.value !== null) { - const valueArray = new Array(); + const valueArray = new Array(); for (const item of that.value) { valueArray.push( this.transform(item) @@ -19063,7 +19063,7 @@ class Serializer extends AasTypes.AbstractTransformer { const jsonable: JsonObject = {}; if (that.extensions !== null) { - const extensionsArray = new Array(); + const extensionsArray = new Array(); for (const item of that.extensions) { extensionsArray.push( this.transform(item) @@ -19083,7 +19083,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.displayName !== null) { - const displayNameArray = new Array(); + const displayNameArray = new Array(); for (const item of that.displayName) { displayNameArray.push( this.transform(item) @@ -19093,7 +19093,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.description !== null) { - const descriptionArray = new Array(); + const descriptionArray = new Array(); for (const item of that.description) { descriptionArray.push( this.transform(item) @@ -19108,7 +19108,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.supplementalSemanticIds !== null) { - const supplementalSemanticIdsArray = new Array(); + const supplementalSemanticIdsArray = new Array(); for (const item of that.supplementalSemanticIds) { supplementalSemanticIdsArray.push( this.transform(item) @@ -19118,7 +19118,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.qualifiers !== null) { - const qualifiersArray = new Array(); + const qualifiersArray = new Array(); for (const item of that.qualifiers) { qualifiersArray.push( this.transform(item) @@ -19128,7 +19128,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.embeddedDataSpecifications !== null) { - const embeddedDataSpecificationsArray = new Array(); + const embeddedDataSpecificationsArray = new Array(); for (const item of that.embeddedDataSpecifications) { embeddedDataSpecificationsArray.push( this.transform(item) @@ -19169,7 +19169,7 @@ class Serializer extends AasTypes.AbstractTransformer { const jsonable: JsonObject = {}; if (that.extensions !== null) { - const extensionsArray = new Array(); + const extensionsArray = new Array(); for (const item of that.extensions) { extensionsArray.push( this.transform(item) @@ -19189,7 +19189,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.displayName !== null) { - const displayNameArray = new Array(); + const displayNameArray = new Array(); for (const item of that.displayName) { displayNameArray.push( this.transform(item) @@ -19199,7 +19199,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.description !== null) { - const descriptionArray = new Array(); + const descriptionArray = new Array(); for (const item of that.description) { descriptionArray.push( this.transform(item) @@ -19214,7 +19214,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.supplementalSemanticIds !== null) { - const supplementalSemanticIdsArray = new Array(); + const supplementalSemanticIdsArray = new Array(); for (const item of that.supplementalSemanticIds) { supplementalSemanticIdsArray.push( this.transform(item) @@ -19224,7 +19224,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.qualifiers !== null) { - const qualifiersArray = new Array(); + const qualifiersArray = new Array(); for (const item of that.qualifiers) { qualifiersArray.push( this.transform(item) @@ -19234,7 +19234,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.embeddedDataSpecifications !== null) { - const embeddedDataSpecificationsArray = new Array(); + const embeddedDataSpecificationsArray = new Array(); for (const item of that.embeddedDataSpecifications) { embeddedDataSpecificationsArray.push( this.transform(item) @@ -19244,7 +19244,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.value !== null) { - const valueArray = new Array(); + const valueArray = new Array(); for (const item of that.value) { valueArray.push( this.transform(item) @@ -19275,7 +19275,7 @@ class Serializer extends AasTypes.AbstractTransformer { const jsonable: JsonObject = {}; if (that.extensions !== null) { - const extensionsArray = new Array(); + const extensionsArray = new Array(); for (const item of that.extensions) { extensionsArray.push( this.transform(item) @@ -19295,7 +19295,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.displayName !== null) { - const displayNameArray = new Array(); + const displayNameArray = new Array(); for (const item of that.displayName) { displayNameArray.push( this.transform(item) @@ -19305,7 +19305,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.description !== null) { - const descriptionArray = new Array(); + const descriptionArray = new Array(); for (const item of that.description) { descriptionArray.push( this.transform(item) @@ -19320,7 +19320,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.supplementalSemanticIds !== null) { - const supplementalSemanticIdsArray = new Array(); + const supplementalSemanticIdsArray = new Array(); for (const item of that.supplementalSemanticIds) { supplementalSemanticIdsArray.push( this.transform(item) @@ -19330,7 +19330,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.qualifiers !== null) { - const qualifiersArray = new Array(); + const qualifiersArray = new Array(); for (const item of that.qualifiers) { qualifiersArray.push( this.transform(item) @@ -19340,7 +19340,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.embeddedDataSpecifications !== null) { - const embeddedDataSpecificationsArray = new Array(); + const embeddedDataSpecificationsArray = new Array(); for (const item of that.embeddedDataSpecifications) { embeddedDataSpecificationsArray.push( this.transform(item) @@ -19381,7 +19381,7 @@ class Serializer extends AasTypes.AbstractTransformer { const jsonable: JsonObject = {}; if (that.extensions !== null) { - const extensionsArray = new Array(); + const extensionsArray = new Array(); for (const item of that.extensions) { extensionsArray.push( this.transform(item) @@ -19401,7 +19401,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.displayName !== null) { - const displayNameArray = new Array(); + const displayNameArray = new Array(); for (const item of that.displayName) { displayNameArray.push( this.transform(item) @@ -19411,7 +19411,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.description !== null) { - const descriptionArray = new Array(); + const descriptionArray = new Array(); for (const item of that.description) { descriptionArray.push( this.transform(item) @@ -19426,7 +19426,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.supplementalSemanticIds !== null) { - const supplementalSemanticIdsArray = new Array(); + const supplementalSemanticIdsArray = new Array(); for (const item of that.supplementalSemanticIds) { supplementalSemanticIdsArray.push( this.transform(item) @@ -19436,7 +19436,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.qualifiers !== null) { - const qualifiersArray = new Array(); + const qualifiersArray = new Array(); for (const item of that.qualifiers) { qualifiersArray.push( this.transform(item) @@ -19446,7 +19446,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.embeddedDataSpecifications !== null) { - const embeddedDataSpecificationsArray = new Array(); + const embeddedDataSpecificationsArray = new Array(); for (const item of that.embeddedDataSpecifications) { embeddedDataSpecificationsArray.push( this.transform(item) @@ -19477,7 +19477,7 @@ class Serializer extends AasTypes.AbstractTransformer { const jsonable: JsonObject = {}; if (that.extensions !== null) { - const extensionsArray = new Array(); + const extensionsArray = new Array(); for (const item of that.extensions) { extensionsArray.push( this.transform(item) @@ -19497,7 +19497,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.displayName !== null) { - const displayNameArray = new Array(); + const displayNameArray = new Array(); for (const item of that.displayName) { displayNameArray.push( this.transform(item) @@ -19507,7 +19507,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.description !== null) { - const descriptionArray = new Array(); + const descriptionArray = new Array(); for (const item of that.description) { descriptionArray.push( this.transform(item) @@ -19522,7 +19522,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.supplementalSemanticIds !== null) { - const supplementalSemanticIdsArray = new Array(); + const supplementalSemanticIdsArray = new Array(); for (const item of that.supplementalSemanticIds) { supplementalSemanticIdsArray.push( this.transform(item) @@ -19532,7 +19532,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.qualifiers !== null) { - const qualifiersArray = new Array(); + const qualifiersArray = new Array(); for (const item of that.qualifiers) { qualifiersArray.push( this.transform(item) @@ -19542,7 +19542,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.embeddedDataSpecifications !== null) { - const embeddedDataSpecificationsArray = new Array(); + const embeddedDataSpecificationsArray = new Array(); for (const item of that.embeddedDataSpecifications) { embeddedDataSpecificationsArray.push( this.transform(item) @@ -19576,7 +19576,7 @@ class Serializer extends AasTypes.AbstractTransformer { const jsonable: JsonObject = {}; if (that.extensions !== null) { - const extensionsArray = new Array(); + const extensionsArray = new Array(); for (const item of that.extensions) { extensionsArray.push( this.transform(item) @@ -19596,7 +19596,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.displayName !== null) { - const displayNameArray = new Array(); + const displayNameArray = new Array(); for (const item of that.displayName) { displayNameArray.push( this.transform(item) @@ -19606,7 +19606,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.description !== null) { - const descriptionArray = new Array(); + const descriptionArray = new Array(); for (const item of that.description) { descriptionArray.push( this.transform(item) @@ -19621,7 +19621,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.supplementalSemanticIds !== null) { - const supplementalSemanticIdsArray = new Array(); + const supplementalSemanticIdsArray = new Array(); for (const item of that.supplementalSemanticIds) { supplementalSemanticIdsArray.push( this.transform(item) @@ -19631,7 +19631,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.qualifiers !== null) { - const qualifiersArray = new Array(); + const qualifiersArray = new Array(); for (const item of that.qualifiers) { qualifiersArray.push( this.transform(item) @@ -19641,7 +19641,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.embeddedDataSpecifications !== null) { - const embeddedDataSpecificationsArray = new Array(); + const embeddedDataSpecificationsArray = new Array(); for (const item of that.embeddedDataSpecifications) { embeddedDataSpecificationsArray.push( this.transform(item) @@ -19675,7 +19675,7 @@ class Serializer extends AasTypes.AbstractTransformer { const jsonable: JsonObject = {}; if (that.extensions !== null) { - const extensionsArray = new Array(); + const extensionsArray = new Array(); for (const item of that.extensions) { extensionsArray.push( this.transform(item) @@ -19695,7 +19695,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.displayName !== null) { - const displayNameArray = new Array(); + const displayNameArray = new Array(); for (const item of that.displayName) { displayNameArray.push( this.transform(item) @@ -19705,7 +19705,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.description !== null) { - const descriptionArray = new Array(); + const descriptionArray = new Array(); for (const item of that.description) { descriptionArray.push( this.transform(item) @@ -19720,7 +19720,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.supplementalSemanticIds !== null) { - const supplementalSemanticIdsArray = new Array(); + const supplementalSemanticIdsArray = new Array(); for (const item of that.supplementalSemanticIds) { supplementalSemanticIdsArray.push( this.transform(item) @@ -19730,7 +19730,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.qualifiers !== null) { - const qualifiersArray = new Array(); + const qualifiersArray = new Array(); for (const item of that.qualifiers) { qualifiersArray.push( this.transform(item) @@ -19740,7 +19740,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.embeddedDataSpecifications !== null) { - const embeddedDataSpecificationsArray = new Array(); + const embeddedDataSpecificationsArray = new Array(); for (const item of that.embeddedDataSpecifications) { embeddedDataSpecificationsArray.push( this.transform(item) @@ -19756,7 +19756,7 @@ class Serializer extends AasTypes.AbstractTransformer { this.transform(that.second); if (that.annotations !== null) { - const annotationsArray = new Array(); + const annotationsArray = new Array(); for (const item of that.annotations) { annotationsArray.push( this.transform(item) @@ -19782,7 +19782,7 @@ class Serializer extends AasTypes.AbstractTransformer { const jsonable: JsonObject = {}; if (that.extensions !== null) { - const extensionsArray = new Array(); + const extensionsArray = new Array(); for (const item of that.extensions) { extensionsArray.push( this.transform(item) @@ -19802,7 +19802,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.displayName !== null) { - const displayNameArray = new Array(); + const displayNameArray = new Array(); for (const item of that.displayName) { displayNameArray.push( this.transform(item) @@ -19812,7 +19812,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.description !== null) { - const descriptionArray = new Array(); + const descriptionArray = new Array(); for (const item of that.description) { descriptionArray.push( this.transform(item) @@ -19827,7 +19827,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.supplementalSemanticIds !== null) { - const supplementalSemanticIdsArray = new Array(); + const supplementalSemanticIdsArray = new Array(); for (const item of that.supplementalSemanticIds) { supplementalSemanticIdsArray.push( this.transform(item) @@ -19837,7 +19837,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.qualifiers !== null) { - const qualifiersArray = new Array(); + const qualifiersArray = new Array(); for (const item of that.qualifiers) { qualifiersArray.push( this.transform(item) @@ -19847,7 +19847,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.embeddedDataSpecifications !== null) { - const embeddedDataSpecificationsArray = new Array(); + const embeddedDataSpecificationsArray = new Array(); for (const item of that.embeddedDataSpecifications) { embeddedDataSpecificationsArray.push( this.transform(item) @@ -19857,7 +19857,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.statements !== null) { - const statementsArray = new Array(); + const statementsArray = new Array(); for (const item of that.statements) { statementsArray.push( this.transform(item) @@ -19877,7 +19877,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.specificAssetIds !== null) { - const specificAssetIdsArray = new Array(); + const specificAssetIdsArray = new Array(); for (const item of that.specificAssetIds) { specificAssetIdsArray.push( this.transform(item) @@ -19951,7 +19951,7 @@ class Serializer extends AasTypes.AbstractTransformer { const jsonable: JsonObject = {}; if (that.extensions !== null) { - const extensionsArray = new Array(); + const extensionsArray = new Array(); for (const item of that.extensions) { extensionsArray.push( this.transform(item) @@ -19971,7 +19971,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.displayName !== null) { - const displayNameArray = new Array(); + const displayNameArray = new Array(); for (const item of that.displayName) { displayNameArray.push( this.transform(item) @@ -19981,7 +19981,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.description !== null) { - const descriptionArray = new Array(); + const descriptionArray = new Array(); for (const item of that.description) { descriptionArray.push( this.transform(item) @@ -19996,7 +19996,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.supplementalSemanticIds !== null) { - const supplementalSemanticIdsArray = new Array(); + const supplementalSemanticIdsArray = new Array(); for (const item of that.supplementalSemanticIds) { supplementalSemanticIdsArray.push( this.transform(item) @@ -20006,7 +20006,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.qualifiers !== null) { - const qualifiersArray = new Array(); + const qualifiersArray = new Array(); for (const item of that.qualifiers) { qualifiersArray.push( this.transform(item) @@ -20016,7 +20016,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.embeddedDataSpecifications !== null) { - const embeddedDataSpecificationsArray = new Array(); + const embeddedDataSpecificationsArray = new Array(); for (const item of that.embeddedDataSpecifications) { embeddedDataSpecificationsArray.push( this.transform(item) @@ -20080,7 +20080,7 @@ class Serializer extends AasTypes.AbstractTransformer { const jsonable: JsonObject = {}; if (that.extensions !== null) { - const extensionsArray = new Array(); + const extensionsArray = new Array(); for (const item of that.extensions) { extensionsArray.push( this.transform(item) @@ -20100,7 +20100,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.displayName !== null) { - const displayNameArray = new Array(); + const displayNameArray = new Array(); for (const item of that.displayName) { displayNameArray.push( this.transform(item) @@ -20110,7 +20110,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.description !== null) { - const descriptionArray = new Array(); + const descriptionArray = new Array(); for (const item of that.description) { descriptionArray.push( this.transform(item) @@ -20125,7 +20125,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.supplementalSemanticIds !== null) { - const supplementalSemanticIdsArray = new Array(); + const supplementalSemanticIdsArray = new Array(); for (const item of that.supplementalSemanticIds) { supplementalSemanticIdsArray.push( this.transform(item) @@ -20135,7 +20135,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.qualifiers !== null) { - const qualifiersArray = new Array(); + const qualifiersArray = new Array(); for (const item of that.qualifiers) { qualifiersArray.push( this.transform(item) @@ -20145,7 +20145,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.embeddedDataSpecifications !== null) { - const embeddedDataSpecificationsArray = new Array(); + const embeddedDataSpecificationsArray = new Array(); for (const item of that.embeddedDataSpecifications) { embeddedDataSpecificationsArray.push( this.transform(item) @@ -20155,7 +20155,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.inputVariables !== null) { - const inputVariablesArray = new Array(); + const inputVariablesArray = new Array(); for (const item of that.inputVariables) { inputVariablesArray.push( this.transform(item) @@ -20165,7 +20165,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.outputVariables !== null) { - const outputVariablesArray = new Array(); + const outputVariablesArray = new Array(); for (const item of that.outputVariables) { outputVariablesArray.push( this.transform(item) @@ -20175,7 +20175,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.inoutputVariables !== null) { - const inoutputVariablesArray = new Array(); + const inoutputVariablesArray = new Array(); for (const item of that.inoutputVariables) { inoutputVariablesArray.push( this.transform(item) @@ -20218,7 +20218,7 @@ class Serializer extends AasTypes.AbstractTransformer { const jsonable: JsonObject = {}; if (that.extensions !== null) { - const extensionsArray = new Array(); + const extensionsArray = new Array(); for (const item of that.extensions) { extensionsArray.push( this.transform(item) @@ -20238,7 +20238,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.displayName !== null) { - const displayNameArray = new Array(); + const displayNameArray = new Array(); for (const item of that.displayName) { displayNameArray.push( this.transform(item) @@ -20248,7 +20248,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.description !== null) { - const descriptionArray = new Array(); + const descriptionArray = new Array(); for (const item of that.description) { descriptionArray.push( this.transform(item) @@ -20263,7 +20263,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.supplementalSemanticIds !== null) { - const supplementalSemanticIdsArray = new Array(); + const supplementalSemanticIdsArray = new Array(); for (const item of that.supplementalSemanticIds) { supplementalSemanticIdsArray.push( this.transform(item) @@ -20273,7 +20273,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.qualifiers !== null) { - const qualifiersArray = new Array(); + const qualifiersArray = new Array(); for (const item of that.qualifiers) { qualifiersArray.push( this.transform(item) @@ -20283,7 +20283,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.embeddedDataSpecifications !== null) { - const embeddedDataSpecificationsArray = new Array(); + const embeddedDataSpecificationsArray = new Array(); for (const item of that.embeddedDataSpecifications) { embeddedDataSpecificationsArray.push( this.transform(item) @@ -20309,7 +20309,7 @@ class Serializer extends AasTypes.AbstractTransformer { const jsonable: JsonObject = {}; if (that.extensions !== null) { - const extensionsArray = new Array(); + const extensionsArray = new Array(); for (const item of that.extensions) { extensionsArray.push( this.transform(item) @@ -20329,7 +20329,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.displayName !== null) { - const displayNameArray = new Array(); + const displayNameArray = new Array(); for (const item of that.displayName) { displayNameArray.push( this.transform(item) @@ -20339,7 +20339,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.description !== null) { - const descriptionArray = new Array(); + const descriptionArray = new Array(); for (const item of that.description) { descriptionArray.push( this.transform(item) @@ -20357,7 +20357,7 @@ class Serializer extends AasTypes.AbstractTransformer { that.id; if (that.embeddedDataSpecifications !== null) { - const embeddedDataSpecificationsArray = new Array(); + const embeddedDataSpecificationsArray = new Array(); for (const item of that.embeddedDataSpecifications) { embeddedDataSpecificationsArray.push( this.transform(item) @@ -20367,7 +20367,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.isCaseOf !== null) { - const isCaseOfArray = new Array(); + const isCaseOfArray = new Array(); for (const item of that.isCaseOf) { isCaseOfArray.push( this.transform(item) @@ -20402,7 +20402,7 @@ class Serializer extends AasTypes.AbstractTransformer { this.transform(that.referredSemanticId); } - const keysArray = new Array(); + const keysArray = new Array(); for (const item of that.keys) { keysArray.push( this.transform(item) @@ -20487,7 +20487,7 @@ class Serializer extends AasTypes.AbstractTransformer { const jsonable: JsonObject = {}; if (that.assetAdministrationShells !== null) { - const assetAdministrationShellsArray = new Array(); + const assetAdministrationShellsArray = new Array(); for (const item of that.assetAdministrationShells) { assetAdministrationShellsArray.push( this.transform(item) @@ -20497,7 +20497,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.submodels !== null) { - const submodelsArray = new Array(); + const submodelsArray = new Array(); for (const item of that.submodels) { submodelsArray.push( this.transform(item) @@ -20507,7 +20507,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.conceptDescriptions !== null) { - const conceptDescriptionsArray = new Array(); + const conceptDescriptionsArray = new Array(); for (const item of that.conceptDescriptions) { conceptDescriptionsArray.push( this.transform(item) @@ -20596,7 +20596,7 @@ class Serializer extends AasTypes.AbstractTransformer { ): JsonObject { const jsonable: JsonObject = {}; - const valueReferencePairsArray = new Array(); + const valueReferencePairsArray = new Array(); for (const item of that.valueReferencePairs) { valueReferencePairsArray.push( this.transform(item) @@ -20678,7 +20678,7 @@ class Serializer extends AasTypes.AbstractTransformer { ): JsonObject { const jsonable: JsonObject = {}; - const preferredNameArray = new Array(); + const preferredNameArray = new Array(); for (const item of that.preferredName) { preferredNameArray.push( this.transform(item) @@ -20687,7 +20687,7 @@ class Serializer extends AasTypes.AbstractTransformer { jsonable["preferredName"] = preferredNameArray; if (that.shortName !== null) { - const shortNameArray = new Array(); + const shortNameArray = new Array(); for (const item of that.shortName) { shortNameArray.push( this.transform(item) @@ -20724,7 +20724,7 @@ class Serializer extends AasTypes.AbstractTransformer { } if (that.definition !== null) { - const definitionArray = new Array(); + const definitionArray = new Array(); for (const item of that.definition) { definitionArray.push( this.transform(item) diff --git a/test_data/typescript/test_main/list_of_primitives/expected_output/common.ts b/test_data/typescript/test_main/list_of_primitives/expected_output/common.ts new file mode 100644 index 000000000..2a9e45ff7 --- /dev/null +++ b/test_data/typescript/test_main/list_of_primitives/expected_output/common.ts @@ -0,0 +1,374 @@ +/** + * Provide common functions shared among the modules. + */ + + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + + +/** + * Create an iterator over the given range of numbers. + * + * @param start - inclusive start of the range + * @param end - exclusive end of the range + * @returns iterator over the range + */ +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export function *range(start: number, end: number): IterableIterator { + for (let i = start; i < end; i++) { + yield i; + } +} + + +/** + * Retrieve the `index`-th item from the `array`. + * + * @remarks + * This is a fill for `Array.prototype.at`. + * See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/at + * + * @param array - to get the element from + * @param index - zero-based index of the `array`. Negative index counts back. + * @returns item, or `undefined` if `index` out-of-bound + * @typeParam T - type of the array items + */ +export function at( + array: Array, + index: number +) { + if (index < 0) { + return array[array.length + index]; + } else { + return array[index]; + } +} + + +/** + * Check that all the values of the iterable are `true`. + * + * @param iterable - to iterate over + * @returns `true` if all values in `iterable` are set + */ +export function every( + iterable: Iterable +): boolean { + // NOTE (mristin, 2022-11-24): + // We introduce this function so that we can keep the constraint verification + // purely functional. Unfortunately, `every` and `some` are only available + // in arrays and not in `IterableIterator`. + + for (const item of iterable) { + if (!item) { + return false; + } + } + + return true; +} + + +/** + * Check that at least one value of the iterable is `true`. + * + * @param iterable - to iterate over + * @returns `true` if at least one value in `iterable` is set + */ +export function some( + iterable: Iterable +): boolean { + // NOTE (mristin, 2022-11-24): + // We introduce this function so that we can keep the constraint verification + // purely functional. Unfortunately, `every` and `some` are only available + // in arrays and not in `IterableIterator`. + + for (const item of iterable) { + if (item) { + return true; + } + } + + return false; +} + + +/** + * Map the items of an iterable. + * + * @param iterable - to be mapped + * @param mappingFunction - to be applied on `iterable` + * @returns mapped items of `iterable` + * @typeParam S - type of an item of the `iterable` + * @typeParam T - type of the transformed item of the `iterable` + */ +export function *map( + iterable: Iterable, + mappingFunction: (item: S) => T +): IterableIterator { + // NOTE (mristin, 2022-11-24): + // We introduce this function so that we can keep the constraint verification + // purely functional. + + for (const item of iterable) { + yield mappingFunction(item); + } +} + + +/** + * Represent either a result, or an error. + * + * @typeParam ValueT - type of the resulting value + * @typeParam ErrorT - type of the error + */ +export class Either { + /** + * value if something successful + */ + readonly value: ValueT | null; + + /** + * error if something failed + */ + readonly error: ErrorT | null; + + /** + * Assert that value is set and return it. + * + * @returns {@link value}, or throw if `null` + */ + mustValue(): ValueT { + if (this.value === null) { + throw new Error("Expected value to be set, but it was null"); + } + return this.value; + } + + constructor(value: ValueT | null, error: ErrorT | null) { + if (value === null && error === null) { + throw new Error("Unexpected both value and error null in an Either"); + } + + if (value !== null && error !== null) { + throw new Error("Unexpected both value and error non-null in an Either"); + } + + this.value = value; + this.error = error; + } +} + + +const BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +const BASE64_LOOKUP = new Uint8Array(256); + +// NOTE (mristin, 2022-11-25): +// Initialize to 255 so that we can detect invalid values in the input during decoding. +for (let i = 0; i < BASE64_LOOKUP.length; i++) { + BASE64_LOOKUP[i] = 255; +} + +// NOTE (mristin, 2022-11-25): +// Initialize valid values to the corresponding decoding points. +for (let i = 0; i < BASE64_CHARS.length; i++) { + BASE64_LOOKUP[BASE64_CHARS.charCodeAt(i)] = i; +} + +/** + * Encode a byte array in base64. + * + * @remarks + * We provide our own implementation so that we do not run into compatibility + * issues with node.js, different browsers etc. + * See: + * https://stackoverflow.com/questions/21797299/convert-base64-string-to-arraybuffer + * + * @param bytes - to be encoded + * @returns `bytes` encoded as base64 text + */ +export function base64Encode(bytes: Uint8Array): string { + // NOTE (mristin, 2022-11-25): + // This implementation is vaguely based on: + // https://github.com/danguer/blog-examples/blob/master/js/base64-binary.js, + // https://github.com/niklasvh/base64-arraybuffer/blob/master/src/index.ts and + // https://github.com/beatgammit/base64-js/blob/master/index.js. + + // NOTE (mristin, 2022-11-25): + // We assume that string concatenation is actually *faster* than joining an array + // of strings, see: + // https://stackoverflow.com/questions/51185/are-javascript-strings-immutable-do-i-need-a-string-builder-in-javascript + + if (bytes.length === 0) { + return ""; + } + + let encoded = ''; + const len = bytes.length; + + for (let i = 0; i < len; i += 3) { + encoded += BASE64_CHARS[bytes[i] >> 2]; + encoded += BASE64_CHARS[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)]; + encoded += BASE64_CHARS[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)]; + encoded += BASE64_CHARS[bytes[i + 2] & 63]; + } + + // NOTE (mristin, 2022-11-25): + // We assume here that `substring` will be optimized for cases where we do not keep + // the original reference to the string. We tested a bit with + // https://www.measurethat.net/. + + if (len % 3 === 2) { + encoded = encoded.substring(0, encoded.length - 1) + '='; + } else if (len % 3 === 1) { + encoded = encoded.substring(0, encoded.length - 2) + '=='; + } else { + // No padding is necessary. + } + + return encoded; +} + + +/** + * Decode a base64-encoded byte array. + * + * @remarks + * We provide our own implementation so that we do not run into compatibility + * issues with node.js, different browsers etc. + * See: + * https://stackoverflow.com/questions/21797299/convert-base64-string-to-arraybuffer + * + * @param text - to be decoded + * @returns either the array or an error, if `text` is not a valid base64 encoding + */ +export function base64Decode(text: string): Either { + // NOTE (mristin, 2022-11-25): + // This implementation is vaguely based on: + // https://github.com/danguer/blog-examples/blob/master/js/base64-binary.js, + // https://github.com/niklasvh/base64-arraybuffer/blob/master/src/index.ts and + // https://github.com/beatgammit/base64-js/blob/master/index.js. + + const len = text.length; + let lenWoPad = len; + + // NOTE (mristin, 2022-11-25): + // Some implementations forget the padding, so we try to be robust and check + // for the padding manually. + let bytesLength = text.length * 0.75; + if (text[len - 1] === '=') { + bytesLength--; + lenWoPad--; + if (text[len - 2] === '=') { + bytesLength--; + lenWoPad--; + } + } + + const bytes = new Uint8Array(bytesLength); + + const base64LookupLen = BASE64_LOOKUP.length; + + let pointer = 0; + + for (let i = 0; i < len; i += 4) { + // NOTE (mristin, 2022-11-25): + // Admittedly, this is very verbose code, but we want to be efficient, so we + // opted for performance over readability here. + + const charCode0 = text.charCodeAt(i); + if (charCode0 >= base64LookupLen) { + return new Either( + null, + "Expected a valid character from base64-encoded string, " + + `but got at index ${i}: ${text[i]} (code: ${charCode0})` + ); + } + const encoded0 = BASE64_LOOKUP[charCode0]; + if (encoded0 === 255) { + return new Either( + null, + "Expected a valid character from base64-encoded string, " + + `but got at index ${i}: ${text[i]} (code: ${charCode0})` + ); + } + + const charCode1 = text.charCodeAt(i + 1); + if (charCode1 >= base64LookupLen) { + return new Either( + null, + "Expected a valid character from base64-encoded string, " + + `but got at index ${i + 1}: ${text[i + 1]} (code: ${charCode1})` + ); + } + const encoded1 = BASE64_LOOKUP[charCode1]; + if (encoded1 === 255) { + return new Either( + null, + "Expected a valid character from base64-encoded string, " + + `but got at index ${i + 1}: ${text[i + 1]} (code: ${charCode1})` + ); + } + + // We map padding to 65, which is the value of "A". + const charCode2 = i + 2 < lenWoPad ? text.charCodeAt(i + 2) : 65; + if (charCode2 >= base64LookupLen) { + return new Either( + null, + "Expected a valid character from base64-encoded string, " + + `but got at index ${i + 2}: ${text[i + 2]} (code: ${charCode2})` + ); + } + const encoded2 = BASE64_LOOKUP[charCode2]; + if (encoded2 === 255) { + return new Either( + null, + "Expected a valid character from base64-encoded string, " + + `but got at index ${i + 2}: ${text[i + 2]} (code: ${charCode2})` + ); + } + + // We map padding to 65, which is the value of "A". + const charCode3 = i + 3 < lenWoPad ? text.charCodeAt(i + 3) : 65; + if (charCode3 >= base64LookupLen) { + return new Either( + null, + "Expected a valid character from base64-encoded string, " + + `but got at index ${i + 3}: ${text[i + 3]} (code: ${charCode3})` + ); + } + const encoded3 = BASE64_LOOKUP[charCode3]; + if (encoded3 === 255) { + return new Either( + null, + "Expected a valid character from base64-encoded string, " + + `but got at index ${i + 3}: ${text[i + 3]} (code: ${charCode3})` + ); + } + + bytes[pointer] = (encoded0 << 2) | (encoded1 >> 4); + pointer++; + + bytes[pointer] = ((encoded1 & 15) << 4) | (encoded2 >> 2); + pointer++; + + bytes[pointer] = ((encoded2 & 3) << 6) | (encoded3 & 63); + pointer++; + } + +// NOTE (mristin, 2022-12-02): +// We expect Uint8Array to silently ignore writes outside of the buffer, +// but we still want to check here in case the underlying platform was flaky about it. + if (bytes.length !== bytesLength) { + throw new Error( + `Expected bytes to have length ${bytesLength}, but got ${bytes.length}` + ); + } + + return new Either(bytes, null); +} + + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. diff --git a/test_data/typescript/test_main/list_of_primitives/expected_output/constants.ts b/test_data/typescript/test_main/list_of_primitives/expected_output/constants.ts new file mode 100644 index 000000000..2120c56ee --- /dev/null +++ b/test_data/typescript/test_main/list_of_primitives/expected_output/constants.ts @@ -0,0 +1,15 @@ +/** + * Provide constant values of the meta-model. + */ + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +/* eslint-disable @typescript-eslint/no-unused-vars */ + +import * as AasTypes from "./types"; + +/* eslint-enable @typescript-eslint/no-unused-vars */ + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. diff --git a/test_data/typescript/test_main/list_of_primitives/expected_output/jsonization.ts b/test_data/typescript/test_main/list_of_primitives/expected_output/jsonization.ts new file mode 100644 index 000000000..bd5c7cfff --- /dev/null +++ b/test_data/typescript/test_main/list_of_primitives/expected_output/jsonization.ts @@ -0,0 +1,757 @@ +/** + * Provide de/serialization of AAS classes to/from JSON. + * + * We can not use one-pass deserialization for JSON since the object + * properties do not have fixed order, and hence we can not read + * `modelType` property ahead of the remaining properties. + */ + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +import * as AasCommon from "./common"; +import * as AasTypes from "./types"; +import * as AasStringification from "./stringification"; + +export type JsonValue = string | number | boolean | JsonObject | JsonArray; + +export type JsonArray = Iterable; +export type JsonObject = { [prop: string]: JsonValue }; + +/** + * Represent a property on a path to the erroneous value. + */ +export class PropertySegment { + /** + * Instance that contains the property + */ + readonly instance: JsonObject; + + /** + * Name of the property + */ + readonly name: string; + + constructor(instance: JsonObject, name: string) { + this.instance = instance; + this.name = name; + } +} + +/** + * Represent an index access on a path to the erroneous value. + */ +export class IndexSegment { + /** + * Container that contains the item + */ + readonly container: JsonArray; + + /** + * Index of the item + */ + readonly index: number; + + constructor(container: JsonArray, index: number) { + if (!Number.isInteger(index)) { + throw new Error(`Expected an integer for the index, but got: ${index}`); + } + + this.container = container; + this.index = index; + } +} + +export type Segment = PropertySegment | IndexSegment; + +/** + * Represent the relative path to the erroneous value. + */ +export class Path { + private readonly _segments = new Array(); + + /** + * Get the segments of the path. + */ + segments(): Array { + return this._segments; + } + + /** + * Insert the `segment` in front of the {@link segments}. + * + * @param segment - segment to be prepended to {@link segments} + */ + prepend(segment: Segment): void { + this._segments.unshift(segment); + } + + toString(): string { + if (this._segments.length === 0) { + return ""; + } + + const parts = new Array(); + + let segment = this._segments[0]; + + if (segment instanceof PropertySegment) { + parts.push(segment.name); + } else if (segment instanceof IndexSegment) { + parts.push(`[${segment.index}]`); + } else { + throw new Error(`Unexpected segment: ${segment}`); + } + + for (let i = 1; i < this._segments.length; i++) { + segment = this._segments[i]; + if (segment instanceof PropertySegment) { + parts.push(`.${segment.name}`); + } else if (segment instanceof IndexSegment) { + parts.push(`[${segment.index}]`); + } else { + throw new Error(`Unexpected segment: ${segment}`); + } + } + + return parts.join(""); + } +} + +// region De-serialization + +/** + * Signal that the JSON de-serialization could not be performed. + */ +export class DeserializationError { + /** + * Human-readable explanation of the error + */ + readonly message: string; + + /** + * Relative path to the erroneous value + */ + readonly path: Path; + + constructor(message: string, path: Path | null = null) { + this.message = message; + this.path = path ?? new Path(); + } +} + +/** + * Create an error as {@link common.Either}. + * + * @param message - human-readable explanation of the error + * @returns An {@link common.Either } with the error set + * @typeParam T - type of the value if there had been no error + */ +function newDeserializationError( + message: string +): AasCommon.Either { + return new AasCommon.Either( + null, + new DeserializationError(message) + ); +} + +/** + * Parse `jsonable` as a boolean. + * + * @param jsonable - to be parsed + * @returns parsed boolean value, or an error + */ +function booleanFromJsonable( + jsonable: JsonValue +): AasCommon.Either { + // `typeof` seems to be optimized these days, so we use it instead of + // literal comparison, see: + // https://stackoverflow.com/questions/61786250/is-typeof-faster-than-literal-comparison + + if (jsonable === null) { + return newDeserializationError( + "Expected a boolean, but got null" + ); + } + if (typeof jsonable !== "boolean") { + return newDeserializationError( + `Expected a boolean, but got ${typeof jsonable}` + ); + } + + return new AasCommon.Either(jsonable, null); +} + +/** + * Parse `jsonable` as an integer. + * + * @param jsonable - to be parsed + * @returns parsed integer value, or an error + */ +// eslint-disable-next-line @typescript-eslint/no-unused-vars +function integerFromJsonable( + jsonable: JsonValue +): AasCommon.Either { + if (jsonable === null) { + return newDeserializationError( + "Expected an integer number, but got null" + ); + } + if (typeof jsonable !== "number") { + return newDeserializationError( + `Expected an integer number, but got: ${typeof jsonable}` + ); + } + + if (!Number.isInteger(jsonable)) { + return newDeserializationError( + `Expected an integer number, but got: ${jsonable}` + ); + } + + return new AasCommon.Either(jsonable, null); +} + +/** + * Parse `jsonable` as a number. + * + * @param jsonable - to be parsed + * @returns parsed numeric value, or an error + */ +// eslint-disable-next-line @typescript-eslint/no-unused-vars +function numberFromJsonable( + jsonable: JsonValue +): AasCommon.Either { + if (jsonable === null) { + return newDeserializationError( + "Expected a number, but got null" + ); + } + if (typeof jsonable !== "number") { + return newDeserializationError( + `Expected a number, but got: ${typeof jsonable}` + ); + } + + return new AasCommon.Either(jsonable, null); +} + +/** + * Parse `jsonable` as a string. + * + * @param jsonable - to be parsed + * @returns parsed string value, or an error + */ +function stringFromJsonable( + jsonable: JsonValue +): AasCommon.Either { + if (jsonable === null) { + return newDeserializationError( + "Expected a string, but got null" + ); + } + if (typeof jsonable !== "string") { + return newDeserializationError( + `Expected a string, but got: ${typeof jsonable}` + ); + } + + return new AasCommon.Either(jsonable, null); +} + +/** + * Parse `jsonable` as a byte array. + * + * @param jsonable - to be parsed + * @returns parsed byte array, or an error + */ +function bytesFromJsonable( + jsonable: JsonValue +): AasCommon.Either { + if (jsonable === null) { + return newDeserializationError( + "Expected a base64-encoded string, but got null" + ); + } + if (typeof jsonable !== "string") { + return newDeserializationError( + `Expected a base64-encoded string, but got: ${typeof jsonable}` + ); + } + + const either = AasCommon.base64Decode(jsonable); + if (either.error !== null) { + return newDeserializationError(either.error); + } + return new AasCommon.Either( + either.mustValue(), null + ); +} + +/** + * Provide de-serialize & set methods for properties + * of {@link types!Foo}. + */ +class SetterForFoo { + +} + +/** + * Parse an instance of {@link types!Foo} from the JSON-able + * structure `jsonable`. + * + * @param jsonable - structure to be parsed + * @returns parsed instance of {@link types!Foo}, + * or an error if any + */ +export function fooFromJsonable( + jsonable: JsonValue +): AasCommon.Either< + AasTypes.Foo, + DeserializationError +> { + if (jsonable === null) { + return newDeserializationError( + "Expected a JSON object, but got null" + ); + } + if (Array.isArray(jsonable)) { + return newDeserializationError( + "Expected a JSON object, but got a JSON array" + ); + } + if (typeof jsonable !== "object") { + return newDeserializationError( + `Expected a JSON object, but got: ${typeof jsonable}` + ); + } + + const setter = new SetterForFoo(); + + for (const key in jsonable) { + const jsonableValue = jsonable[key]; + const setterMethod = + SETTER_MAP_FOR_FOO.get(key); + + // NOTE (mristin, 2022-11-30): + // Since we conflate here a JavaScript object with a JSON object, we ignore + // properties which we do not know how to de-serialize and assume they are + // related to the *JavaScript* properties of the object or `Object` prototype. + if (setterMethod === undefined) { + continue; + } + + const error = setterMethod.call(setter, jsonableValue); + if (error !== null) { + error.path.prepend( + new PropertySegment(jsonable, key) + ); + return new AasCommon.Either< + AasTypes.Foo, + DeserializationError + >( + null, + error + ); + } + } + + return new AasCommon.Either< + AasTypes.Foo, + DeserializationError + >( + new AasTypes.Foo(), + null + ); +} + +/** + * Provide de-serialize & set methods for properties + * of {@link types!ListOfPrimitives}. + */ +class SetterForListOfPrimitives { + strings: Array | null = null; + + integers: Array | null = null; + + booleans: Array | null = null; + + /** + * Parse `jsonable` as the value of {@link strings}. + * + * @param jsonable - to be parsed + * @returns error, if any + */ + setStringsFromJsonable( + jsonable: JsonValue + ): DeserializationError | null { + if (jsonable === null) { + return new DeserializationError( + "Expected an iterable, but got null" + ); + } + if (typeof jsonable !== "object") { + return new DeserializationError( + `Expected an iterable, but got: ${typeof jsonable}` + ); + } + if (typeof jsonable[Symbol.iterator] !== "function") { + return new DeserializationError( + "Expected an iterable with iterator function, " + + `but got iterator of type: ${typeof jsonable[Symbol.iterator]}` + ); + } + + const iterable = >jsonable; + + const items = + new Array(); + + let i = 0; + for (const jsonableItem of iterable) { + const itemOrError = stringFromJsonable( + jsonableItem + ); + + if (itemOrError.error !== null) { + itemOrError.error.path.prepend( + new IndexSegment( + iterable, + i + ) + ); + return itemOrError.error; + } + + items.push(itemOrError.mustValue()); + i++; + } + + this.strings = items; + return null; + } + + /** + * Parse `jsonable` as the value of {@link integers}. + * + * @param jsonable - to be parsed + * @returns error, if any + */ + setIntegersFromJsonable( + jsonable: JsonValue + ): DeserializationError | null { + if (jsonable === null) { + return new DeserializationError( + "Expected an iterable, but got null" + ); + } + if (typeof jsonable !== "object") { + return new DeserializationError( + `Expected an iterable, but got: ${typeof jsonable}` + ); + } + if (typeof jsonable[Symbol.iterator] !== "function") { + return new DeserializationError( + "Expected an iterable with iterator function, " + + `but got iterator of type: ${typeof jsonable[Symbol.iterator]}` + ); + } + + const iterable = >jsonable; + + const items = + new Array(); + + let i = 0; + for (const jsonableItem of iterable) { + const itemOrError = integerFromJsonable( + jsonableItem + ); + + if (itemOrError.error !== null) { + itemOrError.error.path.prepend( + new IndexSegment( + iterable, + i + ) + ); + return itemOrError.error; + } + + items.push(itemOrError.mustValue()); + i++; + } + + this.integers = items; + return null; + } + + /** + * Parse `jsonable` as the value of {@link booleans}. + * + * @param jsonable - to be parsed + * @returns error, if any + */ + setBooleansFromJsonable( + jsonable: JsonValue + ): DeserializationError | null { + if (jsonable === null) { + return new DeserializationError( + "Expected an iterable, but got null" + ); + } + if (typeof jsonable !== "object") { + return new DeserializationError( + `Expected an iterable, but got: ${typeof jsonable}` + ); + } + if (typeof jsonable[Symbol.iterator] !== "function") { + return new DeserializationError( + "Expected an iterable with iterator function, " + + `but got iterator of type: ${typeof jsonable[Symbol.iterator]}` + ); + } + + const iterable = >jsonable; + + const items = + new Array(); + + let i = 0; + for (const jsonableItem of iterable) { + const itemOrError = booleanFromJsonable( + jsonableItem + ); + + if (itemOrError.error !== null) { + itemOrError.error.path.prepend( + new IndexSegment( + iterable, + i + ) + ); + return itemOrError.error; + } + + items.push(itemOrError.mustValue()); + i++; + } + + this.booleans = items; + return null; + } +} + +/** + * Parse an instance of {@link types!ListOfPrimitives} from the JSON-able + * structure `jsonable`. + * + * @param jsonable - structure to be parsed + * @returns parsed instance of {@link types!ListOfPrimitives}, + * or an error if any + */ +export function listOfPrimitivesFromJsonable( + jsonable: JsonValue +): AasCommon.Either< + AasTypes.ListOfPrimitives, + DeserializationError +> { + if (jsonable === null) { + return newDeserializationError( + "Expected a JSON object, but got null" + ); + } + if (Array.isArray(jsonable)) { + return newDeserializationError( + "Expected a JSON object, but got a JSON array" + ); + } + if (typeof jsonable !== "object") { + return newDeserializationError( + `Expected a JSON object, but got: ${typeof jsonable}` + ); + } + + const setter = new SetterForListOfPrimitives(); + + for (const key in jsonable) { + const jsonableValue = jsonable[key]; + const setterMethod = + SETTER_MAP_FOR_LIST_OF_PRIMITIVES.get(key); + + // NOTE (mristin, 2022-11-30): + // Since we conflate here a JavaScript object with a JSON object, we ignore + // properties which we do not know how to de-serialize and assume they are + // related to the *JavaScript* properties of the object or `Object` prototype. + if (setterMethod === undefined) { + continue; + } + + const error = setterMethod.call(setter, jsonableValue); + if (error !== null) { + error.path.prepend( + new PropertySegment(jsonable, key) + ); + return new AasCommon.Either< + AasTypes.ListOfPrimitives, + DeserializationError + >( + null, + error + ); + } + } + + if (setter.strings === null) { + return newDeserializationError< + AasTypes.ListOfPrimitives + >( + "The required property 'strings' is missing" + ); + } + + if (setter.integers === null) { + return newDeserializationError< + AasTypes.ListOfPrimitives + >( + "The required property 'integers' is missing" + ); + } + + if (setter.booleans === null) { + return newDeserializationError< + AasTypes.ListOfPrimitives + >( + "The required property 'booleans' is missing" + ); + } + + return new AasCommon.Either< + AasTypes.ListOfPrimitives, + DeserializationError + >( + new AasTypes.ListOfPrimitives( + setter.strings, + setter.integers, + setter.booleans + ), + null + ); +} + +const SETTER_MAP_FOR_FOO = + new Map< + string, + ( + jsonable: JsonValue + ) => DeserializationError | null + >( + [ + ] + ); + +const SETTER_MAP_FOR_LIST_OF_PRIMITIVES = + new Map< + string, + ( + jsonable: JsonValue + ) => DeserializationError | null + >( + [ + [ + "strings", + SetterForListOfPrimitives.prototype.setStringsFromJsonable + ], + [ + "integers", + SetterForListOfPrimitives.prototype.setIntegersFromJsonable + ], + [ + "booleans", + SetterForListOfPrimitives.prototype.setBooleansFromJsonable + ], + ] + ); + +// endregion + +// region Serialization + +/** + * Transform the instance to its JSON-able representation. + */ +class Serializer extends AasTypes.AbstractTransformer { + + + /** + * Serialize `that` to a JSON-able representation. + * + * @param that - instance to be serialization + * @returns JSON-able representation + */ + transformFoo( + that: AasTypes.Foo + ): JsonObject { + const jsonable: JsonObject = {}; + + return jsonable; + } + + /** + * Serialize `that` to a JSON-able representation. + * + * @param that - instance to be serialization + * @returns JSON-able representation + */ + transformListOfPrimitives( + that: AasTypes.ListOfPrimitives + ): JsonObject { + const jsonable: JsonObject = {}; + + const stringsArray = new Array(); + for (const item of that.strings) { + stringsArray.push( + stringFromJsonable(item).mustValue() + ); + } + jsonable["strings"] = stringsArray; + + const integersArray = new Array(); + for (const item of that.integers) { + integersArray.push( + integerFromJsonable(item).mustValue() + ); + } + jsonable["integers"] = integersArray; + + const booleansArray = new Array(); + for (const item of that.booleans) { + booleansArray.push( + booleanFromJsonable(item).mustValue() + ); + } + jsonable["booleans"] = booleansArray; + + return jsonable; + } +} + +const SERIALIZER = new Serializer(); + +/** + * Convert `that` to a JSON-able structure. + * + * @param that - AAS data to be recursively converted to a JSON-able structure + * @returns + * JSON-able structure which can be further processed with, say, + * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify|JSON.stringify}) + */ +export function toJsonable(that: AasTypes.Class): JsonObject { + return SERIALIZER.transform(that); +} + +// endregion + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. diff --git a/test_data/typescript/test_main/list_of_primitives/expected_output/stdout.txt b/test_data/typescript/test_main/list_of_primitives/expected_output/stdout.txt new file mode 100644 index 000000000..2d755fc5a --- /dev/null +++ b/test_data/typescript/test_main/list_of_primitives/expected_output/stdout.txt @@ -0,0 +1 @@ +Code generated to: diff --git a/test_data/typescript/test_main/list_of_primitives/expected_output/stringification.ts b/test_data/typescript/test_main/list_of_primitives/expected_output/stringification.ts new file mode 100644 index 000000000..f506a4807 --- /dev/null +++ b/test_data/typescript/test_main/list_of_primitives/expected_output/stringification.ts @@ -0,0 +1,81 @@ +/** + * De/serialize enumerations from and to string representations. + */ + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +import * as AasTypes from "./types"; + +const MODEL_TYPE_FROM_STRING = new Map([ + [ + "Foo", + AasTypes.ModelType.Foo + ], + [ + "ListOfPrimitives", + AasTypes.ModelType.ListOfPrimitives + ] +]); + +/** + * Parse `text` as a string representation of {@link types!ModelType}. + * + * @param text - string representation of {@link types!ModelType} + * @returns literal of {@link types!ModelType}, if valid, and `null` otherwise + */ +export function modelTypeFromString( + text: string +): AasTypes.ModelType | null { + const result = MODEL_TYPE_FROM_STRING.get(text); + return result !== undefined ? result : null; +} + +const MODEL_TYPE_TO_STRING = new Map([ + [ + AasTypes.ModelType.Foo, + "Foo" + ], + [ + AasTypes.ModelType.ListOfPrimitives, + "ListOfPrimitives" + ] +]); + +/** + * Translate {@link types!ModelType} to a string. + * + * @param value - to be stringified + * @returns string representation of {@link types!ModelType}, + * if `value` valid, and `null` otherwise + */ +export function modelTypeToString( + value: AasTypes.ModelType +): string | null { + const result = MODEL_TYPE_TO_STRING.get(value); + return result !== undefined ? result : null; +} + +/** + * Translate {@link types!ModelType} to a string. + * + * @param value - to be stringified + * @returns string representation of {@link types!ModelType} + * @throws + * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error|Error} + * if the `value` is invalid + */ +export function mustModelTypeToString( + value: AasTypes.ModelType +): string { + const result = MODEL_TYPE_TO_STRING.get(value); + if (result === undefined) { + throw new Error( + `Invalid literal of ModelType: ${value}` + ); + } + return result; +} + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. diff --git a/test_data/typescript/test_main/list_of_primitives/expected_output/types.ts b/test_data/typescript/test_main/list_of_primitives/expected_output/types.ts new file mode 100644 index 000000000..89df782cb --- /dev/null +++ b/test_data/typescript/test_main/list_of_primitives/expected_output/types.ts @@ -0,0 +1,724 @@ +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +/** + * Represent runtime model type of an instance. + */ +export enum ModelType { + Foo = 0, + ListOfPrimitives = 1 +} + +/** + * Iterate over the literals of {@link ModelType}. + * + * @remark + * TypeScript does not provide an elegant way to iterate over the literals, so + * this function helps you avoid common errors and pitfalls. + * + * @return iterator over the literals + */ +export function *overModelType ( +): Iterable { + // NOTE (mristin, 2022-12-03): + // We yield numbers instead of literals to avoid name lookups on platforms + // which do not provide JIT compilation of hot paths. + yield 0; // Foo + yield 1; // ListOfPrimitives +} + +/** + * Represent the most general class of an AAS model. + */ +export abstract class Class { + /** + * Indicate the runtime model type of an instance. + */ + abstract modelType(): ModelType; + + /** + * Iterate over all the instances referenced from this one. + */ + abstract descendOnce(): IterableIterator; + + /** + * Iterate recursively over all the instances referenced from this one. + */ + abstract descend(): IterableIterator; + + /** + * Dispatch the `visitor` on this instance. + * + * @param visitor - to be dispatched + */ + abstract accept(visitor: AbstractVisitor): void; + + /** + * Dispatch the `visitor` on this instance with `context`. + * + * @param visitor - to be dispatched + * @param context - of the visitation + * @typeParam ContextT - type of the visitation context + */ + abstract acceptWithContext( + visitor: AbstractVisitorWithContext, + context: ContextT + ): void; + + /** + * Dispatch the `transformer` on this instance. + * + * @param transformer - to be dispatched + * @return this instance transformed + * @typeParam T - type of the transformation result + */ + abstract transform(transformer: AbstractTransformer): T; + + /** + * Dispatch the `transformer` on this instance in `context`. + * + * @param transformer - to be dispatched + * @param context - of the transformation + * @return this instance transformed + * @typeParam T - type of the transformation result + */ + abstract transformWithContext( + transformer: AbstractTransformerWithContext, + context: ContextT + ): T; +} + +export class Foo extends Class { + /** + * Indicate the runtime model type of the instance. + */ + modelType(): ModelType { + // NOTE (mristin, 2022-12-03): + // We yield numbers instead of literals to avoid name lookups on platforms + // which do not provide JIT compilation of hot paths. + return 0; // Foo + } + + /** + * Iterate over the instances referenced from this instance. + * + * We do not recurse into the referenced instances. + * + * @returns Iterator over the referenced instances + */ + *descendOnce(): IterableIterator { + // No descendable properties + } + + /** + * Iterate recursively over the instances referenced from this instance. + * + * @returns Iterator over the referenced instances + */ + *descend(): IterableIterator { + // No descendable properties + } + + /** + * Dispatch `visitor` on this instance. + * + * @param visitor - to visit this instance + */ + accept(visitor: AbstractVisitor): void { + visitor.visitFoo(this); + } + + /** + * Dispatch `visitor` with `context` on this instance. + * + * @param visitor - to visit this instance + * @param context - to be passed along to the dispatched visitor method + * @typeParam ContextT - type of the context + */ + acceptWithContext( + visitor: AbstractVisitorWithContext, + context: ContextT + ) { + visitor.visitFooWithContext(this, context); + } + + /** + * Dispatch the `transformer` on this instance. + * + * @param transformer - to transform this instance + * @returns transformation of this instance + * @paramType T - type of the transformation result + */ + transform(transformer: AbstractTransformer): T { + return transformer.transformFoo(this); + } + + /** + * Dispatch the `transformer` on this instance in `context`. + * + * @param transformer - to transform this instance + * @param context - to be passed along to the `transformer` + * @returns transformation of this instance + * @paramType T - type of the transformation result + * @paramType ContextT - type of the transformation context + */ + transformWithContext( + transformer: AbstractTransformerWithContext, + context: ContextT + ): T { + return transformer.transformFooWithContext( + this, context + ); + } +} + +export class ListOfPrimitives extends Class { + /** + * Indicate the runtime model type of the instance. + */ + modelType(): ModelType { + // NOTE (mristin, 2022-12-03): + // We yield numbers instead of literals to avoid name lookups on platforms + // which do not provide JIT compilation of hot paths. + return 1; // ListOfPrimitives + } + + strings: Array; + + integers: Array; + + booleans: Array; + + /** + * Iterate over the instances referenced from this instance. + * + * We do not recurse into the referenced instances. + * + * @returns Iterator over the referenced instances + */ + *descendOnce(): IterableIterator { + // No descendable properties + } + + /** + * Iterate recursively over the instances referenced from this instance. + * + * @returns Iterator over the referenced instances + */ + *descend(): IterableIterator { + // No descendable properties + } + + /** + * Dispatch `visitor` on this instance. + * + * @param visitor - to visit this instance + */ + accept(visitor: AbstractVisitor): void { + visitor.visitListOfPrimitives(this); + } + + /** + * Dispatch `visitor` with `context` on this instance. + * + * @param visitor - to visit this instance + * @param context - to be passed along to the dispatched visitor method + * @typeParam ContextT - type of the context + */ + acceptWithContext( + visitor: AbstractVisitorWithContext, + context: ContextT + ) { + visitor.visitListOfPrimitivesWithContext(this, context); + } + + /** + * Dispatch the `transformer` on this instance. + * + * @param transformer - to transform this instance + * @returns transformation of this instance + * @paramType T - type of the transformation result + */ + transform(transformer: AbstractTransformer): T { + return transformer.transformListOfPrimitives(this); + } + + /** + * Dispatch the `transformer` on this instance in `context`. + * + * @param transformer - to transform this instance + * @param context - to be passed along to the `transformer` + * @returns transformation of this instance + * @paramType T - type of the transformation result + * @paramType ContextT - type of the transformation context + */ + transformWithContext( + transformer: AbstractTransformerWithContext, + context: ContextT + ): T { + return transformer.transformListOfPrimitivesWithContext( + this, context + ); + } + + constructor( + strings: Array, + integers: Array, + booleans: Array + ) { + super(); + this.strings = strings; + this.integers = integers; + this.booleans = booleans; + } +} + +/** + * Visit the instances of the model. + */ +export abstract class AbstractVisitor { + /** + * Double-dispatch on `that`. + */ + visit(that: Class): void { + that.accept(this); + } + + /** + * Visit `that`. + * + * @param that - instance to be visited + */ + abstract visitFoo( + that: Foo + ): void; + + /** + * Visit `that`. + * + * @param that - instance to be visited + */ + abstract visitListOfPrimitives( + that: ListOfPrimitives + ): void; +} + +/** + * Visit the instances of the model with context. + * + * @typeParam ContextT - type of the visitation context + */ +export abstract class AbstractVisitorWithContext { + /** + * Double-dispatch on `that` in `context`. + * + * @param that - instance to be visited + * @param context - of the visitation + */ + visitWithContext( + that: Class, + context: ContextT + ): void { + that.acceptWithContext(this, context); + } + + /** + * Visit `that` in `context`. + * + * @param that - instance to be visited + * @param context - of the visitation + */ + abstract visitFooWithContext( + that: Foo, + context: ContextT + ): void; + + /** + * Visit `that` in `context`. + * + * @param that - instance to be visited + * @param context - of the visitation + */ + abstract visitListOfPrimitivesWithContext( + that: ListOfPrimitives, + context: ContextT + ): void; +} + +/** + * Visit the instances of the model without action. + * + * @remarks + * This visitor is not meant to be directly used. Instead, you usually + * inherit from it, and implement only the relevant visit methods. + */ +export class PassThroughVisitor extends AbstractVisitor { + /** + * Visit `that`. + * + * @param that - instance to be visited + */ + visitFoo( + that: Foo + ): void { + for (const another of that.descendOnce()) { + this.visit(another); + } + } + + /** + * Visit `that`. + * + * @param that - instance to be visited + */ + visitListOfPrimitives( + that: ListOfPrimitives + ): void { + for (const another of that.descendOnce()) { + this.visit(another); + } + } +} + +/** + * Visit the instances of the model without action and in context. + * + * @remarks + * This visitor is not meant to be directly used. Instead, you usually + * inherit from it, and implement only the relevant visit methods. + */ +export class PassThroughVisitorWithContext + extends AbstractVisitorWithContext { + /** + * Double-dispatch on `that` in `context`. + */ + visitWithContext( + that: Class, + context: ContextT + ): void { + that.acceptWithContext(this, context); + } + + /** + * Visit `that` in `context`. + * + * @param that - instance to be visited + * @param context - of the visitation + */ + visitFooWithContext( + that: Foo, + context: ContextT + ): void { + for (const another of that.descendOnce()) { + this.visitWithContext(another, context); + } + } + + /** + * Visit `that` in `context`. + * + * @param that - instance to be visited + * @param context - of the visitation + */ + visitListOfPrimitivesWithContext( + that: ListOfPrimitives, + context: ContextT + ): void { + for (const another of that.descendOnce()) { + this.visitWithContext(another, context); + } + } +} + +/** + * Transform the instance of the model. + * + * @typeParam T - type of the transformation result + */ +export abstract class AbstractTransformer { + /** + * Double-dispatch on `that`. + */ + transform(that: Class): T { + return that.transform(this); + } + + /** + * Transform `that`. + * + * @param that - instance to be transformed + * @returns transformed `that` + */ + abstract transformFoo( + that: Foo + ): T; + + /** + * Transform `that`. + * + * @param that - instance to be transformed + * @returns transformed `that` + */ + abstract transformListOfPrimitives( + that: ListOfPrimitives + ): T; +} + +/** + * Transform the instances of the model in context. + * + * @typeParam ContextT - type of the transformation context + * @typeParam T - type of the transformation result + */ +export abstract class AbstractTransformerWithContext { + /** + * Double-dispatch on `that` in `context`. + * + * @param that - instance to be transformed + * @param context - of the transformation + * @returns transformed `that` + */ + transformWithContext( + that: Class, + context: ContextT + ): T { + return that.transformWithContext(this, context); + } + + /** + * Transform `that` in `context`. + * + * @param that - instance to be transformed + * @param context - of the transformation + * @returns transformed `that` + */ + abstract transformFooWithContext( + that: Foo, + context: ContextT + ): T; + + /** + * Transform `that` in `context`. + * + * @param that - instance to be transformed + * @param context - of the transformation + * @returns transformed `that` + */ + abstract transformListOfPrimitivesWithContext( + that: ListOfPrimitives, + context: ContextT + ): T; +} + +/** + * Transform the instances of the model. + * + * @remarks + * If you do not override the transformation methods, they simply + * return {@link defaultResult}. + * + * @typeParam T - type of the transformation result + */ +export class TransformerWithDefault extends AbstractTransformer { + /** + * Default value which is returned if no override of the transformation + */ + defaultResult: T + + /** + * Initialize with the given `default` value. + * + * @param defaultResult - returned if no override of the transformation + */ + constructor(defaultResult: T) { + super(); + this.defaultResult = defaultResult; + } + + /** + * Transform `that`. + * + * @param that - instance to be transformed + * @returns transformed `that` + */ + /* eslint-disable @typescript-eslint/no-unused-vars */ + transformFoo( + that: Foo + ): T { + return this.defaultResult; + } + /* eslint-enable @typescript-eslint/no-unused-vars */ + + /** + * Transform `that`. + * + * @param that - instance to be transformed + * @returns transformed `that` + */ + /* eslint-disable @typescript-eslint/no-unused-vars */ + transformListOfPrimitives( + that: ListOfPrimitives + ): T { + return this.defaultResult; + } + /* eslint-enable @typescript-eslint/no-unused-vars */ +} + +/** + * Transform the instances of the model in context. + * + * @remarks + * If you do not override the transformation methods, they simply + * return {@link defaultResult}. + * + * @typeParam ContextT - type of the visitation context + * @typeParam T - type of the transformation result + */ +export class TransformerWithDefaultAndContext + extends AbstractTransformerWithContext { + /** + * Default value which is returned if no override of the transformation + */ + defaultResult: T + + /** + * Initialize with the given `default` value. + * + * @param defaultResult - returned if no override of the transformation + */ + constructor(defaultResult: T) { + super(); + this.defaultResult = defaultResult; + } + + /** + * Transform `that` in `context`. + * + * @param that - instance to be transformed + * @param context - of the visitation + * @returns transformed `that` + */ + /* eslint-disable @typescript-eslint/no-unused-vars */ + transformFooWithContext( + that: Foo, + context: ContextT + ): T { + return this.defaultResult; + } + /* eslint-enable @typescript-eslint/no-unused-vars */ + + /** + * Transform `that` in `context`. + * + * @param that - instance to be transformed + * @param context - of the visitation + * @returns transformed `that` + */ + /* eslint-disable @typescript-eslint/no-unused-vars */ + transformListOfPrimitivesWithContext( + that: ListOfPrimitives, + context: ContextT + ): T { + return this.defaultResult; + } + /* eslint-enable @typescript-eslint/no-unused-vars */ +} + +/** + * Try to cast `that` instance to + * the class {@link Foo}. + * + * @param that - instance to be casted + * @returns - casted `that` if cast successful, or `null` + */ +export function asFoo( + that: Class +): Foo | null { + return (that instanceof Foo) + ? that + : null; +} + +/** + * Check the type of `that` instance. + * + * @param that - instance to be type-checked + * @returns `true` if the type check is successful + */ +export function isFoo( + that: Class +): that is Foo { + return that instanceof Foo; +} + +/** + * Try to cast `that` instance to + * the class {@link ListOfPrimitives}. + * + * @param that - instance to be casted + * @returns - casted `that` if cast successful, or `null` + */ +export function asListOfPrimitives( + that: Class +): ListOfPrimitives | null { + return (that instanceof ListOfPrimitives) + ? that + : null; +} + +/** + * Check the type of `that` instance. + * + * @param that - instance to be type-checked + * @returns `true` if the type check is successful + */ +export function isListOfPrimitives( + that: Class +): that is ListOfPrimitives { + return that instanceof ListOfPrimitives; +} + +class TypeMatcher extends AbstractTransformerWithContext< + Readonly, + boolean +> { + /* eslint-disable @typescript-eslint/no-unused-vars */ + transformFooWithContext( + that: Foo, + other: Class + ): boolean { + return isFoo(other); + } + /* eslint-enable @typescript-eslint/no-unused-vars */ + + /* eslint-disable @typescript-eslint/no-unused-vars */ + transformListOfPrimitivesWithContext( + that: ListOfPrimitives, + other: Class + ): boolean { + return isListOfPrimitives(other); + } + /* eslint-enable @typescript-eslint/no-unused-vars */ +} + +const TYPE_MATCHER = new TypeMatcher(); + +/** + * Check whether the type of `that` matches the type of `other` instance. + * + * @remarks + * We check with `is*` function. Hence, if the class of `other` is a subclass of + * the class of `that`, we confirm the match. + * + * @param that - standard instance + * @param other - instance whose type is compared against `that` + */ +export function typesMatch( + that: ClassT, + other: Class +): other is ClassT { + return TYPE_MATCHER.transformWithContext(that, other); +} + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. diff --git a/test_data/typescript/test_main/list_of_primitives/expected_output/verification.ts b/test_data/typescript/test_main/list_of_primitives/expected_output/verification.ts new file mode 100644 index 000000000..8e4a258e1 --- /dev/null +++ b/test_data/typescript/test_main/list_of_primitives/expected_output/verification.ts @@ -0,0 +1,231 @@ +/** + * Verify that the instances of the meta-model satisfy the invariants. + * + * Here is an example how to verify an instance of {@link types.Foo}: + * + * ```ts + * import * as AasTypes from "test/types"; + * import * as AasVerification from "test/verification"; + * + * const anInstance = new AasTypes.Foo( + * // ... some constructor arguments ... + * ); + * + * for (const error of AasVerification.verify(anInstance)) { + * console.log(`${error.message} at: ${error.path}`); + * } + * ``` + */ + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. + +import * as AasCommon from "./common"; +import * as AasConstants from "./constants"; +import * as AasTypes from "./types"; + +// The generated code might contain deliberately double negations. For example, +// when the constraint is formulated as a NAND and we check that the constraint +// is not fulfilled. Therefore, we disable this linting rule. +/* eslint no-extra-boolean-cast: 0 */ + +/** + * Represent a property access on a path to an erroneous value. + */ +export class PropertySegment { + /** + * Instance containing the property + */ + readonly instance: AasTypes.Class; + + /** + * Name of the property + */ + readonly name: string; + + constructor(instance: AasTypes.Class, name: string) { + this.instance = instance; + this.name = name; + } + + toString(): string { + return `.${this.name}`; + } +} + +/** + * Represent an index access on a path to an erroneous value. + */ +export class IndexSegment { + /** + * Sequence containing the item at {@link index} + */ + readonly sequence: Array; + + /** + * Index of the item in the {@link sequence} + */ + readonly index: number; + + constructor(sequence: Array, index: number) { + this.sequence = sequence; + this.index = index; + } + + toString(): string { + return `[${this.index}]`; + } +} + +export type Segment = PropertySegment | IndexSegment; + +/** + * Represent the relative path to the erroneous value. + */ +export class Path { + readonly segments: Array = []; + + prepend(segment: Segment): void { + this.segments.unshift(segment); + } + + toString(): string { + return this.segments.join(""); + } +} + +/** + * Represent a verification error in the data. + */ +export class VerificationError { + // NOTE (mristin, 2022-11-12): + // The name `VerificationError` is redundant since it lives in `verification` module, + // and it would have made more sense to call it simply `Error`. Unfortunately in this case, + // `Error` is a reserved name by JavaScript. + + /** + * Human-readable description of the error + */ + readonly message: string; + + /** + * Path to the erroneous value + */ + readonly path: Path = new Path(); + + /** + * Initialize with the given `message` and `path`. + * + * @remarks + * If no `path` is specified, initialize with an empty path. + */ + constructor(message: string, path: Path | null = null) { + this.message = message; + this.path = (path !== null) + ? path + : new Path(); + } +} + +/** + * Verify an instance of the model recursively or non-recursively (depending on the context). + */ +class Verifier + extends AasTypes.AbstractTransformerWithContext< + boolean, IterableIterator + > { + *transformFooWithContext( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + that: AasTypes.Foo, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + context: boolean + ): IterableIterator { + // No verification has been defined for Foo. + } + + *transformListOfPrimitivesWithContext( + that: AasTypes.ListOfPrimitives, + context: boolean + ): IterableIterator { + if (context === true) { + let stringsIndex = 0; + for (const item of that.strings) { + for (const error of this.transformWithContext(item, context)) { + error.path.prepend( + new IndexSegment( + that.strings, + stringsIndex + ) + ); + error.path.prepend( + new PropertySegment( + that, + "strings" + ) + ); + yield error; + } + stringsIndex++; + } + + let integersIndex = 0; + for (const item of that.integers) { + for (const error of this.transformWithContext(item, context)) { + error.path.prepend( + new IndexSegment( + that.integers, + integersIndex + ) + ); + error.path.prepend( + new PropertySegment( + that, + "integers" + ) + ); + yield error; + } + integersIndex++; + } + + let booleansIndex = 0; + for (const item of that.booleans) { + for (const error of this.transformWithContext(item, context)) { + error.path.prepend( + new IndexSegment( + that.booleans, + booleansIndex + ) + ); + error.path.prepend( + new PropertySegment( + that, + "booleans" + ) + ); + yield error; + } + booleansIndex++; + } + } + } +} + +const VERIFIER = new Verifier(); + +/** + * Verify the constraints of `that`. + * + * @param that - instance to be verified + * @param recurse - if set, continue the verification recursively + * @returns a stream of verification errors + */ +export function *verify( + that: AasTypes.Class, + recurse = true +): IterableIterator { + yield * VERIFIER.transformWithContext(that, recurse); +} + +// This code has been automatically generated by aas-core-codegen. +// Do NOT edit or append. diff --git a/test_data/typescript/test_main/list_of_primitives/input/snippets/package_identifier.txt b/test_data/typescript/test_main/list_of_primitives/input/snippets/package_identifier.txt new file mode 100644 index 000000000..9daeafb98 --- /dev/null +++ b/test_data/typescript/test_main/list_of_primitives/input/snippets/package_identifier.txt @@ -0,0 +1 @@ +test diff --git a/test_data/typescript/test_main/list_of_primitives/meta_model.py b/test_data/typescript/test_main/list_of_primitives/meta_model.py new file mode 100644 index 000000000..49e337b87 --- /dev/null +++ b/test_data/typescript/test_main/list_of_primitives/meta_model.py @@ -0,0 +1,22 @@ +from typing import List + + +class Foo: + pass + + +class List_of_primitives: + strings: List[str] + integers: List[int] + booleans: List[bool] + + def __init__( + self, strings: List[str], integers: List[int], booleans: List[bool] + ) -> None: + self.strings = strings + self.integers = integers + self.booleans = booleans + + +__version__ = "dummy" +__xml_namespace__ = "https://dummy.com" diff --git a/tests/typescript/test_main.py b/tests/typescript/test_main.py index 4f2ce089b..5a67e03d6 100644 --- a/tests/typescript/test_main.py +++ b/tests/typescript/test_main.py @@ -15,26 +15,29 @@ class Test_against_recorded(unittest.TestCase): - def test_cases(self) -> None: - repo_dir = pathlib.Path(os.path.realpath(__file__)).parent.parent.parent - - parent_case_dir = repo_dir / "test_data" / "typescript" / "test_main" - assert parent_case_dir.exists() and parent_case_dir.is_dir(), parent_case_dir - - for module in [aas_core_meta.v3]: - case_dir = parent_case_dir / module.__name__ - assert case_dir.is_dir(), case_dir - - assert ( - module.__file__ is not None - ), f"Expected the module {module!r} to have a __file__, but it has None" - model_pth = pathlib.Path(module.__file__) - assert model_pth.exists() and model_pth.is_file(), model_pth - - snippets_dir = case_dir / "input/snippets" + _REPO_DIR = pathlib.Path(os.path.realpath(__file__)).parent.parent.parent + PARENT_CASE_DIR = _REPO_DIR / "test_data" / "typescript" / "test_main" + + def test_against_meta_models(self) -> None: + assert ( + Test_against_recorded.PARENT_CASE_DIR.exists() + and Test_against_recorded.PARENT_CASE_DIR.is_dir() + ), f"{Test_against_recorded.PARENT_CASE_DIR=}" + + # fmt: off + test_cases = ( + tests.common.find_meta_models_in_parent_directory_of_test_cases_and_modules( + parent_case_dir=Test_against_recorded.PARENT_CASE_DIR, + aas_core_meta_modules=[aas_core_meta.v3] + ) + ) + # fmt: on + + for test_case in test_cases: + snippets_dir = test_case.case_dir / "input/snippets" assert snippets_dir.exists() and snippets_dir.is_dir(), snippets_dir - expected_output_dir = case_dir / "expected_output" + expected_output_dir = test_case.case_dir / "expected_output" with contextlib.ExitStack() as exit_stack: if tests.common.RERECORD: @@ -51,7 +54,7 @@ def test_cases(self) -> None: output_dir = pathlib.Path(tmp_dir.name) params = aas_core_codegen.main.Parameters( - model_path=model_pth, + model_path=test_case.model_path, target=aas_core_codegen.main.Target.TYPESCRIPT, snippets_dir=snippets_dir, output_dir=output_dir, @@ -104,27 +107,14 @@ def test_cases(self) -> None: f"The output file is missing: {output_pth}" ) - try: - output = output_pth.read_text(encoding="utf-8") - except Exception as exception: - raise RuntimeError( - f"Failed to read the output from {output_pth}" - ) from exception - if tests.common.RERECORD: - expected_pth.write_text(output, encoding="utf-8") + expected_pth.write_text( + output_pth.read_text(encoding="utf-8"), encoding="utf-8" + ) else: - try: - expected_output = expected_pth.read_text(encoding="utf-8") - except Exception as exception: - raise RuntimeError( - f"Failed to read the expected output " - f"from {expected_pth}" - ) from exception - self.assertEqual( - expected_output, - output, + expected_pth.read_text(encoding="utf-8"), + output_pth.read_text(encoding="utf-8"), f"The files {expected_pth} and {output_pth} do not match.", ) From 76b8cb67b6d54f707dbb58e4d333447f7c7a63de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Otto?= Date: Thu, 20 Feb 2025 15:55:41 +0100 Subject: [PATCH 12/14] Support java --- aas_core_codegen/java/copying/_generate.py | 3 + aas_core_codegen/java/enhancing/_generate.py | 37 +- aas_core_codegen/java/xmlization/_generate.py | 68 +- .../expected_output/common.py | 22 + .../expected_output/constants.py | 11 + .../expected_output/constants/Constants.java | 37 + .../expected_output/copying/Copying.java | 81 + .../expected_output/enhancing/Enhanced.java | 23 + .../enhancing/EnhancedListOfPrimitives.java | 96 + .../expected_output/enhancing/Enhancer.java | 64 + .../expected_output/enhancing/Unwrapper.java | 56 + .../expected_output/enhancing/Wrapper.java | 91 + .../expected_output/jsonization.py | 446 +++++ .../jsonization/Jsonization.java | 507 ++++++ .../expected_output/reporting/Reporting.java | 168 ++ .../expected_output/stdout.txt | 1 + .../expected_output/stringification.py | 17 + .../stringification/Stringification.java | 22 + .../expected_output/types.py | 291 +++ .../types/impl/ListOfPrimitives.java | 138 ++ .../expected_output/types/model/IClass.java | 61 + .../types/model/IListOfPrimitives.java | 32 + .../expected_output/verification.py | 156 ++ .../verification/Verification.java | 153 ++ .../visitation/AbstractTransformer.java | 32 + .../AbstractTransformerWithContext.java | 39 + .../visitation/AbstractVisitor.java | 28 + .../AbstractVisitorWithContext.java | 33 + .../visitation/ITransformer.java | 30 + .../visitation/ITransformerWithContext.java | 32 + .../expected_output/visitation/IVisitor.java | 28 + .../visitation/IVisitorWithContext.java | 31 + .../visitation/VisitorThrough.java | 36 + .../expected_output/xmlization.py | 1554 +++++++++++++++++ .../xmlization/Xmlization.java | 815 +++++++++ .../input/snippets/package.txt | 1 + .../list_of_primitives/meta_model.py | 18 + tests/java/test_main.py | 223 +-- 38 files changed, 5315 insertions(+), 166 deletions(-) create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/common.py create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/constants.py create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/constants/Constants.java create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/copying/Copying.java create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/enhancing/Enhanced.java create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/enhancing/EnhancedListOfPrimitives.java create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/enhancing/Enhancer.java create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/enhancing/Unwrapper.java create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/enhancing/Wrapper.java create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/jsonization.py create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/jsonization/Jsonization.java create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/reporting/Reporting.java create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/stdout.txt create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/stringification.py create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/stringification/Stringification.java create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/types.py create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/types/impl/ListOfPrimitives.java create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/types/model/IClass.java create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/types/model/IListOfPrimitives.java create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/verification.py create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/verification/Verification.java create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/visitation/AbstractTransformer.java create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/visitation/AbstractTransformerWithContext.java create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/visitation/AbstractVisitor.java create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/visitation/AbstractVisitorWithContext.java create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/visitation/ITransformer.java create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/visitation/ITransformerWithContext.java create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/visitation/IVisitor.java create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/visitation/IVisitorWithContext.java create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/visitation/VisitorThrough.java create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/xmlization.py create mode 100644 test_data/java/test_main/list_of_primitives/expected_output/xmlization/Xmlization.java create mode 100644 test_data/java/test_main/list_of_primitives/input/snippets/package.txt create mode 100644 test_data/java/test_main/list_of_primitives/meta_model.py diff --git a/aas_core_codegen/java/copying/_generate.py b/aas_core_codegen/java/copying/_generate.py index 778ab271f..c5d861358 100644 --- a/aas_core_codegen/java/copying/_generate.py +++ b/aas_core_codegen/java/copying/_generate.py @@ -171,6 +171,9 @@ def _generate_deep_copy_transform_method(cls: intermediate.ConcreteClass) -> Str if not isinstance(type_anno, intermediate.ListTypeAnnotation): continue + if isinstance(type_anno.items, intermediate.PrimitiveTypeAnnotation): + continue + assert isinstance( type_anno.items, intermediate.OurTypeAnnotation ) and isinstance(type_anno.items.our_type, intermediate.Class), ( diff --git a/aas_core_codegen/java/enhancing/_generate.py b/aas_core_codegen/java/enhancing/_generate.py index b8c3607c2..7f3961419 100644 --- a/aas_core_codegen/java/enhancing/_generate.py +++ b/aas_core_codegen/java/enhancing/_generate.py @@ -588,27 +588,24 @@ def _generate_transform(cls: intermediate.ConcreteClass) -> Stripped: else: assert_never(type_anno.our_type) elif isinstance(type_anno, intermediate.ListTypeAnnotation): - # fmt: off - assert ( - isinstance(type_anno.items, intermediate.OurTypeAnnotation) - and isinstance( - type_anno.items.our_type, - (intermediate.AbstractClass, intermediate.ConcreteClass) - ) - ), ( - "We handle only lists of classes in the enhancing at the moment. " - "The meta-model does not contain any other lists, so we wanted to " - "keep the code as simple as possible, and avoid unrolling. Please " - "contact the developers if you need this feature." - ) - # fmt: on + if isinstance(type_anno.items, intermediate.PrimitiveTypeAnnotation): + transformed_name = "FOO" + item_interface_name = "BAR" + elif isinstance( + type_anno.items, intermediate.OurTypeAnnotation + ) and isinstance( + type_anno.items.our_type, + (intermediate.AbstractClass, intermediate.ConcreteClass), + ): + transformed_name = java_naming.variable_name( + Identifier(f"transformed_{prop.name}") + ) - item_interface_name = java_naming.interface_name( - type_anno.items.our_type.name - ) - transformed_name = java_naming.variable_name( - Identifier(f"transformed_{prop.name}") - ) + item_interface_name = java_naming.interface_name( + type_anno.items.our_type.name + ) + else: + assert_never(type_anno) getter_name = java_naming.getter_name(prop.name) diff --git a/aas_core_codegen/java/xmlization/_generate.py b/aas_core_codegen/java/xmlization/_generate.py index cd5309235..4970da0d5 100644 --- a/aas_core_codegen/java/xmlization/_generate.py +++ b/aas_core_codegen/java/xmlization/_generate.py @@ -646,36 +646,35 @@ def _generate_deserialize_list_property( """Generate the code to de-serialize a property ``prop`` as a list.""" type_anno = intermediate.beneath_optional(prop.type_annotation) - # fmt: off - assert ( - isinstance(type_anno, intermediate.ListTypeAnnotation) - and isinstance(type_anno.items, intermediate.OurTypeAnnotation) - and isinstance( - type_anno.items.our_type, - (intermediate.AbstractClass, intermediate.ConcreteClass) - ) - ), "See intermediate._translate._verify_only_simple_type_patterns" - # fmt: on - + assert isinstance(type_anno, intermediate.ListTypeAnnotation) target_var = java_naming.variable_name(Identifier(f"the_{prop.name}")) - item_our_type = type_anno.items.our_type - - if ( - isinstance(item_our_type, intermediate.AbstractClass) - or len(item_our_type.concrete_descendants) > 0 + if isinstance(type_anno.items, intermediate.PrimitiveTypeAnnotation): + deserialize_method = "FOO" + item_type = "BAR" + cls_name = "BAR" + xml_prop_name_literal = "BAR" + elif isinstance(type_anno.items, intermediate.OurTypeAnnotation) and isinstance( + type_anno.items.our_type, + (intermediate.AbstractClass, intermediate.ConcreteClass), ): - interface_name = java_naming.interface_name(type_anno.items.our_type.name) - deserialize_method = f"{interface_name}FromElement" + item_our_type = type_anno.items.our_type + if ( + isinstance(item_our_type, intermediate.AbstractClass) + or len(item_our_type.concrete_descendants) > 0 + ): + interface_name = java_naming.interface_name(type_anno.items.our_type.name) + deserialize_method = f"{interface_name}FromElement" + else: + class_name = java_naming.class_name(type_anno.items.our_type.name) + deserialize_method = f"{class_name}FromElement" + item_type = java_common.generate_type(type_anno.items) + cls_name = java_naming.class_name(cls.name) + xml_prop_name_literal = java_common.string_literal( + naming.xml_property(prop.name) + ) else: - class_name = java_naming.class_name(type_anno.items.our_type.name) - deserialize_method = f"{class_name}FromElement" - - item_type = java_common.generate_type(type_anno.items) - - cls_name = java_naming.class_name(cls.name) - - xml_prop_name_literal = java_common.string_literal(naming.xml_property(prop.name)) + assert_never(type_anno) return Stripped( f"""\ @@ -1768,16 +1767,13 @@ def _generate_serialize_list_property_as_content( """Generate the serialization of a list ``prop`` as a sequence of elements.""" type_anno = intermediate.beneath_optional(prop.type_annotation) - # fmt: off - assert ( - isinstance(type_anno, intermediate.ListTypeAnnotation) - and isinstance(type_anno.items, intermediate.OurTypeAnnotation) - and isinstance( - type_anno.items.our_type, - (intermediate.AbstractClass, intermediate.ConcreteClass) - ) - ), "See intermediate._translate._verify_only_simple_type_patterns" - # fmt: on + assert isinstance(type_anno, intermediate.ListTypeAnnotation) + # and isinstance(type_anno.items, intermediate.OurTypeAnnotation) + # and isinstance( + # type_anno.items.our_type, + # (intermediate.AbstractClass, intermediate.ConcreteClass) + # ) + # ), "See intermediate._translate._verify_only_simple_type_patterns" getter_name = java_naming.getter_name(prop.name) xml_prop_name_literal = java_common.string_literal(naming.xml_property(prop.name)) diff --git a/test_data/java/test_main/list_of_primitives/expected_output/common.py b/test_data/java/test_main/list_of_primitives/expected_output/common.py new file mode 100644 index 000000000..154bf41ec --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/common.py @@ -0,0 +1,22 @@ +"""Provide common functions shared among the modules.""" + + +# This code has been automatically generated by aas-core-codegen. +# Do NOT edit or append. + + +from typing import NoReturn + + +def assert_never(value: NoReturn) -> NoReturn: + """ + Signal to mypy to perform an exhaustive matching. + + Please see the following page for more details: + https://hakibenita.com/python-mypy-exhaustive-checking + """ + assert False, f"Unhandled value: {value} ({type(value).__name__})" + + +# This code has been automatically generated by aas-core-codegen. +# Do NOT edit or append. diff --git a/test_data/java/test_main/list_of_primitives/expected_output/constants.py b/test_data/java/test_main/list_of_primitives/expected_output/constants.py new file mode 100644 index 000000000..cf7b85abb --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/constants.py @@ -0,0 +1,11 @@ +"""Provide constant values of the meta-model.""" + +# This code has been automatically generated by aas-core-codegen. +# Do NOT edit or append. + +from typing import Set + +import test.types as aas_types + +# This code has been automatically generated by aas-core-codegen. +# Do NOT edit or append. diff --git a/test_data/java/test_main/list_of_primitives/expected_output/constants/Constants.java b/test_data/java/test_main/list_of_primitives/expected_output/constants/Constants.java new file mode 100644 index 000000000..0d7674474 --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/constants/Constants.java @@ -0,0 +1,37 @@ +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ + +package test.constants; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collector; +import java.util.stream.Stream; + + + +// Helper to generate read-only collections with less boilerplate. +// See: https://stackoverflow.com/a/37406054 +class ImmutableCollector { + public static Collector, Set> toImmutableSet() { + return Collector.of(HashSet::new, Set::add, (l, r) -> { + l.addAll(r); + return l; + }, Collections::unmodifiableSet); + } +} + +/** + * Provide constant values of the meta-model. + */ +public class Constants { + +} + +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ diff --git a/test_data/java/test_main/list_of_primitives/expected_output/copying/Copying.java b/test_data/java/test_main/list_of_primitives/expected_output/copying/Copying.java new file mode 100644 index 000000000..ec1f42bf0 --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/copying/Copying.java @@ -0,0 +1,81 @@ +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ + +package test.copying; + +import java.util.List; +import java.util.ArrayList; +import test.types.model.IClass; +import test.visitation.AbstractTransformer; +import test.types.impl.*; +import test.types.model.*; + +/** + * Allow for making shallow and deep copies of AAS model instances. + */ +public class Copying +{ + private static final ShallowCopier shallowCopierInstance = new ShallowCopier(); + + private static final DeepCopier deepCopierInstance = new DeepCopier(); + + /** + * Make a shallow copy of {@code that}. + * + *

All the properties are copied by reference. This includes also the lists. + * Hence, a list property is copied by reference, and not, as sometimes might be + * expected, as a new list of underlying references. + * + * @param that to be copied in a shallow manner + */ + @SuppressWarnings("unchecked") + public static T shallow(T that) { + return (T) shallowCopierInstance.transform(that); + } + + /** + * Make a recursively a deep copy of {@code that}. + * + * @param that to be deeply copied in a recursive manner + */ + @SuppressWarnings("unchecked") + public static T deep(T that) { + return (T) deepCopierInstance.transform(that); + } + + /** + * Dispatch the making of shallow copies. + */ + private static class ShallowCopier extends AbstractTransformer { + @Override + public IClass transformListOfPrimitives( + IListOfPrimitives that + ) { + return new ListOfPrimitives( + that.getStrings(), + that.getIntegers(), + that.getBooleans()); + } + } + + /** Dispatch the making of deep copies. */ + private static class DeepCopier extends AbstractTransformer { + @Override + public IClass transformListOfPrimitives ( + IListOfPrimitives that + ) { + return new ListOfPrimitives( + theStrings, + theIntegers, + theBooleans + ); + } + } +} + +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ diff --git a/test_data/java/test_main/list_of_primitives/expected_output/enhancing/Enhanced.java b/test_data/java/test_main/list_of_primitives/expected_output/enhancing/Enhanced.java new file mode 100644 index 000000000..d53bfc49d --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/enhancing/Enhanced.java @@ -0,0 +1,23 @@ +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ + +package test.enhancing; + +public abstract class Enhanced { + protected final EnhancementT enhancement; + + protected Enhanced(EnhancementT enhancement) { + this.enhancement = enhancement; + } + + EnhancementT getEnhancement() { + return enhancement; + } +} + +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ diff --git a/test_data/java/test_main/list_of_primitives/expected_output/enhancing/EnhancedListOfPrimitives.java b/test_data/java/test_main/list_of_primitives/expected_output/enhancing/EnhancedListOfPrimitives.java new file mode 100644 index 000000000..5fb3681f9 --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/enhancing/EnhancedListOfPrimitives.java @@ -0,0 +1,96 @@ +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ + +package test.enhancing; + +import java.lang.Iterable; +import java.util.Optional; +import java.util.List; +import test.visitation.IVisitor; +import test.visitation.IVisitorWithContext; +import test.visitation.ITransformer; +import test.visitation.ITransformerWithContext; +import test.types.enums.*; +import test.types.impl.*; +import test.types.model.*; + +public class EnhancedListOfPrimitives + extends Enhanced + implements IListOfPrimitives { + private final IListOfPrimitives instance; + + public EnhancedListOfPrimitives( + IListOfPrimitives instance, + EnhancementT enhancement + ) { + super(enhancement); + this.instance = instance; + } + + @Override + public List getStrings() { + return instance.getStrings(); + } + + @Override + public void setStrings(List strings) { + instance.setStrings(strings); + } + + @Override + public List getIntegers() { + return instance.getIntegers(); + } + + @Override + public void setIntegers(List integers) { + instance.setIntegers(integers); + } + + @Override + public List getBooleans() { + return instance.getBooleans(); + } + + @Override + public void setBooleans(List booleans) { + instance.setBooleans(booleans); + } + + public Iterable descendOnce() { + return instance.descendOnce(); + } + + public Iterable descend() { + return instance.descend(); + } + + public void accept(IVisitor visitor) { + visitor.visitListOfPrimitives(instance); + } + + public void accept( + IVisitorWithContext visitor, + ContextT context + ) { + visitor.visitListOfPrimitives(instance, context); + } + + public T transform(ITransformer transformer) { + return transformer.transformListOfPrimitives(instance); + } + + public T transform( + ITransformerWithContext transformer, + ContextT context + ) { + return transformer.transformListOfPrimitives(instance, context); + } +} + +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ diff --git a/test_data/java/test_main/list_of_primitives/expected_output/enhancing/Enhancer.java b/test_data/java/test_main/list_of_primitives/expected_output/enhancing/Enhancer.java new file mode 100644 index 000000000..3b2537985 --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/enhancing/Enhancer.java @@ -0,0 +1,64 @@ +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ + +package test.enhancing; + +import java.util.function.Function; +import java.util.Optional; +import test.enhancing.Unwrapper; +import test.types.model.*; + +/** + * Wrap and unwrap the instances of model classes with enhancement. + * + * @param structure of the enhancement + */ +public class Enhancer extends Unwrapper { + private final Wrapper wrapper; + + /** + * @param enhancementFactory how to enhance the instances. + * + *

If it returns {@code null}, the instance will not be wrapped. However, + * the wrapping will continue recursively. + */ + public Enhancer( + Function> enhancementFactory + ) { + this.wrapper = new Wrapper<>(enhancementFactory); + } + + /** + * Wrap the instance with an enhancement. + * + *

Double wraps are not allowed to prevent runtime leakage. + * + *

If you use references to the instance objects, you have to update them + * after the wrapping, as the wrapping is recursive. + * + * @param that model instance to be wrapped + * @return {@code that} instance wrapped recursively with enhancements + */ + public IClass wrap( + IClass that + ) { + IClass wrapped; + try { + wrapped = wrapper.transform(that); + } catch (IllegalArgumentException exception) { + throw new UnsupportedOperationException( + "Expected the wrapped instance to be an instance of IClass, " + + "but got: " + that + ); + } + + return wrapped; + } +} + +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ diff --git a/test_data/java/test_main/list_of_primitives/expected_output/enhancing/Unwrapper.java b/test_data/java/test_main/list_of_primitives/expected_output/enhancing/Unwrapper.java new file mode 100644 index 000000000..7ec7aef73 --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/enhancing/Unwrapper.java @@ -0,0 +1,56 @@ +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ + +package test.enhancing; + +import java.util.Optional; +import test.types.model.*; + +/** + * Unwrap enhancements from the wrapped instances. + * + * @param structure of the expected enhancement + */ +public class Unwrapper { + /** + * Unwrap the given model instance. + * + * @param that model instance to be unwrapped + * @return Enhancement, or {@link java.util.Optional#empty()} if {@code that} + * has not been wrapped yet. + */ + public Optional unwrap(IClass that) + { + if (that instanceof Enhanced) { + @SuppressWarnings("unchecked") + Enhanced enhanced = (Enhanced) that; + return Optional.of(enhanced.getEnhancement()); + } else { + return Optional.empty(); + } + } + + /** + * Unwrap the given model instance. + * + * @param that model instance to be unwrapped + * @return Enhancement wrapped around {@code that} + */ + public EnhancementT mustUnwrap(IClass that) + { + Optional value = unwrap(that); + if (!value.isPresent()) { + throw new IllegalArgumentException( + "Expected the instance to have been wrapped, but it was not: " + that + ); + } + return value.get(); + } +} + +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ diff --git a/test_data/java/test_main/list_of_primitives/expected_output/enhancing/Wrapper.java b/test_data/java/test_main/list_of_primitives/expected_output/enhancing/Wrapper.java new file mode 100644 index 000000000..1b00fd9fb --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/enhancing/Wrapper.java @@ -0,0 +1,91 @@ +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ + +package test.enhancing; + +import java.util.List; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import test.types.model.*; +import test.visitation.AbstractTransformer; + +class Wrapper extends AbstractTransformer { + private final Function> enhancementFactory; + + Wrapper( + Function> enhancementFactory + ) { + this.enhancementFactory = enhancementFactory; + } + + @Override + public IClass transformListOfPrimitives( + IListOfPrimitives that + ) { + if (that instanceof Enhanced) + { + throw new IllegalArgumentException( + "The instance has been already enhanced: " + that + ); + } + + List strings = that.getStrings(); + List FOO = strings.stream() + .map(item -> { + IClass transformed = transform(item); + if (!(transformed instanceof BAR)) { + throw new UnsupportedOperationException( + "Expected the transformed value to be a BAR " + + ", but got: " + transformed + ); + } + return (BAR) transformed; + }).collect(Collectors.toList()); + that.setStrings(FOO); + + List integers = that.getIntegers(); + List FOO = integers.stream() + .map(item -> { + IClass transformed = transform(item); + if (!(transformed instanceof BAR)) { + throw new UnsupportedOperationException( + "Expected the transformed value to be a BAR " + + ", but got: " + transformed + ); + } + return (BAR) transformed; + }).collect(Collectors.toList()); + that.setIntegers(FOO); + + List booleans = that.getBooleans(); + List FOO = booleans.stream() + .map(item -> { + IClass transformed = transform(item); + if (!(transformed instanceof BAR)) { + throw new UnsupportedOperationException( + "Expected the transformed value to be a BAR " + + ", but got: " + transformed + ); + } + return (BAR) transformed; + }).collect(Collectors.toList()); + that.setBooleans(FOO); + + Optional enhancement = enhancementFactory.apply(that); + return !enhancement.isPresent() + ? that + : new EnhancedListOfPrimitives<>( + that, + enhancement.get() + ); + } +} + +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ diff --git a/test_data/java/test_main/list_of_primitives/expected_output/jsonization.py b/test_data/java/test_main/list_of_primitives/expected_output/jsonization.py new file mode 100644 index 000000000..9c4206d32 --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/jsonization.py @@ -0,0 +1,446 @@ +""" +Provide de/serialization of AAS classes to/from JSON. + +We can not use one-pass deserialization for JSON since the object +properties do not have fixed order, and hence we can not read +``modelType`` property ahead of the remaining properties. +""" + + +# This code has been automatically generated by aas-core-codegen. +# Do NOT edit or append. + + +import base64 +import collections.abc +import sys +from typing import ( + cast, + Any, + Callable, + Iterable, + List, + Mapping, + MutableMapping, + Optional, + Sequence, + Union, +) + +if sys.version_info >= (3, 8): + from typing import Final +else: + from typing_extensions import Final + +import test.common as aas_common +import test.stringification as aas_stringification +import test.types as aas_types + + +class PropertySegment: + """Represent a property on a path to the erroneous value.""" + + #: Instance that contains the property + instance: Final[Mapping[str, Any]] + + #: Name of the property + name: Final[str] + + def __init__(self, instance: Mapping[str, Any], name: str) -> None: + """Initialize with the given values.""" + self.instance = instance + self.name = name + + +class IndexSegment: + """Represent an index access on a path to the erroneous value.""" + + #: Container that contains the item + container: Final[Iterable[Any]] + + #: Index of the item + index: Final[int] + + def __init__(self, container: Iterable[Any], index: int) -> None: + """Initialize with the given values.""" + self.container = container + self.index = index + + +Segment = Union[PropertySegment, IndexSegment] + + +class Path: + """Represent the relative path to the erroneous value.""" + + def __init__(self) -> None: + """Initialize as an empty path.""" + self._segments = [] # type: List[Segment] + + @property + def segments(self) -> Sequence[Segment]: + """Get the segments of the path.""" + return self._segments + + def _prepend(self, segment: Segment) -> None: + """Insert the :paramref:`segment` in front of other segments.""" + self._segments.insert(0, segment) + + def __str__(self) -> str: + if len(self._segments) == 0: + return "" + + parts = [] # type: List[str] + + iterator = iter(self._segments) + first = next(iterator) + if isinstance(first, PropertySegment): + parts.append(f"{first.name}") + elif isinstance(first, IndexSegment): + parts.append(f"[{first.index}]") + else: + aas_common.assert_never(first) + + for segment in iterator: + if isinstance(segment, PropertySegment): + parts.append(f".{segment.name}") + elif isinstance(segment, IndexSegment): + parts.append(f"[{segment.index}]") + else: + aas_common.assert_never(segment) + + return "".join(parts) + + +class DeserializationException(Exception): + """Signal that the JSON de-serialization could not be performed.""" + + #: Human-readable explanation of the exception's cause + cause: Final[str] + + #: Relative path to the erroneous value + path: Final[Path] + + def __init__(self, cause: str) -> None: + """Initialize with the given :paramref:`cause` and an empty path.""" + self.cause = cause + self.path = Path() + + +# NOTE (mristin, 2022-10-03): +# Recursive definitions are not yet available in mypy +# (see https://github.com/python/mypy/issues/731). We have to use ``Any`` +# here, instead of recursive type annotations. +Jsonable = Union[bool, int, float, str, Sequence[Any], Mapping[str, Any]] + + +MutableJsonable = Union[bool, int, float, str, List[Any], MutableMapping[str, Any]] + + +# region De-serialization + + +def _bool_from_jsonable(jsonable: Jsonable) -> bool: + """ + Parse :paramref:`jsonable` as a boolean. + + :param jsonable: JSON-able structure to be parsed + :return: parsed boolean + :raise: :py:class:`DeserializationException` if unexpected :paramref:`jsonable` + """ + if not isinstance(jsonable, bool): + raise DeserializationException(f"Expected a bool, but got: {type(jsonable)}") + return jsonable + + +def _int_from_jsonable(jsonable: Jsonable) -> int: + """ + Parse :paramref:`jsonable` as an integer. + + :param jsonable: JSON-able structure to be parsed + :return: parsed integer + :raise: :py:class:`DeserializationException` if unexpected :paramref:`jsonable` + """ + if not isinstance(jsonable, int): + raise DeserializationException(f"Expected an int, but got: {type(jsonable)}") + return jsonable + + +def _float_from_jsonable(jsonable: Jsonable) -> float: + """ + Parse :paramref:`jsonable` as a floating-point number. + + :param jsonable: JSON-able structure to be parsed + :return: parsed floating-point number + :raise: :py:class:`DeserializationException` if unexpected :paramref:`jsonable` + """ + if not isinstance(jsonable, float): + raise DeserializationException(f"Expected a float, but got: {type(jsonable)}") + return jsonable + + +def _str_from_jsonable(jsonable: Jsonable) -> str: + """ + Parse :paramref:`jsonable` as a string. + + :param jsonable: JSON-able structure to be parsed + :return: parsed string + :raise: :py:class:`DeserializationException` if unexpected :paramref:`jsonable` + """ + if not isinstance(jsonable, str): + raise DeserializationException(f"Expected a str, but got: {type(jsonable)}") + return jsonable + + +def _bytes_from_jsonable(jsonable: Jsonable) -> bytes: + """ + Decode :paramref:`jsonable` as base64 string to a ``bytearray``. + + :param jsonable: JSON-able structure to be decoded + :return: decoded bytearray + :raise: :py:class:`DeserializationException` if unexpected :paramref:`jsonable` + """ + if not isinstance(jsonable, str): + raise DeserializationException(f"Expected a str, but got: {type(jsonable)}") + + return base64.b64decode(jsonable.encode("ascii")) + + +def _try_to_cast_to_array_like(jsonable: Jsonable) -> Optional[Iterable[Any]]: + """ + Try to cast the ``jsonable`` to something like a JSON array. + + In particular, we explicitly check that the ``jsonable`` is not a mapping, as we + do not want to mistake dictionaries (*i.e.* de-serialized JSON objects) for lists. + + >>> assert _try_to_cast_to_array_like(True) is None + + >>> assert _try_to_cast_to_array_like(0) is None + + >>> assert _try_to_cast_to_array_like(2.2) is None + + >>> assert _try_to_cast_to_array_like("hello") is None + + >>> assert _try_to_cast_to_array_like(b"hello") is None + + >>> _try_to_cast_to_array_like([1, 2]) + [1, 2] + + >>> assert _try_to_cast_to_array_like({"a": 3}) is None + + >>> assert _try_to_cast_to_array_like(collections.OrderedDict()) is None + + >>> _try_to_cast_to_array_like(range(1, 2)) + range(1, 2) + + >>> _try_to_cast_to_array_like((1, 2)) + (1, 2) + + >>> assert _try_to_cast_to_array_like({1, 2, 3}) is None + """ + if ( + not isinstance(jsonable, (str, bytearray, bytes)) + and hasattr(jsonable, "__iter__") + and not hasattr(jsonable, "keys") + # NOTE (mristin): + # There is no easy way to check for sets as opposed to sequence except + # for checking for direct inheritance. A sequence also inherits from + # a collection, so both sequences and sets provide ``__contains__`` method. + # + # See: https://docs.python.org/3/library/collections.abc.html + and not isinstance(jsonable, collections.abc.Set) + ): + return cast(Iterable[Any], jsonable) + + return None + + +class _SetterForListOfPrimitives: + """Provide de-serialization-setters for properties.""" + + def __init__(self) -> None: + """Initialize with all the properties unset.""" + self.strings: Optional[List[str]] = None + self.integers: Optional[List[int]] = None + self.booleans: Optional[List[bool]] = None + + def ignore(self, jsonable: Jsonable) -> None: + """Ignore :paramref:`jsonable` and do not set anything.""" + pass + + def set_strings_from_jsonable(self, jsonable: Jsonable) -> None: + """ + Parse :paramref:`jsonable` as the value of :py:attr:`~strings`. + + :param jsonable: input to be parsed + """ + array_like = _try_to_cast_to_array_like(jsonable) + if array_like is None: + raise DeserializationException( + f"Expected something array-like, but got: {type(jsonable)}" + ) + + items: List[str] = [] + for i, jsonable_item in enumerate(array_like): + try: + item = _str_from_jsonable(jsonable_item) + except DeserializationException as exception: + exception.path._prepend(IndexSegment(array_like, i)) + raise + + items.append(item) + + self.strings = items + + def set_integers_from_jsonable(self, jsonable: Jsonable) -> None: + """ + Parse :paramref:`jsonable` as the value of :py:attr:`~integers`. + + :param jsonable: input to be parsed + """ + array_like = _try_to_cast_to_array_like(jsonable) + if array_like is None: + raise DeserializationException( + f"Expected something array-like, but got: {type(jsonable)}" + ) + + items: List[int] = [] + for i, jsonable_item in enumerate(array_like): + try: + item = _int_from_jsonable(jsonable_item) + except DeserializationException as exception: + exception.path._prepend(IndexSegment(array_like, i)) + raise + + items.append(item) + + self.integers = items + + def set_booleans_from_jsonable(self, jsonable: Jsonable) -> None: + """ + Parse :paramref:`jsonable` as the value of :py:attr:`~booleans`. + + :param jsonable: input to be parsed + """ + array_like = _try_to_cast_to_array_like(jsonable) + if array_like is None: + raise DeserializationException( + f"Expected something array-like, but got: {type(jsonable)}" + ) + + items: List[bool] = [] + for i, jsonable_item in enumerate(array_like): + try: + item = _bool_from_jsonable(jsonable_item) + except DeserializationException as exception: + exception.path._prepend(IndexSegment(array_like, i)) + raise + + items.append(item) + + self.booleans = items + + +def list_of_primitives_from_jsonable(jsonable: Jsonable) -> aas_types.ListOfPrimitives: + """ + Parse an instance of :py:class:`.types.ListOfPrimitives` from the JSON-able + structure :paramref:`jsonable`. + + :param jsonable: structure to be parsed + :return: Parsed instance of :py:class:`.types.ListOfPrimitives` + :raise: :py:class:`DeserializationException` if unexpected :paramref:`jsonable` + """ + if not isinstance(jsonable, collections.abc.Mapping): + raise DeserializationException(f"Expected a mapping, but got: {type(jsonable)}") + + setter = _SetterForListOfPrimitives() + + for key, jsonable_value in jsonable.items(): + setter_method = _SETTER_MAP_FOR_LIST_OF_PRIMITIVES.get(key) + if setter_method is None: + raise DeserializationException(f"Unexpected property: {key}") + + try: + setter_method(setter, jsonable_value) + except DeserializationException as exception: + exception.path._prepend(PropertySegment(jsonable_value, key)) + raise exception + + if setter.strings is None: + raise DeserializationException("The required property 'strings' is missing") + + if setter.integers is None: + raise DeserializationException("The required property 'integers' is missing") + + if setter.booleans is None: + raise DeserializationException("The required property 'booleans' is missing") + + return aas_types.ListOfPrimitives(setter.strings, setter.integers, setter.booleans) + + +_SETTER_MAP_FOR_LIST_OF_PRIMITIVES: Mapping[ + str, Callable[[_SetterForListOfPrimitives, Jsonable], None] +] = { + "strings": _SetterForListOfPrimitives.set_strings_from_jsonable, + "integers": _SetterForListOfPrimitives.set_integers_from_jsonable, + "booleans": _SetterForListOfPrimitives.set_booleans_from_jsonable, + "modelType": _SetterForListOfPrimitives.ignore, +} + + +# endregion + + +# region Serialization + + +def _bytes_to_base64_str(value: bytes) -> str: + """ + Encode :paramref:`value` as a base64 string. + + :param value: to be encoded + :return: encoded :paramref:`value` in base64 + """ + # We need to decode as ascii as ``base64.b64encode`` returns bytes, + # not a string! + return base64.b64encode(value).decode("ascii") + + +class _Serializer(aas_types.AbstractTransformer[MutableJsonable]): + """Transform the instance to its JSON-able representation.""" + + def transform_list_of_primitives( + self, that: aas_types.ListOfPrimitives + ) -> MutableJsonable: + """Serialize :paramref:`that` to a JSON-able representation.""" + jsonable: MutableMapping[str, MutableJsonable] = dict() + + jsonable["strings"] = [item for item in that.strings] + + jsonable["integers"] = [item for item in that.integers] + + jsonable["booleans"] = [item for item in that.booleans] + + return jsonable + + +_SERIALIZER = _Serializer() + + +def to_jsonable(that: aas_types.Class) -> MutableJsonable: + """ + Convert :paramref:`that` to a JSON-able structure. + + :param that: + AAS data to be recursively converted to a JSON-able structure + :return: + JSON-able structure which can be further encoded with, *e.g.*, :py:mod:`json` + """ + return _SERIALIZER.transform(that) + + +# endregion + + +# This code has been automatically generated by aas-core-codegen. +# Do NOT edit or append. diff --git a/test_data/java/test_main/list_of_primitives/expected_output/jsonization/Jsonization.java b/test_data/java/test_main/list_of_primitives/expected_output/jsonization/Jsonization.java new file mode 100644 index 000000000..a0c548c1b --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/jsonization/Jsonization.java @@ -0,0 +1,507 @@ +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ + +package test.jsonization; + +import aas_core.aas3_0.reporting.Reporting; +import aas_core.aas3_0.types.enums.*; +import aas_core.aas3_0.types.impl.*; +import aas_core.aas3_0.types.model.*; +import aas_core.aas3_0.stringification.Stringification; +import aas_core.aas3_0.visitation.AbstractTransformer; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.util.*; +import java.util.function.Function; + +/** + * Provide de/serialization of meta-model classes to/from JSON. + * + *

We can not use one-pass deserialization for JSON since the object + * properties do not have fixed order, and hence we can not read + * {@code modelType} property ahead of the remaining properties. + */ +public class Jsonization { + /** + * Implement the deserialization of meta-model classes from JSON nodes. + * + *

The implementation propagates an {@link Reporting.Error} instead + * of relying on exceptions. Under the assumption that incorrect data is much + * less frequent than correct data, this makes the deserialization more + * efficient. + * + * However, we do not want to force the client to deal with + * the {@link Reporting.Error} class as this is not intuitive. Therefore + * we distinguish the implementation, realized in + * {@link DeserializeImplementation}, and the facade given in + * {@link Deserialize} class. + */ + private static class DeserializeImplementation { + /** Convert {@code value} to a string. + * @param node JSON node to be parsed + */ + private static Result tryStringFrom(JsonNode value) { + if (!value.isTextual()) { + final Reporting.Error error = new Reporting.Error( + "Expected a JsonValue of String, but got " + value.getNodeType()); + return Result.failure(error); + } + return Result.success(value.asText()); + } + + /** Convert {@code value} to a boolean. + * @param node JSON node to be parsed + */ + private static Result tryBooleanFrom(JsonNode value) { + if (!value.isBoolean()) { + final Reporting.Error error = new Reporting.Error( + "Expected a JsonValue of Boolean, but got " + value.getNodeType()); + return Result.failure(error); + } + return Result.success(value.asBoolean()); + } + + /** Convert {@code value} to a long 64-bit integer. + * @param node JSON node to be parsed + */ + private static Result tryLongFrom(JsonNode value) { + if (!value.isLong()) { + final Reporting.Error error = new Reporting.Error( + "Expected a JsonValue of Long, but got " + value.getNodeType()); + return Result.failure(error); + } + return Result.success(value.asLong()); + } + + /** Convert {@code value} to a double-precision 64-bit float. + * @param node JSON node to be parsed + */ + private static Result tryDoubleFrom(JsonNode value) { + if (!value.isDouble()) { + final Reporting.Error error = new Reporting.Error( + "Expected a JsonValue of Double, but got " + value.getNodeType()); + return Result.failure(error); + } + return Result.success(value.asDouble()); + } + + private static Result tryBytesFrom(JsonNode value) { + if (!value.isTextual()) { + final Reporting.Error error = new Reporting.Error( + "Expected a JsonValue of String, but got " + value.getNodeType()); + return Result.failure(error); + } + final byte[] decodedData; + Base64.Decoder decoder = Base64.getDecoder(); + + try { + decodedData = decoder.decode(value.textValue()); + } catch (Exception exception) { + final Reporting.Error error = new Reporting.Error( + "Expected Base-64 encoded bytes, but the conversion failed " + + "because: " + exception.getMessage()); + return Result.failure(error); + } + + return Result.success(decodedData); + } + + /** + * Deserialize an instance of ListOfPrimitives from {@param node}. + * + * @param node JSON node to be parsed + * @param elem Error, if any, during the deserialization + */ + private static Result tryListOfPrimitivesFrom(JsonNode node) { + if (node == null || !node.isObject()) { + final Reporting.Error error = new Reporting.Error( + "Expected a JsonObject, but got " + (node == null ? "null" : node.getNodeType())); + return Result.failure(error); + } + + List theStrings = null; + List theIntegers = null; + List theBooleans = null; + + for (Iterator> iterator = node.fields(); iterator.hasNext(); ) { + Map.Entry currentNode = iterator.next(); + + switch (currentNode.getKey()) { + case "strings": { + if (currentNode.getValue() == null) { + continue; + } + + final JsonNode arrayStrings = currentNode.getValue(); + if (!arrayStrings.isArray()) { + final Reporting.Error error = new Reporting.Error( + "Expected a JsonArray, but got " + arrayStrings.getNodeType()); + error.prependSegment( + new Reporting.NameSegment( + "strings")); + return Result.failure(error); + } + theStrings = new ArrayList<>( + arrayStrings.size()); + int indexStrings = 0; + for (JsonNode item : arrayStrings) { + if (item == null) { + final Reporting.Error error = new Reporting.Error( + "Expected a non-null item, but got a null"); + error.prependSegment( + new Reporting.IndexSegment( + indexStrings)); + error.prependSegment( + new Reporting.NameSegment( + "strings")); + return Result.failure(error); + } + final Result parsedItemResult = + tryStringFrom(item); + if (parsedItemResult.isError()) { + parsedItemResult + .getError() + .prependSegment( + new Reporting.IndexSegment( + indexStrings)); + parsedItemResult + .getError() + .prependSegment( + new Reporting.NameSegment( + "strings")); + return parsedItemResult.castTo(ListOfPrimitives.class); + } + theStrings.add( + parsedItemResult.getResult()); + indexStrings++; + } + break; + } + case "integers": { + if (currentNode.getValue() == null) { + continue; + } + + final JsonNode arrayIntegers = currentNode.getValue(); + if (!arrayIntegers.isArray()) { + final Reporting.Error error = new Reporting.Error( + "Expected a JsonArray, but got " + arrayIntegers.getNodeType()); + error.prependSegment( + new Reporting.NameSegment( + "integers")); + return Result.failure(error); + } + theIntegers = new ArrayList<>( + arrayIntegers.size()); + int indexIntegers = 0; + for (JsonNode item : arrayIntegers) { + if (item == null) { + final Reporting.Error error = new Reporting.Error( + "Expected a non-null item, but got a null"); + error.prependSegment( + new Reporting.IndexSegment( + indexIntegers)); + error.prependSegment( + new Reporting.NameSegment( + "integers")); + return Result.failure(error); + } + final Result parsedItemResult = + tryLongFrom(item); + if (parsedItemResult.isError()) { + parsedItemResult + .getError() + .prependSegment( + new Reporting.IndexSegment( + indexIntegers)); + parsedItemResult + .getError() + .prependSegment( + new Reporting.NameSegment( + "integers")); + return parsedItemResult.castTo(ListOfPrimitives.class); + } + theIntegers.add( + parsedItemResult.getResult()); + indexIntegers++; + } + break; + } + case "booleans": { + if (currentNode.getValue() == null) { + continue; + } + + final JsonNode arrayBooleans = currentNode.getValue(); + if (!arrayBooleans.isArray()) { + final Reporting.Error error = new Reporting.Error( + "Expected a JsonArray, but got " + arrayBooleans.getNodeType()); + error.prependSegment( + new Reporting.NameSegment( + "booleans")); + return Result.failure(error); + } + theBooleans = new ArrayList<>( + arrayBooleans.size()); + int indexBooleans = 0; + for (JsonNode item : arrayBooleans) { + if (item == null) { + final Reporting.Error error = new Reporting.Error( + "Expected a non-null item, but got a null"); + error.prependSegment( + new Reporting.IndexSegment( + indexBooleans)); + error.prependSegment( + new Reporting.NameSegment( + "booleans")); + return Result.failure(error); + } + final Result parsedItemResult = + tryBooleanFrom(item); + if (parsedItemResult.isError()) { + parsedItemResult + .getError() + .prependSegment( + new Reporting.IndexSegment( + indexBooleans)); + parsedItemResult + .getError() + .prependSegment( + new Reporting.NameSegment( + "booleans")); + return parsedItemResult.castTo(ListOfPrimitives.class); + } + theBooleans.add( + parsedItemResult.getResult()); + indexBooleans++; + } + break; + } + default: { + final Reporting.Error error = new Reporting.Error( + "Unexpected property: " + currentNode.getKey()); + return Result.failure(error); + } + } + } + + if (theStrings == null) { + final Reporting.Error error = new Reporting.Error( + "Required property \"strings\" is missing"); + return Result.failure(error); + } + + if (theIntegers == null) { + final Reporting.Error error = new Reporting.Error( + "Required property \"integers\" is missing"); + return Result.failure(error); + } + + if (theBooleans == null) { + final Reporting.Error error = new Reporting.Error( + "Required property \"booleans\" is missing"); + return Result.failure(error); + } + + return Result.success(new ListOfPrimitives( + theStrings, + theIntegers, + theBooleans)); + } + } + + /** + * Represent a critical error during the deserialization. + */ + @SuppressWarnings("serial") + public static class DeserializeException extends RuntimeException { + private final String path; + private final String reason; + + public DeserializeException(String path, String reason) { + super(reason + " at: " + ("".equals(path) ? "the beginning" : path)); + this.path = path; + this.reason = reason; + } + + public Optional getPath() { + return Optional.ofNullable(path); + } + + public Optional getReason() { + return Optional.ofNullable(reason); + } + } + + private static class Result { + private final T result; + private final Reporting.Error error; + private final boolean success; + + private Result(T result, Reporting.Error error, boolean success) { + this.result = result; + this.error = error; + this.success = success; + } + + public static Result success(T result) { + if (result == null) throw new IllegalArgumentException("Result must not be null."); + return new Result<>(result, null, true); + } + + public static Result failure(Reporting.Error error) { + if (error == null) throw new IllegalArgumentException("Error must not be null."); + return new Result<>(null, error, false); + } + + @SuppressWarnings("unchecked") + public Result castTo(Class type) { + if (isError() || type.isInstance(result)) return (Result) this; + throw new IllegalStateException("Result of type " + + result.getClass().getName() + + " is not an instance of " + + type.getName()); + } + + public T getResult() { + if (!isSuccess()) throw new IllegalStateException("Result is not present."); + return result; + } + + public boolean isSuccess() { + return success; + } + + public boolean isError() { + return !success; + } + + public Reporting.Error getError() { + if (isSuccess()) throw new IllegalStateException("Result is present."); + return error; + } + + public R map(Function successFunction, Function errorFunction) { + return isSuccess() ? successFunction.apply(result) : errorFunction.apply(error); + } + + public T onError(Function errorFunction) { + return map(Function.identity(), errorFunction); + } + } + + /** + * Deserialize instances of meta-model classes from JSON nodes. + * + * Here is an example how to parse an instance of ListOfPrimitives: + *

{@code
+     * String someString = "... some JSON ...";
+     * ObjectMapper objectMapper = new ObjectMapper();
+     * JsonNode node = objectMapper.readTree(someString);
+     * ListOfPrimitives anInstance = Deserialize.deserializeListOfPrimitives(
+     *   node);
+     * }
+ */ + public static class Deserialize + { + /** + * Deserialize an instance of ListOfPrimitives from {@code node}. + * + * @param node JSON node to be parsed + */ + public static ListOfPrimitives deserializeListOfPrimitives(JsonNode node) { + final Result result = + DeserializeImplementation.tryListOfPrimitivesFrom( + node); + + return result.onError(error -> { + throw new DeserializeException( + Reporting.generateJsonPath(error.getPathSegments()), + error.getCause()); + }); + } + } + + private static class Transformer extends AbstractTransformer { + /** + * Convert {@code that} 64-bit long integer to a JSON value. + * + * @param that value to be converted + */ + private static JsonNode toJsonNode(Long that) { + // We need to check that we can perform a lossless conversion. + long primitiveThat = that.longValue(); + if ((long)((double)primitiveThat) != primitiveThat) { + throw new IllegalArgumentException( + "The number can not be losslessly represented in JSON: " + that); + } + return JsonNodeFactory.instance.numberNode(that); + } + + @Override + public JsonNode transformListOfPrimitives( + IListOfPrimitives that + ) { + final ObjectNode result = JsonNodeFactory.instance.objectNode(); + + final ArrayNode arrayStrings = JsonNodeFactory.instance.arrayNode(); + for (String item : that.getStrings()) { + arrayStrings.add( + JsonNodeFactory.instance.textNode( + item)); + } + result.set("strings", arrayStrings); + + final ArrayNode arrayIntegers = JsonNodeFactory.instance.arrayNode(); + for (Long item : that.getIntegers()) { + arrayIntegers.add( + Transformer.toJsonValue( + item)); + } + result.set("integers", arrayIntegers); + + final ArrayNode arrayBooleans = JsonNodeFactory.instance.arrayNode(); + for (Boolean item : that.getBooleans()) { + arrayBooleans.add( + JsonNodeFactory.instance.booleanNode( + item)); + } + result.set("booleans", arrayBooleans); + + return result; + } + } + + /** + * Serialize instances of meta-model classes to JSON elements. + * + * Here is an example how to serialize an instance of ListOfPrimitives: + *
{@code
+     * ListOfPrimitives anInstance = new ListOfPrimitives(
+     *     // ... some constructor arguments ...
+     * );
+     * JsonNode element = Jsonization.Serialize.toJsonObject(
+     *     anInstance));
+     * }
+ */ + public static class Serialize + { + private static final Transformer transformer = new Transformer(); + + /** + * Serialize an instance of the meta-model into a JSON object. + */ + public static JsonNode toJsonObject(IClass that) { + return transformer.transform(that); + } + } +} + +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ diff --git a/test_data/java/test_main/list_of_primitives/expected_output/reporting/Reporting.java b/test_data/java/test_main/list_of_primitives/expected_output/reporting/Reporting.java new file mode 100644 index 000000000..3edf467ce --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/reporting/Reporting.java @@ -0,0 +1,168 @@ +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ + +package test.reporting; + +import java.util.ArrayList; +import java.util.Deque; +import java.util.Collections; +import java.util.Collection; +import java.util.List; +import java.util.LinkedList; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Provide reporting for de/serialization and verification. + */ +public class Reporting +{ + /** + * Capture a path segment of a value in a model. + */ + public static abstract class Segment { + // Intentionally empty. + } + + public static class NameSegment extends Segment { + private final String name; + public NameSegment(String name) { + this.name = Objects.requireNonNull(name, + "Argument \"name\" must be non-null."); + } + public String getName(){ + return name; + } + } + + public static class IndexSegment extends Segment{ + private final Integer index; + public IndexSegment(int index) { + this.index = index; + } + public Integer getIndex(){ + return index; + } + } + + private static final Pattern variableNameRe = Pattern.compile("^[a-zA-Z_][a-zA-Z_0-9]*$"); + + /** + * Generate a JSON Path based on the path segments. + * + *

See, for example, this page for more information on JSON path: + * https://support.smartbear.com/alertsite/docs/monitors/api/endpoint/jsonpath.html + */ + public static String generateJsonPath(Collection segments) { + ArrayList parts = new ArrayList<>(segments.size()); + int i = 0; + + for (Segment segment : segments) { + String part; + + if (segment instanceof NameSegment) { + NameSegment nameSegment = (NameSegment) segment; + Matcher m = variableNameRe.matcher(nameSegment.getName()); + + if (m.matches()) { + part = (i == 0) ? nameSegment.getName() : "." + nameSegment.getName(); + } else { + String escaped = nameSegment.getName() + .replace("\t", "\\t") + .replace("\b", "\\b") + .replace("\n", "\\n") + .replace("\r", "\\r") + .replace("\f", "\\f") + .replace("\"", "\\\"") + .replace("\\", "\\\\"); + + part = "[\"" + escaped + "\"]"; + } + } else if (segment instanceof IndexSegment) { + IndexSegment indexSegment = (IndexSegment) segment; + part = "[" + indexSegment.getIndex() + "]"; + } else { + throw new RuntimeException( + "Unexpected segment type: " + segment.getClass().getSimpleName() + ); + } + + parts.add(part); + i++; + } + return String.join("", parts); + } + + /** + * Escape special characters for XPath. + */ + private static String escapeForXPath(String text) { + return text + .replace("&", "&") + .replace("/", "/") + .replace("<", "<") + .replace(">", ">") + .replace("\"", """) + .replace("'", "'"); + } + + /** + * Generate a relative XPath based on the path segments. + * + *

This method leaves out the leading slash ('/'). This is helpful if + * to embed the error report in a larger document with a prefix etc. + */ + public static String generateRelativeXPath(Collection segments) { + final List parts = new ArrayList<>(); + segments.forEach(segment -> { + String part; + if (segment instanceof NameSegment) { + final NameSegment nameSegment = ((NameSegment) segment); + final String name = nameSegment.getName(); + part = escapeForXPath(name); + } else if (segment instanceof IndexSegment) { + final IndexSegment indexSegment = ((IndexSegment) segment); + final int index = indexSegment.getIndex(); + part = "*[" + index + "]"; + } else { + throw new IllegalArgumentException("Unexpected segment type: " + + segment.getClass().getSimpleName()); + } + parts.add(part); + }); + return String.join("/", parts); + } + + /** + * Represent an error during the deserialization or the verification. + */ + public static class Error { + private final Deque pathSegments = new LinkedList<>(); + private final String cause; + + public Error(String cause) { + this.cause = cause; + } + + public void prependSegment(Segment segment) { + pathSegments.addFirst(segment); + } + + public String getCause() { + return cause; + } + + public Collection getPathSegments() { + return pathSegments; + } + } +} + +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ diff --git a/test_data/java/test_main/list_of_primitives/expected_output/stdout.txt b/test_data/java/test_main/list_of_primitives/expected_output/stdout.txt new file mode 100644 index 000000000..2d755fc5a --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/stdout.txt @@ -0,0 +1 @@ +Code generated to: diff --git a/test_data/java/test_main/list_of_primitives/expected_output/stringification.py b/test_data/java/test_main/list_of_primitives/expected_output/stringification.py new file mode 100644 index 000000000..471133925 --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/stringification.py @@ -0,0 +1,17 @@ +"""De-serialize enumerations from string representations.""" + + +# This code has been automatically generated by aas-core-codegen. +# Do NOT edit or append. + + +from typing import ( + Mapping, + Optional, +) + +import test.types as aas_types + + +# This code has been automatically generated by aas-core-codegen. +# Do NOT edit or append. diff --git a/test_data/java/test_main/list_of_primitives/expected_output/stringification/Stringification.java b/test_data/java/test_main/list_of_primitives/expected_output/stringification/Stringification.java new file mode 100644 index 000000000..b226eb6fb --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/stringification/Stringification.java @@ -0,0 +1,22 @@ +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ + +package test.stringification; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import test.types.enums.*; + +public class Stringification { + +} + +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ diff --git a/test_data/java/test_main/list_of_primitives/expected_output/types.py b/test_data/java/test_main/list_of_primitives/expected_output/types.py new file mode 100644 index 000000000..82ca5b6eb --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/types.py @@ -0,0 +1,291 @@ +# This code has been automatically generated by aas-core-codegen. +# Do NOT edit or append. + + +import abc +import enum +from typing import Generic, Iterator, Optional, TypeVar, List + + +T = TypeVar("T") +ContextT = TypeVar("ContextT") + + +class Class(abc.ABC): + """Represent the most general class of an AAS model.""" + + @abc.abstractmethod + def descend_once(self) -> Iterator["Class"]: + """Iterate over all the instances referenced from this one.""" + raise NotImplementedError() + + @abc.abstractmethod + def descend(self) -> Iterator["Class"]: + """Iterate recursively over all the instances referenced from this one.""" + raise NotImplementedError() + + @abc.abstractmethod + def accept(self, visitor: "AbstractVisitor") -> None: + """ + Dispatch the :paramref:`visitor` on this instance. + + :param visitor: to be dispatched + """ + raise NotImplementedError() + + @abc.abstractmethod + def accept_with_context( + self, visitor: "AbstractVisitorWithContext[ContextT]", context: ContextT + ) -> None: + """ + Dispatch the :paramref:`visitor` on this instance with :paramref:`context`. + + :param visitor: to be dispatched + :param context: of the visitation + """ + raise NotImplementedError() + + @abc.abstractmethod + def transform(self, transformer: "AbstractTransformer[T]") -> T: + """ + Dispatch the :paramref:`transformer` on this instance. + + :param transformer: to be dispatched + :return: transformed self + """ + raise NotImplementedError() + + @abc.abstractmethod + def transform_with_context( + self, + transformer: "AbstractTransformerWithContext[ContextT, T]", + context: ContextT, + ) -> T: + """ + Dispatch the :paramref:`transformer` on this instance with :paramref:`context`. + + :param transformer: to be dispatched + :return: transformed self + """ + raise NotImplementedError() + + +# pylint: disable=redefined-builtin + + +class ListOfPrimitives(Class): + # pylint: disable=missing-class-docstring + + strings: List[str] + + integers: List[int] + + booleans: List[bool] + + def descend_once(self) -> Iterator[Class]: + """ + Iterate over the instances referenced from this instance. + + We do not recurse into the referenced instance. + + :yield: instances directly referenced from this instance + """ + # No descendable properties + return + # For this uncommon return-yield construction, see: + # https://stackoverflow.com/questions/13243766/how-to-define-an-empty-generator-function + # noinspection PyUnreachableCode + yield + + def descend(self) -> Iterator[Class]: + """ + Iterate recursively over the instances referenced from this one. + + :yield: instances recursively referenced from this instance + """ + # No descendable properties + return + # For this uncommon return-yield construction, see: + # https://stackoverflow.com/questions/13243766/how-to-define-an-empty-generator-function + # noinspection PyUnreachableCode + yield + + def accept(self, visitor: "AbstractVisitor") -> None: + """Dispatch the :paramref:`visitor` on this instance.""" + visitor.visit_list_of_primitives(self) + + def accept_with_context( + self, visitor: "AbstractVisitorWithContext[ContextT]", context: ContextT + ) -> None: + """Dispatch the :paramref:`visitor` on this instance in :paramref:`context`.""" + visitor.visit_list_of_primitives_with_context(self, context) + + def transform(self, transformer: "AbstractTransformer[T]") -> T: + """Dispatch the :paramref:`transformer` on this instance.""" + return transformer.transform_list_of_primitives(self) + + def transform_with_context( + self, + transformer: "AbstractTransformerWithContext[ContextT, T]", + context: ContextT, + ) -> T: + """ + Dispatch the :paramref:`transformer` on this instance in :paramref:`context`. + """ + return transformer.transform_list_of_primitives_with_context(self, context) + + def __init__( + self, strings: List[str], integers: List[int], booleans: List[bool] + ) -> None: + """Initialize with the given values.""" + self.strings = strings + self.integers = integers + self.booleans = booleans + + +class AbstractVisitor: + """Visit the instances of the model.""" + + def visit(self, that: Class) -> None: + """Double-dispatch on :paramref:`that`.""" + that.accept(self) + + @abc.abstractmethod + def visit_list_of_primitives(self, that: ListOfPrimitives) -> None: + """Visit :paramref:`that`.""" + raise NotImplementedError() + + +class AbstractVisitorWithContext(Generic[ContextT]): + """Visit the instances of the model with context.""" + + def visit_with_context(self, that: Class, context: ContextT) -> None: + """Double-dispatch on :paramref:`that`.""" + that.accept_with_context(self, context) + + @abc.abstractmethod + def visit_list_of_primitives_with_context( + self, that: ListOfPrimitives, context: ContextT + ) -> None: + """Visit :paramref:`that` in :paramref:`context`.""" + raise NotImplementedError() + + +class PassThroughVisitor(AbstractVisitor): + """ + Visit the instances of the model without action. + + This visitor is not meant to be directly used. Instead, you usually + inherit from it, and implement only the relevant visit methods. + """ + + def visit(self, that: Class) -> None: + """Double-dispatch on :paramref:`that`.""" + that.accept(self) + + def visit_list_of_primitives(self, that: ListOfPrimitives) -> None: + """Visit :paramref:`that`.""" + for another in that.descend_once(): + self.visit(another) + + +class PassThroughVisitorWithContext(AbstractVisitorWithContext[ContextT]): + """ + Visit the instances of the model without action and in context. + + This visitor is not meant to be directly used. Instead, you usually + inherit from it, and implement only the relevant visit methods. + """ + + def visit_with_context(self, that: Class, context: ContextT) -> None: + """Double-dispatch on :paramref:`that`.""" + that.accept_with_context(self, context) + + def visit_list_of_primitives_with_context( + self, that: ListOfPrimitives, context: ContextT + ) -> None: + """Visit :paramref:`that` in :paramref:`context`.""" + for another in that.descend_once(): + self.visit_with_context(another, context) + + +class AbstractTransformer(Generic[T]): + """Transform the instances of the model.""" + + def transform(self, that: Class) -> T: + """Double-dispatch on :paramref:`that`.""" + return that.transform(self) + + @abc.abstractmethod + def transform_list_of_primitives(self, that: ListOfPrimitives) -> T: + """Transform :paramref:`that`.""" + raise NotImplementedError() + + +class AbstractTransformerWithContext(Generic[ContextT, T]): + """Transform the instances of the model in context.""" + + def transform_with_context(self, that: Class, context: ContextT) -> T: + """Double-dispatch on :paramref:`that`.""" + return that.transform_with_context(self, context) + + @abc.abstractmethod + def transform_list_of_primitives_with_context( + self, that: ListOfPrimitives, context: ContextT + ) -> T: + """Transform :paramref:`that` in :paramref:`context`.""" + raise NotImplementedError() + + +class TransformerWithDefault(AbstractTransformer[T]): + """ + Transform the instances of the model. + + If you do not override the transformation methods, they simply + return :py:attr:`.default`. + """ + + #: Default value which is returned if no override of the transformation + default: T + + def __init__(self, default: T) -> None: + """Initialize with the given :paramref:`default` value.""" + self.default = default + + def transform(self, that: Class) -> T: + """Double-dispatch on :paramref:`that`.""" + return that.transform(self) + + def transform_list_of_primitives(self, that: ListOfPrimitives) -> T: + """Transform :paramref:`that`.""" + return self.default + + +class TransformerWithDefaultAndContext(AbstractTransformerWithContext[ContextT, T]): + """ + Transform the instances of the model in context. + + If you do not override the transformation methods, they simply + return :py:attr:`.default`. + """ + + #: Default value which is returned if no override of the transformation + default: T + + def __init__(self, default: T) -> None: + """Initialize with the given :paramref:`default` value.""" + self.default = default + + def transform_with_context(self, that: Class, context: ContextT) -> T: + """Double-dispatch on :paramref:`that`.""" + return that.transform_with_context(self, context) + + def transform_list_of_primitives_with_context( + self, that: ListOfPrimitives, context: ContextT + ) -> T: + """Transform :paramref:`that` in :paramref:`context`.""" + return self.default + + +# This code has been automatically generated by aas-core-codegen. +# Do NOT edit or append. diff --git a/test_data/java/test_main/list_of_primitives/expected_output/types/impl/ListOfPrimitives.java b/test_data/java/test_main/list_of_primitives/expected_output/types/impl/ListOfPrimitives.java new file mode 100644 index 000000000..fc64708be --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/types/impl/ListOfPrimitives.java @@ -0,0 +1,138 @@ +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ + +package test.types.impl; + +import test.visitation.IVisitor; +import test.visitation.IVisitorWithContext; +import test.visitation.ITransformer; +import test.visitation.ITransformerWithContext; +import test.types.enums.*; +import test.types.impl.*; +import test.types.model.*; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.Objects; +import test.types.model.IListOfPrimitives; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +public class ListOfPrimitives implements IListOfPrimitives { + private List strings; + + private List integers; + + private List booleans; + + public ListOfPrimitives( + List strings, + List integers, + List booleans) { + this.strings = Objects.requireNonNull( + strings, + "Argument \"strings\" must be non-null."); + this.integers = Objects.requireNonNull( + integers, + "Argument \"integers\" must be non-null."); + this.booleans = Objects.requireNonNull( + booleans, + "Argument \"booleans\" must be non-null."); + } + + @Override + public List getStrings() { + return strings; + } + + @Override + public void setStrings(List strings) { + this.strings = Objects.requireNonNull( + strings, + "Argument \"strings\" must be non-null."); + } + + @Override + public List getIntegers() { + return integers; + } + + @Override + public void setIntegers(List integers) { + this.integers = Objects.requireNonNull( + integers, + "Argument \"integers\" must be non-null."); + } + + @Override + public List getBooleans() { + return booleans; + } + + @Override + public void setBooleans(List booleans) { + this.booleans = Objects.requireNonNull( + booleans, + "Argument \"booleans\" must be non-null."); + } + + /** + * Iterate recursively over all the class instances referenced from this instance. + */ + public Iterable descend() { + return Collections.emptyList(); + } + + /** + * Iterate over all the class instances referenced from this instance. + */ + public Iterable descendOnce() { + return Collections.emptyList(); + } + + /** + * Accept the {@code visitor} to visit this instance for double dispatch. + **/ + @Override + public void accept(IVisitor visitor) { + visitor.visitListOfPrimitives(this); + } + + /** + * Accept the {@code visitor} to visit this instance for double dispatch + * with the {@code context}. + **/ + @Override + public void accept( + IVisitorWithContext visitor, + ContextT context) { + visitor.visitListOfPrimitives(this, context); + } + + /** + * Accept the {@code transformer} to visit this instance for double dispatch. + **/ + @Override + public T transform(ITransformer transformer) { + return transformer.transformListOfPrimitives(this); + } + + /** + * Accept the {@code transformer} to visit this instance for double dispatch + * with the {@code context}. + **/ + @Override + public T transform( + ITransformerWithContext transformer, + ContextT context) { + return transformer.transformListOfPrimitives(this, context); + } +} + +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ diff --git a/test_data/java/test_main/list_of_primitives/expected_output/types/model/IClass.java b/test_data/java/test_main/list_of_primitives/expected_output/types/model/IClass.java new file mode 100644 index 000000000..3f96b6f7d --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/types/model/IClass.java @@ -0,0 +1,61 @@ +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ + +package test.types.model; + +import test.visitation.ITransformer; +import test.visitation.ITransformerWithContext; +import test.visitation.IVisitor; +import test.visitation.IVisitorWithContext; +import java.lang.Iterable; + +/** + * Represent a general class of an AAS model. + */ +public interface IClass { + /** + * Iterate over all the class instances referenced from this instance + * without further recursion. + */ + Iterable descendOnce(); + + /** + * Iterate recursively over all the class instances referenced from this instance. + */ + Iterable descend(); + + /** + * Accept the {@code visitor} to visit this instance + * for double dispatch. + */ + void accept(IVisitor visitor); + + /** + * Accept the visitor to visit this instance for double dispatch + * with the {@code context}. + */ + void accept( + IVisitorWithContext visitor, + ContextT context); + + /** + * Accept the {@code transformer} to transform this instance + * for double dispatch. + */ + T transform(ITransformer transformer); + + /** + * Accept the {@code transformer} to visit this instance + * for double dispatch with the {@code context}. + */ + T transform( + ITransformerWithContext transformer, + ContextT context); +} + +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ diff --git a/test_data/java/test_main/list_of_primitives/expected_output/types/model/IListOfPrimitives.java b/test_data/java/test_main/list_of_primitives/expected_output/types/model/IListOfPrimitives.java new file mode 100644 index 000000000..0f39dc389 --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/types/model/IListOfPrimitives.java @@ -0,0 +1,32 @@ +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ + +package test.types.model; + +import test.types.enums.*; +import test.types.impl.*; +import test.types.model.*; +import java.util.List; +import test.types.model.IClass; +import java.util.Optional; + +public interface IListOfPrimitives extends IClass { + List getStrings(); + + void setStrings(List strings); + + List getIntegers(); + + void setIntegers(List integers); + + List getBooleans(); + + void setBooleans(List booleans); +} + +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ diff --git a/test_data/java/test_main/list_of_primitives/expected_output/verification.py b/test_data/java/test_main/list_of_primitives/expected_output/verification.py new file mode 100644 index 000000000..bc5ae3731 --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/verification.py @@ -0,0 +1,156 @@ +""" +Verify that the instances of the meta-model satisfy the invariants. + +Here is an example how to verify an instance of :py:class:`test.types.ListOfPrimitives`: + +.. code-block:: + + import test.types as aas_types + import test.verification as aas_verification + + an_instance = aas_types.ListOfPrimitives( + # ... some constructor arguments ... + ) + + for error in aas_verification.verify(an_instance): + print(f"{error.cause} at: {error.path}") +""" + + +# This code has been automatically generated by aas-core-codegen. +# Do NOT edit or append. + + +import math +import re +import struct +import sys +from typing import ( + Callable, + Iterable, + Iterator, + List, + Mapping, + Optional, + Pattern, + Sequence, + Set, + Union, +) + +if sys.version_info >= (3, 8): + from typing import Final +else: + from typing_extensions import Final + +from test import ( + constants as aas_constants, + types as aas_types, +) + + +class PropertySegment: + """Represent a property access on a path to an erroneous value.""" + + #: Instance containing the property + instance: Final[aas_types.Class] + + #: Name of the property + name: Final[str] + + def __init__(self, instance: aas_types.Class, name: str) -> None: + """Initialize with the given values.""" + self.instance = instance + self.name = name + + def __str__(self) -> str: + return f".{self.name}" + + +class IndexSegment: + """Represent an index access on a path to an erroneous value.""" + + #: Sequence containing the item at :py:attr:`~index` + sequence: Final[Sequence[aas_types.Class]] + + #: Index of the item + index: Final[int] + + def __init__(self, sequence: Sequence[aas_types.Class], index: int) -> None: + """Initialize with the given values.""" + self.sequence = sequence + self.index = index + + def __str__(self) -> str: + return f"[{self.index}]" + + +Segment = Union[PropertySegment, IndexSegment] + + +class Path: + """Represent the relative path to the erroneous value.""" + + def __init__(self) -> None: + """Initialize as an empty path.""" + self._segments = [] # type: List[Segment] + + @property + def segments(self) -> Sequence[Segment]: + """Get the segments of the path.""" + return self._segments + + def _prepend(self, segment: Segment) -> None: + """Insert the :paramref:`segment` in front of other segments.""" + self._segments.insert(0, segment) + + def __str__(self) -> str: + return "".join(str(segment) for segment in self._segments) + + +class Error: + """Represent a verification error in the data.""" + + #: Human-readable description of the error + cause: Final[str] + + #: Path to the erroneous value + path: Final[Path] + + def __init__(self, cause: str) -> None: + """Initialize as an error with an empty path.""" + self.cause = cause + self.path = Path() + + def __repr__(self) -> str: + return f"Error(path={self.path}, cause={self.cause})" + + +class _Transformer(aas_types.AbstractTransformer[Iterator[Error]]): + # noinspection PyMethodMayBeStatic + def transform_list_of_primitives( + self, that: aas_types.ListOfPrimitives + ) -> Iterator[Error]: + # No verification has been defined for ListOfPrimitives. + return + # For this uncommon return-yield construction, see: + # https://stackoverflow.com/questions/13243766/how-to-define-an-empty-generator-function + # noinspection PyUnreachableCode + yield + + +_TRANSFORMER = _Transformer() + + +def verify(that: aas_types.Class) -> Iterator[Error]: + """ + Verify the constraints of :paramref:`that` recursively. + + :param that: instance whose constraints we want to verify + :yield: constraint violations + """ + yield from _TRANSFORMER.transform(that) + + +# This code has been automatically generated by aas-core-codegen. +# Do NOT edit or append. diff --git a/test_data/java/test_main/list_of_primitives/expected_output/verification/Verification.java b/test_data/java/test_main/list_of_primitives/expected_output/verification/Verification.java new file mode 100644 index 000000000..83d904e31 --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/verification/Verification.java @@ -0,0 +1,153 @@ +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ + +package test.verification; + +import java.lang.Iterable; +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Collections; +import java.util.function.Consumer; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.Set; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.stream.IntStream; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; +import aas_core.aas3_0.constants.*; +import aas_core.aas3_0.reporting.Reporting; +import aas_core.aas3_0.types.enums.*; +import aas_core.aas3_0.types.model.*; +import aas_core.aas3_0.visitation.AbstractTransformer; + +public class Verification { + /** + * Hash allowed enum values for efficient validation of enums. + */ + private static class EnumValueSet { + + } + + private static final Transformer transformer = new Transformer(); + + private static class Transformer extends AbstractTransformer> { + @Override + public Stream transformListOfPrimitives( + IListOfPrimitives that) { + Stream errorStream = Stream.empty(); + + // No verification has been defined for ListOfPrimitives. + + return errorStream; + } + } + + public static Stream verifyToErrorStream(IClass that) { + return transformer.transform(that); + } + + private static class ValidationErrorIterable implements Iterable { + private final IClass element; + + public ValidationErrorIterable(IClass element) { + this.element = element; + } + + @Override + public Iterator iterator() { + Stream stream = stream(); + + return stream.iterator(); + } + + @Override + public void forEach(Consumer action) { + Stream stream = stream(); + + stream.forEach(action); + } + + @Override + public Spliterator spliterator() { + Stream stream = stream(); + + return stream.spliterator(); + } + + private Stream stream() { + return Verification.verifyToErrorStream(element); + } + } + + /** + * Verify the constraints of {@code that} recursively. + * + * @param that The instance of the meta-model to be verified + */ + public static Iterable verify(IClass that) { + return new ValidationErrorIterable(that); + } + + private static class Pair { + private final A first; + private final B second; + + public Pair(A first, B second) { + this.first = first; + this.second = second; + } + + public A getFirst() { + return first; + } + + public B getSecond() { + return second; + } + } + + // Java 8 doesn't provide a split operation out of the box, so we have to ship our own. + // Adapted from: https://stackoverflow.com/a/23529010 + private static Stream> zip( + Stream a, + Stream b) { + Spliterator aSplit = Objects.requireNonNull(a).spliterator(); + Spliterator bSplit = Objects.requireNonNull(b).spliterator(); + + int characteristics = aSplit.characteristics() & bSplit.characteristics() & + ~(Spliterator.DISTINCT | Spliterator.SORTED); + + long zipSize = ((characteristics & Spliterator.SIZED) != 0) + ? Math.min(aSplit.getExactSizeIfKnown(), bSplit.getExactSizeIfKnown()) + : -1; + + Iterator aIter = Spliterators.iterator(aSplit); + Iterator bIter = Spliterators.iterator(bSplit); + Iterator> cIter = new Iterator>() { + @Override + public boolean hasNext() { + return aIter.hasNext() && bIter.hasNext(); + } + + @Override + public Pair next() { + return new Pair<>(aIter.next(), bIter.next()); + } + }; + + Spliterator> split = Spliterators.spliterator(cIter, zipSize, characteristics); + return StreamSupport.stream(split, false); + } +} + +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ diff --git a/test_data/java/test_main/list_of_primitives/expected_output/visitation/AbstractTransformer.java b/test_data/java/test_main/list_of_primitives/expected_output/visitation/AbstractTransformer.java new file mode 100644 index 000000000..b016a493c --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/visitation/AbstractTransformer.java @@ -0,0 +1,32 @@ +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ + +package test.visitation; + +import test.types.model.*; +import test.visitation.ITransformer; + +/** + * Perform double-dispatch to transform recursively + * the instances into something else. + * + * @param type of the transformation result + */ +public abstract class AbstractTransformer implements ITransformer +{ + public T transform(IClass that) + { + return that.transform(this); + } + + public abstract T transformListOfPrimitives( + IListOfPrimitives that + ); +} + +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ diff --git a/test_data/java/test_main/list_of_primitives/expected_output/visitation/AbstractTransformerWithContext.java b/test_data/java/test_main/list_of_primitives/expected_output/visitation/AbstractTransformerWithContext.java new file mode 100644 index 000000000..84a44cbb6 --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/visitation/AbstractTransformerWithContext.java @@ -0,0 +1,39 @@ +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ + +package test.visitation; + +import test.types.model.*; +import test.visitation.ITransformerWithContext; + +/** + * Perform double-dispatch to transform recursively + * the instances into something else. + * + *

When you use the transformer, please always call the main dispatching method + * {@link AbstractTransformerWithContext#transform}. You should most probably never call the {@code transform} + * methods directly. They are only made public so that model classes can access them. + * + * @param structure of the context + * @param type of the transformation result + */ +public abstract class AbstractTransformerWithContext + implements ITransformerWithContext +{ + public T transform(IClass that, ContextT context) + { + return that.transform(this, context); + } + + public abstract T transformListOfPrimitives( + IListOfPrimitives that, + ContextT context + ); +} + +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ diff --git a/test_data/java/test_main/list_of_primitives/expected_output/visitation/AbstractVisitor.java b/test_data/java/test_main/list_of_primitives/expected_output/visitation/AbstractVisitor.java new file mode 100644 index 000000000..4f236a95f --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/visitation/AbstractVisitor.java @@ -0,0 +1,28 @@ +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ + +package test.visitation; + +import test.types.model.*; +import test.visitation.IVisitor; + +/** + * Perform double-dispatch to visit the concrete instances. + */ +public abstract class AbstractVisitor implements IVisitor +{ + public void visit(IClass that) + { + that.accept(this); + } + public abstract void visitListOfPrimitives( + IListOfPrimitives that + ); +} + +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ diff --git a/test_data/java/test_main/list_of_primitives/expected_output/visitation/AbstractVisitorWithContext.java b/test_data/java/test_main/list_of_primitives/expected_output/visitation/AbstractVisitorWithContext.java new file mode 100644 index 000000000..1c4e0a891 --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/visitation/AbstractVisitorWithContext.java @@ -0,0 +1,33 @@ +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ + +package test.visitation; + +import test.types.model.*; +import test.visitation.IVisitorWithContext; + +/** + * Perform double-dispatch to visit the concrete instances + * with context. + * + * @param structure of the context + */ +public abstract class AbstractVisitorWithContext + implements IVisitorWithContext +{ + public void visit(IClass that, ContextT context) + { + that.accept(this, context); + } + public abstract void visitListOfPrimitives( + IListOfPrimitives that, + ContextT context + ); +} + +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ diff --git a/test_data/java/test_main/list_of_primitives/expected_output/visitation/ITransformer.java b/test_data/java/test_main/list_of_primitives/expected_output/visitation/ITransformer.java new file mode 100644 index 000000000..328532935 --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/visitation/ITransformer.java @@ -0,0 +1,30 @@ +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ + +package test.visitation; + +import test.types.model.*; + +/** + * Define the interface for a transformer which transforms recursively + * the instances into something else. + * + *

When you use the transformer, please always call the main dispatching method + * {@link ITransformer#transform}. You should most probably never call the {@code transform} + * methods directly. They are only made public so that model classes can access them. + * + * @param type of the transformation result + */ +public interface ITransformer { + T transform(IClass that); + T transformListOfPrimitives( + IListOfPrimitives that + ); +} + +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ diff --git a/test_data/java/test_main/list_of_primitives/expected_output/visitation/ITransformerWithContext.java b/test_data/java/test_main/list_of_primitives/expected_output/visitation/ITransformerWithContext.java new file mode 100644 index 000000000..1622d8470 --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/visitation/ITransformerWithContext.java @@ -0,0 +1,32 @@ +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ + +package test.visitation; + +import test.types.model.*; + +/** + * Define the interface for a transformer which recursively transforms + * the instances into something else while the context is passed along. + * + *

When you use the transformer, please always call the main dispatching method + * {@link ITransformerWithContext#transform}. You should most probably never call the {@code transform} + * methods directly. They are only made public so that model classes can access them. + * + * @param structure of the context + * @param type of the transformation result + */ +public interface ITransformerWithContext { + T transform(IClass that, ContextT context); + T transformListOfPrimitives( + IListOfPrimitives that, + ContextT context + ); +} + +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ diff --git a/test_data/java/test_main/list_of_primitives/expected_output/visitation/IVisitor.java b/test_data/java/test_main/list_of_primitives/expected_output/visitation/IVisitor.java new file mode 100644 index 000000000..29c375a7f --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/visitation/IVisitor.java @@ -0,0 +1,28 @@ +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ + +package test.visitation; + +import test.types.model.*; + +/** + * Define the interface for a visitor which visits the instances of the model. + * + *

When you use the visitor, please always call the main dispatching method + * {@link IVisitor#visit}. You should most probably never call the {@code visit*} + * methods directly. They are only made public so that model classes can access them. + */ +public interface IVisitor +{ + void visit(IClass that); + void visitListOfPrimitives( + IListOfPrimitives that + ); +} + +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ diff --git a/test_data/java/test_main/list_of_primitives/expected_output/visitation/IVisitorWithContext.java b/test_data/java/test_main/list_of_primitives/expected_output/visitation/IVisitorWithContext.java new file mode 100644 index 000000000..ac113a52d --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/visitation/IVisitorWithContext.java @@ -0,0 +1,31 @@ +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ + +package test.visitation; + +import test.types.model.*; + +/** + * Define the interface for a visitor which visits the instances of the model. + * + *

When you use the visitor, please always call the main dispatching method + * {@link IVisitorWithContext#visit}. You should most probably never call the {@code visit} + * methods directly. They are only made public so that model classes can access them. + * + * @param structure of the context + */ +public interface IVisitorWithContext +{ + void visit(IClass that, ContextT context); + void visitListOfPrimitives( + IListOfPrimitives that, + ContextT context + ); +} + +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ diff --git a/test_data/java/test_main/list_of_primitives/expected_output/visitation/VisitorThrough.java b/test_data/java/test_main/list_of_primitives/expected_output/visitation/VisitorThrough.java new file mode 100644 index 000000000..25783c8e9 --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/visitation/VisitorThrough.java @@ -0,0 +1,36 @@ +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ + +package test.visitation; + +import test.types.model.*; +import test.visitation.IVisitor; + +/** + * Just descend through the instances without any action. + * + *

This class is meaningless for itself. However, it is a good base if you + * want to descend through instances and apply actions only on a subset of + * classes. + */ +public class VisitorThrough implements IVisitor { + public void visit(IClass that) { + that.accept(this); + } + + public void visitListOfPrimitives( + IListOfPrimitives that + ) { + // Just descend through, do nothing with {@code that} + for (IClass something : that.descendOnce()) { + visit(something); + } + } +} + +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ diff --git a/test_data/java/test_main/list_of_primitives/expected_output/xmlization.py b/test_data/java/test_main/list_of_primitives/expected_output/xmlization.py new file mode 100644 index 000000000..53cf725a2 --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/xmlization.py @@ -0,0 +1,1554 @@ +""" +Read and write AAS models as XML. + +For reading, we provide different reading functions, each handling a different kind +of input. All the reading functions operate in one pass, *i.e.*, the source is read +incrementally and the complete XML is not held in memory. + +We provide the following four reading functions (where ``X`` represents the name of +the class): + +1) ``X_from_iterparse`` reads from a stream of ``(event, element)`` tuples coming from + :py:func:`xml.etree.ElementTree.iterparse` with the argument + ``events=["start", "end"]``. If you do not trust the source, please consider + using `defusedxml.ElementTree`_. +2) ``X_from_stream`` reads from the given text stream. +3) ``X_from_file`` reads from a file on disk. +4) ``X_from_str`` reads from the given string. + +The functions ``X_from_stream``, ``X_from_file`` and ``X_from_str`` provide +an extra parameter, ``has_iterparse``, which allows you to use a parsing library +different from :py:mod:`xml.etree.ElementTree`. For example, you can pass in +`defusedxml.ElementTree`_. + +.. _defusedxml.ElementTree: https://pypi.org/project/defusedxml/#defusedxml-elementtree + +All XML elements are expected to live in the :py:attr:`~NAMESPACE`. + +For writing, use the function :py:func:`test.xmlization.write` which +translates the instance of the model into an XML document and writes it in one pass +to the stream. + +Here is an example usage how to de-serialize from a file: + +.. code-block:: + + import pathlib + import xml.etree.ElementTree as ET + + import test.xmlization as aas_xmlization + + path = pathlib.Path(...) + instance = aas_xmlization.read_list_of_primitives_from_file( + path + ) + + # Do something with the ``instance`` + +Here is another code example where we serialize the instance: + +.. code-block:: + + import pathlib + + import test.types as aas_types + import test.xmlization as aas_xmlization + + instance = ListOfPrimitives( + ... # some constructor arguments + ) + + pth = pathlib.Path(...) + with pth.open("wt") as fid: + aas_xmlization.write(instance, fid) +""" + + +# This code has been automatically generated by aas-core-codegen. +# Do NOT edit or append. + + +import base64 +import io +import math +import os +import sys +from typing import ( + Any, + Callable, + Iterator, + List, + Mapping, + Optional, + Sequence, + TextIO, + Tuple, + Union, + TYPE_CHECKING, +) +import xml.etree.ElementTree + +if sys.version_info >= (3, 8): + from typing import Final, Protocol +else: + from typing_extensions import Final, Protocol + +import test.stringification as aas_stringification +import test.types as aas_types + +# See: https://stackoverflow.com/questions/55076778/why-isnt-this-function-type-annotated-correctly-error-missing-type-parameters +if TYPE_CHECKING: + PathLike = os.PathLike[Any] +else: + PathLike = os.PathLike + + +#: XML namespace in which all the elements are expected to reside +NAMESPACE = "https://dummy.com" + + +# region De-serialization + + +#: XML namespace as a prefix specially tailored for +#: :py:mod:`xml.etree.ElementTree` +_NAMESPACE_IN_CURLY_BRACKETS = f"{{{NAMESPACE}}}" + + +class Element(Protocol): + """Behave like :py:meth:`xml.etree.ElementTree.Element`.""" + + @property + def attrib(self) -> Optional[Mapping[str, str]]: + """Attributes of the element""" + raise NotImplementedError() + + @property + def text(self) -> Optional[str]: + """Text content of the element""" + raise NotImplementedError() + + @property + def tail(self) -> Optional[str]: + """Tail text of the element""" + raise NotImplementedError() + + @property + def tag(self) -> str: + """Tag of the element; with a namespace provided as a ``{...}`` prefix""" + raise NotImplementedError() + + def clear(self) -> None: + """Behave like :py:meth:`xml.etree.ElementTree.Element.clear`.""" + raise NotImplementedError() + + +class HasIterparse(Protocol): + """Parse an XML document incrementally.""" + + # NOTE (mristin, 2022-10-26): + # ``self`` is not used in this context, but is necessary for Mypy, + # see: https://github.com/python/mypy/issues/5018 and + # https://github.com/python/mypy/commit/3efbc5c5e910296a60ed5b9e0e7eb11dd912c3ed#diff-e165eb7aed9dca0a5ebd93985c8cd263a6462d36ac185f9461348dc5a1396d76R9937 + + def iterparse( + self, source: TextIO, events: Optional[Sequence[str]] = None + ) -> Iterator[Tuple[str, Element]]: + """Behave like :py:func:`xml.etree.ElementTree.iterparse`.""" + + +class ElementSegment: + """Represent an element on a path to the erroneous value.""" + + #: Erroneous element + element: Final[Element] + + def __init__(self, element: Element) -> None: + """Initialize with the given values.""" + self.element = element + + def __str__(self) -> str: + """ + Render the segment as a tag without the namespace. + + We deliberately omit the namespace in the tag names. If you want to actually + query with the resulting XPath, you have to insert the namespaces manually. + We did not know how to include the namespace in a meaningful way, as XPath + assumes namespace prefixes to be defined *outside* of the document. At least + the path thus rendered is informative, and you should be able to descend it + manually. + """ + _, has_namespace, tag_wo_ns = self.element.tag.rpartition("}") + if not has_namespace: + return self.element.tag + else: + return tag_wo_ns + + +class IndexSegment: + """Represent an element in a sequence on a path to the erroneous value.""" + + #: Erroneous element + element: Final[Element] + + #: Index of the element in the sequence + index: Final[int] + + def __init__(self, element: Element, index: int) -> None: + """Initialize with the given values.""" + self.element = element + self.index = index + + def __str__(self) -> str: + """Render the segment as an element wildcard with the index.""" + return f"*[{self.index}]" + + +Segment = Union[ElementSegment, IndexSegment] + + +class Path: + """Represent the relative path to the erroneous element.""" + + def __init__(self) -> None: + """Initialize as an empty path.""" + self._segments = [] # type: List[Segment] + + @property + def segments(self) -> Sequence[Segment]: + """Get the segments of the path.""" + return self._segments + + def _prepend(self, segment: Segment) -> None: + """Insert the :paramref:`segment` in front of other segments.""" + self._segments.insert(0, segment) + + def __str__(self) -> str: + """Render the path as a relative XPath. + + We omit the leading ``/`` so that you can easily prefix it as you need. + """ + return "/".join(str(segment) for segment in self._segments) + + +class DeserializationException(Exception): + """Signal that the XML de-serialization could not be performed.""" + + #: Human-readable explanation of the exception's cause + cause: Final[str] + + #: Relative path to the erroneous value + path: Final[Path] + + def __init__(self, cause: str) -> None: + """Initialize with the given :paramref:`cause` and an empty path.""" + self.cause = cause + self.path = Path() + + +def _with_elements_cleared_after_yield( + iterator: Iterator[Tuple[str, Element]] +) -> Iterator[Tuple[str, Element]]: + """ + Map the :paramref:`iterator` such that the element is ``clear()``'ed + *after* every ``yield``. + + :param iterator: to be mapped + :yield: event and element from :paramref:`iterator` + """ + for event, element in iterator: + yield event, element + element.clear() + + +def list_of_primitives_from_iterparse( + iterator: Iterator[Tuple[str, Element]] +) -> aas_types.ListOfPrimitives: + """ + Read an instance of :py:class:`.types.ListOfPrimitives` from + the :paramref:`iterator`. + + Example usage: + + .. code-block:: + + import pathlib + import xml.etree.ElementTree as ET + + import test.xmlization as aas_xmlization + + path = pathlib.Path(...) + with path.open("rt") as fid: + iterator = ET.iterparse( + source=fid, + events=['start', 'end'] + ) + instance = aas_xmlization.list_of_primitives_from_iterparse( + iterator + ) + + # Do something with the ``instance`` + + :param iterator: + Input stream of ``(event, element)`` coming from + :py:func:`xml.etree.ElementTree.iterparse` with the argument + ``events=["start", "end"]`` + :raise: :py:class:`DeserializationException` if unexpected input + :return: + Instance of :py:class:`.types.ListOfPrimitives` read from + :paramref:`iterator` + """ + next_event_element = next(iterator, None) + if next_event_element is None: + raise DeserializationException( + # fmt: off + "Expected the start element for ListOfPrimitives, " + "but got the end-of-input" + # fmt: on + ) + + next_event, next_element = next_event_element + if next_event != "start": + raise DeserializationException( + f"Expected the start element for ListOfPrimitives, " + f"but got event {next_event!r} and element {next_element.tag!r}" + ) + + try: + return _read_list_of_primitives_as_element(next_element, iterator) + except DeserializationException as exception: + exception.path._prepend(ElementSegment(next_element)) + raise exception + + +def list_of_primitives_from_stream( + stream: TextIO, has_iterparse: HasIterparse = xml.etree.ElementTree +) -> aas_types.ListOfPrimitives: + """ + Read an instance of :py:class:`.types.ListOfPrimitives` from + the :paramref:`stream`. + + Example usage: + + .. code-block:: + + import test.xmlization as aas_xmlization + + with open_some_stream_over_network(...) as stream: + instance = aas_xmlization.list_of_primitives_from_stream( + stream + ) + + # Do something with the ``instance`` + + :param stream: + representing an instance of + :py:class:`.types.ListOfPrimitives` in XML + :param has_iterparse: + Module containing ``iterparse`` function. + + Default is to use :py:mod:`xml.etree.ElementTree` from the standard + library. If you have to deal with malicious input, consider using + a library such as `defusedxml.ElementTree`_. + :raise: :py:class:`DeserializationException` if unexpected input + :return: + Instance of :py:class:`.types.ListOfPrimitives` read from + :paramref:`stream` + """ + iterator = has_iterparse.iterparse(stream, ["start", "end"]) + return list_of_primitives_from_iterparse( + _with_elements_cleared_after_yield(iterator) + ) + + +def list_of_primitives_from_file( + path: PathLike, has_iterparse: HasIterparse = xml.etree.ElementTree +) -> aas_types.ListOfPrimitives: + """ + Read an instance of :py:class:`.types.ListOfPrimitives` from + the :paramref:`path`. + + Example usage: + + .. code-block:: + + import pathlib + import test.xmlization as aas_xmlization + + path = pathlib.Path(...) + instance = aas_xmlization.list_of_primitives_from_file( + path + ) + + # Do something with the ``instance`` + + :param path: + to the file representing an instance of + :py:class:`.types.ListOfPrimitives` in XML + :param has_iterparse: + Module containing ``iterparse`` function. + + Default is to use :py:mod:`xml.etree.ElementTree` from the standard + library. If you have to deal with malicious input, consider using + a library such as `defusedxml.ElementTree`_. + :raise: :py:class:`DeserializationException` if unexpected input + :return: + Instance of :py:class:`.types.ListOfPrimitives` read from + :paramref:`path` + """ + with open(os.fspath(path), "rt", encoding="utf-8") as fid: + iterator = has_iterparse.iterparse(fid, ["start", "end"]) + return list_of_primitives_from_iterparse( + _with_elements_cleared_after_yield(iterator) + ) + + +def list_of_primitives_from_str( + text: str, has_iterparse: HasIterparse = xml.etree.ElementTree +) -> aas_types.ListOfPrimitives: + """ + Read an instance of :py:class:`.types.ListOfPrimitives` from + the :paramref:`text`. + + Example usage: + + .. code-block:: + + import pathlib + import test.xmlization as aas_xmlization + + text = "<...>..." + instance = aas_xmlization.list_of_primitives_from_str( + text + ) + + # Do something with the ``instance`` + + :param text: + representing an instance of + :py:class:`.types.ListOfPrimitives` in XML + :param has_iterparse: + Module containing ``iterparse`` function. + + Default is to use :py:mod:`xml.etree.ElementTree` from the standard + library. If you have to deal with malicious input, consider using + a library such as `defusedxml.ElementTree`_. + :raise: :py:class:`DeserializationException` if unexpected input + :return: + Instance of :py:class:`.types.ListOfPrimitives` read from + :paramref:`text` + """ + iterator = has_iterparse.iterparse(io.StringIO(text), ["start", "end"]) + return list_of_primitives_from_iterparse( + _with_elements_cleared_after_yield(iterator) + ) + + +def from_iterparse(iterator: Iterator[Tuple[str, Element]]) -> aas_types.Class: + """ + Read an instance from the :paramref:`iterator`. + + The type of the instance is determined by the very first start element. + + Example usage: + + .. code-block:: + + import pathlib + import xml.etree.ElementTree as ET + + import test.xmlization as aas_xmlization + + path = pathlib.Path(...) + with path.open("rt") as fid: + iterator = ET.iterparse( + source=fid, + events=['start', 'end'] + ) + instance = aas_xmlization.from_iterparse( + iterator + ) + + # Do something with the ``instance`` + + :param iterator: + Input stream of ``(event, element)`` coming from + :py:func:`xml.etree.ElementTree.iterparse` with the argument + ``events=["start", "end"]`` + :raise: :py:class:`DeserializationException` if unexpected input + :return: + Instance of :py:class:`.types.Class` read from the :paramref:`iterator` + """ + next_event_element = next(iterator, None) + if next_event_element is None: + raise DeserializationException( + # fmt: off + "Expected the start element of an instance, " + "but got the end-of-input" + # fmt: on + ) + + next_event, next_element = next_event_element + if next_event != "start": + raise DeserializationException( + f"Expected the start element of an instance, " + f"but got event {next_event!r} and element {next_element.tag!r}" + ) + + try: + return _read_as_element(next_element, iterator) + except DeserializationException as exception: + exception.path._prepend(ElementSegment(next_element)) + raise exception + + +def from_stream( + stream: TextIO, has_iterparse: HasIterparse = xml.etree.ElementTree +) -> aas_types.Class: + """ + Read an instance from the :paramref:`stream`. + + The type of the instance is determined by the very first start element. + + Example usage: + + .. code-block:: + + import test.xmlization as aas_xmlization + + with open_some_stream_over_network(...) as stream: + instance = aas_xmlization.from_stream( + stream + ) + + # Do something with the ``instance`` + + :param stream: + representing an instance in XML + :param has_iterparse: + Module containing ``iterparse`` function. + + Default is to use :py:mod:`xml.etree.ElementTree` from the standard + library. If you have to deal with malicious input, consider using + a library such as `defusedxml.ElementTree`_. + :raise: :py:class:`DeserializationException` if unexpected input + :return: + Instance read from :paramref:`stream` + """ + iterator = has_iterparse.iterparse(stream, ["start", "end"]) + return from_iterparse(_with_elements_cleared_after_yield(iterator)) + + +def from_file( + path: PathLike, has_iterparse: HasIterparse = xml.etree.ElementTree +) -> aas_types.Class: + """ + Read an instance from the file at the :paramref:`path`. + + Example usage: + + .. code-block:: + + import pathlib + import test.xmlization as aas_xmlization + + path = pathlib.Path(...) + instance = aas_xmlization.from_file( + path + ) + + # Do something with the ``instance`` + + :param path: + to the file representing an instance in XML + :param has_iterparse: + Module containing ``iterparse`` function. + + Default is to use :py:mod:`xml.etree.ElementTree` from the standard + library. If you have to deal with malicious input, consider using + a library such as `defusedxml.ElementTree`_. + :raise: :py:class:`DeserializationException` if unexpected input + :return: + Instance read from the file at :paramref:`path` + """ + with open(os.fspath(path), "rt", encoding="utf-8") as fid: + iterator = has_iterparse.iterparse(fid, ["start", "end"]) + return from_iterparse(_with_elements_cleared_after_yield(iterator)) + + +def from_str( + text: str, has_iterparse: HasIterparse = xml.etree.ElementTree +) -> aas_types.Class: + """ + Read an instance from the :paramref:`text`. + + Example usage: + + .. code-block:: + + import pathlib + import test.xmlization as aas_xmlization + + text = "<...>..." + instance = aas_xmlization.from_str( + text + ) + + # Do something with the ``instance`` + + :param text: + representing an instance in XML + :param has_iterparse: + Module containing ``iterparse`` function. + + Default is to use :py:mod:`xml.etree.ElementTree` from the standard + library. If you have to deal with malicious input, consider using + a library such as `defusedxml.ElementTree`_. + :raise: :py:class:`DeserializationException` if unexpected input + :return: + Instance read from :paramref:`text` + """ + iterator = has_iterparse.iterparse(io.StringIO(text), ["start", "end"]) + return from_iterparse(_with_elements_cleared_after_yield(iterator)) + + +# NOTE (mristin, 2022-10-08): +# Directly using the iterator turned out to result in very complex function +# designs. The design became much simpler as soon as we considered one look-ahead +# element. We came up finally with the following pattern which all the protected +# reading functions below roughly follow: +# +# ..code-block:: +# +# _read_*( +# look-ahead element, +# iterator +# ) -> result +# +# The reading functions all read from the ``iterator`` coming from +# :py:func:`xml.etree.ElementTree.iterparse` with the argument +# ``events=["start", "end"]``. The exception :py:class:`.DeserializationException` +# is raised in case of unexpected input. +# +# The reading functions are responsible to read the end element corresponding to the +# start look-ahead element. +# +# When it comes to error reporting, we use exceptions. The exceptions are raised in +# the *callee*, as usual. However, the context of the exception, such as the error path, +# is added in the *caller*, as only the caller knows the context of +# the lookahead-element. In particular, prepending the path segment corresponding to +# the lookahead-element is the responsibility of the *caller*, and not of +# the *callee*. + + +def _parse_element_tag(element: Element) -> str: + """ + Extract the tag name without the namespace prefix from :paramref:`element`. + + :param element: whose tag without namespace we want to extract + :return: tag name without the namespace prefix + :raise: :py:class:`DeserializationException` if unexpected :paramref:`element` + """ + if not element.tag.startswith(_NAMESPACE_IN_CURLY_BRACKETS): + namespace, got_namespace, tag_wo_ns = element.tag.rpartition("}") + if got_namespace: + if namespace.startswith("{"): + namespace = namespace[1:] + + raise DeserializationException( + f"Expected the element in the namespace {NAMESPACE!r}, " + f"but got the element {tag_wo_ns!r} in the namespace {namespace!r}" + ) + else: + raise DeserializationException( + f"Expected the element in the namespace {NAMESPACE!r}, " + f"but got the element {tag_wo_ns!r} without the namespace prefix" + ) + + return element.tag[len(_NAMESPACE_IN_CURLY_BRACKETS) :] + + +def _raise_if_has_tail_or_attrib(element: Element) -> None: + """ + Check that :paramref:`element` has no trailing text and no attributes. + + :param element: to be verified + :raise: + :py:class:`.DeserializationException` if trailing text or attributes; + conforming to the convention about handling error paths, + the exception path is left empty. + """ + if element.tail is not None and len(element.tail.strip()) != 0: + raise DeserializationException( + f"Expected no trailing text, but got: {element.tail!r}" + ) + + if element.attrib is not None and len(element.attrib) > 0: + raise DeserializationException( + f"Expected no attributes, but got: {element.attrib}" + ) + + +def _read_end_element( + element: Element, iterator: Iterator[Tuple[str, Element]] +) -> Element: + """ + Read the end element corresponding to the start :paramref:`element` + from :paramref:`iterator`. + + :param element: corresponding start element + :param iterator: + Input stream of ``(event, element)`` coming from + :py:func:`xml.etree.ElementTree.iterparse` with the argument + ``events=["start", "end"]`` + :raise: :py:class:`DeserializationException` if unexpected input + """ + next_event_element = next(iterator, None) + if next_event_element is None: + raise DeserializationException( + f"Expected the end element for {element.tag}, " f"but got the end-of-input" + ) + + next_event, next_element = next_event_element + if next_event != "end" or next_element.tag != element.tag: + raise DeserializationException( + f"Expected the end element for {element.tag!r}, " + f"but got the event {next_event!r} and element {next_element.tag!r}" + ) + + _raise_if_has_tail_or_attrib(next_element) + + return next_element + + +def _read_text_from_element( + element: Element, iterator: Iterator[Tuple[str, Element]] +) -> str: + """ + Extract the text from the :paramref:`element`, and read + the end element from :paramref:`iterator`. + + The :paramref:`element` is expected to contain text. Otherwise, + it is considered as unexpected input. + + :param element: start element enclosing the text + :param iterator: + Input stream of ``(event, element)`` coming from + :py:func:`xml.etree.ElementTree.iterparse` with the argument + ``events=["start", "end"]`` + :raise: :py:class:`DeserializationException` if unexpected input + """ + _raise_if_has_tail_or_attrib(element) + + text = element.text + + end_element = _read_end_element( + element, + iterator, + ) + + if text is None: + if end_element.text is None: + raise DeserializationException( + "Expected an element with text, but got an element with no text." + ) + + text = end_element.text + + return text + + +_XS_BOOLEAN_LITERAL_SET = { + "1", + "true", + "0", + "false", +} + + +def _read_bool_from_element_text( + element: Element, iterator: Iterator[Tuple[str, Element]] +) -> bool: + """ + Parse the text of :paramref:`element` as a boolean, and + read the corresponding end element from :paramref:`iterator`. + + :param element: start element + :param iterator: + Input stream of ``(event, element)`` coming from + :py:func:`xml.etree.ElementTree.iterparse` with the argument + ``events=["start", "end"]`` + :raise: :py:class:`DeserializationException` if unexpected input + :return: parsed value + """ + text = _read_text_from_element(element, iterator) + + if text not in _XS_BOOLEAN_LITERAL_SET: + raise DeserializationException( + f"Expected a boolean, " f"but got an element with text: {text!r}" + ) + + return text in ("1", "true") + + +def _read_int_from_element_text( + element: Element, iterator: Iterator[Tuple[str, Element]] +) -> int: + """ + Parse the text of :paramref:`element` as an integer, and + read the corresponding end element from :paramref:`iterator`. + + :param element: start element + :param iterator: + Input stream of ``(event, element)`` coming from + :py:func:`xml.etree.ElementTree.iterparse` with the argument + ``events=["start", "end"]`` + :raise: :py:class:`DeserializationException` if unexpected input + :return: parsed value + """ + text = _read_text_from_element(element, iterator) + + try: + value = int(text) + except ValueError: + # pylint: disable=raise-missing-from + raise DeserializationException( + f"Expected an integer, " f"but got an element with text: {text!r}" + ) + + return value + + +_TEXT_TO_XS_DOUBLE_LITERALS = { + "NaN": math.nan, + "INF": math.inf, + "-INF": -math.inf, +} + + +def _read_float_from_element_text( + element: Element, iterator: Iterator[Tuple[str, Element]] +) -> float: + """ + Parse the text of :paramref:`element` as a floating-point number, and + read the corresponding end element from :paramref:`iterator`. + + :param element: start element + :param iterator: + Input stream of ``(event, element)`` coming from + :py:func:`xml.etree.ElementTree.iterparse` with the argument + ``events=["start", "end"]`` + :raise: :py:class:`DeserializationException` if unexpected input + :return: parsed value + """ + text = _read_text_from_element(element, iterator) + + value = _TEXT_TO_XS_DOUBLE_LITERALS.get(text, None) + if value is None: + try: + value = float(text) + except ValueError: + # pylint: disable=raise-missing-from + raise DeserializationException( + f"Expected a floating-point number, " + f"but got an element with text: {text!r}" + ) + + return value + + +def _read_str_from_element_text( + element: Element, iterator: Iterator[Tuple[str, Element]] +) -> str: + """ + Parse the text of :paramref:`element` as a string, and + read the corresponding end element from :paramref:`iterator`. + + If there is no text, empty string is returned. + + :param element: start element + :param iterator: + Input stream of ``(event, element)`` coming from + :py:func:`xml.etree.ElementTree.iterparse` with the argument + ``events=["start", "end"]`` + :raise: :py:class:`DeserializationException` if unexpected input + :return: parsed value + """ + # NOTE (mristin, 2022-10-26): + # We do not use ``_read_text_from_element`` as that function expects + # the ``element`` to contain *some* text. In contrast, this function + # can also deal with empty text, in which case it returns an empty string. + + text = element.text + + end_element = _read_end_element(element, iterator) + + if text is None: + text = end_element.text + + _raise_if_has_tail_or_attrib(element) + result = text if text is not None else "" + + return result + + +def _read_bytes_from_element_text( + element: Element, iterator: Iterator[Tuple[str, Element]] +) -> bytes: + """ + Parse the text of :paramref:`element` as base64-encoded bytes, and + read the corresponding end element from :paramref:`iterator`. + + :param element: look-ahead element + :param iterator: + Input stream of ``(event, element)`` coming from + :py:func:`xml.etree.ElementTree.iterparse` with the argument + ``events=["start", "end"]`` + :raise: :py:class:`DeserializationException` if unexpected input + :return: parsed value + """ + text = _read_text_from_element(element, iterator) + + try: + value = base64.b64decode(text) + except Exception: + # pylint: disable=raise-missing-from + raise DeserializationException( + f"Expected a text as base64-encoded bytes, " + f"but got an element with text: {text!r}" + ) + + return value + + +class _ReaderAndSetterForListOfPrimitives: + """ + Provide a buffer for reading and setting the properties for the class + :py:class:`ListOfPrimitives`. + + The properties correspond to the constructor arguments of + :py:class:`ListOfPrimitives`. We use this buffer to facilitate dispatching when + parsing the properties in a streaming fashion. + """ + + def __init__(self) -> None: + """Initialize with all the properties unset.""" + self.strings: Optional[List[str]] = None + self.integers: Optional[List[int]] = None + self.booleans: Optional[List[bool]] = None + + def read_and_set_strings( + self, element: Element, iterator: Iterator[Tuple[str, Element]] + ) -> None: + """ + Read :paramref:`element` as the property + :py:attr:`.types.ListOfPrimitives.strings` and set it. + """ + if element.text is not None and len(element.text.strip()) != 0: + raise DeserializationException( + f"Expected only item elements and whitespace text, " + f"but got text: {element.text!r}" + ) + + result: List[PrimitiveType.STR] = [] + + item_i = 0 + + while True: + next_event_element = next(iterator, None) + if next_event_element is None: + raise DeserializationException( + "Expected one or more items from a list or the end element, " + "but got end-of-input" + ) + + next_event, next_element = next_event_element + if next_event == "end" and next_element.tag == element.tag: + # We reached the end of the list. + break + + if next_event != "start": + raise DeserializationException( + "Expected a start element corresponding to an item, " + f"but got event {next_event!r} and element {next_element.tag!r}" + ) + + try: + item = _read_str_from_element_text(next_element, iterator) + except DeserializationException as exception: + exception.path._prepend(IndexSegment(next_element, item_i)) + raise + + result.append(item) + item_i += 1 + + self.strings = result + + def read_and_set_integers( + self, element: Element, iterator: Iterator[Tuple[str, Element]] + ) -> None: + """ + Read :paramref:`element` as the property + :py:attr:`.types.ListOfPrimitives.integers` and set it. + """ + if element.text is not None and len(element.text.strip()) != 0: + raise DeserializationException( + f"Expected only item elements and whitespace text, " + f"but got text: {element.text!r}" + ) + + result: List[PrimitiveType.INT] = [] + + item_i = 0 + + while True: + next_event_element = next(iterator, None) + if next_event_element is None: + raise DeserializationException( + "Expected one or more items from a list or the end element, " + "but got end-of-input" + ) + + next_event, next_element = next_event_element + if next_event == "end" and next_element.tag == element.tag: + # We reached the end of the list. + break + + if next_event != "start": + raise DeserializationException( + "Expected a start element corresponding to an item, " + f"but got event {next_event!r} and element {next_element.tag!r}" + ) + + try: + item = _read_int_from_element_text(next_element, iterator) + except DeserializationException as exception: + exception.path._prepend(IndexSegment(next_element, item_i)) + raise + + result.append(item) + item_i += 1 + + self.integers = result + + def read_and_set_booleans( + self, element: Element, iterator: Iterator[Tuple[str, Element]] + ) -> None: + """ + Read :paramref:`element` as the property + :py:attr:`.types.ListOfPrimitives.booleans` and set it. + """ + if element.text is not None and len(element.text.strip()) != 0: + raise DeserializationException( + f"Expected only item elements and whitespace text, " + f"but got text: {element.text!r}" + ) + + result: List[PrimitiveType.BOOL] = [] + + item_i = 0 + + while True: + next_event_element = next(iterator, None) + if next_event_element is None: + raise DeserializationException( + "Expected one or more items from a list or the end element, " + "but got end-of-input" + ) + + next_event, next_element = next_event_element + if next_event == "end" and next_element.tag == element.tag: + # We reached the end of the list. + break + + if next_event != "start": + raise DeserializationException( + "Expected a start element corresponding to an item, " + f"but got event {next_event!r} and element {next_element.tag!r}" + ) + + try: + item = _read_bool_from_element_text(next_element, iterator) + except DeserializationException as exception: + exception.path._prepend(IndexSegment(next_element, item_i)) + raise + + result.append(item) + item_i += 1 + + self.booleans = result + + +def _read_list_of_primitives_as_sequence( + element: Element, iterator: Iterator[Tuple[str, Element]] +) -> aas_types.ListOfPrimitives: + """ + Read an instance of :py:class:`.types.ListOfPrimitives` + as a sequence of XML-encoded properties. + + The end element corresponding to the :paramref:`element` will be + read as well. + + :param element: start element, parent of the sequence + :param iterator: + Input stream of ``(event, element)`` coming from + :py:func:`xml.etree.ElementTree.iterparse` with the argument + ``events=["start", "end"]`` + :raise: :py:class:`DeserializationException` if unexpected input + :return: parsed instance + """ + if element.text is not None and len(element.text.strip()) != 0: + raise DeserializationException( + f"Expected only XML elements representing the properties and whitespace text, " + f"but got text: {element.text!r}" + ) + + _raise_if_has_tail_or_attrib(element) + + reader_and_setter = _ReaderAndSetterForListOfPrimitives() + + while True: + next_event_element = next(iterator, None) + if next_event_element is None: + raise DeserializationException( + "Expected one or more XML-encoded properties or the end element, " + "but got the end-of-input" + ) + + next_event, next_element = next_event_element + if next_event == "end" and next_element.tag == element.tag: + # We reached the end element enclosing the sequence. + break + + if next_event != "start": + raise DeserializationException( + "Expected a start element corresponding to a property, " + f"but got event {next_event!r} and element {next_element.tag!r}" + ) + + try: + tag_wo_ns = _parse_element_tag(next_element) + except DeserializationException as exception: + exception.path._prepend(ElementSegment(next_element)) + raise + + read_and_set_method = _READ_AND_SET_DISPATCH_FOR_LIST_OF_PRIMITIVES.get( + tag_wo_ns, None + ) + if read_and_set_method is None: + an_exception = DeserializationException( + f"Expected an element representing a property, " + f"but got an element with unexpected tag: {tag_wo_ns!r}" + ) + an_exception.path._prepend(ElementSegment(next_element)) + raise an_exception + + try: + read_and_set_method(reader_and_setter, next_element, iterator) + except DeserializationException as exception: + exception.path._prepend(ElementSegment(next_element)) + raise + + if reader_and_setter.strings is None: + raise DeserializationException("The required property 'strings' is missing") + + if reader_and_setter.integers is None: + raise DeserializationException("The required property 'integers' is missing") + + if reader_and_setter.booleans is None: + raise DeserializationException("The required property 'booleans' is missing") + + return aas_types.ListOfPrimitives( + reader_and_setter.strings, + reader_and_setter.integers, + reader_and_setter.booleans, + ) + + +def _read_list_of_primitives_as_element( + element: Element, iterator: Iterator[Tuple[str, Element]] +) -> aas_types.ListOfPrimitives: + """ + Read an instance of :py:class:`.types.ListOfPrimitives` from + :paramref:`iterator`, including the end element. + + :param element: start element + :param iterator: + Input stream of ``(event, element)`` coming from + :py:func:`xml.etree.ElementTree.iterparse` with the argument + ``events=["start", "end"]`` + :raise: :py:class:`DeserializationException` if unexpected input + :return: parsed instance + """ + tag_wo_ns = _parse_element_tag(element) + + if tag_wo_ns != "listOfPrimitives": + raise DeserializationException( + f"Expected the element with the tag 'listOfPrimitives', " + f"but got tag: {tag_wo_ns}" + ) + + return _read_list_of_primitives_as_sequence(element, iterator) + + +def _read_as_element( + element: Element, iterator: Iterator[Tuple[str, Element]] +) -> aas_types.Class: + """ + Read an instance from :paramref:`iterator`, including the end element. + + :param element: start element + :param iterator: + Input stream of ``(event, element)`` coming from + :py:func:`xml.etree.ElementTree.iterparse` with the argument + ``events=["start", "end"]`` + :raise: :py:class:`DeserializationException` if unexpected input + :return: parsed instance + """ + tag_wo_ns = _parse_element_tag(element) + read_as_sequence = _GENERAL_DISPATCH.get(tag_wo_ns, None) + + if read_as_sequence is None: + raise DeserializationException( + f"Expected the element tag to be a valid model type " + f"of a concrete instance, " + f"but got tag {tag_wo_ns!r}" + ) + + return read_as_sequence(element, iterator) + + +#: Dispatch XML property name to read & set method in +#: :py:class:`_ReaderAndSetterForListOfPrimitives` +_READ_AND_SET_DISPATCH_FOR_LIST_OF_PRIMITIVES: Mapping[ + str, + Callable[ + [_ReaderAndSetterForListOfPrimitives, Element, Iterator[Tuple[str, Element]]], + None, + ], +] = { + "strings": _ReaderAndSetterForListOfPrimitives.read_and_set_strings, + "integers": _ReaderAndSetterForListOfPrimitives.read_and_set_integers, + "booleans": _ReaderAndSetterForListOfPrimitives.read_and_set_booleans, +} + + +#: Dispatch XML class names to read-as-sequence functions +#: corresponding to the concrete classes +_GENERAL_DISPATCH: Mapping[ + str, Callable[[Element, Iterator[Tuple[str, Element]]], aas_types.Class] +] = { + "listOfPrimitives": _read_list_of_primitives_as_sequence, +} + + +# endregion + + +# region Serialization + + +class _Serializer(aas_types.AbstractVisitor): + """Encode instances as XML and write them to :py:attr:`~stream`.""" + + #: Stream to be written to when we visit the instances + stream: Final[TextIO] + + #: Method pointer to be invoked for writing the start element with or without + #: specifying a namespace (depending on the state of the serializer) + _write_start_element: Callable[[str], None] + + #: Method pointer to be invoked for writing an empty element with or without + #: specifying a namespace (depending on the state of the serializer) + _write_empty_element: Callable[[str], None] + + # NOTE (mristin, 2022-10-14): + # The serialization procedure is quite rigid. We leverage the specifics of + # the serialization procedure to optimize the code a bit. + # + # Namely, we model the writing of the XML elements as a state machine. + # The namespace is only specified for the very first element. All the subsequent + # elements will *not* have the namespace specified. We implement that behavior by + # using pointers to methods, as Python treats the methods as first-class citizens. + # + # The ``_write_start_element`` will point to + # ``_write_first_start_element_with_namespace`` on the *first* invocation. + # Afterwards, it will be redirected to ``_write_start_element_without_namespace``. + # + # Analogously for ``_write_empty_element``. + # + # Please see the implementation for the details, but this should give you at least + # a rough overview. + + def _write_first_start_element_with_namespace(self, name: str) -> None: + """ + Write the start element with the tag name :paramref:`name` and specify + its namespace. + + The :py:attr:`~_write_start_element` is set to + :py:meth:`~_write_start_element_without_namespace` after the first invocation + of this method. + + :param name: of the element tag. Expected to contain no XML special characters. + """ + self.stream.write(f'<{name} xmlns="{NAMESPACE}">') + + # NOTE (mristin, 2022-10-14): + # Any subsequence call to `_write_start_element` or `_write_empty_element` + # should not specify the namespace of the element as we specified now already + # specified it. + self._write_start_element = self._write_start_element_without_namespace + self._write_empty_element = self._write_empty_element_without_namespace + + def _write_start_element_without_namespace(self, name: str) -> None: + """ + Write the start element with the tag name :paramref:`name`. + + The first element, written *before* this one, is expected to have been + already written with the namespace specified. + + :param name: of the element tag. Expected to contain no XML special characters. + """ + self.stream.write(f"<{name}>") + + def _escape_and_write_text(self, text: str) -> None: + """ + Escape :paramref:`text` for XML and write it. + + :param text: to be escaped and written + """ + # NOTE (mristin, 2022-10-14): + # We ran ``timeit`` on manual code which escaped XML special characters with + # a dictionary, and on another snippet which called three ``.replace()``. + # The code with ``.replace()`` was an order of magnitude faster on our computers. + self.stream.write( + text.replace("&", "&").replace("<", "<").replace(">", ">") + ) + + def _write_end_element(self, name: str) -> None: + """ + Write the end element with the tag name :paramref:`name`. + + :param name: of the element tag. Expected to contain no XML special characters. + """ + self.stream.write(f"") + + def _write_first_empty_element_with_namespace(self, name: str) -> None: + """ + Write the first (and only) empty element with the tag name :paramref:`name`. + + No elements are expected to be written to the stream afterwards. The element + includes the namespace specification. + + :param name: of the element tag. Expected to contain no XML special characters. + """ + self.stream.write(f'<{name} xmlns="{NAMESPACE}"/>') + self._write_empty_element = self._rase_if_write_element_called_again + self._write_start_element = self._rase_if_write_element_called_again + + def _rase_if_write_element_called_again(self, name: str) -> None: + raise AssertionError( + f"We expected to call ``_write_first_empty_element_with_namespace`` " + f"only once. This is an unexpected second call for writing " + f"an (empty or non-empty) element with the tag name: {name!r}" + ) + + def _write_empty_element_without_namespace(self, name: str) -> None: + """ + Write the empty element with the tag name :paramref:`name`. + + The call to this method is expected to occur *after* the enclosing element with + a specified namespace has been written. + + :param name: of the element tag. Expected to contain no XML special characters. + """ + self.stream.write(f"<{name}/>") + + def _write_bool_property(self, name: str, value: bool) -> None: + """ + Write the :paramref:`value` of a boolean property enclosed in + the :paramref:`name` element. + + :param name: of the corresponding element tag + :param value: of the property + """ + self._write_start_element(name) + self.stream.write("true" if value else "false") + self._write_end_element(name) + + def _write_int_property(self, name: str, value: int) -> None: + """ + Write the :paramref:`value` of an integer property enclosed in + the :paramref:`name` element. + + :param name: of the corresponding element tag + :param value: of the property + """ + self._write_start_element(name) + self.stream.write(str(value)) + self._write_end_element(name) + + def _write_float_property(self, name: str, value: float) -> None: + """ + Write the :paramref:`value` of a floating-point property enclosed in + the :paramref:`name` element. + + :param name: of the corresponding element tag + :param value: of the property + """ + self._write_start_element(name) + + if value == math.inf: + self.stream.write("INF") + elif value == -math.inf: + self.stream.write("-INF") + elif math.isnan(value): + self.stream.write("NaN") + elif value == 0: + if math.copysign(1.0, value) < 0.0: + self.stream.write("-0.0") + else: + self.stream.write("0.0") + else: + self.stream.write(str(value)) + + def _write_str_property(self, name: str, value: str) -> None: + """ + Write the :paramref:`value` of a string property enclosed in + the :paramref:`name` element. + + :param name: of the corresponding element tag + :param value: of the property + """ + self._write_start_element(name) + self._escape_and_write_text(value) + self._write_end_element(name) + + def _write_bytes_property(self, name: str, value: bytes) -> None: + """ + Write the :paramref:`value` of a binary-content property enclosed in + the :paramref:`name` element. + + :param name: of the corresponding element tag + :param value: of the property + """ + self._write_start_element(name) + + # NOTE (mristin, 2022-10-14): + # We need to decode the result of the base64-encoding to ASCII since we are + # writing to an XML *text* stream. ``base64.b64encode(.)`` gives us bytes, + # not a string. + encoded = base64.b64encode(value).decode("ascii") + + # NOTE (mristin, 2022-10-14): + # Base64 alphabet excludes ``<``, ``>`` and ``&``, so we can directly + # write the ``encoded`` content to the stream as XML text. + # + # See: https://datatracker.ietf.org/doc/html/rfc4648#section-4 + self.stream.write(encoded) + self._write_end_element(name) + + def __init__(self, stream: TextIO) -> None: + """ + Initialize the visitor to write to :paramref:`stream`. + + The first element will include the :py:attr:`~.NAMESPACE`. Every other + element will not have the namespace specified. + + :param stream: where to write to + """ + self.stream = stream + self._write_start_element = self._write_first_start_element_with_namespace + self._write_empty_element = self._write_first_empty_element_with_namespace + + def _write_list_of_primitives_as_sequence( + self, that: aas_types.ListOfPrimitives + ) -> None: + """ + Serialize :paramref:`that` to :py:attr:`~stream` as a sequence of + XML elements. + + Each element in the sequence corresponds to a property. If no properties + are set, nothing is written to the :py:attr:`~stream`. + + :param that: instance to be serialized + """ + if len(that.strings) == 0: + self._write_empty_element("strings") + else: + self._write_start_element("strings") + for an_item in that.strings: + self.visit(an_item) + self._write_end_element("strings") + + if len(that.integers) == 0: + self._write_empty_element("integers") + else: + self._write_start_element("integers") + for another_item in that.integers: + self.visit(another_item) + self._write_end_element("integers") + + if len(that.booleans) == 0: + self._write_empty_element("booleans") + else: + self._write_start_element("booleans") + for yet_another_item in that.booleans: + self.visit(yet_another_item) + self._write_end_element("booleans") + + def visit_list_of_primitives(self, that: aas_types.ListOfPrimitives) -> None: + """ + Serialize :paramref:`that` to :py:attr:`~stream` as an XML element. + + The enclosing XML element designates the class of the instance, where its + children correspond to the properties of the instance. + + :param that: instance to be serialized + """ + self._write_start_element("listOfPrimitives") + self._write_list_of_primitives_as_sequence(that) + self._write_end_element("listOfPrimitives") + + +def write(instance: aas_types.Class, stream: TextIO) -> None: + """ + Write the XML representation of :paramref:`instance` to :paramref:`stream`. + + Example usage: + + .. code-block:: + + import pathlib + + import test.types as aas_types + import test.xmlization as aas_xmlization + + instance = ListOfPrimitives( + ... # some constructor arguments + ) + + pth = pathlib.Path(...) + with pth.open("wt") as fid: + aas_xmlization.write(instance, fid) + + :param instance: to be serialized + :param stream: to write to + """ + serializer = _Serializer(stream) + serializer.visit(instance) + + +def to_str(that: aas_types.Class) -> str: + """ + Serialize :paramref:`that` to an XML-encoded text. + + :param that: instance to be serialized + :return: :paramref:`that` serialized to XML serialized to text + """ + writer = io.StringIO() + write(that, writer) + return writer.getvalue() + + +# endregion diff --git a/test_data/java/test_main/list_of_primitives/expected_output/xmlization/Xmlization.java b/test_data/java/test_main/list_of_primitives/expected_output/xmlization/Xmlization.java new file mode 100644 index 000000000..3a31b6d08 --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/expected_output/xmlization/Xmlization.java @@ -0,0 +1,815 @@ +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ + +package test.xmlization; + +import javax.xml.stream.events.XMLEvent; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; +import java.util.ArrayList; +import java.util.Base64; +import java.util.function.Function; +import java.util.List; +import java.util.Optional; +import test.reporting.Reporting; +import test.stringification.Stringification; +import test.types.enums.*; +import test.types.impl.*; +import test.types.model.*; +import test.visitation.*; + +/** + * Provide de/serialization of meta-model classes to/from XML. + */ +public class Xmlization { + /** + * Represent a critical error during the deserialization. + */ + @SuppressWarnings("serial") + public static class DeserializeException extends RuntimeException { + private final String path; + private final String reason; + + public DeserializeException(String path, String reason) { + super(reason + " at: " + ("".equals(path) ? "the beginning" : path)); + this.path = path; + this.reason = reason; + } + + public Optional getPath() { + return Optional.ofNullable(path); + } + + public Optional getReason() { + return Optional.ofNullable(reason); + } + } + + /** + * Represent a critical error during the serialization. + */ + @SuppressWarnings("serial") + public static class SerializeException extends RuntimeException { + private final String path; + private final String reason; + + public SerializeException(String path, String reason) { + super(reason + " at: " + ("".equals(path) ? "the beginning" : path)); + this.path = path; + this.reason = reason; + } + + public Optional getPath() { + return Optional.ofNullable(path); + } + + public Optional getReason() { + return Optional.ofNullable(reason); + } + } + + /** + * The XML namespace of the meta-model + */ + public static final String AAS_NAME_SPACE = + "https://dummy.com"; + + private static class Result { + private final T result; + private final Reporting.Error error; + private final boolean success; + + private Result(T result, Reporting.Error error, boolean success) { + this.result = result; + this.error = error; + this.success = success; + } + + public static Result success(T result) { + if(result == null) throw new IllegalArgumentException("Result must not be null."); + return new Result<>(result, null, true); + } + + public static Result failure(Reporting.Error error) { + if(error == null) throw new IllegalArgumentException("Error must not be null."); + return new Result<>(null, error, false); + } + + @SuppressWarnings("unchecked") + public Result castTo(Class type){ + if(isError() || type.isInstance(result)) return (Result) this; + throw new IllegalStateException("Result of type " + + result.getClass().getName() + + " is not an instance of " + + type.getName()); + } + + public T getResult() { + if (!isSuccess()) throw new IllegalStateException("Result is not present."); + return result; + } + + public boolean isSuccess() { + return success; + } + + public boolean isError(){return !success;} + + public Reporting.Error getError() { + if (isSuccess()) throw new IllegalStateException("Result is present."); + return error; + } + + public R map(Function successFunction, Function errorFunction) { + return isSuccess() ? successFunction.apply(result) : errorFunction.apply(error); + } + + public T onError(Function errorFunction){ + return map(Function.identity(), errorFunction); + } + } + + /** + * Implement the deserialization of meta-model classes from XML. + * + *

The implementation propagates an {@link Reporting.Error} instead of + * relying on exceptions. Under the assumption that incorrect data is much less + * frequent than correct data, this makes the deserialization more + * efficient. + * + *

However, we do not want to force the client to deal with + * the {@link Reporting.Error} class as this is not intuitive. + * Therefore we distinguish the implementation, realized in + * {@link DeserializeImplementation}, and the facade given in + * {@link Deserialize} class. + */ + private static class DeserializeImplementation + { + private static XMLEvent currentEvent(XMLEventReader reader) { + try { + return reader.peek(); + } catch (XMLStreamException xmlStreamException) { + throw new Xmlization.DeserializeException("", + "Failed in method peek because of: " + + xmlStreamException.getMessage()); + } + } + + private static String getEventTypeAsString(XMLEvent event) { + switch (event.getEventType()) { + case XMLStreamConstants.START_ELEMENT: + return "Start-Element"; + case XMLStreamConstants.END_ELEMENT: + return "End-Element"; + case XMLStreamConstants.PROCESSING_INSTRUCTION: + return "Processing-Instruction"; + case XMLStreamConstants.CHARACTERS: + return "Characters"; + case XMLStreamConstants.COMMENT: + return "Comment"; + case XMLStreamConstants.SPACE: + return "Space"; + case XMLStreamConstants.START_DOCUMENT: + return "Start-Document"; + case XMLStreamConstants.END_DOCUMENT: + return "End-Document"; + case XMLStreamConstants.ENTITY_REFERENCE: + return "Entity-Reference"; + case XMLStreamConstants.ATTRIBUTE: + return "Attribute"; + case XMLStreamConstants.NOTATION_DECLARATION: + return "Notation-Declaration"; + default: + return "Unknown-Type"; + } + } + + private static boolean isEmptyElement(XMLEventReader reader) { + // Skip the element node and go to the content + try { + reader.nextEvent(); + } catch (XMLStreamException xmlStreamException) { + throw new Xmlization.DeserializeException("", + "Failed in method isEmptyElement because of: " + + xmlStreamException.getMessage()); + } + return currentEvent(reader).isEndElement(); + } + + private static boolean isWrongClosingTag( + Result tryElementName, + Result tryEndElementName) { + return !tryElementName.getResult().equals(tryEndElementName.getResult()); + } + + private static Result verifyClosingTagForClass( + String className, + XMLEventReader reader, + Result tryElementName) { + final XMLEvent currentEvent = currentEvent(reader); + if (currentEvent.isEndDocument()) { + final Reporting.Error error = new Reporting.Error( + "Expected an XML end element to conclude a property of class " + className + + " with the element name " + tryElementName.getResult() + ", " + + "but got the end-of-file."); + return Result.failure(error); + } + + if (!currentEvent.isEndElement()) { + final Reporting.Error error = new Reporting.Error( + "Expected an XML end element to conclude a property of class " + className + + " with the element name " + tryElementName.getResult() + ", " + + "but got the node of type " + getEventTypeAsString(currentEvent) + + " with the value " + currentEvent); + return Result.failure(error); + } + final Result tryEndElementName = tryElementName(reader); + if (tryEndElementName.isError()) { + return tryEndElementName.castTo(XMLEvent.class); + } + if (isWrongClosingTag(tryElementName, tryEndElementName)) { + final Reporting.Error error = new Reporting.Error( + "Expected an XML end element to conclude a property of class " + className + + " with the element name " + tryElementName.getResult() + ", " + + "but got the end element with the name " + tryEndElementName.getResult()); + return Result.failure(error); + } + try { + return Result.success(reader.nextEvent()); + } catch (XMLStreamException xmlStreamException) { + throw new Xmlization.DeserializeException("", + "Failed in method verifyClosingTagForClass because of: " + + xmlStreamException.getMessage()); + } + } + + private static void skipWhitespaceAndComments(XMLEventReader reader) { + while (whiteSpaceOrComment(reader)) { + reader.next(); + } + } + + private static boolean whiteSpaceOrComment(XMLEventReader reader) { + final XMLEvent currentEvent = currentEvent(reader); + final boolean isComment = (currentEvent != null && + currentEvent.getEventType() == XMLStreamConstants.COMMENT); + final boolean isWhiteSpace = (currentEvent != null && + currentEvent.getEventType() == XMLStreamConstants.CHARACTERS && + currentEvent.asCharacters().isWhiteSpace()); + return isComment || isWhiteSpace; + } + + private static void skipStartDocument(XMLEventReader reader){ + if (currentEvent(reader).isStartDocument()){ + reader.next(); + } + } + + private static boolean invalidNameSpace(XMLEvent event) { + if (event.isStartElement()) { + return !AAS_NAME_SPACE.equals(event.asStartElement().getName().getNamespaceURI()); + } else { + return !AAS_NAME_SPACE.equals(event.asEndElement().getName().getNamespaceURI()); + } + } + + /** + * Check the namespace and extract the element's name. + */ + private static Result tryElementName(XMLEventReader reader) { + final XMLEvent currentEvent = currentEvent(reader); + final boolean precondition = currentEvent.isStartElement() || currentEvent.isEndElement(); + if (!precondition) { + throw new IllegalStateException("Expected to be at a start or an end element " + + "but got: " + getEventTypeAsString(currentEvent)); + } + + if (invalidNameSpace(currentEvent)) { + String namespace = currentEvent.isStartElement() + ? currentEvent.asStartElement().getName().getNamespaceURI() + : currentEvent.asEndElement().getName().getNamespaceURI(); + final Reporting.Error error = new Reporting.Error( + "Expected an element within a namespace " + + AAS_NAME_SPACE + ", " + "but got: " + namespace); + return Result.failure(error); + } + return Result.success(currentEvent.isStartElement() + ? currentEvent.asStartElement().getName().getLocalPart() + : currentEvent.asEndElement().getName().getLocalPart()); + } + + private static String readContentAsString(XMLEventReader reader) throws XMLStreamException { + final StringBuilder content = new StringBuilder(); + + while (reader.peek().isCharacters() || reader.peek().getEventType() == XMLStreamConstants.COMMENT) { + if (reader.peek().isCharacters()) { + content.append(reader.peek().asCharacters().getData()); + } + reader.nextEvent(); + } + + return content.toString(); + } + + private static Boolean readContentAsBool(XMLEventReader reader) throws XMLStreamException { + final StringBuilder content = new StringBuilder(); + + while (reader.peek().isCharacters() || reader.peek().getEventType() == XMLStreamConstants.COMMENT) { + if (reader.peek().isCharacters()) { + content.append(reader.peek().asCharacters().getData()); + } + reader.nextEvent(); + } + if(!("true".equals(content.toString()) || "false".equals(content.toString()))){ + throw new IllegalStateException("Content cannot be converted to the type Boolean."); + } + return Boolean.valueOf(content.toString()); + } + + private static Long readContentAsLong(XMLEventReader reader) throws XMLStreamException { + final StringBuilder content = new StringBuilder(); + + while (reader.peek().isCharacters() || reader.peek().getEventType() == XMLStreamConstants.COMMENT) { + if (reader.peek().isCharacters()) { + content.append(reader.peek().asCharacters().getData()); + } + reader.nextEvent(); + } + + return Long.valueOf(content.toString()); + } + + private static Double readContentAsDouble(XMLEventReader reader) throws XMLStreamException { + final StringBuilder content = new StringBuilder(); + + while (reader.peek().isCharacters() || reader.peek().getEventType() == XMLStreamConstants.COMMENT) { + if (reader.peek().isCharacters()) { + content.append(reader.peek().asCharacters().getData()); + } + reader.nextEvent(); + } + + return Double.valueOf(content.toString()); + } + + /** + * Read the whole content of an element into memory. + */ + private static byte[] readContentAsBase64( + XMLEventReader reader) throws XMLStreamException { + final StringBuilder content = new StringBuilder(); + while (reader.peek().isCharacters() || reader.peek().getEventType() == XMLStreamConstants.COMMENT) { + if (reader.peek().isCharacters()) { + content.append(reader.peek().asCharacters().getData()); + } + reader.nextEvent(); + } + + String encodedData = content.toString(); + final byte[] decodedData; + Base64.Decoder decoder = Base64.getDecoder(); + + try { + decodedData = decoder.decode(encodedData); + } catch (IllegalArgumentException exception) { + throw new XMLStreamException( + "Failed to read base64 encoded data: " + + exception.getMessage()); + } + + return decodedData; + } + + /** + * Deserialize an instance of class ListOfPrimitives from a sequence of XML elements. + * + *

If {@code isEmptySequence} is set, we should try to deserialize + * the instance from an empty sequence. That is, the parent element + * was a self-closing element. + */ + private static Result tryListOfPrimitivesFromSequence( + XMLEventReader reader, + boolean isEmptySequence) { + List theStrings = null; + List theIntegers = null; + List theBooleans = null; + + if (!isEmptySequence) { + skipWhitespaceAndComments(reader); + if (currentEvent(reader).isEndDocument()) { + final Reporting.Error error = new Reporting.Error( + "Expected an XML element representing " + + "a property of an instance of class ListOfPrimitives, " + + "but reached the end-of-file"); + return Result.failure(error); + } + while (true) { + skipWhitespaceAndComments(reader); + + if (currentEvent(reader).isEndElement() || currentEvent(reader).isEndDocument()) { + break; + } + + if (!currentEvent(reader).isStartElement()) { + final Reporting.Error error = new Reporting.Error( + "Expected an XML start element representing " + + "a property of an instance of class ListOfPrimitives, " + + "but got the node of type " + getEventTypeAsString(currentEvent(reader)) + + " with the value " + currentEvent(reader)); + return Result.failure(error); + } + + final Result tryElementName = tryElementName(reader); + if (tryElementName.isError()) { + return tryElementName.castTo(ListOfPrimitives.class); + } + + final boolean isEmptyProperty = isEmptyElement(reader); + final String elementName = tryElementName.getResult(); + + switch (tryElementName.getResult()) { + case "strings": + { + theStrings = new ArrayList<>(); + if (!isEmptyProperty) { + skipWhitespaceAndComments(reader); + int index = 0; + if(!currentEvent(reader).isStartElement()){ + final Reporting.Error error = new Reporting.Error( + "Expected a start element opening an instance of BAR, but got an XML " + + getEventTypeAsString(currentEvent(reader))); + error.prependSegment(new Reporting.IndexSegment(index)); + error.prependSegment(new Reporting.NameSegment(BAR)); + return Result.failure(error); + } + while (currentEvent(reader).isStartElement()) { + + Result itemResult = tryFOO(reader); + + if (itemResult.isError()) { + itemResult.getError() + .prependSegment( + new Reporting.IndexSegment(index)); + itemResult.getError() + .prependSegment( + new Reporting.NameSegment(BAR)); + return itemResult.castTo(BAR.class); + } + + theStrings.add(itemResult.getResult()); + index++; + skipWhitespaceAndComments(reader); + } + } + break; + } + case "integers": + { + theIntegers = new ArrayList<>(); + if (!isEmptyProperty) { + skipWhitespaceAndComments(reader); + int index = 0; + if(!currentEvent(reader).isStartElement()){ + final Reporting.Error error = new Reporting.Error( + "Expected a start element opening an instance of BAR, but got an XML " + + getEventTypeAsString(currentEvent(reader))); + error.prependSegment(new Reporting.IndexSegment(index)); + error.prependSegment(new Reporting.NameSegment(BAR)); + return Result.failure(error); + } + while (currentEvent(reader).isStartElement()) { + + Result itemResult = tryFOO(reader); + + if (itemResult.isError()) { + itemResult.getError() + .prependSegment( + new Reporting.IndexSegment(index)); + itemResult.getError() + .prependSegment( + new Reporting.NameSegment(BAR)); + return itemResult.castTo(BAR.class); + } + + theIntegers.add(itemResult.getResult()); + index++; + skipWhitespaceAndComments(reader); + } + } + break; + } + case "booleans": + { + theBooleans = new ArrayList<>(); + if (!isEmptyProperty) { + skipWhitespaceAndComments(reader); + int index = 0; + if(!currentEvent(reader).isStartElement()){ + final Reporting.Error error = new Reporting.Error( + "Expected a start element opening an instance of BAR, but got an XML " + + getEventTypeAsString(currentEvent(reader))); + error.prependSegment(new Reporting.IndexSegment(index)); + error.prependSegment(new Reporting.NameSegment(BAR)); + return Result.failure(error); + } + while (currentEvent(reader).isStartElement()) { + + Result itemResult = tryFOO(reader); + + if (itemResult.isError()) { + itemResult.getError() + .prependSegment( + new Reporting.IndexSegment(index)); + itemResult.getError() + .prependSegment( + new Reporting.NameSegment(BAR)); + return itemResult.castTo(BAR.class); + } + + theBooleans.add(itemResult.getResult()); + index++; + skipWhitespaceAndComments(reader); + } + } + break; + } + default: + final Reporting.Error error = new Reporting.Error( + "We expected properties of the class ListOfPrimitives, " + + "but got an unexpected element " + + "with the name " + elementName); + return Result.failure(error); + } + + skipWhitespaceAndComments(reader); + + + final Result checkEndElement = verifyClosingTagForClass( + "ListOfPrimitives", + reader, + tryElementName); + if (checkEndElement.isError()) return checkEndElement.castTo(ListOfPrimitives.class); + + } + } + + if (theStrings == null) { + final Reporting.Error error = new Reporting.Error( + "The required property strings has not been given " + + "in the XML representation of an instance of class ListOfPrimitives"); + return Result.failure(error); + } + + if (theIntegers == null) { + final Reporting.Error error = new Reporting.Error( + "The required property integers has not been given " + + "in the XML representation of an instance of class ListOfPrimitives"); + return Result.failure(error); + } + + if (theBooleans == null) { + final Reporting.Error error = new Reporting.Error( + "The required property booleans has not been given " + + "in the XML representation of an instance of class ListOfPrimitives"); + return Result.failure(error); + } + + return Result.success(new ListOfPrimitives( + theStrings, + theIntegers, + theBooleans)); + } + + /** + * Deserialize an instance of class ListOfPrimitives from an XML element. + */ + private static Result tryListOfPrimitivesFromElement( + XMLEventReader reader) { + skipWhitespaceAndComments(reader); + + final XMLEvent currentEvent = currentEvent(reader); + if (currentEvent.getEventType() == XMLStreamConstants.END_DOCUMENT) { + final Reporting.Error error = new Reporting.Error( + "Expected an XML element representing an instance of class ListOfPrimitives, " + + "but reached the end-of-file"); + return Result.failure(error); + } + + if (currentEvent.getEventType() != XMLStreamConstants.START_ELEMENT) { + final Reporting.Error error = new Reporting.Error( + "Expected an XML element representing an instance of class ListOfPrimitives, " + + "but got a node of type " + getEventTypeAsString(currentEvent) + + " with value " + currentEvent); + return Result.failure(error); + } + + final Result tryElementName = tryElementName(reader); + if (tryElementName.isError()) { + return tryElementName.castTo(ListOfPrimitives.class); + } + + final String elementName = tryElementName.getResult(); + if (!"listOfPrimitives".equals(tryElementName.getResult())) { + final Reporting.Error error = new Reporting.Error( + "Expected an element representing an instance of class ListOfPrimitives " + + "with element name listOfPrimitives, but got: " + elementName); + return Result.failure(error); + } + + final boolean isEmptyElement = isEmptyElement(reader); + + Result result = tryListOfPrimitivesFromSequence( + reader, + isEmptyElement); + if (result.isError()) return result.castTo(ListOfPrimitives.class); + + + final Result checkEndElement = verifyClosingTagForClass( + "ListOfPrimitives", + reader, + tryElementName); + if (checkEndElement.isError()) return checkEndElement.castTo(ListOfPrimitives.class); + + + return result; + } + } + + /** + * Deserialize instances of meta-model classes from XML. + */ + /**

+   * Here is an example how to parse an instance of class ListOfPrimitives:
+   * {@code
+   * XMLEventReader reader = xmlFactory.createXMLEventReader(...some arguments...);
+   * ListOfPrimitives anInstance = Deserialize.deserializeListOfPrimitives(
+   *   reader);
+   * }
+   * 
+ * + *
+   * If the elements live in a namespace, you have to supply it. For example:
+   * {@code
+   * XMLEventReader reader = xmlFactory.createXMLEventReader(...some arguments...);
+   * ListOfPrimitives anInstance = Deserialize.deserializeListOfPrimitives(
+   *   reader,
+   *   "http://www.example.com/5/12");
+   * }
+   * 
+ */ + public static class Deserialize + { + /** + * Deserialize an instance of ListOfPrimitives from {@code reader}. + * + * @param reader Initialized XML reader with reader.peek() set to the element + */ + public static ListOfPrimitives deserializeListOfPrimitives( + XMLEventReader reader) { + + DeserializeImplementation.skipStartDocument(reader); + DeserializeImplementation.skipWhitespaceAndComments(reader); + + Result result = + DeserializeImplementation.tryListOfPrimitivesFromElement( + reader); + + return result.onError(error -> { + error.prependSegment(new Reporting.NameSegment("listofprimitives")); + throw new DeserializeException( + Reporting.generateRelativeXPath(error.getPathSegments()), + error.getCause()); + }); + } + } + + /** + * Serialize recursively the instances as XML elements. + */ + static class VisitorWithWriter + extends AbstractVisitorWithContext { + + private boolean topLevel = true; + + private void listOfPrimitivesToSequence( + IListOfPrimitives that, + XMLStreamWriter writer) { + try { + writer.writeStartElement( + "strings"); + if (topLevel) { + writer.writeNamespace("xmlns", AAS_NAME_SPACE); + topLevel = false; + } + + for (IClass item : that.getStrings()) { + this.visit( + item, + writer); + } + + writer.writeEndElement(); + } catch (XMLStreamException exception) { + throw new SerializeException("",exception.getMessage()); + } + + try { + writer.writeStartElement( + "integers"); + if (topLevel) { + writer.writeNamespace("xmlns", AAS_NAME_SPACE); + topLevel = false; + } + + for (IClass item : that.getIntegers()) { + this.visit( + item, + writer); + } + + writer.writeEndElement(); + } catch (XMLStreamException exception) { + throw new SerializeException("",exception.getMessage()); + } + + try { + writer.writeStartElement( + "booleans"); + if (topLevel) { + writer.writeNamespace("xmlns", AAS_NAME_SPACE); + topLevel = false; + } + + for (IClass item : that.getBooleans()) { + this.visit( + item, + writer); + } + + writer.writeEndElement(); + } catch (XMLStreamException exception) { + throw new SerializeException("",exception.getMessage()); + } + } + + @Override + public void visitListOfPrimitives( + IListOfPrimitives that, + XMLStreamWriter writer) { + try { + writer.writeStartElement( + "listOfPrimitives"); + if (topLevel) { + writer.writeNamespace("xmlns", AAS_NAME_SPACE); + topLevel = false; + } + this.listOfPrimitivesToSequence( + that, + writer); + writer.writeEndElement(); + } catch (XMLStreamException exception) { + throw new SerializeException("", exception.getMessage()); + } + } + } + + /** + * Serialize instances of meta-model classes to XML. + */ + /** + *
+   * Here is an example how to serialize an instance of ListOfPrimitives:
+   * {@code
+   * IClass anInstance = new ListOfPrimitives(
+   *     ... some constructor arguments ...
+   * );
+   * XMLStreamWriter writer = xmlWriterFactory.createXMLStreamWriter(...some arguments...);
+   * Serialize.to(
+   *   anInstance,
+   *   writer);
+   * }
+   * 
+ */ + public static class Serialize + { + /** + * Serialize an instance of the meta-model to XML. + */ + public static void to( + IClass that, + XMLStreamWriter writer) throws SerializeException { + VisitorWithWriter visitor = new VisitorWithWriter(); + visitor.visit( + that, writer); + } + } +} + +/* + * This code has been automatically generated by aas-core-codegen. + * Do NOT edit or append. + */ diff --git a/test_data/java/test_main/list_of_primitives/input/snippets/package.txt b/test_data/java/test_main/list_of_primitives/input/snippets/package.txt new file mode 100644 index 000000000..9daeafb98 --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/input/snippets/package.txt @@ -0,0 +1 @@ +test diff --git a/test_data/java/test_main/list_of_primitives/meta_model.py b/test_data/java/test_main/list_of_primitives/meta_model.py new file mode 100644 index 000000000..531303f43 --- /dev/null +++ b/test_data/java/test_main/list_of_primitives/meta_model.py @@ -0,0 +1,18 @@ +from typing import List + + +class List_of_primitives: + strings: List[str] + integers: List[int] + booleans: List[bool] + + def __init__( + self, strings: List[str], integers: List[int], booleans: List[bool] + ) -> None: + self.strings = strings + self.integers = integers + self.booleans = booleans + + +__version__ = "dummy" +__xml_namespace__ = "https://dummy.com" diff --git a/tests/java/test_main.py b/tests/java/test_main.py index b34884bc8..0a3f168ce 100644 --- a/tests/java/test_main.py +++ b/tests/java/test_main.py @@ -1,5 +1,6 @@ # pylint: disable=missing-docstring +from typing import List import contextlib import io import os @@ -13,7 +14,7 @@ import tests.common -_TYPES = [ +AAS_TYPES = [ "AdministrativeInformation", "AnnotatedRelationshipElement", "AssetAdministrationShell", @@ -54,103 +55,110 @@ "ValueReferencePair", ] -_CONSTANTS = [pathlib.Path("constants/Constants.java")] -_COPYING = [pathlib.Path("copying/Copying.java")] -_ENHANCING = [pathlib.Path(f"enhancing/Enhanced{t}.java") for t in _TYPES] + [ - pathlib.Path("enhancing/Enhanced.java"), - pathlib.Path("enhancing/Enhancer.java"), - pathlib.Path("enhancing/Unwrapper.java"), - pathlib.Path("enhancing/Wrapper.java"), +AAS_ENUMS = [ + "AasSubmodelElements", + "AssetKind", + "DataTypeDefXsd", + "DataTypeIec61360", + "Direction", + "EntityType", + "KeyTypes", + "ModellingKind", + "QualifierKind", + "ReferenceTypes", + "StateOfEvent", ] -# NOTE (empwilli 2024-03-26): we create generators only for types that have -# non-mandatory attributes. -_GENERATION = [ - pathlib.Path(f"generation/{t}Builder.java") - for t in _TYPES - if t - not in ( - "EmbeddedDataSpecification", - "Key", - "LangStringDefinitionTypeIec61360", - "LangStringNameType", - "LangStringPreferredNameTypeIec61360", - "LangStringShortNameTypeIec61360", - "LangStringTextType", - "LevelType", - "OperationVariable", - "ValueList", - "ValueReferencePair", + + +def generate_files(types: List[str], enums: List[str]): + _CONSTANTS = [pathlib.Path("constants/Constants.java")] + _COPYING = [pathlib.Path("copying/Copying.java")] + _ENHANCING = [pathlib.Path(f"enhancing/Enhanced{t}.java") for t in types] + [ + pathlib.Path("enhancing/Enhanced.java"), + pathlib.Path("enhancing/Enhancer.java"), + pathlib.Path("enhancing/Unwrapper.java"), + pathlib.Path("enhancing/Wrapper.java"), + ] + # NOTE (empwilli 2024-03-26): we create generators only for types that have + # non-mandatory attributes. + _GENERATION = [ + pathlib.Path(f"generation/{t}Builder.java") + for t in types + if t + not in ( + "EmbeddedDataSpecification", + "Key", + "LangStringDefinitionTypeIec61360", + "LangStringNameType", + "LangStringPreferredNameTypeIec61360", + "LangStringShortNameTypeIec61360", + "LangStringTextType", + "LevelType", + "OperationVariable", + "ValueList", + "ValueReferencePair", + ) + ] + _JSONIZATION = [pathlib.Path("jsonization/Jsonization.java")] + _REPORTING = [pathlib.Path("reporting/Reporting.java")] + _STRINGIFICATION = [pathlib.Path("stringification/Stringification.java")] + _VERIFICATION = [pathlib.Path("verification/Verification.java")] + _STRUCTURE = ( + [pathlib.Path(f"types/enums/{i}.java") for i in enums] + + [pathlib.Path(f"types/impl/{t}.java") for t in types] + + [pathlib.Path(f"types/model/I{t}.java") for t in types] ) -] -_JSONIZATION = [pathlib.Path("jsonization/Jsonization.java")] -_REPORTING = [pathlib.Path("reporting/Reporting.java")] -_STRINGIFICATION = [pathlib.Path("stringification/Stringification.java")] -_VERIFICATION = [pathlib.Path("verification/Verification.java")] -_STRUCTURE = ( - [ - pathlib.Path("types/enums/AasSubmodelElements.java"), - pathlib.Path("types/enums/AssetKind.java"), - pathlib.Path("types/enums/DataTypeDefXsd.java"), - pathlib.Path("types/enums/DataTypeIec61360.java"), - pathlib.Path("types/enums/Direction.java"), - pathlib.Path("types/enums/EntityType.java"), - pathlib.Path("types/enums/KeyTypes.java"), - pathlib.Path("types/enums/ModellingKind.java"), - pathlib.Path("types/enums/QualifierKind.java"), - pathlib.Path("types/enums/ReferenceTypes.java"), - pathlib.Path("types/enums/StateOfEvent.java"), + _VISITATION = [ + pathlib.Path("visitation/AbstractTransformer.java"), + pathlib.Path("visitation/AbstractTransformerWithContext.java"), + pathlib.Path("visitation/AbstractVisitor.java"), + pathlib.Path("visitation/AbstractVisitorWithContext.java"), + pathlib.Path("visitation/ITransformer.java"), + pathlib.Path("visitation/ITransformerWithContext.java"), + pathlib.Path("visitation/IVisitor.java"), + pathlib.Path("visitation/IVisitorWithContext.java"), + pathlib.Path("visitation/VisitorThrough.java"), ] - + [pathlib.Path(f"types/impl/{t}.java") for t in _TYPES] - + [pathlib.Path(f"types/model/I{t}.java") for t in _TYPES] -) -_VISITATION = [ - pathlib.Path("visitation/AbstractTransformer.java"), - pathlib.Path("visitation/AbstractTransformerWithContext.java"), - pathlib.Path("visitation/AbstractVisitor.java"), - pathlib.Path("visitation/AbstractVisitorWithContext.java"), - pathlib.Path("visitation/ITransformer.java"), - pathlib.Path("visitation/ITransformerWithContext.java"), - pathlib.Path("visitation/IVisitor.java"), - pathlib.Path("visitation/IVisitorWithContext.java"), - pathlib.Path("visitation/VisitorThrough.java"), -] -XMLIZATION = [pathlib.Path("xmlization/Xmlization.java")] - -GENERATED_FILES = ( - _CONSTANTS - + _COPYING - + _ENHANCING - + _GENERATION - + _JSONIZATION - + _REPORTING - + _STRINGIFICATION - + _VERIFICATION - + _STRUCTURE - + _VISITATION -) + XMLIZATION = [pathlib.Path("xmlization/Xmlization.java")] + + return ( + _CONSTANTS + + _COPYING + + _ENHANCING + + _GENERATION + + _JSONIZATION + + _REPORTING + + _STRINGIFICATION + + _VERIFICATION + + _STRUCTURE + + _VISITATION + ) class Test_against_recorded(unittest.TestCase): - def test_cases(self) -> None: - repo_dir = pathlib.Path(os.path.realpath(__file__)).parent.parent.parent - - parent_case_dir = repo_dir / "test_data" / "java" / "test_main" - assert parent_case_dir.exists() and parent_case_dir.is_dir(), parent_case_dir - - for module in [aas_core_meta.v3]: - case_dir = parent_case_dir / module.__name__ - assert case_dir.is_dir(), case_dir - - assert ( - module.__file__ is not None - ), f"Expected the module {module!r} to have a __file__, but it has None" - model_pth = pathlib.Path(module.__file__) - assert model_pth.exists() and model_pth.is_file(), model_pth - - snippets_dir = case_dir / "input/snippets" + _REPO_DIR = pathlib.Path(os.path.realpath(__file__)).parent.parent.parent + PARENT_CASE_DIR = _REPO_DIR / "test_data" / "java" / "test_main" + + def test_against_meta_models(self) -> None: + assert ( + Test_against_recorded.PARENT_CASE_DIR.exists() + and Test_against_recorded.PARENT_CASE_DIR.is_dir() + ), f"{Test_against_recorded.PARENT_CASE_DIR=}" + + # fmt: off + test_cases = ( + tests.common.find_meta_models_in_parent_directory_of_test_cases_and_modules( + parent_case_dir=Test_against_recorded.PARENT_CASE_DIR, + aas_core_meta_modules=[aas_core_meta.v3] + ) + ) + # fmt: on + + for test_case in test_cases: + snippets_dir = test_case.case_dir / "input/snippets" assert snippets_dir.exists() and snippets_dir.is_dir(), snippets_dir - expected_output_dir = case_dir / "expected_output" + expected_output_dir = test_case.case_dir / "expected_output" with contextlib.ExitStack() as exit_stack: if tests.common.RERECORD: @@ -167,7 +175,7 @@ def test_cases(self) -> None: output_dir = pathlib.Path(tmp_dir.name) params = aas_core_codegen.main.Parameters( - model_path=model_pth, + model_path=test_case.model_path, target=aas_core_codegen.main.Target.JAVA, snippets_dir=snippets_dir, output_dir=output_dir, @@ -204,7 +212,15 @@ def test_cases(self) -> None: stdout_pth, ) - for relevant_rel_pth in GENERATED_FILES: + if test_case.case_dir.name.endswith("aas_core_meta.v3"): + types = AAS_TYPES + enums = AAS_ENUMS + else: + # TODO + types = [] + enums = [] + + for relevant_rel_pth in generate_files(types, enums): expected_pth = expected_output_dir / relevant_rel_pth output_pth = output_dir / relevant_rel_pth @@ -213,27 +229,14 @@ def test_cases(self) -> None: f"The output file is missing: {output_pth}" ) - try: - output = output_pth.read_text(encoding="utf-8") - except Exception as exception: - raise RuntimeError( - f"Failed to read the output from {output_pth}" - ) from exception - if tests.common.RERECORD: - expected_pth.write_text(output, encoding="utf-8") + expected_pth.write_text( + output_pth.read_text(encoding="utf-8"), encoding="utf-8" + ) else: - try: - expected_output = expected_pth.read_text(encoding="utf-8") - except Exception as exception: - raise RuntimeError( - f"Failed to read the expected output " - f"from {expected_pth}" - ) from exception - self.assertEqual( - expected_output, - output, + expected_pth.read_text(encoding="utf-8"), + output_pth.read_text(encoding="utf-8"), f"The files {expected_pth} and {output_pth} do not match.", ) From 4966ca25a9a23e42f2f3512f734a6387b9ecce06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Otto?= Date: Thu, 20 Feb 2025 16:00:37 +0100 Subject: [PATCH 13/14] Fix test data --- .../expected_output/jsonization.ts | 102 -------- .../expected_output/stringification.ts | 8 - .../expected_output/types.ts | 228 +----------------- .../expected_output/verification.ts | 13 +- .../list_of_primitives/meta_model.py | 4 - 5 files changed, 5 insertions(+), 350 deletions(-) diff --git a/test_data/typescript/test_main/list_of_primitives/expected_output/jsonization.ts b/test_data/typescript/test_main/list_of_primitives/expected_output/jsonization.ts index bd5c7cfff..290890418 100644 --- a/test_data/typescript/test_main/list_of_primitives/expected_output/jsonization.ts +++ b/test_data/typescript/test_main/list_of_primitives/expected_output/jsonization.ts @@ -289,83 +289,6 @@ function bytesFromJsonable( ); } -/** - * Provide de-serialize & set methods for properties - * of {@link types!Foo}. - */ -class SetterForFoo { - -} - -/** - * Parse an instance of {@link types!Foo} from the JSON-able - * structure `jsonable`. - * - * @param jsonable - structure to be parsed - * @returns parsed instance of {@link types!Foo}, - * or an error if any - */ -export function fooFromJsonable( - jsonable: JsonValue -): AasCommon.Either< - AasTypes.Foo, - DeserializationError -> { - if (jsonable === null) { - return newDeserializationError( - "Expected a JSON object, but got null" - ); - } - if (Array.isArray(jsonable)) { - return newDeserializationError( - "Expected a JSON object, but got a JSON array" - ); - } - if (typeof jsonable !== "object") { - return newDeserializationError( - `Expected a JSON object, but got: ${typeof jsonable}` - ); - } - - const setter = new SetterForFoo(); - - for (const key in jsonable) { - const jsonableValue = jsonable[key]; - const setterMethod = - SETTER_MAP_FOR_FOO.get(key); - - // NOTE (mristin, 2022-11-30): - // Since we conflate here a JavaScript object with a JSON object, we ignore - // properties which we do not know how to de-serialize and assume they are - // related to the *JavaScript* properties of the object or `Object` prototype. - if (setterMethod === undefined) { - continue; - } - - const error = setterMethod.call(setter, jsonableValue); - if (error !== null) { - error.path.prepend( - new PropertySegment(jsonable, key) - ); - return new AasCommon.Either< - AasTypes.Foo, - DeserializationError - >( - null, - error - ); - } - } - - return new AasCommon.Either< - AasTypes.Foo, - DeserializationError - >( - new AasTypes.Foo(), - null - ); -} - /** * Provide de-serialize & set methods for properties * of {@link types!ListOfPrimitives}. @@ -640,17 +563,6 @@ export function listOfPrimitivesFromJsonable( ); } -const SETTER_MAP_FOR_FOO = - new Map< - string, - ( - jsonable: JsonValue - ) => DeserializationError | null - >( - [ - ] - ); - const SETTER_MAP_FOR_LIST_OF_PRIMITIVES = new Map< string, @@ -684,20 +596,6 @@ const SETTER_MAP_FOR_LIST_OF_PRIMITIVES = class Serializer extends AasTypes.AbstractTransformer { - /** - * Serialize `that` to a JSON-able representation. - * - * @param that - instance to be serialization - * @returns JSON-able representation - */ - transformFoo( - that: AasTypes.Foo - ): JsonObject { - const jsonable: JsonObject = {}; - - return jsonable; - } - /** * Serialize `that` to a JSON-able representation. * diff --git a/test_data/typescript/test_main/list_of_primitives/expected_output/stringification.ts b/test_data/typescript/test_main/list_of_primitives/expected_output/stringification.ts index f506a4807..ad02403b1 100644 --- a/test_data/typescript/test_main/list_of_primitives/expected_output/stringification.ts +++ b/test_data/typescript/test_main/list_of_primitives/expected_output/stringification.ts @@ -8,10 +8,6 @@ import * as AasTypes from "./types"; const MODEL_TYPE_FROM_STRING = new Map([ - [ - "Foo", - AasTypes.ModelType.Foo - ], [ "ListOfPrimitives", AasTypes.ModelType.ListOfPrimitives @@ -32,10 +28,6 @@ export function modelTypeFromString( } const MODEL_TYPE_TO_STRING = new Map([ - [ - AasTypes.ModelType.Foo, - "Foo" - ], [ AasTypes.ModelType.ListOfPrimitives, "ListOfPrimitives" diff --git a/test_data/typescript/test_main/list_of_primitives/expected_output/types.ts b/test_data/typescript/test_main/list_of_primitives/expected_output/types.ts index 89df782cb..73fc0929e 100644 --- a/test_data/typescript/test_main/list_of_primitives/expected_output/types.ts +++ b/test_data/typescript/test_main/list_of_primitives/expected_output/types.ts @@ -5,8 +5,7 @@ * Represent runtime model type of an instance. */ export enum ModelType { - Foo = 0, - ListOfPrimitives = 1 + ListOfPrimitives = 0 } /** @@ -23,8 +22,7 @@ export function *overModelType ( // NOTE (mristin, 2022-12-03): // We yield numbers instead of literals to avoid name lookups on platforms // which do not provide JIT compilation of hot paths. - yield 0; // Foo - yield 1; // ListOfPrimitives + yield 0; // ListOfPrimitives } /** @@ -88,90 +86,6 @@ export abstract class Class { ): T; } -export class Foo extends Class { - /** - * Indicate the runtime model type of the instance. - */ - modelType(): ModelType { - // NOTE (mristin, 2022-12-03): - // We yield numbers instead of literals to avoid name lookups on platforms - // which do not provide JIT compilation of hot paths. - return 0; // Foo - } - - /** - * Iterate over the instances referenced from this instance. - * - * We do not recurse into the referenced instances. - * - * @returns Iterator over the referenced instances - */ - *descendOnce(): IterableIterator { - // No descendable properties - } - - /** - * Iterate recursively over the instances referenced from this instance. - * - * @returns Iterator over the referenced instances - */ - *descend(): IterableIterator { - // No descendable properties - } - - /** - * Dispatch `visitor` on this instance. - * - * @param visitor - to visit this instance - */ - accept(visitor: AbstractVisitor): void { - visitor.visitFoo(this); - } - - /** - * Dispatch `visitor` with `context` on this instance. - * - * @param visitor - to visit this instance - * @param context - to be passed along to the dispatched visitor method - * @typeParam ContextT - type of the context - */ - acceptWithContext( - visitor: AbstractVisitorWithContext, - context: ContextT - ) { - visitor.visitFooWithContext(this, context); - } - - /** - * Dispatch the `transformer` on this instance. - * - * @param transformer - to transform this instance - * @returns transformation of this instance - * @paramType T - type of the transformation result - */ - transform(transformer: AbstractTransformer): T { - return transformer.transformFoo(this); - } - - /** - * Dispatch the `transformer` on this instance in `context`. - * - * @param transformer - to transform this instance - * @param context - to be passed along to the `transformer` - * @returns transformation of this instance - * @paramType T - type of the transformation result - * @paramType ContextT - type of the transformation context - */ - transformWithContext( - transformer: AbstractTransformerWithContext, - context: ContextT - ): T { - return transformer.transformFooWithContext( - this, context - ); - } -} - export class ListOfPrimitives extends Class { /** * Indicate the runtime model type of the instance. @@ -180,7 +94,7 @@ export class ListOfPrimitives extends Class { // NOTE (mristin, 2022-12-03): // We yield numbers instead of literals to avoid name lookups on platforms // which do not provide JIT compilation of hot paths. - return 1; // ListOfPrimitives + return 0; // ListOfPrimitives } strings: Array; @@ -284,15 +198,6 @@ export abstract class AbstractVisitor { that.accept(this); } - /** - * Visit `that`. - * - * @param that - instance to be visited - */ - abstract visitFoo( - that: Foo - ): void; - /** * Visit `that`. * @@ -322,17 +227,6 @@ export abstract class AbstractVisitorWithContext { that.acceptWithContext(this, context); } - /** - * Visit `that` in `context`. - * - * @param that - instance to be visited - * @param context - of the visitation - */ - abstract visitFooWithContext( - that: Foo, - context: ContextT - ): void; - /** * Visit `that` in `context`. * @@ -353,19 +247,6 @@ export abstract class AbstractVisitorWithContext { * inherit from it, and implement only the relevant visit methods. */ export class PassThroughVisitor extends AbstractVisitor { - /** - * Visit `that`. - * - * @param that - instance to be visited - */ - visitFoo( - that: Foo - ): void { - for (const another of that.descendOnce()) { - this.visit(another); - } - } - /** * Visit `that`. * @@ -399,21 +280,6 @@ export class PassThroughVisitorWithContext that.acceptWithContext(this, context); } - /** - * Visit `that` in `context`. - * - * @param that - instance to be visited - * @param context - of the visitation - */ - visitFooWithContext( - that: Foo, - context: ContextT - ): void { - for (const another of that.descendOnce()) { - this.visitWithContext(another, context); - } - } - /** * Visit `that` in `context`. * @@ -443,16 +309,6 @@ export abstract class AbstractTransformer { return that.transform(this); } - /** - * Transform `that`. - * - * @param that - instance to be transformed - * @returns transformed `that` - */ - abstract transformFoo( - that: Foo - ): T; - /** * Transform `that`. * @@ -485,18 +341,6 @@ export abstract class AbstractTransformerWithContext { return that.transformWithContext(this, context); } - /** - * Transform `that` in `context`. - * - * @param that - instance to be transformed - * @param context - of the transformation - * @returns transformed `that` - */ - abstract transformFooWithContext( - that: Foo, - context: ContextT - ): T; - /** * Transform `that` in `context`. * @@ -535,20 +379,6 @@ export class TransformerWithDefault extends AbstractTransformer { this.defaultResult = defaultResult; } - /** - * Transform `that`. - * - * @param that - instance to be transformed - * @returns transformed `that` - */ - /* eslint-disable @typescript-eslint/no-unused-vars */ - transformFoo( - that: Foo - ): T { - return this.defaultResult; - } - /* eslint-enable @typescript-eslint/no-unused-vars */ - /** * Transform `that`. * @@ -591,22 +421,6 @@ export class TransformerWithDefaultAndContext this.defaultResult = defaultResult; } - /** - * Transform `that` in `context`. - * - * @param that - instance to be transformed - * @param context - of the visitation - * @returns transformed `that` - */ - /* eslint-disable @typescript-eslint/no-unused-vars */ - transformFooWithContext( - that: Foo, - context: ContextT - ): T { - return this.defaultResult; - } - /* eslint-enable @typescript-eslint/no-unused-vars */ - /** * Transform `that` in `context`. * @@ -624,33 +438,6 @@ export class TransformerWithDefaultAndContext /* eslint-enable @typescript-eslint/no-unused-vars */ } -/** - * Try to cast `that` instance to - * the class {@link Foo}. - * - * @param that - instance to be casted - * @returns - casted `that` if cast successful, or `null` - */ -export function asFoo( - that: Class -): Foo | null { - return (that instanceof Foo) - ? that - : null; -} - -/** - * Check the type of `that` instance. - * - * @param that - instance to be type-checked - * @returns `true` if the type check is successful - */ -export function isFoo( - that: Class -): that is Foo { - return that instanceof Foo; -} - /** * Try to cast `that` instance to * the class {@link ListOfPrimitives}. @@ -682,15 +469,6 @@ class TypeMatcher extends AbstractTransformerWithContext< Readonly, boolean > { - /* eslint-disable @typescript-eslint/no-unused-vars */ - transformFooWithContext( - that: Foo, - other: Class - ): boolean { - return isFoo(other); - } - /* eslint-enable @typescript-eslint/no-unused-vars */ - /* eslint-disable @typescript-eslint/no-unused-vars */ transformListOfPrimitivesWithContext( that: ListOfPrimitives, diff --git a/test_data/typescript/test_main/list_of_primitives/expected_output/verification.ts b/test_data/typescript/test_main/list_of_primitives/expected_output/verification.ts index 8e4a258e1..f9ecf56ce 100644 --- a/test_data/typescript/test_main/list_of_primitives/expected_output/verification.ts +++ b/test_data/typescript/test_main/list_of_primitives/expected_output/verification.ts @@ -1,13 +1,13 @@ /** * Verify that the instances of the meta-model satisfy the invariants. * - * Here is an example how to verify an instance of {@link types.Foo}: + * Here is an example how to verify an instance of {@link types.ListOfPrimitives}: * * ```ts * import * as AasTypes from "test/types"; * import * as AasVerification from "test/verification"; * - * const anInstance = new AasTypes.Foo( + * const anInstance = new AasTypes.ListOfPrimitives( * // ... some constructor arguments ... * ); * @@ -134,15 +134,6 @@ class Verifier extends AasTypes.AbstractTransformerWithContext< boolean, IterableIterator > { - *transformFooWithContext( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - that: AasTypes.Foo, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - context: boolean - ): IterableIterator { - // No verification has been defined for Foo. - } - *transformListOfPrimitivesWithContext( that: AasTypes.ListOfPrimitives, context: boolean diff --git a/test_data/typescript/test_main/list_of_primitives/meta_model.py b/test_data/typescript/test_main/list_of_primitives/meta_model.py index 49e337b87..531303f43 100644 --- a/test_data/typescript/test_main/list_of_primitives/meta_model.py +++ b/test_data/typescript/test_main/list_of_primitives/meta_model.py @@ -1,10 +1,6 @@ from typing import List -class Foo: - pass - - class List_of_primitives: strings: List[str] integers: List[int] From 6134faf3cc97bfea21b5a9a6afe21e84e873f016 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Otto?= Date: Thu, 20 Feb 2025 16:20:55 +0100 Subject: [PATCH 14/14] Improve java --- aas_core_codegen/java/enhancing/_generate.py | 4 +- aas_core_codegen/java/xmlization/_generate.py | 51 +++++++++++-------- .../expected_output/enhancing/Wrapper.java | 42 --------------- .../xmlization/Xmlization.java | 30 +++++------ 4 files changed, 48 insertions(+), 79 deletions(-) diff --git a/aas_core_codegen/java/enhancing/_generate.py b/aas_core_codegen/java/enhancing/_generate.py index 7f3961419..451e4e0b4 100644 --- a/aas_core_codegen/java/enhancing/_generate.py +++ b/aas_core_codegen/java/enhancing/_generate.py @@ -589,8 +589,8 @@ def _generate_transform(cls: intermediate.ConcreteClass) -> Stripped: assert_never(type_anno.our_type) elif isinstance(type_anno, intermediate.ListTypeAnnotation): if isinstance(type_anno.items, intermediate.PrimitiveTypeAnnotation): - transformed_name = "FOO" - item_interface_name = "BAR" + # We can not enhance primitive types; nothing to do here. + continue elif isinstance( type_anno.items, intermediate.OurTypeAnnotation ) and isinstance( diff --git a/aas_core_codegen/java/xmlization/_generate.py b/aas_core_codegen/java/xmlization/_generate.py index 4970da0d5..139627f96 100644 --- a/aas_core_codegen/java/xmlization/_generate.py +++ b/aas_core_codegen/java/xmlization/_generate.py @@ -249,6 +249,31 @@ def _generate_is_empty_element() -> Stripped: ) +_PRIMITIVE_TYPE_TO_DESERIALIZE = { + intermediate.PrimitiveType.BOOL: "readContentAsBool", + intermediate.PrimitiveType.INT: "readContentAsInt", + intermediate.PrimitiveType.FLOAT: "readContentAsFloat", + intermediate.PrimitiveType.STR: "readContentAsString", + intermediate.PrimitiveType.BYTEARRAY: "readContentAsBase64", +} +assert all( + primitive_type in _PRIMITIVE_TYPE_TO_DESERIALIZE + for primitive_type in intermediate.PrimitiveType +) + +_PRIMITIVE_TYPE_TO_NATIVE_TYPE = { + intermediate.PrimitiveType.BOOL: "bool", + intermediate.PrimitiveType.INT: "int", + intermediate.PrimitiveType.FLOAT: "double", + intermediate.PrimitiveType.STR: "String", + intermediate.PrimitiveType.BYTEARRAY: "bytes", +} +assert all( + primitive_type in _PRIMITIVE_TYPE_TO_NATIVE_TYPE + for primitive_type in intermediate.PrimitiveType +) + + def _generate_deserialize_primitive_property( prop: intermediate.Property, cls: intermediate.ConcreteClass ) -> Stripped: @@ -258,19 +283,7 @@ def _generate_deserialize_primitive_property( a_type = intermediate.try_primitive_type(type_anno) assert a_type is not None, f"Unexpected type annotation: {prop.type_annotation}" - deserialization_expr: str - if a_type is intermediate.PrimitiveType.BOOL: - deserialization_expr = "readContentAsBool(reader)" - elif a_type is intermediate.PrimitiveType.INT: - deserialization_expr = "readContentAsInt(reader)" - elif a_type is intermediate.PrimitiveType.FLOAT: - deserialization_expr = "readContentAsFloat(reader)" - elif a_type is intermediate.PrimitiveType.STR: - deserialization_expr = "readContentAsString(reader)" - elif a_type is intermediate.PrimitiveType.BYTEARRAY: - deserialization_expr = "readContentAsBase64(reader)" - else: - assert_never(a_type) + deserialization_expr: str = f"{_PRIMITIVE_TYPE_TO_DESERIALIZE[a_type]}(reader)" target_var = java_naming.variable_name(Identifier(f"the_{prop.name}")) @@ -650,10 +663,9 @@ def _generate_deserialize_list_property( target_var = java_naming.variable_name(Identifier(f"the_{prop.name}")) if isinstance(type_anno.items, intermediate.PrimitiveTypeAnnotation): - deserialize_method = "FOO" - item_type = "BAR" - cls_name = "BAR" - xml_prop_name_literal = "BAR" + deserialize_method = _PRIMITIVE_TYPE_TO_DESERIALIZE[type_anno.items.a_type] + item_type = _PRIMITIVE_TYPE_TO_NATIVE_TYPE[type_anno.items.a_type] + cls_name = _PRIMITIVE_TYPE_TO_NATIVE_TYPE[type_anno.items.a_type] elif isinstance(type_anno.items, intermediate.OurTypeAnnotation) and isinstance( type_anno.items.our_type, (intermediate.AbstractClass, intermediate.ConcreteClass), @@ -670,12 +682,11 @@ def _generate_deserialize_list_property( deserialize_method = f"{class_name}FromElement" item_type = java_common.generate_type(type_anno.items) cls_name = java_naming.class_name(cls.name) - xml_prop_name_literal = java_common.string_literal( - naming.xml_property(prop.name) - ) else: assert_never(type_anno) + xml_prop_name_literal = java_common.string_literal(naming.xml_property(prop.name)) + return Stripped( f"""\ {target_var} = new ArrayList<>(); diff --git a/test_data/java/test_main/list_of_primitives/expected_output/enhancing/Wrapper.java b/test_data/java/test_main/list_of_primitives/expected_output/enhancing/Wrapper.java index 1b00fd9fb..0c85b6363 100644 --- a/test_data/java/test_main/list_of_primitives/expected_output/enhancing/Wrapper.java +++ b/test_data/java/test_main/list_of_primitives/expected_output/enhancing/Wrapper.java @@ -33,48 +33,6 @@ public IClass transformListOfPrimitives( ); } - List strings = that.getStrings(); - List FOO = strings.stream() - .map(item -> { - IClass transformed = transform(item); - if (!(transformed instanceof BAR)) { - throw new UnsupportedOperationException( - "Expected the transformed value to be a BAR " + - ", but got: " + transformed - ); - } - return (BAR) transformed; - }).collect(Collectors.toList()); - that.setStrings(FOO); - - List integers = that.getIntegers(); - List FOO = integers.stream() - .map(item -> { - IClass transformed = transform(item); - if (!(transformed instanceof BAR)) { - throw new UnsupportedOperationException( - "Expected the transformed value to be a BAR " + - ", but got: " + transformed - ); - } - return (BAR) transformed; - }).collect(Collectors.toList()); - that.setIntegers(FOO); - - List booleans = that.getBooleans(); - List FOO = booleans.stream() - .map(item -> { - IClass transformed = transform(item); - if (!(transformed instanceof BAR)) { - throw new UnsupportedOperationException( - "Expected the transformed value to be a BAR " + - ", but got: " + transformed - ); - } - return (BAR) transformed; - }).collect(Collectors.toList()); - that.setBooleans(FOO); - Optional enhancement = enhancementFactory.apply(that); return !enhancement.isPresent() ? that diff --git a/test_data/java/test_main/list_of_primitives/expected_output/xmlization/Xmlization.java b/test_data/java/test_main/list_of_primitives/expected_output/xmlization/Xmlization.java index 3a31b6d08..e1789b356 100644 --- a/test_data/java/test_main/list_of_primitives/expected_output/xmlization/Xmlization.java +++ b/test_data/java/test_main/list_of_primitives/expected_output/xmlization/Xmlization.java @@ -440,15 +440,15 @@ private static Result tryListOfPrimitivesFromSequence( int index = 0; if(!currentEvent(reader).isStartElement()){ final Reporting.Error error = new Reporting.Error( - "Expected a start element opening an instance of BAR, but got an XML " + "Expected a start element opening an instance of std::wstring, but got an XML " + getEventTypeAsString(currentEvent(reader))); error.prependSegment(new Reporting.IndexSegment(index)); - error.prependSegment(new Reporting.NameSegment(BAR)); + error.prependSegment(new Reporting.NameSegment("strings")); return Result.failure(error); } while (currentEvent(reader).isStartElement()) { - Result itemResult = tryFOO(reader); + Result itemResult = tryreadContentAsString(reader); if (itemResult.isError()) { itemResult.getError() @@ -456,8 +456,8 @@ private static Result tryListOfPrimitivesFromSequence( new Reporting.IndexSegment(index)); itemResult.getError() .prependSegment( - new Reporting.NameSegment(BAR)); - return itemResult.castTo(BAR.class); + new Reporting.NameSegment("strings")); + return itemResult.castTo(std::wstring.class); } theStrings.add(itemResult.getResult()); @@ -475,15 +475,15 @@ private static Result tryListOfPrimitivesFromSequence( int index = 0; if(!currentEvent(reader).isStartElement()){ final Reporting.Error error = new Reporting.Error( - "Expected a start element opening an instance of BAR, but got an XML " + "Expected a start element opening an instance of int64_t, but got an XML " + getEventTypeAsString(currentEvent(reader))); error.prependSegment(new Reporting.IndexSegment(index)); - error.prependSegment(new Reporting.NameSegment(BAR)); + error.prependSegment(new Reporting.NameSegment("integers")); return Result.failure(error); } while (currentEvent(reader).isStartElement()) { - Result itemResult = tryFOO(reader); + Result itemResult = tryreadContentAsInt(reader); if (itemResult.isError()) { itemResult.getError() @@ -491,8 +491,8 @@ private static Result tryListOfPrimitivesFromSequence( new Reporting.IndexSegment(index)); itemResult.getError() .prependSegment( - new Reporting.NameSegment(BAR)); - return itemResult.castTo(BAR.class); + new Reporting.NameSegment("integers")); + return itemResult.castTo(int64_t.class); } theIntegers.add(itemResult.getResult()); @@ -510,15 +510,15 @@ private static Result tryListOfPrimitivesFromSequence( int index = 0; if(!currentEvent(reader).isStartElement()){ final Reporting.Error error = new Reporting.Error( - "Expected a start element opening an instance of BAR, but got an XML " + "Expected a start element opening an instance of bool, but got an XML " + getEventTypeAsString(currentEvent(reader))); error.prependSegment(new Reporting.IndexSegment(index)); - error.prependSegment(new Reporting.NameSegment(BAR)); + error.prependSegment(new Reporting.NameSegment("booleans")); return Result.failure(error); } while (currentEvent(reader).isStartElement()) { - Result itemResult = tryFOO(reader); + Result itemResult = tryreadContentAsBool(reader); if (itemResult.isError()) { itemResult.getError() @@ -526,8 +526,8 @@ private static Result tryListOfPrimitivesFromSequence( new Reporting.IndexSegment(index)); itemResult.getError() .prependSegment( - new Reporting.NameSegment(BAR)); - return itemResult.castTo(BAR.class); + new Reporting.NameSegment("booleans")); + return itemResult.castTo(bool.class); } theBooleans.add(itemResult.getResult());