CDR (Common Data Representation)

The cdr component provides a small, standalone Common Data Representation reader/writer utility aimed at standards-oriented protocols such as DDS/RTPS.

This initial slice focuses on the pieces needed to start building interoperable payloads without forcing applications to adopt DDS or RTPS as a whole:

  • CDR / PL_CDR encapsulation identifiers

  • endian-aware primitive serialization helpers

  • CDR alignment and padding handling

  • string helpers using the standard CDR length-prefix + null terminator layout

  • body helpers for CDR fields embedded inside larger protocol elements

  • fixed-array helpers and zero-copy payload/span views

  • primitive sequence helpers

  • standalone usage outside RTPS

Current scope:

  • useful as a reusable building block for future DDS/RTPS payload work

  • suitable for direct use in other protocols that want CDR-style payloads

  • not yet a full XTypes / XCDR2 implementation

API Reference

Header File

Classes

class CdrWriter

Small helper for building CDR/XCDR1-style byte streams.

CDR Example

  espp::CdrWriter writer({
      .encapsulation = espp::CdrEncapsulation::CDR_LE,
      .include_encapsulation = true,
  });
  writer.write<uint32_t>(42);
  writer.write<float>(3.25f);
  writer.write_string("hello cdr");
  writer.write_sequence<uint16_t>(input_values);

  auto payload = writer.take_buffer();
  logger.info("Serialized {} bytes of CDR data", payload.size());

  auto inline_writer = espp::CdrWriter::make_body_writer(espp::CdrEncapsulation::CDR_LE);
  inline_writer.write_array(input_magic);
  inline_writer.write_string("embedded field");
  auto inline_payload =
      espp::CdrWriter::encapsulate(inline_writer.payload(), espp::CdrEncapsulation::PL_CDR_LE);

  espp::CdrReader reader(payload);
  espp::CdrReader inline_reader(inline_payload);
  uint32_t decoded_count = 0;
  float decoded_scale = 0.0f;
  std::string decoded_text;
  std::vector<uint16_t> decoded_values;
  std::array<uint8_t, 4> decoded_magic{};
  std::string decoded_inline_text;

  bool ok = reader.read<uint32_t>(decoded_count) && reader.read<float>(decoded_scale) &&
            reader.read_string(decoded_text) && reader.read_sequence<uint16_t>(decoded_values);
  bool inline_ok = inline_reader.encapsulation() == espp::CdrEncapsulation::PL_CDR_LE &&
                   inline_reader.read_array(decoded_magic) &&
                   inline_reader.read_string(decoded_inline_text);

Public Functions

inline CdrWriter()

Construct a writer using the default little-endian encapsulated configuration.

inline explicit CdrWriter(const Config &config)

Construct a writer using an explicit configuration.

Parameters:

config – Writer configuration controlling encapsulation and endianness behavior.

inline void reset()

Clear the current buffer and reinitialize the encapsulation header if configured.

inline CdrEncapsulation encapsulation() const

Get the configured encapsulation kind for this writer.

Returns:

The encapsulation kind associated with this writer.

inline bool uses_little_endian() const

Determine whether values are encoded in little-endian order.

Returns:

True for little-endian encapsulations, false for big-endian ones.

inline size_t size() const

Get the total number of bytes currently written.

Returns:

The size of the backing byte buffer, including any encapsulation header.

inline const std::vector<uint8_t> &buffer() const

Access the full serialized buffer built so far.

Returns:

A const reference to the complete buffer, including any encapsulation header.

inline std::span<const uint8_t> payload() const

Access only the payload portion of the buffer.

Returns:

A view over the serialized bytes after any encapsulation header.

inline std::vector<uint8_t> take_buffer()

Move the complete serialized buffer out of the writer.

Returns:

The current buffer contents, including any encapsulation header.

inline bool align(size_t alignment)

Pad the buffer with zeros until it satisfies the requested alignment.

Parameters:

alignment – Required alignment in bytes. Values less than or equal to 1 are ignored.

Returns:

Always returns true. This matches the reader API even though writer-side alignment cannot currently fail.

template<typename T>
inline bool write(T value)

Append a primitive scalar using CDR alignment and endianness rules.

Template Parameters:

T – Primitive integral or floating-point type to encode.

Parameters:

value – Value to append to the serialized buffer.

