1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
5 * Copyright (C) 2011 Data Differential, http://datadifferential.com/
6 * Copyright (C) 2006-2009 Brian Aker All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following disclaimer
17 * in the documentation and/or other materials provided with the
20 * * The names of its contributors may not be used to endorse or
21 * promote products derived from this software without specific prior
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 #include "libmemcached/common.h"
41 inline static memcached_return_t
_string_check(memcached_string_st
*string
, size_t need
)
43 if (need
&& need
> (size_t)(string
->current_size
- (size_t)(string
->end
- string
->string
)))
45 size_t current_offset
= (size_t) (string
->end
- string
->string
);
47 /* This is the block multiplier. To keep it larger and surive division errors we must round it up */
48 size_t adjust
= (need
- (size_t)(string
->current_size
- (size_t)(string
->end
- string
->string
))) / MEMCACHED_BLOCK_SIZE
;
51 size_t new_size
= sizeof(char) * (size_t)((adjust
* MEMCACHED_BLOCK_SIZE
) + string
->current_size
);
52 /* Test for overflow */
55 char error_message
[1024];
56 int error_message_length
= snprintf(error_message
, sizeof(error_message
),"Needed %ld, got %ld", (long)need
, (long)new_size
);
57 return memcached_set_error(*string
->root
, MEMCACHED_MEMORY_ALLOCATION_FAILURE
, MEMCACHED_AT
, error_message
, error_message_length
);
60 char *new_value
= libmemcached_xrealloc(string
->root
, string
->string
, new_size
, char);
62 if (new_value
== NULL
)
64 return memcached_set_error(*string
->root
, MEMCACHED_MEMORY_ALLOCATION_FAILURE
, MEMCACHED_AT
);
67 string
->string
= new_value
;
68 string
->end
= string
->string
+ current_offset
;
70 string
->current_size
+= (MEMCACHED_BLOCK_SIZE
* adjust
);
73 return MEMCACHED_SUCCESS
;
76 static inline void _init_string(memcached_string_st
*self
)
78 self
->current_size
= 0;
79 self
->end
= self
->string
= NULL
;
82 memcached_string_st
*memcached_string_create(Memcached
*memc
, memcached_string_st
*self
, size_t initial_size
)
84 WATCHPOINT_ASSERT(memc
);
86 /* Saving malloc calls :) */
89 WATCHPOINT_ASSERT(self
->options
.is_initialized
== false);
91 memcached_set_allocated(self
, false);
95 self
= libmemcached_xmalloc(memc
, memcached_string_st
);
102 memcached_set_allocated(self
, true);
108 if (memcached_failed(_string_check(self
, initial_size
)))
110 if (memcached_is_allocated(self
))
112 libmemcached_free(memc
, self
);
118 memcached_set_initialized(self
, true);
120 WATCHPOINT_ASSERT(self
->string
== self
->end
);
125 static memcached_return_t
memcached_string_append_null(memcached_string_st
& string
)
127 if (memcached_failed(_string_check(&string
, 1)))
129 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
134 return MEMCACHED_SUCCESS
;
137 static memcached_return_t
memcached_string_append_null(memcached_string_st
*string
)
139 if (memcached_failed(_string_check(string
, 1)))
141 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
146 return MEMCACHED_SUCCESS
;
149 memcached_return_t
memcached_string_append_character(memcached_string_st
*string
,
152 if (memcached_failed(_string_check(string
, 1)))
154 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
157 *string
->end
= character
;
160 return MEMCACHED_SUCCESS
;
163 memcached_return_t
memcached_string_append(memcached_string_st
*string
,
164 const char *value
, size_t length
)
166 if (memcached_failed(_string_check(string
, length
)))
168 return MEMCACHED_MEMORY_ALLOCATION_FAILURE
;
171 WATCHPOINT_ASSERT(length
<= string
->current_size
);
172 WATCHPOINT_ASSERT(string
->string
);
173 WATCHPOINT_ASSERT(string
->end
>= string
->string
);
175 memcpy(string
->end
, value
, length
);
176 string
->end
+= length
;
178 return MEMCACHED_SUCCESS
;
181 char *memcached_string_c_copy(memcached_string_st
*string
)
183 if (memcached_string_length(string
) == 0)
188 char *c_ptr
= static_cast<char *>(libmemcached_malloc(string
->root
, (memcached_string_length(string
)+1) * sizeof(char)));
195 memcpy(c_ptr
, memcached_string_value(string
), memcached_string_length(string
));
196 c_ptr
[memcached_string_length(string
)]= 0;
201 bool memcached_string_set(memcached_string_st
& string
, const char* value
, size_t length
)
203 memcached_string_reset(&string
);
204 if (memcached_success(memcached_string_append(&string
, value
, length
)))
206 memcached_string_append_null(string
);
213 void memcached_string_reset(memcached_string_st
*string
)
215 string
->end
= string
->string
;
218 void memcached_string_free(memcached_string_st
& ptr
)
220 memcached_string_free(&ptr
);
223 void memcached_string_free(memcached_string_st
*ptr
)
232 libmemcached_free(ptr
->root
, ptr
->string
);
235 if (memcached_is_allocated(ptr
))
237 libmemcached_free(ptr
->root
, ptr
);
241 ptr
->options
.is_initialized
= false;
245 memcached_return_t
memcached_string_check(memcached_string_st
*string
, size_t need
)
247 return _string_check(string
, need
);
250 bool memcached_string_resize(memcached_string_st
& string
, const size_t need
)
252 return memcached_success(_string_check(&string
, need
));
255 size_t memcached_string_length(const memcached_string_st
*self
)
257 return size_t(self
->end
-self
->string
);
260 size_t memcached_string_length(const memcached_string_st
& self
)
262 return size_t(self
.end
-self
.string
);
265 size_t memcached_string_size(const memcached_string_st
*self
)
267 return self
->current_size
;
270 const char *memcached_string_value(const memcached_string_st
*self
)
275 const char *memcached_string_value(const memcached_string_st
& self
)
280 char *memcached_string_take_value(memcached_string_st
*self
)
284 assert_msg(self
, "Invalid memcached_string_st");
287 if (memcached_string_length(self
))
289 // If we fail at adding the null, we copy and move on
290 if (memcached_failed(memcached_string_append_null(self
)))
303 char *memcached_string_value_mutable(const memcached_string_st
*self
)
308 char *memcached_string_c_str(memcached_string_st
& self
)
313 void memcached_string_set_length(memcached_string_st
*self
, size_t length
)
315 self
->end
= self
->string
+length
;
318 void memcached_string_set_length(memcached_string_st
& self
, const size_t length
)
320 assert(self
.current_size
>= length
);
321 size_t set_length
= length
;
322 if (self
.current_size
> length
)
324 if (memcached_failed(_string_check(&self
, length
)))
326 set_length
= self
.current_size
;
329 self
.end
= self
.string
+set_length
;