diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2c55fde4..c27a592d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -250,13 +250,6 @@ FetchContent_Declare(
GIT_TAG v2.0.1 # latest tag as of 2023-12-18
)
-FetchContent_Declare(
- yaml-cpp
- GIT_REPOSITORY https://github.com/jbeder/yaml-cpp.git
- GIT_TAG 0.8.0
- PATCH_COMMAND git apply ${CMAKE_CURRENT_SOURCE_DIR}/patches/yaml-cpp/0001-Avoid-static-reference-to-temporary.patch
- UPDATE_DISCONNECTED 1)
-
FetchContent_Declare(
vir-simd
GIT_REPOSITORY https://github.com/mattkretz/vir-simd.git
@@ -271,7 +264,6 @@ FetchContent_MakeAvailable(
fmt
pmt
ut
- yaml-cpp
vir-simd
cpp-httplib)
diff --git a/blocks/basic/CMakeLists.txt b/blocks/basic/CMakeLists.txt
index a6e37553..6480533a 100644
--- a/blocks/basic/CMakeLists.txt
+++ b/blocks/basic/CMakeLists.txt
@@ -1,7 +1,23 @@
-add_library(gr-basic INTERFACE)
+add_library(
+ gr-basic
+ INTERFACE
+ include/gnuradio-4.0/basic/clock_source.hpp
+ include/gnuradio-4.0/basic/common_blocks.hpp
+ include/gnuradio-4.0/basic/ConverterBlocks.hpp
+ include/gnuradio-4.0/basic/DataSink.hpp
+ include/gnuradio-4.0/basic/function_generator.hpp
+ include/gnuradio-4.0/basic/FunctionGenerator.hpp
+ include/gnuradio-4.0/basic/PythonBlock.hpp
+ include/gnuradio-4.0/basic/PythonInterpreter.hpp
+ include/gnuradio-4.0/basic/Selector.hpp
+ include/gnuradio-4.0/basic/SignalGenerator.hpp
+ include/gnuradio-4.0/basic/StreamToDataSet.hpp
+ include/gnuradio-4.0/basic/SyncBlock.hpp
+ include/gnuradio-4.0/basic/Trigger.hpp)
target_link_libraries(gr-basic INTERFACE gnuradio-core gnuradio-algorithm)
-target_include_directories(gr-basic INTERFACE $ $)
+target_include_directories(gr-basic INTERFACE $
+ $)
-if (ENABLE_TESTING)
- add_subdirectory(test)
-endif ()
+if(ENABLE_TESTING)
+ add_subdirectory(test)
+endif()
diff --git a/blocks/basic/include/gnuradio-4.0/basic/common_blocks.hpp b/blocks/basic/include/gnuradio-4.0/basic/common_blocks.hpp
index c600cc07..195198ef 100644
--- a/blocks/basic/include/gnuradio-4.0/basic/common_blocks.hpp
+++ b/blocks/basic/include/gnuradio-4.0/basic/common_blocks.hpp
@@ -39,7 +39,7 @@ class builtin_multiply : public gr::Block> {
template
class builtin_counter : public gr::Block> {
public:
- static std::size_t s_event_count;
+ static gr::Size_t s_event_count;
gr::PortIn in;
gr::PortOut out;
@@ -53,7 +53,7 @@ class builtin_counter : public gr::Block> {
};
template
-std::size_t builtin_counter::s_event_count = 0;
+gr::Size_t builtin_counter::s_event_count = 0;
template
struct MultiAdder : public gr::Block> {
diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt
index 12a750e2..1e1e06c8 100644
--- a/core/CMakeLists.txt
+++ b/core/CMakeLists.txt
@@ -1,20 +1,64 @@
-add_library(gnuradio-core INTERFACE)
-target_include_directories(gnuradio-core INTERFACE $ $ $ $)
-target_link_libraries(gnuradio-core INTERFACE gnuradio-options gnuradio-meta magic_enum pmtv vir yaml-cpp::yaml-cpp)
+add_library(
+ gnuradio-core
+ INTERFACE
+ include/gnuradio-4.0/Settings.hpp
+ include/gnuradio-4.0/annotated.hpp
+ include/gnuradio-4.0/AtomicBitset.hpp
+ include/gnuradio-4.0/Block.hpp
+ include/gnuradio-4.0/BlockModel.hpp
+ include/gnuradio-4.0/BlockRegistry.hpp
+ include/gnuradio-4.0/BlockTraits.hpp
+ include/gnuradio-4.0/Buffer.hpp
+ include/gnuradio-4.0/BufferSkeleton.hpp
+ include/gnuradio-4.0/CircularBuffer.hpp
+ include/gnuradio-4.0/ClaimStrategy.hpp
+ include/gnuradio-4.0/DataSet.hpp
+ include/gnuradio-4.0/Graph_yaml_importer.hpp
+ include/gnuradio-4.0/Graph.hpp
+ include/gnuradio-4.0/HistoryBuffer.hpp
+ include/gnuradio-4.0/LifeCycle.hpp
+ include/gnuradio-4.0/Message.hpp
+ include/gnuradio-4.0/plugin.hpp
+ include/gnuradio-4.0/PluginLoader.hpp
+ include/gnuradio-4.0/Port.hpp
+ include/gnuradio-4.0/PortTraits.hpp
+ include/gnuradio-4.0/Profiler.hpp
+ include/gnuradio-4.0/reader_writer_lock.hpp
+ include/gnuradio-4.0/Scheduler.hpp
+ include/gnuradio-4.0/Sequence.hpp
+ include/gnuradio-4.0/Settings.hpp
+ include/gnuradio-4.0/Tag.hpp
+ include/gnuradio-4.0/TriggerMatcher.hpp
+ include/gnuradio-4.0/WaitStrategy.hpp
+ include/gnuradio-4.0/YamlPmt.hpp)
+target_include_directories(
+ gnuradio-core
+ INTERFACE $
+ $
+ $
+ $)
+target_link_libraries(
+ gnuradio-core
+ INTERFACE gnuradio-options
+ gnuradio-meta
+ magic_enum
+ pmtv
+ vir)
# configure a header file to pass the CMake settings to the source code
-configure_file("${PROJECT_SOURCE_DIR}/cmake/config.hpp.in" "${CMAKE_CURRENT_BINARY_DIR}/include/gnuradio-4.0/config.hpp" @ONLY)
-# TODO: install configure file... but not really meaningful for header only library, since compile flags are defined by the user...
+configure_file("${PROJECT_SOURCE_DIR}/cmake/config.hpp.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/include/gnuradio-4.0/config.hpp" @ONLY)
+# TODO: install configure file... but not really meaningful for header only library, since compile flags are defined by
+# the user...
install(
- TARGETS gnuradio-core
- EXPORT graphTargets
- PUBLIC_HEADER DESTINATION include/
-)
+ TARGETS gnuradio-core
+ EXPORT graphTargets
+ PUBLIC_HEADER DESTINATION include/)
add_subdirectory(src)
-if (ENABLE_TESTING)
- add_subdirectory(test)
- add_subdirectory(benchmarks)
-endif ()
+if(ENABLE_TESTING)
+ add_subdirectory(test)
+ add_subdirectory(benchmarks)
+endif()
diff --git a/core/include/gnuradio-4.0/Graph_yaml_importer.hpp b/core/include/gnuradio-4.0/Graph_yaml_importer.hpp
index c0ae8fb5..6ac02041 100644
--- a/core/include/gnuradio-4.0/Graph_yaml_importer.hpp
+++ b/core/include/gnuradio-4.0/Graph_yaml_importer.hpp
@@ -3,53 +3,59 @@
#include
-#ifdef __GNUC__
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wold-style-cast"
-#pragma GCC diagnostic ignored "-Wshadow"
-#endif
-#include
-#ifdef __GNUC__
-#pragma GCC diagnostic pop
-#endif
+#include
#include "Graph.hpp"
#include "PluginLoader.hpp"
-#include "YamlUtils.hpp"
namespace gr {
-inline gr::Graph loadGrc(PluginLoader& loader, const std::string& yamlSrc) {
+inline gr::Graph loadGrc(PluginLoader& loader, std::string_view yamlSrc) {
Graph testGraph;
std::map createdBlocks;
- YAML::Node tree = YAML::Load(yamlSrc);
- auto blocks = tree["blocks"];
- for (const auto& grcBlock : blocks) {
- auto name = grcBlock["name"].as();
- auto id = grcBlock["id"].as();
+ const auto yaml = pmtv::yaml::deserialize(yamlSrc);
+ if (!yaml) {
+ throw gr::exception(fmt::format("Could not parse yaml: {}:{}\n{}", yaml.error().message, yaml.error().line, yamlSrc));
+ }
+
+ auto blks = std::get>(yaml.value().at("blocks"));
+ for (const auto& blk : blks) {
+ auto grcBlock = std::get(blk);
+
+ const auto name = std::get(grcBlock["name"]);
+ const auto id = std::get(grcBlock["id"]);
+
+ std::string type = "double";
/// TODO: when using saveGrc template_args is not saved, this has to be implemented
- auto templateArgs = grcBlock["template_args"];
+ if (auto it = grcBlock.find("template_args"); it != grcBlock.end()) {
+ type = std::get(it->second);
+ }
- auto currentBlock = loader.instantiate(id, templateArgs.IsDefined() ? templateArgs.as() : "double");
+ auto currentBlock = loader.instantiate(id, type);
if (!currentBlock) {
throw fmt::format("Unable to create block of type '{}'", id);
}
currentBlock->setName(name);
- property_map newProperties;
-
- auto parameters = grcBlock["parameters"];
- currentBlock->settings().loadParametersFromYAML(parameters);
- auto parametersCtx = grcBlock["ctx_parameters"];
- if (parametersCtx.IsDefined()) {
- for (const auto& ctxPar : parametersCtx) {
- auto ctxName = ctxPar["context"].as();
- auto ctxTime = ctxPar["time"].as(); // in ns
- auto ctxParameters = ctxPar["parameters"];
-
- currentBlock->settings().loadParametersFromYAML(ctxParameters, SettingsCtx{ctxTime, ctxName});
+
+ const auto parametersPmt = grcBlock["parameters"];
+ if (const auto parameters = std::get_if(¶metersPmt)) {
+ currentBlock->settings().loadParametersFromPropertyMap(*parameters);
+ } else {
+ currentBlock->settings().loadParametersFromPropertyMap({});
+ }
+
+ if (auto it = grcBlock.find("ctx_parameters"); it != grcBlock.end()) {
+ auto parametersCtx = std::get>(it->second);
+ for (const auto& ctxPmt : parametersCtx) {
+ auto ctxPar = std::get(ctxPmt);
+ const auto ctxName = std::get(ctxPar["context"]);
+ const auto ctxTime = std::get(ctxPar["time"]); // in ns
+ const auto ctxParameters = std::get(ctxPar["parameters"]);
+
+ currentBlock->settings().loadParametersFromPropertyMap(ctxParameters, SettingsCtx{ctxTime, ctxName});
}
}
if (const auto failed = currentBlock->settings().activateContext(); failed == std::nullopt) {
@@ -58,14 +64,16 @@ inline gr::Graph loadGrc(PluginLoader& loader, const std::string& yamlSrc) {
createdBlocks[name] = &testGraph.addBlock(std::move(currentBlock));
} // for blocks
- for (const auto& connection : tree["connections"]) {
+ auto connections = std::get>(yaml.value().at("connections"));
+ for (const auto& conn : connections) {
+ auto connection = std::get>(conn);
if (connection.size() != 4) {
throw fmt::format("Unable to parse connection ({} instead of 4 elements)", connection.size());
}
auto parseBlockPort = [&](const auto& blockField, const auto& portField) {
- auto blockName = blockField.template as();
- auto node = createdBlocks.find(blockName);
+ const auto blockName = std::get(blockField);
+ auto node = createdBlocks.find(blockName);
if (node == createdBlocks.end()) {
throw fmt::format("Unknown node '{}'", blockName);
}
@@ -75,138 +83,131 @@ inline gr::Graph loadGrc(PluginLoader& loader, const std::string& yamlSrc) {
PortDefinition port_definition;
};
- if (portField.IsSequence()) {
- if (portField.size() != 2) {
- throw fmt::format("Port definition has invalid length ({} instead of 2)", portField.size());
+ if (const auto portFields = std::get_if>(&portField)) {
+ if (portFields->size() != 2) {
+ throw fmt::format("Port definition has invalid length ({} instead of 2)", portFields->size());
}
- const auto indexStr = portField[0].template as();
- const auto subIndexStr = portField[1].template as();
- return result{node, {detail::parseIndex(indexStr), detail::parseIndex(subIndexStr)}};
+ const auto index = std::get(portFields->at(0));
+ const auto subIndex = std::get(portFields->at(1));
+ return result{node, {static_cast(index), static_cast(subIndex)}};
+
} else {
- const auto indexStr = portField.template as();
- return result{node, {detail::parseIndex(indexStr)}};
+ const auto index = std::get(portField);
+ return result{node, {static_cast(index)}};
}
};
- if (connection.size() == 4) {
- auto src = parseBlockPort(connection[0], connection[1]);
- auto dst = parseBlockPort(connection[2], connection[3]);
- testGraph.connect(*src.block_it->second, src.port_definition, *dst.block_it->second, dst.port_definition);
- } else {
- }
+ auto src = parseBlockPort(connection[0], connection[1]);
+ auto dst = parseBlockPort(connection[2], connection[3]);
+ testGraph.connect(*src.block_it->second, src.port_definition, *dst.block_it->second, dst.port_definition);
} // for connections
return testGraph;
}
inline std::string saveGrc(const gr::Graph& testGraph) {
- YAML::Emitter out;
- {
- detail::YamlMap root(out);
-
- root.writeFn("blocks", [&]() {
- detail::YamlSeq nodes(out);
-
- auto writeBlock = [&](const auto& node) {
- detail::YamlMap map(out);
- map.write("name", std::string(node.name()));
-
- const auto& fullTypeName = node.typeName();
- std::string typeName(fullTypeName.cbegin(), std::find(fullTypeName.cbegin(), fullTypeName.cend(), '<'));
- map.write("id", std::move(typeName));
-
- const auto& stored = node.settings().getStoredAll();
- // Helper function to write parameters
- auto writeParameters = [&](const property_map& settingsMap, const property_map& metaInformation = {}) {
- detail::YamlMap parameters(out);
- auto writeMap = [&](const auto& localMap) {
- for (const auto& [settingsKey, settingsValue] : localMap) {
- std::visit([&](const T& value) { parameters.write(settingsKey, value); }, settingsValue);
- }
- };
- writeMap(settingsMap);
- if (!metaInformation.empty()) {
- writeMap(metaInformation);
- }
- };
-
- if (stored.contains("")) {
- const auto& ctxParameters = stored.at("");
- const auto& settingsMap = ctxParameters.back().second; // write only the last parameters
- if (!node.metaInformation().empty() || !settingsMap.empty()) {
- map.writeFn("parameters", [&]() { writeParameters(settingsMap, node.metaInformation()); });
- }
- }
- // write context parameters
- map.writeFn("ctx_parameters", [&]() {
- detail::YamlSeq ctxParamsSeq(out);
+ pmtv::map_t yaml;
- for (const auto& [ctx, ctxParameters] : stored) {
- if (ctx == "") {
- continue;
- }
+ std::vector blocks;
+ testGraph.forEachBlock([&](const auto& node) {
+ pmtv::map_t map;
+ map["name"] = std::string(node.name());
- for (const auto& [ctxTime, settingsMap] : ctxParameters) {
- detail::YamlMap ctxParamMap(out);
-
- // Convert ctxTime.context to a string, regardless of its actual type
- std::string contextStr = std::visit(
- [](const auto& arg) -> std::string {
- using T = std::decay_t;
- if constexpr (std::is_same_v) {
- return arg;
- } else if constexpr (std::is_arithmetic_v) {
- return std::to_string(arg);
- }
- return "";
- },
- ctxTime.context);
-
- ctxParamMap.write("context", contextStr);
- ctxParamMap.write("time", ctxTime.time);
- ctxParamMap.writeFn("parameters", [&]() { writeParameters(settingsMap); });
- }
- }
- });
- };
+ const auto& fullTypeName = node.typeName();
+ std::string typeName(fullTypeName.cbegin(), std::find(fullTypeName.cbegin(), fullTypeName.cend(), '<'));
+ map.emplace("id", std::move(typeName));
- testGraph.forEachBlock(writeBlock);
- });
-
- root.writeFn("connections", [&]() {
- detail::YamlSeq nodes(out);
-
- auto writePortDefinition = [&](const auto& definition) { //
- std::visit(meta::overloaded( //
- [&](const PortDefinition::IndexBased& _definition) {
- if (_definition.subIndex != meta::invalid_index) {
- detail::YamlSeq seqPort(out);
- out << _definition.topLevel;
- out << _definition.subIndex;
- } else {
- out << _definition.topLevel;
- }
- }, //
- [&](const PortDefinition::StringBased& _definition) { out << _definition.name; }),
- definition.definition);
+ // Helper function to write parameters
+ auto writeParameters = [&](const property_map& settingsMap, const property_map& metaInformation = {}) {
+ pmtv::map_t parameters;
+ auto writeMap = [&](const auto& localMap) {
+ for (const auto& [settingsKey, settingsValue] : localMap) {
+ std::visit([&](const T& value) { parameters[settingsKey] = value; }, settingsValue);
+ }
};
+ writeMap(settingsMap);
+ if (!metaInformation.empty()) {
+ writeMap(metaInformation);
+ }
+ return parameters;
+ };
- auto writeEdge = [&](const auto& edge) {
- out << YAML::Flow;
- detail::YamlSeq seq(out);
- out << edge.sourceBlock().name().data();
- writePortDefinition(edge.sourcePortDefinition());
+ const auto& stored = node.settings().getStoredAll();
+ if (stored.contains("")) {
+ const auto& ctxParameters = stored.at("");
+ const auto& settingsMap = ctxParameters.back().second; // write only the last parameters
+ if (!node.metaInformation().empty() || !settingsMap.empty()) {
+ map["parameters"] = writeParameters(settingsMap, node.metaInformation());
+ }
+ }
- out << edge.destinationBlock().name().data();
- writePortDefinition(edge.destinationPortDefinition());
- };
+ std::vector ctxParamsSeq;
+ for (const auto& [ctx, ctxParameters] : stored) {
+ if (ctx == "") {
+ continue;
+ }
- testGraph.forEachEdge(writeEdge);
- });
- }
+ for (const auto& [ctxTime, settingsMap] : ctxParameters) {
+ pmtv::map_t ctxParam;
+
+ // Convert ctxTime.context to a string, regardless of its actual type
+ std::string contextStr = std::visit(
+ [](const auto& arg) -> std::string {
+ using T = std::decay_t;
+ if constexpr (std::is_same_v) {
+ return arg;
+ } else if constexpr (std::is_arithmetic_v) {
+ return std::to_string(arg);
+ }
+ return "";
+ },
+ ctxTime.context);
+
+ ctxParam["context"] = contextStr;
+ ctxParam["time"] = ctxTime.time;
+ ctxParam["parameters"] = writeParameters(settingsMap);
+ ctxParamsSeq.emplace_back(std::move(ctxParam));
+ }
+ }
+ map["ctx_parameters"] = ctxParamsSeq;
+
+ blocks.emplace_back(std::move(map));
+ });
+ yaml["blocks"] = blocks;
+
+ std::vector connections;
+ testGraph.forEachEdge([&](const auto& edge) {
+ std::vector seq;
+
+ auto writePortDefinition = [&](const auto& definition) { //
+ std::visit(meta::overloaded( //
+ [&](const PortDefinition::IndexBased& _definition) {
+ if (_definition.subIndex != meta::invalid_index) {
+ std::vector seqPort;
+
+ seqPort.push_back(std::int64_t(_definition.topLevel));
+ seqPort.push_back(std::int64_t(_definition.subIndex));
+ seq.push_back(seqPort);
+ } else {
+ seq.push_back(std::int64_t(_definition.topLevel));
+ }
+ }, //
+ [&](const PortDefinition::StringBased& _definition) { seq.push_back(_definition.name); }),
+ definition.definition);
+ };
+
+ seq.push_back(edge.sourceBlock().name().data());
+ writePortDefinition(edge.sourcePortDefinition());
+
+ seq.push_back(edge.destinationBlock().name().data());
+ writePortDefinition(edge.destinationPortDefinition());
+
+ connections.emplace_back(seq);
+ });
+ yaml["connections"] = connections;
- return out.c_str();
+ return pmtv::yaml::serialize(yaml);
}
} // namespace gr
diff --git a/core/include/gnuradio-4.0/Settings.hpp b/core/include/gnuradio-4.0/Settings.hpp
index 8cfc8d4d..c1e8ec0d 100644
--- a/core/include/gnuradio-4.0/Settings.hpp
+++ b/core/include/gnuradio-4.0/Settings.hpp
@@ -31,8 +31,6 @@
#define NO_INLINE
#endif
-#include "YamlUtils.hpp"
-
namespace gr {
namespace settings {
@@ -276,10 +274,10 @@ struct SettingsBase {
virtual void updateActiveParameters() noexcept = 0;
/**
- * @brief Loads parameters from a YAML node into a property map by matching YAML keys to TBlock's writable data members.
+ * @brief Loads parameters from a property_map by matching pmt keys to TBlock's writable data members.
* Handles type conversion and special cases, such as std::vector.
*/
- virtual void loadParametersFromYAML(YAML::Node& parameters, SettingsCtx ctx = {}) = 0;
+ virtual void loadParametersFromPropertyMap(const property_map& parameters, SettingsCtx ctx = {}) = 0;
}; // struct SettingsBase
@@ -847,52 +845,34 @@ class CtxSettings : public SettingsBase {
}
}
- NO_INLINE void loadParametersFromYAML(YAML::Node& parameters, SettingsCtx ctx = {}) override {
- // Once PMT supports loading and saving YAML files, this function should accept a property_map, similar to how Settings::set() operates.
+ NO_INLINE void loadParametersFromPropertyMap(const property_map& parameters, SettingsCtx ctx = {}) override {
property_map newProperties;
- if (parameters && parameters.IsMap()) {
- for (const auto& kv : parameters) {
- const auto& key = kv.first.template as();
- const YAML::Node& grcValue = kv.second;
- bool isSet = false;
- refl::for_each_data_member_index([&](auto kIdx) {
- using MemberType = refl::data_member_type;
- using Type = unwrap_if_wrapped_t>;
- if constexpr (settings::isWritableMember()) {
- const auto fieldName = refl::data_member_name.view();
- if (!isSet && fieldName == key) {
-#if (defined __clang__) && (!defined __EMSCRIPTEN__)
- if constexpr (std::is_same_v>) {
- // gcc-stdlibc++/clang-libc++ have different implementations for std::vector, see https://en.cppreference.com/w/cpp/container/vector_bool for details
- const auto& intVector = grcValue.template as>(); // need intermediary vector
- std::vector boolVector(intVector.size());
- std::ranges::transform(intVector, boolVector.begin(), [](int intValue) { return static_cast(intValue); });
- newProperties[key] = boolVector;
- isSet = true;
- return;
- }
-#endif
- if constexpr (!std::is_same_v) {
- newProperties[key] = grcValue.template as();
- isSet = true;
- }
+ for (const auto& [key, value] : parameters) {
+ bool isSet = false;
+ refl::for_each_data_member_index([&](auto kIdx) {
+ using MemberType = refl::data_member_type;
+ using Type = unwrap_if_wrapped_t>;
+ if constexpr (settings::isWritableMember()) {
+ const auto fieldName = refl::data_member_name.view();
+ if (!isSet && fieldName == key) {
+ if constexpr (!std::is_same_v) {
+ newProperties[key] = value;
+ isSet = true;
}
}
- });
+ }
+ });
- if (!isSet) {
- if (ctx.context == "") { // store meta_information only for default
- if (grcValue.IsScalar()) {
- _block->meta_information[key] = grcValue.template as();
- }
- }
+ if (!isSet) {
+ if (ctx.context == "") { // store meta_information only for default
+ _block->meta_information[key] = value;
}
}
}
if (const property_map failed = set(newProperties, ctx); !failed.empty()) {
- throw gr::exception(fmt::format("settings from YAML could not be loaded: {}", failed));
+ throw gr::exception(fmt::format("settings from property_map could not be loaded: {}", failed));
}
}
diff --git a/core/include/gnuradio-4.0/YamlPmt.hpp b/core/include/gnuradio-4.0/YamlPmt.hpp
index 5131e9df..0a92861e 100644
--- a/core/include/gnuradio-4.0/YamlPmt.hpp
+++ b/core/include/gnuradio-4.0/YamlPmt.hpp
@@ -1,3 +1,5 @@
+#pragma once
+
#include
#include
#include
@@ -214,6 +216,8 @@ struct ParseContext {
std::size_t lineIdx = 0;
std::size_t columnIdx = 0;
+ std::string_view currentLine() { return lineIdx < lines.size() ? lines[lineIdx] : std::string_view{}; }
+
bool documentStart() const { return lineIdx == 0 && columnIdx == 0; }
bool startsWith(std::string_view sv) const {
diff --git a/core/include/gnuradio-4.0/YamlUtils.hpp b/core/include/gnuradio-4.0/YamlUtils.hpp
deleted file mode 100644
index e70259e6..00000000
--- a/core/include/gnuradio-4.0/YamlUtils.hpp
+++ /dev/null
@@ -1,128 +0,0 @@
-#ifndef GNURADIO_YAML_UTILS_H
-#define GNURADIO_YAML_UTILS_H
-
-#include
-
-#ifdef __GNUC__
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wold-style-cast"
-#pragma GCC diagnostic ignored "-Wshadow"
-#endif
-#include
-#ifdef __GNUC__
-#pragma GCC diagnostic pop
-#endif
-
-namespace YAML {
-// YAML custom converter for complex numbers
-template
-requires std::same_as || std::same_as
-struct convert> {
- static Node encode(const std::complex& rhs) {
- Node node;
- node.push_back(rhs.real());
- node.push_back(rhs.imag());
- return node;
- }
-
- static bool decode(const Node& node, std::complex& rhs) {
- if (!node.IsSequence() || node.size() != 2) {
- return false;
- }
- rhs = std::complex(node[0].as(), node[1].as());
- return true;
- }
-};
-} // namespace YAML
-
-namespace gr {
-
-namespace detail {
-
-template
-inline auto toYamlString(const T& value) {
- if constexpr (std::is_same_v>) {
- return value;
- } else if constexpr (std::is_same_v>) {
- return value ? "true" : "false";
- } else if constexpr (requires { std::to_string(value); }) {
- return std::to_string(value);
- } else {
- return "";
- }
-}
-
-struct YamlSeq {
- YAML::Emitter& out;
-
- YamlSeq(YAML::Emitter& out_) : out(out_) { out << YAML::BeginSeq; }
-
- ~YamlSeq() { out << YAML::EndSeq; }
-
- template
- requires std::is_invocable_v
- void writeFn(const char* /*key*/, F&& fun) {
- fun();
- }
-};
-
-struct YamlMap {
- YAML::Emitter& out;
-
- YamlMap(YAML::Emitter& out_) : out(out_) { out << YAML::BeginMap; }
-
- ~YamlMap() { out << YAML::EndMap; }
-
- template
- void write(const std::string_view& key, const std::vector& value) {
- out << YAML::Key << key.data();
- YamlSeq seq(out);
- for (const auto& elem : value) {
- if constexpr (std::same_as> || std::same_as>) {
- writeComplexValue(out, elem);
- } else {
- out << YAML::Value << toYamlString(elem);
- }
- }
- }
-
- template
- void write(const std::string_view& key, const T& value) {
- out << YAML::Key << key.data();
- if constexpr (std::same_as> || std::same_as>) {
- writeComplexValue(out, value);
- } else {
- out << YAML::Value << toYamlString(value);
- }
- }
-
- template
- void writeFn(const std::string_view& key, F&& fun) {
- out << YAML::Key << key.data();
- out << YAML::Value;
- fun();
- }
-
-private:
- template
- requires std::same_as> || std::same_as>
- void writeComplexValue(YAML::Emitter& outEmitter, const T& value) {
- YamlSeq seq(outEmitter);
- outEmitter << YAML::Value << toYamlString(value.real());
- outEmitter << YAML::Value << toYamlString(value.imag());
- }
-};
-
-inline std::size_t parseIndex(std::string_view str) {
- std::size_t index{};
- auto [_, src_ec] = std::from_chars(str.begin(), str.end(), index);
- if (src_ec != std::errc()) {
- throw fmt::format("Unable to parse the index");
- }
- return index;
-}
-
-} // namespace detail
-} // namespace gr
-
-#endif // include guard
diff --git a/core/src/CMakeLists.txt b/core/src/CMakeLists.txt
index efba2755..c02bd14f 100644
--- a/core/src/CMakeLists.txt
+++ b/core/src/CMakeLists.txt
@@ -1,26 +1,37 @@
-if (ENABLE_TESTS)
- add_subdirectory(test)
- add_subdirectory(benchmarks)
-endif ()
+if(ENABLE_TESTS)
+ add_subdirectory(test)
+ add_subdirectory(benchmarks)
+endif()
-if (NOT EMSCRIPTEN)
- set(CMAKE_BUILD_WITH_INSTALL_RPATH ON)
- add_library(gnuradio-plugin SHARED plugin.cpp)
- target_include_directories(gnuradio-plugin PUBLIC $ $)
- target_link_libraries(gnuradio-plugin PUBLIC gnuradio-core gnuradio-options pmtv fmt yaml-cpp::yaml-cpp)
+if(NOT EMSCRIPTEN)
+ set(CMAKE_BUILD_WITH_INSTALL_RPATH ON)
+ add_library(gnuradio-plugin SHARED plugin.cpp)
+ target_include_directories(
+ gnuradio-plugin PUBLIC $
+ $)
+ target_link_libraries(
+ gnuradio-plugin
+ PUBLIC gnuradio-core
+ gnuradio-options
+ pmtv
+ fmt)
- include(GenerateExportHeader)
- generate_export_header(gnuradio-plugin)
- # TODO install exported headers
+ include(GenerateExportHeader)
+ generate_export_header(gnuradio-plugin)
+ # TODO install exported headers
- install(
- TARGETS gnuradio-plugin
- EXPORT graphPluginTargets
- PUBLIC_HEADER DESTINATION include/
- )
-endif ()
+ install(
+ TARGETS gnuradio-plugin
+ EXPORT graphPluginTargets
+ PUBLIC_HEADER DESTINATION include/)
+endif()
-if (ENABLE_EXAMPLES)
- add_executable(main main.cpp)
- target_link_libraries(main PUBLIC gnuradio-options gnuradio-core fmt::fmt magic_enum)
-endif ()
+if(ENABLE_EXAMPLES)
+ add_executable(main main.cpp)
+ target_link_libraries(
+ main
+ PUBLIC gnuradio-options
+ gnuradio-core
+ fmt::fmt
+ magic_enum)
+endif()
diff --git a/core/test/CMakeLists.txt b/core/test/CMakeLists.txt
index de72e8a1..049d67d0 100644
--- a/core/test/CMakeLists.txt
+++ b/core/test/CMakeLists.txt
@@ -10,7 +10,6 @@ function(setup_test_no_asan TEST_NAME)
PRIVATE gnuradio-options
gnuradio-core
fmt
- yaml-cpp::yaml-cpp
fftw
gr-basic
gr-fileio
diff --git a/core/test/qa_Settings.cpp b/core/test/qa_Settings.cpp
index 82dbf929..21e4216a 100644
--- a/core/test/qa_Settings.cpp
+++ b/core/test/qa_Settings.cpp
@@ -1002,8 +1002,8 @@ const boost::ut::suite TransactionTests = [] {
- name: source
id: gr::setting_test::Source
parameters:
- n_samples_max: 100
- sample_rate: 123456
+ n_samples_max: !!uint32 100
+ sample_rate: !!float32 123456
- name: test_block
id: gr::setting_test::TestBlock
- name: sink
diff --git a/core/test/qa_grc.cpp b/core/test/qa_grc.cpp
index deef62aa..23f71927 100644
--- a/core/test/qa_grc.cpp
+++ b/core/test/qa_grc.cpp
@@ -8,6 +8,7 @@
#include
#include
+#include
#include
#include
@@ -142,12 +143,21 @@ constexpr std::string_view testGrc = R"(
- [ArraySource, [1, 1], ArraySink, [0, 1]]
)";
+std::string ymlDecodeEncode(std::string_view yml) {
+ const auto yaml = pmtv::yaml::deserialize(yml);
+ if (!yaml) {
+ throw gr::exception(fmt::format("Could not parse yaml: {}:{} content:\n{}", yaml.error().message, yaml.error().line, yml));
+ }
+
+ return pmtv::yaml::serialize(yaml.value());
+}
+
const boost::ut::suite GrcTests = [] {
"Basic graph loading and storing"_test = [] {
try {
using namespace gr;
const auto context = getContext();
- const auto graphSrc = std::string(testGrc);
+ const auto graphSrc = ymlDecodeEncode(testGrc);
auto graph = gr::loadGrc(context->loader, graphSrc);
auto graphSavedSrc = gr::saveGrc(graph);
expect(checkAndPrintMissingLines(graphSrc, graphSavedSrc));
@@ -167,7 +177,7 @@ const boost::ut::suite GrcTests = [] {
- name: main_source
id: good::fixed_source
parameters:
- event_count: 100
+ event_count: !!uint32 100
unknown_property: 42
- name: multiplier
id: good::multiply
@@ -176,7 +186,7 @@ const boost::ut::suite GrcTests = [] {
- name: sink
id: good::cout_sink
parameters:
- total_count: 100
+ total_count: !!uint32 100
unknown_property: 42
connections:
- [main_source, 0, multiplier, 0]
@@ -185,7 +195,7 @@ const boost::ut::suite GrcTests = [] {
)";
const auto context = getContext();
- const auto graphSrc = std::string(pluginsTestGrc);
+ const auto graphSrc = ymlDecodeEncode(pluginsTestGrc);
auto graph = gr::loadGrc(context->loader, graphSrc);
auto graphSavedSrc = gr::saveGrc(graph);
@@ -204,11 +214,10 @@ const boost::ut::suite GrcTests = [] {
// Test if we get the same graph when saving it and loading the saved
// data into another graph
using namespace gr;
- const auto graphSrc = std::string(testGrc);
try {
const auto context = getContext();
- auto graph1 = gr::loadGrc(context->loader, graphSrc);
+ auto graph1 = gr::loadGrc(context->loader, testGrc);
auto graphSavedSrc = gr::saveGrc(graph1);
auto graph2 = gr::loadGrc(context->loader, graphSavedSrc);
expect(eq(collectBlocks(graph1), collectBlocks(graph2)));
diff --git a/patches/yaml-cpp/0001-Avoid-static-reference-to-temporary.patch b/patches/yaml-cpp/0001-Avoid-static-reference-to-temporary.patch
deleted file mode 100644
index 9af3ba3a..00000000
--- a/patches/yaml-cpp/0001-Avoid-static-reference-to-temporary.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From 20544e648743bc783802ffc05676825b47fc1100 Mon Sep 17 00:00:00 2001
-From: Frank Osterfeld
-Date: Thu, 11 Apr 2024 23:16:44 +0200
-Subject: [PATCH] Avoid static reference to temporary
-
-These caused issues when used in a wasm project.
----
- src/emitterutils.cpp | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/src/emitterutils.cpp b/src/emitterutils.cpp
-index 6cdf6de..fc41011 100644
---- a/src/emitterutils.cpp
-+++ b/src/emitterutils.cpp
-@@ -173,11 +173,11 @@ bool IsValidPlainScalar(const std::string& str, FlowType::value flowType,
- }
-
- // then check until something is disallowed
-- static const RegEx& disallowed_flow =
-+ static const RegEx disallowed_flow =
- Exp::EndScalarInFlow() | (Exp::BlankOrBreak() + Exp::Comment()) |
- Exp::NotPrintable() | Exp::Utf8_ByteOrderMark() | Exp::Break() |
- Exp::Tab() | Exp::Ampersand();
-- static const RegEx& disallowed_block =
-+ static const RegEx disallowed_block =
- Exp::EndScalar() | (Exp::BlankOrBreak() + Exp::Comment()) |
- Exp::NotPrintable() | Exp::Utf8_ByteOrderMark() | Exp::Break() |
- Exp::Tab() | Exp::Ampersand();
---
-2.34.1
-