Returns:

True after the value has been encoded and appended.

inline bool write_bool(bool value)

Append a boolean value using the standard CDR 1-byte representation.

Parameters:

value – Boolean value to encode.

Returns:

True after the value has been appended.

inline bool write_string(std::string_view text)

Append a CDR string.

Parameters:

text – UTF-8 text to encode. A terminating null byte is written automatically.

Returns:

True after the string length, contents, terminator, and alignment padding are written.

inline bool write_bytes(std::span<const uint8_t> bytes, size_t alignment = 1)

Append raw bytes with optional alignment.

Parameters:
  • bytes – Bytes to copy into the serialized buffer.

  • alignment – Alignment in bytes to satisfy before appending the data.

Returns:

True after the bytes have been appended.

template<typename T, size_t N>
inline bool write_array(const std::array<T, N> &values)

Append a fixed-size array of primitive values.

Template Parameters:
  • T – Primitive integral or floating-point element type.

  • N – Number of elements in the array.

Parameters:

values – Array to encode element-by-element.

Returns:

True after all elements have been encoded.

template<typename T>
inline bool write_sequence(std::span<const T> values)

Append a variable-length CDR sequence of primitive values.

Template Parameters:

T – Primitive integral or floating-point element type.

Parameters:

values – Sequence elements to encode.

Returns:

True after the sequence length and all elements have been encoded.

Public Static Functions

static inline Config body_config(CdrEncapsulation encapsulation = CdrEncapsulation::CDR_LE)

Create a configuration for writing a CDR body without an encapsulation header.

Parameters:

encapsulation – Endianness/encapsulation rules to use for the body payload.

Returns:

A configuration with encapsulation emission disabled.

static inline CdrWriter make_body_writer(CdrEncapsulation encapsulation = CdrEncapsulation::CDR_LE)

Create a writer configured for a headerless/body-only CDR payload.

Note

CDR alignment is measured from the start of the buffer. Because a body-only writer has no 4-byte encapsulation header, 8-byte-aligned members (e.g. int64/double) land at different offsets than in an encapsulated writer. A body produced here and later wrapped with encapsulate() is therefore not byte-compatible with a directly-encapsulated buffer when it contains 8-byte-aligned types. Current RTPS usage only emits <= 4-byte-aligned types.

Parameters:

encapsulation – Endianness/encapsulation rules to use for the body payload.

Returns:

A ready-to-use writer with no encapsulation header in its output.

static inline std::vector<uint8_t> encapsulate(std::span<const uint8_t> payload, CdrEncapsulation encapsulation = CdrEncapsulation::CDR_LE)

Wrap an existing payload with a CDR encapsulation header.

Parameters:
  • payload – Raw bytes to append after the generated encapsulation header.

  • encapsulation – Encapsulation header to prepend.

Returns:

A new byte buffer containing the encapsulation header followed by the payload.

struct Config

Configuration for a CDR writer instance.

Public Members

CdrEncapsulation encapsulation = {CdrEncapsulation::CDR_LE}

Encapsulation kind to emit when writing.

bool include_encapsulation{true}

If true, prepend the 4-byte encapsulation header to the buffer.

class CdrReader

Small helper for parsing CDR/XCDR1-style byte streams.

Public Functions

inline explicit CdrReader(std::span<const uint8_t> data)

Construct a reader that expects a standard encapsulated CDR payload.

Parameters:

data – Serialized bytes to parse.

inline CdrReader(std::span<const uint8_t> data, const Config &config)

Construct a reader with an explicit configuration.

Parameters:
  • data – Serialized bytes to parse.

  • config – Reader configuration controlling encapsulation handling.

inline void reset(std::span<const uint8_t> data)

Reset the reader to the beginning of a new serialized buffer.

Parameters:

data – Serialized bytes to parse.

inline bool valid() const

Check whether the reader is still in a valid state.

Returns:

True if parsing can continue, false if a prior operation failed.

inline CdrEncapsulation encapsulation() const

Get the active encapsulation for the current buffer.

Returns:

The parsed or assumed encapsulation value.

inline bool uses_little_endian() const

Determine whether values are decoded as little-endian.

Returns:

True for little-endian encapsulations, false for big-endian ones.

inline std::span<const uint8_t> payload() const

Access only the payload bytes after any encapsulation header.

