Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/generate ostream operators #472

Merged
2 changes: 1 addition & 1 deletion CMakeLists.txt
Expand Up @@ -189,7 +189,7 @@ if(ENABLE_LEGACY)
set(cyclonedds_cpp_std_to_use 11)
set(DDSCXX_USE_BOOST "1")
find_package(Boost)
include_directories(${Boost_INCLUDE_DIR})
include_directories(SYSTEM ${Boost_INCLUDE_DIR})
endif()

include(CMakePackageConfigHelpers)
Expand Down
2 changes: 2 additions & 0 deletions examples/helloworld/CMakeLists.txt
Expand Up @@ -12,6 +12,8 @@
project(helloworld LANGUAGES C CXX)
cmake_minimum_required(VERSION 3.16)

set(CMAKE_CXX_STANDARD 17)

if(NOT TARGET CycloneDDS-CXX::ddscxx)
find_package(CycloneDDS-CXX REQUIRED)
endif()
Expand Down
2 changes: 1 addition & 1 deletion examples/helloworld/publisher.cpp
Expand Up @@ -54,7 +54,7 @@ int main() {
HelloWorldData::Msg msg(1, "Hello World");

/* Write the message. */
std::cout << "=== [Publisher] Write sample." << std::endl;
std::cout << "=== [Publisher] Write sample: " << msg << std::endl;
writer.write(msg);

/* With a normal configuration (see dds::pub::qos::DataWriterQos
Expand Down
4 changes: 1 addition & 3 deletions examples/helloworld/subscriber.cpp
Expand Up @@ -72,9 +72,7 @@ int main() {
* is set. The other data parts are not.
* Check if this sample has valid data. */
if (info.valid()) {
std::cout << "=== [Subscriber] Message received:" << std::endl;
std::cout << " userID : " << msg.userID() << std::endl;
std::cout << " Message : \"" << msg.message() << "\"" << std::endl;
std::cout << "=== [Subscriber] Message received: " << msg << std::endl;

/* Only 1 message is expected in this example. */
poll = false;
Expand Down
2 changes: 2 additions & 0 deletions examples/roundtrip/CMakeLists.txt
Expand Up @@ -12,6 +12,8 @@
project(throughput LANGUAGES C CXX)
cmake_minimum_required(VERSION 3.16)

set(CMAKE_CXX_STANDARD 17)

if(NOT TARGET CycloneDDS-CXX::ddscxx)
find_package(CycloneDDS-CXX REQUIRED)
endif()
Expand Down
2 changes: 2 additions & 0 deletions examples/throughput/CMakeLists.txt
Expand Up @@ -12,6 +12,8 @@
project(throughput LANGUAGES C CXX)
cmake_minimum_required(VERSION 3.16)

set(CMAKE_CXX_STANDARD 17)

if(NOT TARGET CycloneDDS-CXX::ddscxx)
find_package(CycloneDDS-CXX REQUIRED)
endif()
Expand Down
@@ -0,0 +1,74 @@
// Copyright(c) 2006 to 2020 ZettaScale Technology and others
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License
// v. 1.0 which is available at
// http://www.eclipse.org/org/documents/edl-v10.php.
//
// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause

/**
* @file
*/

#ifndef CYCLONEDDS_UTIL_OSTREAM_OPERATORS_HPP_
#define CYCLONEDDS_UTIL_OSTREAM_OPERATORS_HPP_

#include "dds/features.hpp"

#include <array>
#include <vector>
#if DDSCXX_USE_BOOST
#include <boost/optional.hpp>
#define DDSCXX_STD_IMPL boost
#else
#include <optional>
#define DDSCXX_STD_IMPL std
#endif


namespace std
{

template <typename T, size_t N>
std::ostream& operator<<(std::ostream& os, const std::array<T, N>& rhs)
{
os << "[";
for (std::size_t i = 0; i < N; i++)
{
os << rhs[i];
if (i < N - 1)
{
os << ", ";
}
}
os << "]";
return os;
}

template<typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& rhs)
{
os << "[";
for(size_t i=0; i<rhs.size(); i++)
{
if (i != 0)
{
os << ", ";
}
os << rhs[i];
}
os << "]";
return os;
}

template<typename T>
std::ostream& operator<<(std::ostream& os, const DDSCXX_STD_IMPL::optional<T>& rhs)
{
return rhs ? os << rhs.value() : os;
}

} //namespace std

#endif /* CYCLONEDDS_UTIL_OSTREAM_OPERATORS_HPP_ */
13 changes: 12 additions & 1 deletion src/idlcxx/src/generator.c
Expand Up @@ -861,8 +861,9 @@ generate_includes(const idl_pstate_t *pstate, struct generator *generator)
}

