Files
qt6-migration-pipeline/external/rti_connext_dds-7.7.0/include/rti/apputils/StringBuffer.hpp
T
torstenandCopilot 342ffd3e5c Update submodule to latest BUILD_RTI fixes
- HandlerMinelayerData: BUILD_RTI Guards für RTI-Abhängigkeiten
- svcTabCommon: Export-Header-Fix via Fallback-Target
- TrainingAreaBase: Stub-Header für BUILD_RTI=OFF
- ddsfts: Include-Pfad und Dependency-Fixes
- BUILD_RTI=OFF Compilation vollständig unterstützt

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Entire-Checkpoint: 01M0JNZA586SACX1PRZ2DJAE5S
2026-08-21 19:30:20 +02:00

296 lines
9.0 KiB
C++

/*
* (c) Copyright, Real-Time Innovations, 2022.
* All rights reserved.
*
* No duplications, whole or partial, manual or electronic, may be made
* without express written permission. Any such copies, or
* revisions thereof, must display this notice unaltered.
* This code contains trade secrets of Real-Time Innovations, Inc.
*/
#ifndef STRING_BUFFER_HPP
#define STRING_BUFFER_HPP
#include "rti/apputils/ServiceException.hpp"
namespace rti { namespace apputils {
// Default value of a StringBuffer
constexpr size_t STRING_BUFFER_LENGTH = 1000;
/**
* A GenericStringBuffer is a smart buffer that allocates an INITIAL_CAPACITY
* in the stack and allocates more capacity in the heap if needed. The template
* parameter INITIAL_CAPACITY determines the capacity that is allocated in the
* stack. In case there is a resize which involves heap allocation, the
* destructor of the GenericStringBuffer class frees the memory.
*/
template <std::size_t INITIAL_CAPACITY>
class GenericStringBuffer {
public:
/**
* This constructor creates a new empty GenericStringBuffer with
* INITIAL_CAPACITY.
*/
GenericStringBuffer() : capacity_(INITIAL_CAPACITY), c_str_ptr_(nullptr)
{
RTIOsapiMemory_zero(c_str_, capacity_);
c_str_ptr_ = c_str_;
}
/**
* This constructor creates a new GenericStringBuffer ensuring the size
* of the input parameter. It allocates memory in the heap if necessary.
* @param size Size to ensure.
*/
GenericStringBuffer(const size_t size)
: capacity_(INITIAL_CAPACITY), c_str_ptr_(nullptr)
{
RTIOsapiMemory_zero(c_str_, capacity_);
c_str_ptr_ = c_str_;
ensure_capacity(size);
}
/**
* This constructor creates a new GenericStringBuffer object containing
* an input string. It ensures whatever capacity is necessary for the input
* string.
* @param str std::string that initializes the GenericStringBuffer.
*/
GenericStringBuffer(const std::string& str)
: capacity_(INITIAL_CAPACITY), c_str_ptr_(nullptr)
{
RTIOsapiMemory_zero(c_str_, capacity_);
c_str_ptr_ = c_str_;
ensure_capacity(str.length() + 1);
RTIOsapiUtility_unusedReturnValue(
RTIOsapiUtility_strcpy(c_str_ptr_, str.length(), str.c_str()),
char *);
}
/**
* Copy constructor.
* @param other String buffer that we want to copy
*/
GenericStringBuffer(const GenericStringBuffer& other)
: capacity_(INITIAL_CAPACITY), c_str_ptr_(nullptr)
{
RTIOsapiMemory_zero(c_str_, capacity_);
c_str_ptr_ = c_str_;
ensure_capacity(other.length() + 1);
RTIOsapiUtility_unusedReturnValue(
RTIOsapiUtility_strcpy(
c_str_ptr_,
other.length(),
other.c_str()),
char *);
}
/**
* Move constructor.
* @param other String buffer that we want to move
*/
GenericStringBuffer(GenericStringBuffer&& other)
: capacity_(INITIAL_CAPACITY), c_str_ptr_(nullptr)
{
*this = std::move(other);
}
/**
* Destructor of the GenericStringBuffer. It frees whatever memory may
* have been allocated by the ensure_capacity method().
*/
~GenericStringBuffer()
{
if (capacity_ > INITIAL_CAPACITY) {
DDS_String_free(c_str_ptr_);
c_str_ptr_ = nullptr;
}
}
/**
* Copy-assignment operator
* @param other The buffer we want to copy.
* @return Object in which we have copied.
*/
GenericStringBuffer& operator=(const GenericStringBuffer& other)
{
if (this != &other) {
ensure_capacity(other.length() + 1);
RTIOsapiUtility_unusedReturnValue(
RTIOsapiUtility_strcpy(
c_str_ptr_,
other.length(),
other.c_str()),
char *);
}
return *this;
}
/**
* Move-assignment operator
* @param other The buffer we want to move.
* @return Object in which we have moved.
*/
GenericStringBuffer& operator=(GenericStringBuffer&& other)
{
if (this != &other) {
if (other.capacity_ <= INITIAL_CAPACITY) {
RTIOsapiMemory_move(c_str_, other.c_str_, INITIAL_CAPACITY);
c_str_ptr_ = c_str_;
} else {
capacity_ = other.capacity_;
c_str_ptr_ = other.c_str_ptr_;
other.capacity_ = INITIAL_CAPACITY;
other.c_str_ptr_ = nullptr;
}
}
return *this;
}
/**
* Returns the number of bytes that can be written in the internal char *
* buffer
* @return Capacity of the internal char * buffer.
*/
size_t capacity() const
{
return capacity_;
}
/**
* Returns the length of the internal char * buffer. That is the strlen
* of whatever is in there.
* @return Size of the string stored in the internal char * buffer.
*/
size_t length() const
{
return strlen(c_str_ptr_);
}
/**
* Returns a const pointer to the internal char * buffer.
* @return Const pointer to the internal char * buffer.
*/
const char *c_str() const
{
return c_str_ptr_;
}
/**
* Returns a pointer to the internal char * buffer
* @return Pointer to the internal char * buffer.
*/
char *c_str_ptr()
{
return c_str_ptr_;
}
/**
* This method ensures a capacity by either asserting that the
* GenericStringBuffer has enough space to allocate a string, or
* reallocating some space in the heap. If that is the case more space is
* allocated in the heap via DDS_String_alloc().
* @param capacity Size that needs to be ensured.
*/
void ensure_capacity(const size_t capacity)
{
if (capacity > capacity_) {
// We need to free the string if it was already allocated, this
// happens when _capacity > INITIAL_CAPACITY
if (capacity_ > INITIAL_CAPACITY) {
DDS_String_free(c_str_ptr_);
}
// DDS_String_alloc adds one to the input parameter. We could
// spare a byte, but we want to be precise.
c_str_ptr_ = DDS_String_alloc(capacity - 1);
if (c_str_ptr_ == nullptr) {
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_ANY_FAILURE_s,
"Error allocating string.");
}
RTIOsapiMemory_zero(c_str_ptr_, capacity_);
capacity_ = capacity;
}
}
private:
size_t capacity_;
char *c_str_ptr_;
char c_str_[INITIAL_CAPACITY];
};
/**
* A StringBuffer is a GenericStringBuffer with an initial STRING_BUFFER_LENGTH.
*/
typedef GenericStringBuffer<STRING_BUFFER_LENGTH> StringBuffer;
/**
* This method saves a "freeform string" into a StringBuffer object.
* @param [in,out] string_buffer StringBuffer in which the input string will
* be saved. Note that if there's not enough capacity, the method will
* automatically allocate more space for the string.
* @param format Format of the string to be saved.
* @param ... Parameters to the formatted string.
*/
inline void StringBuffer_save_freeform(
StringBuffer& string_buffer,
const char *format,
...)
{
char *c_str_ptr = string_buffer.c_str_ptr();
size_t capacity = string_buffer.capacity();
va_list args, args_aux;
RTIXMLSaveContext save_ctxt = RTIXMLSaveContext_INITIALIZER;
RTIXMLSaveContext_initialize(&save_ctxt);
save_ctxt.sout = c_str_ptr;
if (!RTIOsapiUtility_sizeToUInt32(save_ctxt.ssize, capacity)) {
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_ANY_FAILURE_s,
"Error allocating string.");
}
// Wrap RTIXMLSaveContext_freeform_w_argsI call with va_start and va_end
// of the va_list that we need to pass in.
va_start(args, format);
va_start(args_aux, format);
RTIXMLSaveContext_freeform_v(&save_ctxt, format, args, args_aux);
va_end(args);
va_end(args_aux);
if (save_ctxt.outputStringLength + 1 > capacity) {
capacity = save_ctxt.outputStringLength + 1;
string_buffer.ensure_capacity(capacity);
RTIXMLSaveContext_initialize(&save_ctxt);
save_ctxt.sout = string_buffer.c_str_ptr();
if (!RTIOsapiUtility_sizeToUInt32(save_ctxt.ssize, capacity)) {
RTI_THROW_SERVICE_EXCEPTION(
&RTI_LOG_ANY_FAILURE_s,
"Error allocating string.");
}
// Wrap RTIXMLSaveContext_freeform_w_argsI call with va_start and
// va_end of the va_list that we need to pass in.
va_start(args, format);
va_start(args_aux, format);
RTIXMLSaveContext_freeform_v(&save_ctxt, format, args, args_aux);
va_end(args);
va_end(args_aux);
}
}
}} // namespace rti::apputils
#endif // STRING_BUFFER_HPP