1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef __packetq_refcountstring_h
#define __packetq_refcountstring_h
#include <cstdlib>
#include <cstring>
// 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<RefCountString*>(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
|