{ int len = 0;
const char *incs[11];
const char *incs[12];
incs[len++] = "<utility>";
incs[len++] = "<ostream>";

if (generator->uses_integers)
incs[len++] = "<cstdint>";
Expand Down Expand Up @@ -898,6 +899,16 @@ generate_includes(const idl_pstate_t *pstate, struct generator *generator)
if (fputs("\n", generator->header.handle) < 0)
return IDL_RETCODE_NO_MEMORY;

if (generator->uses_array || generator->uses_sequence || generator->uses_bounded_sequence || generator->uses_optional)
{
// ostream cpp
// streaming operators for the used std types
const char *fmt;
fmt = "#include <org/eclipse/cyclonedds/util/ostream_operators.hpp>\n\n";
if (fputs(fmt, generator->impl.handle) < 0)
return IDL_RETCODE_NO_MEMORY;
}

return IDL_RETCODE_OK;
}

Expand Down
116 changes: 112 additions & 4 deletions src/idlcxx/src/types.c
Expand Up @@ -129,6 +129,13 @@ emit_parameter(
return IDL_RETCODE_NO_MEMORY;
if (idl_fprintf(gen->header.handle, fmt, sep, type, name, eofmt) < 0)
return IDL_RETCODE_NO_MEMORY;

// ostream - cpp
fmt = " os << \"%1$s%2$s: \" << rhs.%2$s();\n";
sep = is_first(node) ? "" : ", ";
if (idl_fprintf(gen->impl.handle, fmt, sep, name) < 0)
return IDL_RETCODE_NO_MEMORY;

return IDL_RETCODE_OK;
}

Expand Down Expand Up @@ -263,6 +270,13 @@ emit_struct(
return IDL_RETCODE_NO_MEMORY;
}

// ostream - cpp
fmt = "std::ostream& operator<<(std::ostream& os, %s const& rhs)\n{\n"
" (void) rhs;\n"
" os << \"[\";\n";
if (idl_fprintf(gen->impl.handle, fmt, name) < 0)
return IDL_RETCODE_NO_MEMORY;

if (fputs("{\nprivate:\n", gen->header.handle) < 0)
return IDL_RETCODE_NO_MEMORY;

Expand Down Expand Up @@ -326,6 +340,11 @@ emit_struct(
fmt = "%2$s static_cast<const %1$s&>(*this) == static_cast<const %1$s&>(_other)";
if (idl_fprintf(gen->header.handle, fmt, base, _struct->members ? " &&\n " : "") < 0)
return IDL_RETCODE_NO_MEMORY;

// ostream cpp
fmt = " os << \"%2$s%1$s: \" << static_cast<const %1$s&>(rhs);\n";
if (idl_fprintf(gen->impl.handle, fmt, base, _struct->members ? ", " : "") < 0)
return IDL_RETCODE_NO_MEMORY;
}

