- 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
296 lines
9.0 KiB
C++
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
|