00001 /* Part of the culibs project, <http://www.eideticdew.org/culibs/>. 00002 * Copyright (C) 2004--2010 Petter Urkedal <paurkedal@eideticdew.org> 00003 * 00004 * This program is free software: you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation, either version 3 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00016 */ 00017 00018 #ifndef CU_BUFFER_H 00019 #define CU_BUFFER_H 00020 00021 #include <cu/fwd.h> 00022 #include <cu/ptr.h> 00023 #include <cu/debug.h> 00024 00025 CU_BEGIN_DECLARATIONS 00026 00027 void cuP_buffer_fix_fullcap(cu_buffer_t buf, size_t fullcap); 00028 void cuP_buffer_fix_freecap(cu_buffer_t buf, size_t freecap); 00029 00030 /** \defgroup cu_buffer_h cu/buffer.h: Generic Self-Extending Buffer 00031 ** @{ \ingroup cu_seq_mod 00032 ** 00033 ** \figure \svgimage{buffer.svg,440,120} 00034 ** <p>The structure of a buffer, illustrating the terminology used in 00035 ** the function names.</p> 00036 ** \endfigure 00037 ** 00038 ** This header defines a buffer for use with any data which can be moved 00039 ** around. It has a storage which is dynamically re-allocated as needed. 00040 ** Within the storage is a sub-region with the current content. The content 00041 ** can be resized and moved upwards within the storage by moving its start and 00042 ** end pointers. When the content region reaches the limit of the storage, it 00043 ** will be move to the start of the storage, possibly reallocating a bigger 00044 ** storage region first. To guarantee good time complexity, the storage is 00045 ** extended in geometric progression, and the storage is kept big enough that 00046 ** the content is moved at most once on the average. 00047 **/ 00048 00049 struct cu_buffer 00050 { 00051 void *storage_start; 00052 void *content_start; 00053 void *content_end; 00054 void *storage_end; 00055 }; 00056 00057 /** Returns an empty buffer with initial capacity \a init_cap. */ 00058 cu_buffer_t cu_buffer_new(size_t init_cap); 00059 00060 /** Initialise \a buf to an empty buffer of with initial capacity 00061 ** \a init_cap. */ 00062 void cu_buffer_init(cu_buffer_t buf, size_t init_cap); 00063 00064 /** Set the content of \a buf to the empty sequence aligned to the start of the 00065 ** storage. */ 00066 CU_SINLINE void cu_buffer_clear(cu_buffer_t buf) 00067 { buf->content_start = buf->content_end = buf->storage_start; } 00068 00069 /** Initialise \a buf with the data of \a buf_drop, and invalidate 00070 ** \a buf_drop. */ 00071 void cu_buffer_init_drop(cu_buffer_t buf, cu_buffer_t buf_drop); 00072 00073 /** Swap the states of \a buf0 and \a buf1. */ 00074 void cu_buffer_swap(cu_buffer_t buf0, cu_buffer_t buf1); 00075 00076 /** The start of the current buffer storage. */ 00077 CU_SINLINE void * 00078 cu_buffer_storage_start(cu_buffer_t buf) 00079 { return buf->storage_start; } 00080 00081 /** The end of the current buffer storage. */ 00082 CU_SINLINE void * 00083 cu_buffer_storage_end(cu_buffer_t buf) 00084 { return buf->storage_end; } 00085 00086 /** The number of bytes stored in \a buf. */ 00087 CU_SINLINE size_t 00088 cu_buffer_storage_size(cu_buffer_t buf) 00089 { return cu_ptr_diff(cu_buffer_storage_end(buf), 00090 cu_buffer_storage_start(buf)); } 00091 00092 /** The number of bytes from the start of the buffer contents to the end of the 00093 ** end of the current buffer storage. */ 00094 CU_SINLINE size_t 00095 cu_buffer_fullcap(cu_buffer_t buf) 00096 { return cu_ptr_diff(buf->storage_end, buf->content_start); } 00097 00098 /** Makes sure there is at least \a fullcap bytes allocated after the start of 00099 ** the buffer content. This is done either by moving the content to the start 00100 ** of the buffer or by allocating a bigger chunck of memory. */ 00101 CU_SINLINE void 00102 cu_buffer_extend_fullcap(cu_buffer_t buf, size_t fullcap) 00103 { 00104 if (cu_ptr_add(buf->content_start, fullcap) > buf->storage_end) 00105 cuP_buffer_fix_fullcap(buf, fullcap); 00106 } 00107 00108 /** The number of bytes allocated after the current contents. */ 00109 CU_SINLINE size_t 00110 cu_buffer_freecap(cu_buffer_t buf) 00111 { return cu_ptr_diff(buf->storage_end, buf->content_end); } 00112 00113 /** Makes sure there is at least \a freecap bytes allocated after the end of 00114 ** the buffer content. */ 00115 CU_SINLINE void 00116 cu_buffer_extend_freecap(cu_buffer_t buf, size_t freecap) 00117 { 00118 if (cu_ptr_add(buf->content_end, freecap) > buf->storage_end) 00119 cuP_buffer_fix_freecap(buf, freecap); 00120 } 00121 00122 /** Unconditionally realign the content to the start of the storage. */ 00123 void cu_buffer_force_realign(cu_buffer_t buf); 00124 00125 /** Realign content to the start of storage if the displacement is larger than 00126 ** the content size. */ 00127 void cu_buffer_maybe_realign(cu_buffer_t buf); 00128 00129 /** The address of the start of the content of \a buf. */ 00130 CU_SINLINE void * 00131 cu_buffer_content_start(cu_buffer_t buf) 00132 { return buf->content_start; } 00133 00134 /** The address of the end of the content of \a buf. */ 00135 CU_SINLINE void * 00136 cu_buffer_content_end(cu_buffer_t buf) 00137 { return buf->content_end; } 00138 00139 /** The size in bytes of the buffer contents. */ 00140 CU_SINLINE size_t 00141 cu_buffer_content_size(cu_buffer_t buf) 00142 { return cu_ptr_diff(buf->content_end, buf->content_start); } 00143 00144 /** Sets the start of content pointer. 00145 ** \pre \a start must be within the buffer, and less than the content end. */ 00146 CU_SINLINE void 00147 cu_buffer_set_content_start(cu_buffer_t buf, void *start) 00148 { 00149 cu_debug_assert(buf->storage_start <= start && start <= buf->content_end); 00150 buf->content_start = start; 00151 } 00152 00153 /** Increment the start-of-content pointer by \a incr bytes, which in essence 00154 ** indicates that the corresponding content is consumed, so that the related 00155 ** buffer space can be re-used. 00156 ** \pre \a incr must be less than or equal to the content size. */ 00157 CU_SINLINE void 00158 cu_buffer_incr_content_start(cu_buffer_t buf, size_t incr) 00159 { 00160 buf->content_start = cu_ptr_add(buf->content_start, incr); 00161 cu_debug_assert(buf->content_start <= buf->content_end); 00162 } 00163 00164 /** Sets the end-of-content pointer. 00165 ** \pre \a end must be within the buffer and after the content start. */ 00166 CU_SINLINE void 00167 cu_buffer_set_content_end(cu_buffer_t buf, void *end) 00168 { 00169 cu_debug_assert(buf->content_start <= end && end <= buf->storage_end); 00170 buf->content_end = end; 00171 } 00172 00173 /** Inclement the end-of-content pointer by \a incr bytes, which in essence 00174 ** indicates that the corresponding content is produced. This function 00175 ** extends the buffer capacity if needed. */ 00176 void cu_buffer_incr_content_end(cu_buffer_t buf, size_t incr); 00177 00178 /** Sets the size of the content of \a buf. This function extends the buffer 00179 ** capacity if needed. */ 00180 void cu_buffer_resize_content(cu_buffer_t buf, size_t size); 00181 00182 /** This is a shortcut to increment the end-of-content pointer by \a incr and 00183 ** return it's value befor the increment. It is useful for appending data to 00184 ** the buffer. */ 00185 void *cu_buffer_produce(cu_buffer_t buf, size_t incr); 00186 00187 /** Append the \a size bytes starting at \a data to the content of \a buf. */ 00188 void cu_buffer_write(cu_buffer_t buf, void const *data, size_t size); 00189 00190 #define cu_buffer_put(buf, data_t, data) \ 00191 (*(data_t *)cu_buffer_produce(buf, sizeof(data_t)) = (data)) 00192 00193 /** @} */ 00194 CU_END_DECLARATIONS 00195 00196 #endif