Skip to content

Commit 190d66e

Browse files
committed
update
1 parent d23d297 commit 190d66e

10 files changed

Lines changed: 194 additions & 188 deletions

File tree

.clang-format

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
Language: Cpp
33
Standard: c++20
4+
IndentWidth: 4
45
ColumnLimit: 120
56
AccessModifierOffset: -2
67
DerivePointerAlignment: false
@@ -11,4 +12,6 @@ AllowShortFunctionsOnASingleLine: Empty
1112
AllowShortLambdasOnASingleLine: Empty
1213
AllowShortBlocksOnASingleLine: Empty
1314
AlignAfterOpenBracket: DontAlign
15+
AllowShortCaseLabelsOnASingleLine: true
16+
EmptyLineBeforeAccessModifier: LogicalBlock
1417
...

CMakeLists.txt

Lines changed: 49 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5,51 +5,55 @@ project(sbe-code-gen)
55
# TODO: setup env should be done once?
66

77
function(sbe_make_codec TARGET)
8-
set(options)
9-
set(oneValueArgs SCHEMA OUTPUT GENERATOR INCLUDE_BASE PACKAGE)
10-
set(multiValueArgs)
11-
12-
cmake_parse_arguments(PARSED "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
13-
14-
find_package(Python3 COMPONENTS Interpreter REQUIRED)
15-
16-
if (PARSED_INCLUDE_BASE)
17-
set(destDir "${PARSED_OUTPUT}/${PARSED_INCLUDE_BASE}")
18-
else()
19-
set(destDir "${PARSED_OUTPUT}")
20-
endif()
21-
22-
set(extraArgs)
23-
if (PARSED_PACKAGE)
24-
set(extraArgs ${extraArgs} --package="${PARSED_PACKAGE}")
25-
endif()
26-
27-
set(cppCodegenRoot ${CMAKE_CURRENT_FUNCTION_LIST_DIR})
28-
set(pythonEnvRoot ${CMAKE_CURRENT_BINARY_DIR}/venv)
29-
set(pythonEnvExe ${CMAKE_CURRENT_BINARY_DIR}/venv/bin/python)
30-
31-
# Setup venv
32-
add_custom_command(
33-
OUTPUT ${pythonEnvExe} ${pythonEnvRoot}/pyvenv.cfg
34-
COMMAND ${Python3_EXECUTABLE} -m venv ${pythonEnvRoot}
35-
COMMAND ${pythonEnvExe} -m pip install --upgrade pip
36-
COMMAND ${pythonEnvExe} -m pip install -r ${cppCodegenRoot}/requirements.txt
37-
COMMENT "Creating python virtualenv at ${pythonEnvRoot}"
38-
)
39-
40-
add_custom_command(
41-
OUTPUT ${destDir}/schema.h
42-
DEPENDS ${PARSED_SCHEMA} ${pythonEnvRoot}/pyvenv.cfg
43-
COMMAND ${CMAKE_COMMAND} -E rm -rf "${PARSED_OUTPUT}"
44-
COMMAND ${pythonEnvExe} -m app --schema="${PARSED_SCHEMA}" --destination="${destDir}" --generator="${PARSED_GENERATOR}" ${extraArgs}
45-
WORKING_DIRECTORY ${cppCodegenRoot}
46-
COMMENT "Generating schema (${PARSED_SCHEMA})"
47-
)
48-
49-
add_library(${TARGET} INTERFACE EXCLUDE_FROM_ALL)
50-
target_compile_features(${TARGET} INTERFACE cxx_std_20)
51-
target_sources(${TARGET} INTERFACE ${destDir}/schema.h)
52-
target_include_directories(${TARGET} INTERFACE "${PARSED_OUTPUT}")
8+
set(options)
9+
set(oneValueArgs SCHEMA OUTPUT GENERATOR INCLUDE_BASE PACKAGE)
10+
set(multiValueArgs)
11+
12+
cmake_parse_arguments(PARSED "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
13+
14+
find_package(Python3 COMPONENTS Interpreter REQUIRED)
15+
16+
if (PARSED_INCLUDE_BASE)
17+
set(destDir "${PARSED_OUTPUT}/${PARSED_INCLUDE_BASE}")
18+
else()
19+
set(destDir "${PARSED_OUTPUT}")
20+
endif()
21+
22+
set(extraArgs)
23+
if (PARSED_PACKAGE)
24+
set(extraArgs ${extraArgs} --package="${PARSED_PACKAGE}")
25+
endif()
26+
27+
if (NOT PARSED_GENERATOR)
28+
set(PARSED_GENERATOR cpp)
29+
endif()
30+
31+
set(cppCodegenRoot ${CMAKE_CURRENT_FUNCTION_LIST_DIR})
32+
set(pythonEnvRoot ${CMAKE_CURRENT_BINARY_DIR}/venv)
33+
set(pythonEnvExe ${CMAKE_CURRENT_BINARY_DIR}/venv/bin/python)
34+
35+
# Setup venv
36+
add_custom_command(
37+
OUTPUT ${pythonEnvExe} ${pythonEnvRoot}/pyvenv.cfg
38+
COMMAND ${Python3_EXECUTABLE} -m venv ${pythonEnvRoot}
39+
COMMAND ${pythonEnvExe} -m pip install --upgrade pip
40+
COMMAND ${pythonEnvExe} -m pip install -r ${cppCodegenRoot}/requirements.txt
41+
COMMENT "Creating python virtualenv at ${pythonEnvRoot}"
42+
)
43+
44+
add_custom_command(
45+
OUTPUT ${destDir}/schema.h
46+
DEPENDS ${PARSED_SCHEMA} ${pythonEnvRoot}/pyvenv.cfg
47+
COMMAND ${CMAKE_COMMAND} -E rm -rf "${PARSED_OUTPUT}"
48+
COMMAND ${pythonEnvExe} -m app --schema="${PARSED_SCHEMA}" --destination="${destDir}" --generator="${PARSED_GENERATOR}" ${extraArgs}
49+
WORKING_DIRECTORY ${cppCodegenRoot}
50+
COMMENT "Generating schema (${PARSED_SCHEMA})"
51+
)
52+
53+
add_library(${TARGET} INTERFACE EXCLUDE_FROM_ALL)
54+
target_compile_features(${TARGET} INTERFACE cxx_std_23)
55+
target_sources(${TARGET} INTERFACE ${destDir}/schema.h)
56+
target_include_directories(${TARGET} INTERFACE "${PARSED_OUTPUT}")
5357
endfunction()
5458

5559
enable_testing()

app/generation/cpp/generator.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ def _generate_impl(self, schema: dict) -> None:
4343
print(f'Generating message {message_class_name} (to {message_class_h_file})')
4444
self.generate_document(message_class_h_file, 'message.tmpl', message=message, schema=schema)
4545

46+
self.generate_document('schema.h', 'schema.tmpl', schema=schema)
47+
4648
def generate_document(self, document_name: str, template_name: str, **kwargs) -> None:
4749
template = self.env.get_template(template_name)
4850
document_path = f'{self.path}/{document_name}'

app/generation/cpp/templates/composite.tmpl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
{% block includes %}
66
#include <algorithm>
77
#include <bit>
8+
#include <cmath>
89
#include <cstddef>
910
{% if type.name == schema.header_type.name %}
1011
#include <span>

app/generation/cpp/templates/generate.tmpl

Lines changed: 52 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -133,19 +133,19 @@ public:
133133
os << '[';
134134
{% set count = type.choices | length %}
135135
{% if count > 1 %}
136-
bool atLeastOnePrinter = false;
136+
bool atLeastOnePrinted{false};
137137
{% endif %}
138138
{% for choice in type.choices %}
139139
{% set choice_method = choice.name[0].lower() ~ choice.name[1:] %}
140140
if (value.{{ choice_method }}()) {
141141
{% if not loop.first and count > 1 %}
142-
if (atLeastOnePrinter) {
142+
if (atLeastOnePrinted) {
143143
os << ", ";
144144
}
145145
{% endif %}
146146
os << "{{ choice.name }}";
147147
{% if not loop.last and count > 1 %}
148-
atLeastOnePrinter = true;
148+
atLeastOnePrinted = true;
149149
{% endif %}
150150
}
151151
{% endfor %}
@@ -374,30 +374,31 @@ public:
374374

375375
{{ meta_decl() | indent(4) }}
376376

377+
{% if message.fields | length > 0 %}
377378
using Fields = TypeList<
378-
{% for field in message.fields %}
379-
{% set field_ref_name = field.name | fmt_class_ref %}
379+
{% for field in message.fields %}
380+
{% set field_ref_name = field.name | fmt_class_ref %}
380381
{{ field_ref_name }}{% if not loop.last %},{% endif +%}
381-
{% endfor %}
382+
{% endfor %}
382383
>;
383384

384385
template <std::size_t I>
385386
[[nodiscard]] constexpr auto get() noexcept {
386-
{% for field in message.fields %}
387-
{% set field_ref_name = field.name | fmt_class_ref %}
388-
{% if loop.first %}
387+
{% for field in message.fields %}
388+
{% set field_ref_name = field.name | fmt_class_ref %}
389+
{% if loop.first %}
389390
if constexpr (I == {{ loop.index0 }}) {
390-
{% else %}
391+
{% else %}
391392
} else if constexpr (I == {{ loop.index0 }}) {
392-
{% endif %}
393-
{% if field.token == 'field' %}
393+
{% endif %}
394+
{% if field.token == 'field' %}
394395
return {{ field_ref_name }}{buffer_.data() + offset_, actingVersion_};
395-
{% elif field.token == 'group' %}
396+
{% elif field.token == 'group' %}
396397
return {{ field_ref_name }}{buffer_, &position_, actingVersion_};
397-
{% elif field.token == 'data' %}
398+
{% elif field.token == 'data' %}
398399
return {{ field_ref_name }}{buffer_, &position_, actingVersion_};
399-
{% endif %}
400-
{% endfor %}
400+
{% endif %}
401+
{% endfor %}
401402
} else {
402403
static_assert(I < 0, "Field index out of range ({{ class_cpp_t }})");
403404
}
@@ -406,25 +407,38 @@ public:
406407
template <CtStr N>
407408
[[nodiscard]] constexpr auto get() noexcept {
408409
constexpr auto name = static_cast<std::string_view>(N);
409-
{% for field in message.fields %}
410-
{% set field_ref_name = field.name | fmt_class_ref %}
411-
{% if loop.first %}
410+
{% for field in message.fields %}
411+
{% set field_ref_name = field.name | fmt_class_ref %}
412+
{% if loop.first %}
412413
if constexpr (name == {{ field_ref_name }}::sbeRefName()) {
413-
{% else %}
414+
{% else %}
414415
} else if constexpr (name == {{ field_ref_name }}::sbeRefName()) {
415-
{% endif %}
416-
{% if field.token == 'field' %}
416+
{% endif %}
417+
{% if field.token == 'field' %}
417418
return {{ field_ref_name }}{buffer_.data() + offset_, actingVersion_};
418-
{% elif field.token == 'group' %}
419+
{% elif field.token == 'group' %}
419420
return {{ field_ref_name }}{buffer_, &position_, actingVersion_};
420-
{% elif field.token == 'data' %}
421+
{% elif field.token == 'data' %}
421422
return {{ field_ref_name }}{buffer_, &position_, actingVersion_};
422-
{% endif %}
423-
{% endfor %}
423+
{% endif %}
424+
{% endfor %}
424425
} else {
425426
static_assert(name.size() + 1 < 0, "Field not found ({{ class_cpp_t }})");
426427
}
427428
}
429+
{% else %}
430+
using Fields = TypeList<>;
431+
432+
template <std::size_t I>
433+
[[nodiscard]] constexpr auto get() noexcept {
434+
static_assert(I < 0, "Field index out of range ({{ class_cpp_t }})");
435+
}
436+
437+
template <CtStr N>
438+
[[nodiscard]] constexpr auto get() noexcept {
439+
static_assert(static_cast<std::string_view>(N).size() + 1 < 0, "Field not found ({{ class_cpp_t }})");
440+
}
441+
{% endif %}
428442
};
429443
{%- endmacro %}
430444

@@ -463,6 +477,10 @@ public:
463477
*positionPtr_ = *positionPtr_ + {{ dimension.encoded_length }};
464478
}
465479

480+
[[nodiscard]] static constexpr auto sbeGroupName() noexcept -> char const* {
481+
return "{{ group.name }}";
482+
}
483+
466484
[[nodiscard]] static constexpr auto sbeBlockLength() noexcept -> {{ block_length_cpp_t }} {
467485
return {{ group.block_length }};
468486
}
@@ -1129,6 +1147,10 @@ struct {{ class_cpp_t }} : public {{ group_class_cpp_t }} {
11291147
[[nodiscard]] static constexpr auto sbeSinceVersion() noexcept -> {{ version_cpp_t }} {
11301148
return {{ entry.since_version }};
11311149
}
1150+
1151+
[[nodiscard]] constexpr auto present() const noexcept -> bool {
1152+
return true;
1153+
}
11321154
};
11331155
{%- endmacro %}
11341156

@@ -1152,6 +1174,10 @@ struct {{ class_cpp_t }} : public {{ group_class_cpp_t }} {
11521174
[[nodiscard]] static constexpr auto sbeSinceVersion() noexcept -> {{ version_cpp_t }} {
11531175
return {{ entry.since_version }};
11541176
}
1177+
1178+
[[nodiscard]] constexpr auto present() const noexcept -> bool {
1179+
return true;
1180+
}
11551181
};
11561182
{%- endmacro %}
11571183

app/generation/cpp/templates/message.tmpl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
{% block includes %}
66
#include <algorithm>
77
#include <bit>
8+
#include <cmath>
89
#include <cstddef>
910
#include <span>
1011
{# let's find all non-trivial types recursively #}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Generated simple binary encoding message codec
2+
// Message codec generator: https://github.com/ksergey/sbe-code-gen
3+
4+
#pragma once
5+
6+
{% import 'generate.tmpl' as generate with context %}
7+
{% for message in schema.messages %}
8+
#include "{{ message.name | fmt_class_type | fmt_header_name }}"
9+
{% endfor %}

tests/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ endif()
1010

1111
if (NOT TARGET fmt::fmt)
1212
FetchContent_Declare(fmt
13-
URL https://github.com/fmtlib/fmt/archive/refs/tags/11.0.2.tar.gz
13+
URL https://github.com/fmtlib/fmt/archive/refs/tags/12.1.0.tar.gz
1414
DOWNLOAD_EXTRACT_TIMESTAMP ON
1515
)
1616
FetchContent_MakeAvailable(fmt)

tests/binance/CMakeLists.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
sbe_make_codec(spot_2_0
2-
SCHEMA ${CMAKE_CURRENT_SOURCE_DIR}/../../resources/spot_2_0.xml
3-
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/spot_2_0
4-
GENERATOR cppng
2+
SCHEMA ${CMAKE_CURRENT_SOURCE_DIR}/../../resources/spot_2_0.xml
3+
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/spot_2_0
4+
GENERATOR cpp
55
)
66

77
set(Target binance)
88
add_executable(${Target} main.cpp)
99
target_compile_features(${Target} PRIVATE cxx_std_20)
1010
target_compile_options(${Target} PRIVATE -Wall -Wextra)
11-
target_link_libraries(${Target} PRIVATE doctest_with_main fmt::fmt spot_2_0)
11+
target_link_libraries(${Target} PRIVATE doctest_with_main spot_2_0)
1212
add_test(${Target} ${Target})

0 commit comments

Comments
 (0)