2 +--------------------------------------------------------------------+
3 | libmemcached-awesome - C/C++ Client Library for memcached |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted under the terms of the BSD license. |
7 | You should have received a copy of the license in a bundled file |
8 | named LICENSE; in case you did not receive a copy you can review |
9 | the terms online at: https://opensource.org/licenses/BSD-3-Clause |
10 +--------------------------------------------------------------------+
11 | Copyright (c) 2006-2014 Brian Aker https://datadifferential.com/ |
12 | Copyright (c) 2020-2021 Michael Wallner https://awesome.co/ |
13 +--------------------------------------------------------------------+
16 #include "libmemcached/common.h"
18 inline static memcached_return_t
_string_check(memcached_string_st
*string
, size_t need
) {
19 if (need
&& need
> (size_t)(string
->current_size
- (size_t)(string
->end
- string
->string
))) {
20 size_t current_offset
= (size_t)(string
->end
- string
->string
);
22 /* This is the block multiplier. To keep it larger and surive division errors we must round it
24 size_t adjust
= (need
- (size_t)(string
->current_size
- (size_t)(string
->end
- string
->string
)))
25 / MEMCACHED_BLOCK_SIZE
;
29 sizeof(char) * (size_t)((adjust
* MEMCACHED_BLOCK_SIZE
) + string
->current_size
);
30 /* Test for overflow */
31 if (new_size
< need
) {
32 char error_message
[1024];
33 int error_message_length
= snprintf(error_message
, sizeof(error_message
),
34 "Needed %ld, got %ld", (long) need
, (long) new_size
);
35 return memcached_set_error(*string
->root
, MEMCACHED_MEMORY_ALLOCATION_FAILURE
, MEMCACHED_AT
,
36 error_message
, error_message_length
);
39 char *new_value
= libmemcached_xrealloc(string
->root
, string
->string
, new_size
, char);
41 if (new_value
== NULL
) {
42 return memcached_set_error(*string
->root
, MEMCACHED_MEMORY_ALLOCATION_FAILURE
, MEMCACHED_AT
);
45 string
->string
= new_value
;
46 string
->end
= string
->string
+ current_offset
;
48 string
->current_size
+= (MEMCACHED_BLOCK_SIZE
* adjust
);
51 return MEMCACHED_SUCCESS
;
54 static inline void _init_string(memcached_string_st
*self
) {
55 self
->current_size
= 0;
56 self
->end
= self
->string
= NULL
;
59 memcached_string_st
*memcached_string_create(Memcached
*memc
, memcached_string_st
*self
,
60 size_t initial_size
) {
61 WATCHPOINT_ASSERT(memc
);
63 /* Saving malloc calls :) */
65 WATCHPOINT_ASSERT(self
->options
.is_initialized
== false);
67 memcached_set_allocated(self
, false);
69 self
= libmemcached_xmalloc(memc
, memcached_string_st
);
75 memcached_set_allocated(self
, true);
81 if (memcached_failed(_string_check(self
, initial_size
))) {
82 if (memcached_is_allocated(self
)) {
83 libmemcached_free(memc
, self
);
89 memcached_set_initialized(self
, true);
91 WATCHPOINT_ASSERT(self
->string
== self
->end
);
96 static memcached_return_t
memcached_string_append_null(memcached_string_st
&string
) {
97 if (memcached_failed(_string_check(&string
, 1))) {
98 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
103 return MEMCACHED_SUCCESS
;
106 static memcached_return_t
memcached_string_append_null(memcached_string_st
*string
) {
107 if (memcached_failed(_string_check(string
, 1))) {
108 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
113 return MEMCACHED_SUCCESS
;
116 memcached_return_t
memcached_string_append_character(memcached_string_st
*string
, char character
) {
117 if (memcached_failed(_string_check(string
, 1))) {
118 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
121 *string
->end
= character
;
124 return MEMCACHED_SUCCESS
;
127 memcached_return_t
memcached_string_append(memcached_string_st
*string
, const char *value
,
129 if (memcached_failed(_string_check(string
, length
))) {
130 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
133 WATCHPOINT_ASSERT(length
<= string
->current_size
);
134 WATCHPOINT_ASSERT(string
->string
);
135 WATCHPOINT_ASSERT(string
->end
>= string
->string
);
137 memcpy(string
->end
, value
, length
);
138 string
->end
+= length
;
140 return MEMCACHED_SUCCESS
;
143 char *memcached_string_c_copy(memcached_string_st
*string
) {
144 if (memcached_string_length(string
) == 0) {
148 char *c_ptr
= static_cast<char *>(
149 libmemcached_malloc(string
->root
, (memcached_string_length(string
) + 1) * sizeof(char)));
155 memcpy(c_ptr
, memcached_string_value(string
), memcached_string_length(string
));
156 c_ptr
[memcached_string_length(string
)] = 0;
161 bool memcached_string_set(memcached_string_st
&string
, const char *value
, size_t length
) {
162 memcached_string_reset(&string
);
163 if (memcached_success(memcached_string_append(&string
, value
, length
))) {
164 memcached_string_append_null(string
);
171 void memcached_string_reset(memcached_string_st
*string
) {
172 string
->end
= string
->string
;
175 void memcached_string_free(memcached_string_st
&ptr
) {
176 memcached_string_free(&ptr
);
179 void memcached_string_free(memcached_string_st
*ptr
) {
185 libmemcached_free(ptr
->root
, ptr
->string
);
188 if (memcached_is_allocated(ptr
)) {
189 libmemcached_free(ptr
->root
, ptr
);
191 ptr
->options
.is_initialized
= false;
195 memcached_return_t
memcached_string_check(memcached_string_st
*string
, size_t need
) {
196 return _string_check(string
, need
);
199 bool memcached_string_resize(memcached_string_st
&string
, const size_t need
) {
200 return memcached_success(_string_check(&string
, need
));
203 size_t memcached_string_length(const memcached_string_st
*self
) {
204 return size_t(self
->end
- self
->string
);
207 size_t memcached_string_length(const memcached_string_st
&self
) {
208 return size_t(self
.end
- self
.string
);
211 size_t memcached_string_size(const memcached_string_st
*self
) {
212 return self
->current_size
;
215 const char *memcached_string_value(const memcached_string_st
*self
) {
219 const char *memcached_string_value(const memcached_string_st
&self
) {
223 char *memcached_string_take_value(memcached_string_st
*self
) {
226 assert_msg(self
, "Invalid memcached_string_st");
228 if (memcached_string_length(self
)) {
229 // If we fail at adding the null, we copy and move on
230 if (memcached_failed(memcached_string_append_null(self
))) {
234 value
= self
->string
;
242 char *memcached_string_value_mutable(const memcached_string_st
*self
) {
246 char *memcached_string_c_str(memcached_string_st
&self
) {
250 void memcached_string_set_length(memcached_string_st
*self
, size_t length
) {
251 self
->end
= self
->string
+ length
;
254 void memcached_string_set_length(memcached_string_st
&self
, const size_t length
) {
255 assert(self
.current_size
>= length
);
256 size_t set_length
= length
;
257 if (self
.current_size
> length
) {
258 if (memcached_failed(_string_check(&self
, length
))) {
259 set_length
= self
.current_size
;
262 self
.end
= self
.string
+ set_length
;