Returns:

A view over the unread buffer excluding the encapsulation header.

inline size_t remaining() const

Get the number of unread bytes remaining.

Returns:

Remaining unread byte count, or 0 if the offset is beyond the buffer.

inline std::span<const uint8_t> remaining_view() const

Access a view of the unread bytes without copying.

Returns:

A span over the unread tail of the buffer, or an empty span if the reader is invalid.

inline bool skip(size_t length)

Advance the read cursor by a fixed number of bytes.

Parameters:

length – Number of bytes to skip.

Returns:

True if the bytes were skipped, false if the reader became invalid.

inline bool align(size_t alignment)

Advance the read cursor to satisfy an alignment requirement.

Parameters:

alignment – Required alignment in bytes. Values less than or equal to 1 are ignored.

Returns:

True if the padding bytes were skipped successfully, false if the reader became invalid.

template<typename T>
inline bool read(T &value)

Read a primitive scalar using CDR alignment and endianness rules.

Template Parameters:

T – Primitive integral or floating-point type to decode.

Parameters:

value – Output variable that receives the decoded value on success.

Returns:

True if a complete value was decoded, false otherwise.

inline bool read_bool(bool &value)

Read a boolean value encoded with the CDR 1-byte representation.

Parameters:

value – Output variable that receives the decoded boolean on success.

Returns:

True if the boolean was read successfully, false otherwise.

inline bool read_string(std::string &text)

Read a CDR string.

Parameters:

text – Output string receiving the decoded text without the trailing null terminator.

Returns:

True if the string was decoded successfully, false otherwise.

inline std::span<const uint8_t> read_span(size_t length, size_t alignment = 1)

Read a fixed number of bytes as a zero-copy span.

Parameters:
  • length – Number of bytes to expose.

  • alignment – Alignment in bytes to satisfy before reading.

Returns:

A span over the requested bytes, or an empty span if the read failed.

inline bool read_bytes(std::span<uint8_t> bytes, size_t alignment = 1)

Read bytes into a caller-provided mutable span.

Parameters:
  • bytes – Destination span that receives the copied bytes.

  • alignment – Alignment in bytes to satisfy before reading.

Returns:

True if all requested bytes were read successfully, false otherwise.

inline bool read_bytes(std::vector<uint8_t> &bytes, size_t length, size_t alignment = 1)

Read bytes into a vector.

Parameters:
  • bytes – Output vector replaced with the decoded bytes on success.

  • length – Number of bytes to read.

  • alignment – Alignment in bytes to satisfy before reading.

Returns:

True if the requested bytes were read successfully, false otherwise.

template<typename T, size_t N>
inline bool read_array(std::array<T, N> &values)

Read a fixed-size array of primitive values.

Template Parameters:
  • T – Primitive integral or floating-point element type.

  • N – Number of elements in the array.

Parameters:

values – Output array receiving the decoded elements.

Returns:

True if all array elements were read successfully, false otherwise.

template<typename T>
inline bool read_sequence(std::vector<T> &values)

Read a variable-length CDR sequence of primitive values.

Template Parameters:

T – Primitive integral or floating-point element type.

Parameters:

values – Output vector replaced with the decoded sequence elements on success.

Returns:

True if the sequence length and all elements were decoded successfully, false otherwise.

Public Static Functions

static inline Config body_config(CdrEncapsulation encapsulation = CdrEncapsulation::CDR_LE)

Create a configuration for reading a headerless/body-only CDR payload.

Parameters:

encapsulation – Encapsulation/endian rules to assume for the payload body.

Returns:

A configuration with encapsulation consumption disabled.

static inline CdrReader make_body_reader(std::span<const uint8_t> data, CdrEncapsulation encapsulation = CdrEncapsulation::CDR_LE)

Create a reader for a headerless/body-only CDR payload.

Parameters:
  • data – Serialized payload bytes to read.

  • encapsulation – Encapsulation/endian rules to assume for the payload body.

Returns:

A reader initialized for body-only parsing.

struct Config

Configuration for a CDR reader instance.

Public Members

bool expect_encapsulation{true}

If true, consume and validate a 4-byte encapsulation header on reset.

CdrEncapsulation default_encapsulation = {CdrEncapsulation::CDR_LE}

Encapsulation to assume when no header is expected.