if (!_struct->members &&
Expand All @@ -345,6 +364,15 @@ emit_struct(
if (fputs("\n};\n\n", gen->header.handle) < 0)
return IDL_RETCODE_NO_MEMORY;

// ostream - hpp
fmt = "std::ostream& operator<<(std::ostream& os, %s const& rhs);\n\n";
if (idl_fprintf(gen->header.handle, fmt, name) < 0)
return IDL_RETCODE_NO_MEMORY;

// ostream - cpp
if (fputs(" os << \"]\";\n return os;\n}\n\n", gen->impl.handle) < 0)
return IDL_RETCODE_NO_MEMORY;

return IDL_RETCODE_OK;
}

Expand All @@ -370,19 +398,43 @@ emit_enum(
if (idl_fprintf(gen->header.handle, "enum class %s\n{\n", name) < 0)
return IDL_RETCODE_NO_MEMORY;

// ostream cpp
fmt = "std::ostream& operator<<(std::ostream& os, %s const& rhs)\n{\n"
" (void) rhs;\n"
" switch (rhs)\n {\n";
if (idl_fprintf(gen->impl.handle, fmt, name) < 0)
return IDL_RETCODE_NO_MEMORY;

const char* struct_name = get_cpp11_name(node);

IDL_FOREACH(enumerator, _enum->enumerators) {
name = get_cpp11_name(enumerator);
value = enumerator->value.value;
fmt = (value == skip) ? "%s%s" : "%s%s = %" PRIu32 "\n";
if (idl_fprintf(gen->header.handle, fmt, sep, name, value) < 0)
return IDL_RETCODE_NO_MEMORY;

// ostream cpp
fmt = " case %2$s::%1$s:\n"
" os << \"%2$s::%1$s\"; break;\n";
if (idl_fprintf(gen->impl.handle, fmt, name, struct_name) < 0)
return IDL_RETCODE_NO_MEMORY;

skip = value + 1;
sep = ",\n ";
}

if (fputs("};\n\n", gen->header.handle) < 0)
return IDL_RETCODE_NO_MEMORY;

// ostream cpp
if (fputs(" default: break;\n }\n return os;\n}\n\n", gen->impl.handle) < 0)
return IDL_RETCODE_NO_MEMORY;

// ostream hpp
if (idl_fprintf(gen->header.handle, "std::ostream& operator<<(std::ostream& os, %s const& rhs);\n\n", struct_name) < 0)
return IDL_RETCODE_NO_MEMORY;

return IDL_VISIT_DONT_RECURSE;
}

Expand Down Expand Up @@ -447,13 +499,22 @@ emit_module(
(void)pstate;
(void)path;

name = get_cpp11_name(node);
if (revisit) {
if (fputs("}\n\n", gen->header.handle) < 0)
if (idl_fprintf(gen->header.handle, "} //namespace %s\n\n", name) < 0)
return IDL_RETCODE_NO_MEMORY;

// ostream cpp
if (idl_fprintf(gen->impl.handle, "} //namespace %s\n\n", name) < 0)
return IDL_RETCODE_NO_MEMORY;
} else {
name = get_cpp11_name(node);
if (idl_fprintf(gen->header.handle, "namespace %s\n{\n", name) < 0)
return IDL_RETCODE_NO_MEMORY;

// ostream cpp
if (idl_fprintf(gen->impl.handle, "namespace %s\n{\n", name) < 0)
return IDL_RETCODE_NO_MEMORY;

return IDL_VISIT_REVISIT;
}

Expand Down Expand Up @@ -570,6 +631,8 @@ emit_case(
return IDL_RETCODE_OK;
}

static bool gen_ostream_case = false;

static idl_retcode_t
emit_case_label(
const idl_pstate_t *pstate,
Expand All @@ -593,9 +656,23 @@ emit_case_label(
{
if (idl_fprintf(gen->header.handle, " default:\n") < 0)
return IDL_RETCODE_NO_MEMORY;
} else if (idl_fprintf(gen->header.handle, " case %s:\n", value) < 0)
return IDL_RETCODE_NO_MEMORY;

// ostream cpp
if (gen_ostream_case) {
if (idl_fprintf(gen->impl.handle, " default:\n") < 0)
return IDL_RETCODE_NO_MEMORY;
}

} else {
if (idl_fprintf(gen->header.handle, " case %s:\n", value) < 0)
return IDL_RETCODE_NO_MEMORY;

// ostream cpp
if (gen_ostream_case) {
if (idl_fprintf(gen->impl.handle, " case %s:\n", value) < 0)
return IDL_RETCODE_NO_MEMORY;
}
}
return IDL_RETCODE_OK;
}

Expand All @@ -621,6 +698,11 @@ emit_case_comparison(
if (idl_fprintf(gen->header.handle, fmt, branch_name) < 0)
return IDL_RETCODE_NO_MEMORY;

// ostream cpp
static const char* fmt2 = " os << \"%1$s: \" << rhs.%1$s(); break;\n";
if (idl_fprintf(gen->impl.handle, fmt2, branch_name) < 0)
return IDL_RETCODE_NO_MEMORY;

return IDL_RETCODE_OK;
}

Expand Down Expand Up @@ -1012,6 +1094,14 @@ emit_union(
if (idl_fprintf(gen->header.handle, fmt, type, value) < 0)
return IDL_RETCODE_NO_MEMORY;

// ostream cpp
fmt = "std::ostream& operator<<(std::ostream& os, %1$s const& rhs)\n"
"{\n"
" (void) rhs;\n"
" switch (rhs._d()) {\n";
if (idl_fprintf(gen->impl.handle, fmt, name) < 0)
return IDL_RETCODE_NO_MEMORY;

visitor.visit = IDL_CASE | IDL_CASE_LABEL;
visitor.accept[IDL_ACCEPT_CASE] = emit_case;
visitor.accept[IDL_ACCEPT_CASE_LABEL] = emit_case_label;
Expand Down Expand Up @@ -1076,17 +1166,25 @@ emit_union(
if (idl_fprintf(gen->header.handle, fmt, name) < 0)
return IDL_RETCODE_NO_MEMORY;

gen_ostream_case = true;
visitor.visit = IDL_CASE | IDL_CASE_LABEL;
visitor.accept[IDL_ACCEPT_CASE] = emit_case_comparison;
visitor.accept[IDL_ACCEPT_CASE_LABEL] = emit_case_label;
if ((ret = idl_visit(pstate, _union->cases, &visitor, user_data)))
return ret;

gen_ostream_case = false;

if (gen_default) {
fmt = " default:\n"
" return true;\n";
if (idl_fprintf(gen->header.handle, fmt, name) < 0)
return IDL_RETCODE_NO_MEMORY;

fmt = " default:\n {\n"
" // Prevent compiler warnings\n }\n";
if (idl_fprintf(gen->impl.handle, fmt, name) < 0)
return IDL_RETCODE_NO_MEMORY;
}

fmt = " }\n"
Expand All @@ -1099,6 +1197,10 @@ emit_union(
if (idl_fprintf(gen->header.handle, fmt, name) < 0)
return IDL_RETCODE_NO_MEMORY;

// ostream cpp
if (idl_fprintf(gen->impl.handle, " }\n return os;\n}\n\n") < 0)
return IDL_RETCODE_NO_MEMORY;


/* implicit default setter */
if (idl_mask(_union->default_case) == IDL_IMPLICIT_DEFAULT_CASE_LABEL) {
Expand All @@ -1116,6 +1218,12 @@ emit_union(
if (fputs("};\n\n", gen->header.handle) < 0)
return IDL_RETCODE_NO_MEMORY;

// ostream hpp
fmt = "std::ostream& operator<<(std::ostream& os, %s const& rhs);\n";
if (idl_fprintf(gen->header.handle, fmt, name) < 0)
return IDL_RETCODE_NO_MEMORY;


return IDL_RETCODE_OK;
}

Expand Down