/*
* Copyright (c) 2017-2024 OARC, Inc.
* Copyright (c) 2011-2017, IIS - The Internet Foundation in Sweden
* All rights reserved.
*
* This file is part of PacketQ.
*
* PacketQ is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PacketQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PacketQ. If not, see .
*/
#ifndef __packetq_refcountstring_h
#define __packetq_refcountstring_h
#include
#include
// A simple reference-counted C string, intended to be used through a pointer
// as RefCountString * with manual management of the reference count in order
// to stay a POD (for use in unions). For the same reason, constructors are
// static. The wrapper RefCountStringHandle can be used where automatic
// reference handling is possible.
struct RefCountString {
// data
int count;
char data[];
// implementation
void inc_refcount()
{
count += 1;
}
void dec_refcount()
{
count -= 1;
if (count == 0)
std::free(this);
}
static RefCountString* allocate(int data_length)
{
void* chunk = std::calloc(1, sizeof(RefCountString) + data_length);
if (!chunk)
throw std::bad_alloc();
RefCountString* new_str = static_cast(chunk);
new_str->count = 1;
return new_str;
}
static RefCountString* construct(const char* c_string)
{
std::size_t length = std::strlen(c_string);
RefCountString* str = RefCountString::allocate(length + 1);
std::memcpy(str->data, c_string, length + 1);
return str;
}
static RefCountString* construct(const char* data, int from, int to)
{
int length = to - from;
if (length < 0)
length = 0;
RefCountString* str = RefCountString::allocate(length + 1);
std::memcpy(str->data, data + from, length);
str->data[length - 1 + 1] = '\0';
return str;
}
};
class RefCountStringHandle {
private:
RefCountStringHandle& operator=(const RefCountStringHandle& other);
RefCountStringHandle(RefCountStringHandle&& other) noexcept;
RefCountStringHandle const& operator=(RefCountStringHandle&& other);
public:
RefCountStringHandle()
{
value = 0;
}
RefCountStringHandle(RefCountString* str)
{
value = str;
}
~RefCountStringHandle()
{
if (value)
value->dec_refcount();
}
RefCountString* operator*()
{
return value;
}
void set(RefCountString* str)
{
if (value != str) {
if (value)
value->dec_refcount();
value = str;
}
}
RefCountString* value;
};
#endif // __packetq_refcountstring_h