add ported UCX buffer implementation

Mon, 27 Dec 2021 16:51:10 +0100

author
Mike Becker <universe@uap-core.de>
date
Mon, 27 Dec 2021 16:51:10 +0100
changeset 483
929016224c3c
parent 482
0d998f19d130
child 484
9e6900b1cf9d

add ported UCX buffer implementation

Notes:
* ucx_buffer_extend has been removed
in favor of cxBufferMinimumCapacity
* the buffer struct now has a union for
char* and unsigned char* buffers

src/CMakeLists.txt file | annotate | diff | comparison | revisions
src/buffer.c file | annotate | diff | comparison | revisions
src/cx/buffer.h file | annotate | diff | comparison | revisions
src/cx/common.h file | annotate | diff | comparison | revisions
src/cx/utils.h file | annotate | diff | comparison | revisions
src/utils.c file | annotate | diff | comparison | revisions
     1.1 --- a/src/CMakeLists.txt	Mon Dec 27 14:44:08 2021 +0100
     1.2 +++ b/src/CMakeLists.txt	Mon Dec 27 16:51:10 2021 +0100
     1.3 @@ -1,13 +1,17 @@
     1.4  set(sources
     1.5 +        utils.c
     1.6          allocator.c
     1.7          linked_list.c
     1.8          tree.c
     1.9 +        buffer.c
    1.10  )
    1.11  set(headers
    1.12 +        cx/utils.h
    1.13          cx/allocator.h
    1.14          cx/list.h
    1.15          cx/linked_list.h
    1.16          cx/tree.h
    1.17 +        cx/buffer.h
    1.18  )
    1.19  
    1.20  add_library(ucx SHARED ${sources})
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/src/buffer.c	Mon Dec 27 16:51:10 2021 +0100
     2.3 @@ -0,0 +1,328 @@
     2.4 +/*
     2.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     2.6 + *
     2.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
     2.8 + *
     2.9 + * Redistribution and use in source and binary forms, with or without
    2.10 + * modification, are permitted provided that the following conditions are met:
    2.11 + *
    2.12 + *   1. Redistributions of source code must retain the above copyright
    2.13 + *      notice, this list of conditions and the following disclaimer.
    2.14 + *
    2.15 + *   2. Redistributions in binary form must reproduce the above copyright
    2.16 + *      notice, this list of conditions and the following disclaimer in the
    2.17 + *      documentation and/or other materials provided with the distribution.
    2.18 + *
    2.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    2.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    2.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    2.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    2.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    2.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    2.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    2.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    2.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    2.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    2.29 + * POSSIBILITY OF SUCH DAMAGE.
    2.30 + */
    2.31 +
    2.32 +#include "cx/buffer.h"
    2.33 +#include "cx/utils.h"
    2.34 +
    2.35 +#include <stdlib.h>
    2.36 +#include <string.h>
    2.37 +
    2.38 +CxBuffer cxBufferCreate(
    2.39 +        void *space,
    2.40 +        size_t capacity,
    2.41 +        int flags
    2.42 +) {
    2.43 +    CxBuffer buffer = (CxBuffer) malloc(sizeof(cx_buffer_s));
    2.44 +    if (buffer) {
    2.45 +        buffer->flags = flags;
    2.46 +        if (!space) {
    2.47 +            buffer->bytes = malloc(capacity);
    2.48 +            if (!buffer->bytes) {
    2.49 +                free(buffer);
    2.50 +                return NULL;
    2.51 +            }
    2.52 +            memset(buffer->bytes, 0, capacity);
    2.53 +            buffer->flags |= CX_BUFFER_FREE_CONTENTS;
    2.54 +        } else {
    2.55 +            buffer->bytes = space;
    2.56 +        }
    2.57 +        buffer->capacity = capacity;
    2.58 +        buffer->size = 0;
    2.59 +
    2.60 +        buffer->pos = 0;
    2.61 +    }
    2.62 +
    2.63 +    return buffer;
    2.64 +}
    2.65 +
    2.66 +void cxBufferDestroy(CxBuffer buffer) {
    2.67 +    if ((buffer->flags & CX_BUFFER_FREE_CONTENTS) == CX_BUFFER_FREE_CONTENTS) {
    2.68 +        free(buffer->bytes);
    2.69 +    }
    2.70 +    free(buffer);
    2.71 +}
    2.72 +
    2.73 +CxBuffer cxBufferExtract(
    2.74 +        CxBuffer src,
    2.75 +        size_t start,
    2.76 +        size_t length,
    2.77 +        int flags
    2.78 +) {
    2.79 +    if (src->size == 0 || length == 0 ||
    2.80 +        ((size_t) -1) - start < length || start + length > src->capacity) {
    2.81 +        return NULL;
    2.82 +    }
    2.83 +
    2.84 +    CxBuffer dst = (CxBuffer) malloc(sizeof(cx_buffer_s));
    2.85 +    if (dst) {
    2.86 +        dst->bytes = malloc(length);
    2.87 +        if (!dst->bytes) {
    2.88 +            free(dst);
    2.89 +            return NULL;
    2.90 +        }
    2.91 +        dst->capacity = length;
    2.92 +        dst->size = length;
    2.93 +        dst->flags = flags | CX_BUFFER_FREE_CONTENTS;
    2.94 +        dst->pos = 0;
    2.95 +        memcpy(dst->bytes, src->bytes + start, length);
    2.96 +    }
    2.97 +    return dst;
    2.98 +}
    2.99 +
   2.100 +int cxBufferSeek(
   2.101 +        CxBuffer buffer,
   2.102 +        off_t offset,
   2.103 +        int whence
   2.104 +) {
   2.105 +    size_t npos;
   2.106 +    switch (whence) {
   2.107 +        case SEEK_CUR:
   2.108 +            npos = buffer->pos;
   2.109 +            break;
   2.110 +        case SEEK_END:
   2.111 +            npos = buffer->size;
   2.112 +            break;
   2.113 +        case SEEK_SET:
   2.114 +            npos = 0;
   2.115 +            break;
   2.116 +        default:
   2.117 +            return -1;
   2.118 +    }
   2.119 +
   2.120 +    size_t opos = npos;
   2.121 +    npos += offset;
   2.122 +
   2.123 +    if ((offset > 0 && npos < opos) || (offset < 0 && npos > opos)) {
   2.124 +        return -1;
   2.125 +    }
   2.126 +
   2.127 +    if (npos >= buffer->size) {
   2.128 +        return -1;
   2.129 +    } else {
   2.130 +        buffer->pos = npos;
   2.131 +        return 0;
   2.132 +    }
   2.133 +
   2.134 +}
   2.135 +
   2.136 +int cxBufferEof(CxBuffer buffer) {
   2.137 +    return buffer->pos >= buffer->size;
   2.138 +}
   2.139 +
   2.140 +int cxBufferMinimumCapacity(
   2.141 +        CxBuffer buffer,
   2.142 +        size_t additional_bytes
   2.143 +) {
   2.144 +    size_t newcap = buffer->capacity + additional_bytes;
   2.145 +
   2.146 +    // overflow protection
   2.147 +    if (newcap < buffer->capacity) {
   2.148 +        return -1;
   2.149 +    }
   2.150 +
   2.151 +    unsigned char *newspace = realloc(buffer->bytes, newcap);
   2.152 +    if (newspace) {
   2.153 +        memset(newspace + buffer->size, 0, newcap - buffer->size);
   2.154 +        buffer->bytes = newspace;
   2.155 +        buffer->capacity = newcap;
   2.156 +    } else {
   2.157 +        return -1;
   2.158 +    }
   2.159 +
   2.160 +    return 0;
   2.161 +}
   2.162 +
   2.163 +size_t cxBufferWrite(
   2.164 +        const void *ptr,
   2.165 +        size_t size,
   2.166 +        size_t nitems,
   2.167 +        CxBuffer buffer
   2.168 +) {
   2.169 +    size_t len;
   2.170 +    if (cx_szmul(size, nitems, &len)) {
   2.171 +        return 0;
   2.172 +    }
   2.173 +    size_t required = buffer->pos + len;
   2.174 +    if (buffer->pos > required) {
   2.175 +        return 0;
   2.176 +    }
   2.177 +
   2.178 +    if (required > buffer->capacity) {
   2.179 +        if ((buffer->flags & CX_BUFFER_AUTO_EXTEND) == CX_BUFFER_AUTO_EXTEND) {
   2.180 +            if (cxBufferMinimumCapacity(buffer, required)) {
   2.181 +                return 0;
   2.182 +            }
   2.183 +        } else {
   2.184 +            len = buffer->capacity - buffer->pos;
   2.185 +            if (size > 1) {
   2.186 +                len -= len % size;
   2.187 +            }
   2.188 +        }
   2.189 +    }
   2.190 +
   2.191 +    if (len == 0) {
   2.192 +        return len;
   2.193 +    }
   2.194 +
   2.195 +    memcpy(buffer->bytes + buffer->pos, ptr, len);
   2.196 +    buffer->pos += len;
   2.197 +    if (buffer->pos > buffer->size) {
   2.198 +        buffer->size = buffer->pos;
   2.199 +    }
   2.200 +
   2.201 +    return len / size;
   2.202 +}
   2.203 +
   2.204 +size_t cxBufferRead(
   2.205 +        void *ptr,
   2.206 +        size_t size,
   2.207 +        size_t nitems,
   2.208 +        CxBuffer buffer
   2.209 +) {
   2.210 +    size_t len;
   2.211 +    if (cx_szmul(size, nitems, &len)) {
   2.212 +        return 0;
   2.213 +    }
   2.214 +    if (buffer->pos + len > buffer->size) {
   2.215 +        len = buffer->size - buffer->pos;
   2.216 +        if (size > 1) len -= len % size;
   2.217 +    }
   2.218 +
   2.219 +    if (len <= 0) {
   2.220 +        return len;
   2.221 +    }
   2.222 +
   2.223 +    memcpy(ptr, buffer->bytes + buffer->pos, len);
   2.224 +    buffer->pos += len;
   2.225 +
   2.226 +    return len / size;
   2.227 +}
   2.228 +
   2.229 +int cxBufferPut(
   2.230 +        CxBuffer buffer,
   2.231 +        int c
   2.232 +) {
   2.233 +    if (buffer->pos >= buffer->capacity) {
   2.234 +        if ((buffer->flags & CX_BUFFER_AUTO_EXTEND) == CX_BUFFER_AUTO_EXTEND) {
   2.235 +            if (cxBufferMinimumCapacity(buffer, buffer->capacity + 1)) {
   2.236 +                return EOF;
   2.237 +            }
   2.238 +        } else {
   2.239 +            return EOF;
   2.240 +        }
   2.241 +    }
   2.242 +
   2.243 +    c &= 0xFF;
   2.244 +    buffer->bytes[buffer->pos] = (unsigned char) c;
   2.245 +    buffer->pos++;
   2.246 +    if (buffer->pos > buffer->size) {
   2.247 +        buffer->size = buffer->pos;
   2.248 +    }
   2.249 +    return c;
   2.250 +}
   2.251 +
   2.252 +int cxBufferGet(CxBuffer buffer) {
   2.253 +    if (cxBufferEof(buffer)) {
   2.254 +        return EOF;
   2.255 +    } else {
   2.256 +        int c = buffer->bytes[buffer->pos];
   2.257 +        buffer->pos++;
   2.258 +        return c;
   2.259 +    }
   2.260 +}
   2.261 +
   2.262 +size_t cxBufferPutString(
   2.263 +        CxBuffer buffer,
   2.264 +        const char *str
   2.265 +) {
   2.266 +    return cxBufferWrite(str, 1, strlen(str), buffer);
   2.267 +}
   2.268 +
   2.269 +int cxBufferShiftLeft(
   2.270 +        CxBuffer buffer,
   2.271 +        size_t shift
   2.272 +) {
   2.273 +    if (shift >= buffer->size) {
   2.274 +        buffer->pos = buffer->size = 0;
   2.275 +    } else {
   2.276 +        memmove(buffer->bytes, buffer->bytes + shift, buffer->size - shift);
   2.277 +        buffer->size -= shift;
   2.278 +
   2.279 +        if (buffer->pos >= shift) {
   2.280 +            buffer->pos -= shift;
   2.281 +        } else {
   2.282 +            buffer->pos = 0;
   2.283 +        }
   2.284 +    }
   2.285 +    return 0;
   2.286 +}
   2.287 +
   2.288 +int cxBufferShiftRight(
   2.289 +        CxBuffer buffer,
   2.290 +        size_t shift
   2.291 +) {
   2.292 +    size_t req_capacity = buffer->size + shift;
   2.293 +    size_t movebytes;
   2.294 +
   2.295 +    // auto extend buffer, if required and enabled
   2.296 +    if (buffer->capacity < req_capacity) {
   2.297 +        if ((buffer->flags & CX_BUFFER_AUTO_EXTEND) == CX_BUFFER_AUTO_EXTEND) {
   2.298 +            if (cxBufferMinimumCapacity(buffer, req_capacity)) {
   2.299 +                return 1;
   2.300 +            }
   2.301 +            movebytes = buffer->size;
   2.302 +        } else {
   2.303 +            movebytes = buffer->capacity - shift;
   2.304 +        }
   2.305 +    } else {
   2.306 +        movebytes = buffer->size;
   2.307 +    }
   2.308 +
   2.309 +    memmove(buffer->bytes + shift, buffer->bytes, movebytes);
   2.310 +    buffer->size = shift + movebytes;
   2.311 +
   2.312 +    buffer->pos += shift;
   2.313 +    if (buffer->pos > buffer->size) {
   2.314 +        buffer->pos = buffer->size;
   2.315 +    }
   2.316 +
   2.317 +    return 0;
   2.318 +}
   2.319 +
   2.320 +int cxBufferShift(
   2.321 +        CxBuffer buffer,
   2.322 +        off_t shift
   2.323 +) {
   2.324 +    if (shift < 0) {
   2.325 +        return cxBufferShiftLeft(buffer, (size_t) (-shift));
   2.326 +    } else if (shift > 0) {
   2.327 +        return cxBufferShiftRight(buffer, (size_t) shift);
   2.328 +    } else {
   2.329 +        return 0;
   2.330 +    }
   2.331 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/src/cx/buffer.h	Mon Dec 27 16:51:10 2021 +0100
     3.3 @@ -0,0 +1,377 @@
     3.4 +/*
     3.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3.6 + *
     3.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
     3.8 + *
     3.9 + * Redistribution and use in source and binary forms, with or without
    3.10 + * modification, are permitted provided that the following conditions are met:
    3.11 + *
    3.12 + *   1. Redistributions of source code must retain the above copyright
    3.13 + *      notice, this list of conditions and the following disclaimer.
    3.14 + *
    3.15 + *   2. Redistributions in binary form must reproduce the above copyright
    3.16 + *      notice, this list of conditions and the following disclaimer in the
    3.17 + *      documentation and/or other materials provided with the distribution.
    3.18 + *
    3.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    3.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    3.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    3.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    3.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    3.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    3.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    3.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    3.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    3.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    3.29 + * POSSIBILITY OF SUCH DAMAGE.
    3.30 + */
    3.31 +
    3.32 +/**
    3.33 + * \file buffer.h
    3.34 + *
    3.35 + * \brief Advanced buffer implementation.
    3.36 + *
    3.37 + * Instances of CxBuffer can be used to read from or to write to like one
    3.38 + * would do with a stream.
    3.39 + *
    3.40 + * Some features for convenient use of the buffer
    3.41 + * can be enabled. See the documentation of the macro constants for more
    3.42 + * information.
    3.43 + *
    3.44 + * \author Mike Becker
    3.45 + * \author Olaf Wintermann
    3.46 + * \version 3.0
    3.47 + * \copyright 2-Clause BSD License
    3.48 + */
    3.49 +
    3.50 +#ifndef UCX_BUFFER_H
    3.51 +#define    UCX_BUFFER_H
    3.52 +
    3.53 +#include <sys/types.h>
    3.54 +#include <stdio.h>
    3.55 +
    3.56 +#ifdef    __cplusplus
    3.57 +extern "C" {
    3.58 +#endif
    3.59 +
    3.60 +/**
    3.61 + * No buffer features enabled (all flags cleared).
    3.62 + */
    3.63 +#define CX_BUFFER_DEFAULT 0x00
    3.64 +
    3.65 +/**
    3.66 + * If this flag is enabled, the buffer will automatically free its contents when destroyed.
    3.67 + */
    3.68 +#define CX_BUFFER_FREE_CONTENTS 0x01
    3.69 +
    3.70 +/**
    3.71 + * If this flag is enabled, the buffer will automatically extends its capacity.
    3.72 + */
    3.73 +#define CX_BUFFER_AUTO_EXTEND 0x02
    3.74 +
    3.75 +/** Structure for the UCX buffer data. */
    3.76 +typedef struct {
    3.77 +    /** A pointer to the buffer contents. */
    3.78 +    union {
    3.79 +        /**
    3.80 +         * Data is interpreted as text.
    3.81 +         */
    3.82 +        char *space;
    3.83 +        /**
    3.84 +         * Data is interpreted as binary.
    3.85 +         */
    3.86 +        unsigned char *bytes;
    3.87 +    };
    3.88 +    /** Current position of the buffer. */
    3.89 +    size_t pos;
    3.90 +    /** Current capacity (i.e. maximum size) of the buffer. */
    3.91 +    size_t capacity;
    3.92 +    /** Current size of the buffer content. */
    3.93 +    size_t size;
    3.94 +    /**
    3.95 +     * Flag register for buffer features.
    3.96 +     * \see #CX_BUFFER_DEFAULT
    3.97 +     * \see #CX_BUFFER_FREE_CONTENTS
    3.98 +     * \see #CX_BUFFER_AUTO_EXTEND
    3.99 +     */
   3.100 +    int flags;
   3.101 +} cx_buffer_s;
   3.102 +
   3.103 +/**
   3.104 + * UCX buffer.
   3.105 + */
   3.106 +typedef cx_buffer_s *CxBuffer;
   3.107 +
   3.108 +/**
   3.109 + * Creates a new buffer.
   3.110 + *
   3.111 + * \note You may provide \c NULL as argument for \p space.
   3.112 + * Then this function will allocate the space and enforce
   3.113 + * the #CX_BUFFER_FREE_CONTENTS flag.
   3.114 + *
   3.115 + * \param space pointer to the memory area, or <code>NULL</code> to allocate
   3.116 + * new memory
   3.117 + * \param capacity the capacity of the buffer
   3.118 + * \param flags buffer features (see cx_buffer_s.flags)
   3.119 + * \return the new buffer
   3.120 + */
   3.121 +CxBuffer cxBufferCreate(
   3.122 +        void *space,
   3.123 +        size_t capacity,
   3.124 +        int flags
   3.125 +);
   3.126 +
   3.127 +/**
   3.128 + * Destroys a buffer.
   3.129 + *
   3.130 + * If the #CX_BUFFER_FREE_CONTENTS feature is enabled, the contents of the buffer
   3.131 + * are also freed.
   3.132 + *
   3.133 + * \param buffer the buffer to destroy
   3.134 + */
   3.135 +void cxBufferDestroy(CxBuffer buffer);
   3.136 +
   3.137 +/**
   3.138 + * Creates a new buffer and fills it with content copied from another buffer.
   3.139 + *
   3.140 + * \note The #CX_BUFFER_FREE_CONTENTS feature is enforced for the new buffer.
   3.141 + *
   3.142 + * \param src the source buffer
   3.143 + * \param start the start position of extraction
   3.144 + * \param length the count of bytes to extract (must not be zero)
   3.145 + * \param flags features for the new buffer (#CX_BUFFER_FREE_CONTENTS will always be enabled)
   3.146 + * \return a new buffer containing the extraction
   3.147 + */
   3.148 +CxBuffer cxBufferExtract(
   3.149 +        CxBuffer src,
   3.150 +        size_t start,
   3.151 +        size_t length,
   3.152 +        int flags
   3.153 +);
   3.154 +
   3.155 +/**
   3.156 + * A shorthand macro for copying an entire buffer.
   3.157 + *
   3.158 + * \param src the source buffer
   3.159 + * \param flags features for the new buffer (#CX_BUFFER_FREE_CONTENTS will always be enabled)
   3.160 + * \return a new buffer with the copied content
   3.161 + */
   3.162 +#define cxBufferClone(src, flags) cxBufferExtract(src, 0, (src)->capacity, flags)
   3.163 +
   3.164 +
   3.165 +/**
   3.166 + * Shifts the contents of the buffer by the given offset.
   3.167 + *
   3.168 + * If the offset is positive, the contents are shifted to the right.
   3.169 + * If auto extension is enabled, the buffer grows, if necessary.
   3.170 + * In case the auto extension fails, this function returns a non-zero value and
   3.171 + * no contents are changed.
   3.172 + * If auto extension is disabled, the contents that do not fit into the buffer
   3.173 + * are discarded.
   3.174 + *
   3.175 + * If the offset is negative, the contents are shifted to the left where the
   3.176 + * first \p shift bytes are discarded.
   3.177 + * The new size of the buffer is the old size minus the absolute shift value.
   3.178 + * If this value is larger than the buffer size, the buffer is emptied (but
   3.179 + * not cleared, see the security note below).
   3.180 + *
   3.181 + * The buffer position gets shifted alongside with the content but is kept
   3.182 + * within the boundaries of the buffer.
   3.183 + *
   3.184 + * \note For situations where \c off_t is not large enough, there are specialized cxBufferShiftLeft() and
   3.185 + * cxBufferShiftRight() functions using a \c size_t as parameter type.
   3.186 + *
   3.187 + * \par Security Note
   3.188 + * The shifting operation does \em not erase the previously occupied memory cells.
   3.189 + * You can easily do that manually, e.g. by calling
   3.190 + * <code>memset(buffer->bytes, 0, shift)</code> for a right shift or
   3.191 + * <code>memset(buffer->size, 0, buffer->capacity - buffer->size)</code>
   3.192 + * for a left shift.
   3.193 + *
   3.194 + * \param buffer the buffer
   3.195 + * \param shift the shift offset (negative means left shift)
   3.196 + * \return 0 on success, non-zero if a required auto-extension fails
   3.197 + */
   3.198 +int cxBufferShift(
   3.199 +        CxBuffer buffer,
   3.200 +        off_t shift
   3.201 +);
   3.202 +
   3.203 +/**
   3.204 + * Shifts the buffer to the right.
   3.205 + * See cxBufferShift() for details.
   3.206 + *
   3.207 + * \param buffer the buffer
   3.208 + * \param shift the shift offset
   3.209 + * \return 0 on success, non-zero if a required auto-extension fails
   3.210 + * \see cxBufferShift()
   3.211 + */
   3.212 +int cxBufferShiftRight(
   3.213 +        CxBuffer buffer,
   3.214 +        size_t shift
   3.215 +);
   3.216 +
   3.217 +/**
   3.218 + * Shifts the buffer to the left.
   3.219 + * See cxBufferShift() for details.
   3.220 + *
   3.221 + * \note Since a left shift cannot fail due to memory allocation problems, this
   3.222 + * function always returns zero.
   3.223 + *
   3.224 + * \param buffer the buffer
   3.225 + * \param shift the positive shift offset
   3.226 + * \return always zero
   3.227 + * \see cxBufferShift()
   3.228 + */
   3.229 +int cxBufferShiftLeft(
   3.230 +        CxBuffer buffer,
   3.231 +        size_t shift
   3.232 +);
   3.233 +
   3.234 +
   3.235 +/**
   3.236 + * Moves the position of the buffer.
   3.237 + *
   3.238 + * The new position is relative to the \p whence argument.
   3.239 + *
   3.240 + * \li \c SEEK_SET marks the start of the buffer.
   3.241 + * \li \c SEEK_CUR marks the current position.
   3.242 + * \li \c SEEK_END marks the end of the buffer.
   3.243 + *
   3.244 + * With an offset of zero, this function sets the buffer position to zero
   3.245 + * (\c SEEK_SET), the buffer size (\c SEEK_END) or leaves the buffer position
   3.246 + * unchanged (\c SEEK_CUR).
   3.247 + *
   3.248 + * \param buffer the buffer
   3.249 + * \param offset position offset relative to \p whence
   3.250 + * \param whence one of \c SEEK_SET, \c SEEK_CUR or \c SEEK_END
   3.251 + * \return 0 on success, non-zero if the position is invalid
   3.252 + *
   3.253 + */
   3.254 +int cxBufferSeek(
   3.255 +        CxBuffer buffer,
   3.256 +        off_t offset,
   3.257 +        int whence
   3.258 +);
   3.259 +
   3.260 +/**
   3.261 + * Clears the buffer by resetting the position and deleting the data.
   3.262 + *
   3.263 + * The data is deleted by zeroing it with a call to memset().
   3.264 + *
   3.265 + * \param buffer the buffer to be cleared
   3.266 + */
   3.267 +#define cxBufferClear(buffer) memset((buffer)->bytes, 0, (buffer)->size); \
   3.268 +        (buffer)->size = 0; (buffer)->pos = 0;
   3.269 +
   3.270 +/**
   3.271 + * Tests, if the buffer position has exceeded the buffer capacity.
   3.272 + *
   3.273 + * \param buffer the buffer to test
   3.274 + * \return non-zero, if the current buffer position has exceeded the last
   3.275 + * available byte of the buffer.
   3.276 + */
   3.277 +int cxBufferEof(CxBuffer buffer);
   3.278 +
   3.279 +
   3.280 +/**
   3.281 + * Ensures that the buffer has a minimum capacity.
   3.282 + *
   3.283 + * If the current capacity is not sufficient, the buffer will be extended.
   3.284 + *
   3.285 + * \param buffer the buffer
   3.286 + * \param capacity the minimum required capacity for this buffer
   3.287 + * \return 0 on success or a non-zero value on failure
   3.288 + */
   3.289 +int cxBufferMinimumCapacity(
   3.290 +        CxBuffer buffer,
   3.291 +        size_t capacity
   3.292 +);
   3.293 +
   3.294 +/**
   3.295 + * Writes data to a CxBuffer.
   3.296 + *
   3.297 + * The position of the buffer is increased by the number of bytes written.
   3.298 + *
   3.299 + * \note The signature is compatible with the fwrite() family of functions.
   3.300 + *
   3.301 + * \param ptr a pointer to the memory area containing the bytes to be written
   3.302 + * \param size the length of one element
   3.303 + * \param nitems the element count
   3.304 + * \param buffer the CxBuffer to write to
   3.305 + * \return the total count of bytes written
   3.306 + */
   3.307 +size_t cxBufferWrite(
   3.308 +        const void *ptr,
   3.309 +        size_t size,
   3.310 +        size_t nitems,
   3.311 +        CxBuffer buffer
   3.312 +);
   3.313 +
   3.314 +/**
   3.315 + * Reads data from a CxBuffer.
   3.316 + *
   3.317 + * The position of the buffer is increased by the number of bytes read.
   3.318 + *
   3.319 + * \note The signature is compatible with the fread() family of functions.
   3.320 + *
   3.321 + * \param ptr a pointer to the memory area where to store the read data
   3.322 + * \param size the length of one element
   3.323 + * \param nitems the element count
   3.324 + * \param buffer the CxBuffer to read from
   3.325 + * \return the total number of elements read
   3.326 + */
   3.327 +size_t cxBufferRead(
   3.328 +        void *ptr,
   3.329 +        size_t size,
   3.330 +        size_t nitems,
   3.331 +        CxBuffer buffer
   3.332 +);
   3.333 +
   3.334 +/**
   3.335 + * Writes a character to a buffer.
   3.336 + *
   3.337 + * The least significant byte of the argument is written to the buffer. If the
   3.338 + * end of the buffer is reached and #CX_BUFFER_AUTO_EXTEND feature is enabled,
   3.339 + * the buffer capacity is extended by cxBufferMinimumCapacity(). If the feature is
   3.340 + * disabled or buffer extension fails, \c EOF is returned.
   3.341 + *
   3.342 + * On successful write, the position of the buffer is increased.
   3.343 + *
   3.344 + * \param buffer the buffer to write to
   3.345 + * \param c the character to write
   3.346 + * \return the byte that has bean written or \c EOF when the end of the stream is
   3.347 + * reached and automatic extension is not enabled or not possible
   3.348 + */
   3.349 +int cxBufferPut(
   3.350 +        CxBuffer buffer,
   3.351 +        int c
   3.352 +);
   3.353 +
   3.354 +/**
   3.355 + * Gets a character from a buffer.
   3.356 + *
   3.357 + * The current position of the buffer is increased after a successful read.
   3.358 + *
   3.359 + * \param buffer the buffer to read from
   3.360 + * \return the character or \c EOF, if the end of the buffer is reached
   3.361 + */
   3.362 +int cxBufferGet(CxBuffer buffer);
   3.363 +
   3.364 +/**
   3.365 + * Writes a string to a buffer.
   3.366 + *
   3.367 + * \param buffer the buffer
   3.368 + * \param str the zero-terminated string
   3.369 + * \return the number of bytes written
   3.370 + */
   3.371 +size_t cxBufferPutString(
   3.372 +        CxBuffer buffer,
   3.373 +        const char *str
   3.374 +);
   3.375 +
   3.376 +#ifdef __cplusplus
   3.377 +}
   3.378 +#endif
   3.379 +
   3.380 +#endif /* UCX_BUFFER_H */
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/src/cx/common.h	Mon Dec 27 16:51:10 2021 +0100
     4.3 @@ -0,0 +1,73 @@
     4.4 +/*
     4.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     4.6 + *
     4.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
     4.8 + *
     4.9 + * Redistribution and use in source and binary forms, with or without
    4.10 + * modification, are permitted provided that the following conditions are met:
    4.11 + *
    4.12 + *   1. Redistributions of source code must retain the above copyright
    4.13 + *      notice, this list of conditions and the following disclaimer.
    4.14 + *
    4.15 + *   2. Redistributions in binary form must reproduce the above copyright
    4.16 + *      notice, this list of conditions and the following disclaimer in the
    4.17 + *      documentation and/or other materials provided with the distribution.
    4.18 + *
    4.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    4.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    4.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    4.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    4.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    4.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    4.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    4.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    4.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    4.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    4.29 + * POSSIBILITY OF SUCH DAMAGE.
    4.30 + */
    4.31 +
    4.32 +/**
    4.33 + * \file common.h
    4.34 + *
    4.35 + * \brief Common definitions and feature checks.
    4.36 + *
    4.37 + * \author Mike Becker
    4.38 + * \author Olaf Wintermann
    4.39 + * \version 3.0
    4.40 + * \copyright 2-Clause BSD License
    4.41 + */
    4.42 +
    4.43 +#ifndef UCX_COMMON_H
    4.44 +#define UCX_COMMON_H
    4.45 +
    4.46 +/** Major UCX version as integer constant. */
    4.47 +#define UCX_VERSION_MAJOR   3
    4.48 +
    4.49 +/** Minor UCX version as integer constant. */
    4.50 +#define UCX_VERSION_MINOR   0
    4.51 +
    4.52 +/** Version constant which ensures to increase monotonically. */
    4.53 +#define UCX_VERSION (((UCX_VERSION_MAJOR)<<16)|UCX_VERSION_MINOR)
    4.54 +
    4.55 +
    4.56 +#ifdef _WIN32
    4.57 +#if !(defined __ssize_t_defined || defined _SSIZE_T_)
    4.58 +#include <BaseTsd.h>
    4.59 +typedef SSIZE_T ssize_t;
    4.60 +#define __ssize_t_defined
    4.61 +#define _SSIZE_T_
    4.62 +#endif /* __ssize_t_defined and _SSIZE_T */
    4.63 +#ifndef __WORDSIZE
    4.64 +#ifdef _WIN64
    4.65 +#define __WORDSIZE 64
    4.66 +#else
    4.67 +#define __WORDSIZE 32
    4.68 +#endif
    4.69 +#endif /* __WORDSIZE */
    4.70 +#else /* !_WIN32 */
    4.71 +
    4.72 +#include <sys/types.h>
    4.73 +
    4.74 +#endif /* _WIN32 */
    4.75 +
    4.76 +#endif /* UCX_COMMON_H */
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/cx/utils.h	Mon Dec 27 16:51:10 2021 +0100
     5.3 @@ -0,0 +1,120 @@
     5.4 +/*
     5.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     5.6 + *
     5.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
     5.8 + *
     5.9 + * Redistribution and use in source and binary forms, with or without
    5.10 + * modification, are permitted provided that the following conditions are met:
    5.11 + *
    5.12 + *   1. Redistributions of source code must retain the above copyright
    5.13 + *      notice, this list of conditions and the following disclaimer.
    5.14 + *
    5.15 + *   2. Redistributions in binary form must reproduce the above copyright
    5.16 + *      notice, this list of conditions and the following disclaimer in the
    5.17 + *      documentation and/or other materials provided with the distribution.
    5.18 + *
    5.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    5.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    5.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    5.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    5.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    5.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    5.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    5.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    5.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    5.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    5.29 + * POSSIBILITY OF SUCH DAMAGE.
    5.30 + */
    5.31 +
    5.32 +/**
    5.33 + * \file utils.h
    5.34 + *
    5.35 + * \brief General purpose utility functions.
    5.36 + *
    5.37 + * \author Mike Becker
    5.38 + * \author Olaf Wintermann
    5.39 + * \version 3.0
    5.40 + * \copyright 2-Clause BSD License
    5.41 + */
    5.42 +
    5.43 +#ifndef UCX_UTILS_H
    5.44 +#define UCX_UTILS_H
    5.45 +
    5.46 +#include "common.h"
    5.47 +
    5.48 +#ifdef __cplusplus
    5.49 +extern "C" {
    5.50 +#endif
    5.51 +
    5.52 +/* ----------------------
    5.53 + * cx_szmul() definition.
    5.54 + * ---------------------- */
    5.55 +
    5.56 +#if (__GNUC__ >= 5 || defined(__clang__)) && !defined(CX_NO_SZMUL_BUILTIN)
    5.57 +#define CX_SZMUL_BUILTIN
    5.58 +
    5.59 +#if __WORDSIZE == 32
    5.60 +/**
    5.61 + * Alias for \c __builtin_umul_overflow.
    5.62 + *
    5.63 + * Performs a multiplication of size_t values and checks for overflow.
    5.64 + *
    5.65 + * @param a first operand
    5.66 + * @param b second operand
    5.67 + * @param result a pointer to a size_t, where the result should
    5.68 + * be stored
    5.69 + * @return zero, if no overflow occurred and the result is correct, non-zero
    5.70 + * otherwise
    5.71 + */
    5.72 +#define cx_szmul(a, b, result) __builtin_umul_overflow(a, b, result)
    5.73 +#else /* __WORDSIZE != 32 */
    5.74 +/**
    5.75 + * Alias for \c __builtin_umull_overflow.
    5.76 + *
    5.77 + * Performs a multiplication of size_t values and checks for overflow.
    5.78 + *
    5.79 + * @param a first operand
    5.80 + * @param b second operand
    5.81 + * @param result a pointer to a size_t, where the result should
    5.82 + * be stored
    5.83 + * @return zero, if no overflow occurred and the result is correct, non-zero
    5.84 + * otherwise
    5.85 + */
    5.86 +#define cx_szmul(a, b, result) __builtin_umull_overflow(a, b, result)
    5.87 +#endif /* __WORDSIZE */
    5.88 +
    5.89 +#else /* no GNUC or clang bultin */
    5.90 +
    5.91 +/**
    5.92 + * Performs a multiplication of size_t values and checks for overflow.
    5.93 +  *
    5.94 + * @param a first operand
    5.95 + * @param b second operand
    5.96 + * @param result a pointer to a size_t, where the result should
    5.97 + * be stored
    5.98 + * @return zero, if no overflow occurred and the result is correct, non-zero
    5.99 + * otherwise
   5.100 + */
   5.101 +#define cx_szmul(a, b, result) cx_szmul_impl(a, b, result)
   5.102 +
   5.103 +/**
   5.104 + * Performs a multiplication of size_t values and checks for overflow.
   5.105 + *
   5.106 + * This is a custom implementation in case there is no compiler builtin
   5.107 + * available.
   5.108 + *
   5.109 + * @param a first operand
   5.110 + * @param b second operand
   5.111 + * @param result a pointer to a size_t where the result should be stored
   5.112 + * @return zero, if no overflow occurred and the result is correct, non-zero
   5.113 + * otherwise
   5.114 + */
   5.115 +int cx_szmul_impl(size_t a, size_t b, size_t *result);
   5.116 +
   5.117 +#endif
   5.118 +
   5.119 +#ifdef __cplusplus
   5.120 +}
   5.121 +#endif
   5.122 +
   5.123 +#endif /* UCX_UTILS_H */
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/utils.c	Mon Dec 27 16:51:10 2021 +0100
     6.3 @@ -0,0 +1,46 @@
     6.4 +/*
     6.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     6.6 + *
     6.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
     6.8 + *
     6.9 + * Redistribution and use in source and binary forms, with or without
    6.10 + * modification, are permitted provided that the following conditions are met:
    6.11 + *
    6.12 + *   1. Redistributions of source code must retain the above copyright
    6.13 + *      notice, this list of conditions and the following disclaimer.
    6.14 + *
    6.15 + *   2. Redistributions in binary form must reproduce the above copyright
    6.16 + *      notice, this list of conditions and the following disclaimer in the
    6.17 + *      documentation and/or other materials provided with the distribution.
    6.18 + *
    6.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    6.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    6.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    6.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    6.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    6.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    6.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    6.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    6.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    6.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    6.29 + * POSSIBILITY OF SUCH DAMAGE.
    6.30 + */
    6.31 +
    6.32 +#include "cx/utils.h"
    6.33 +
    6.34 +#ifndef CX_SZMUL_BUILTIN
    6.35 +int cx_szmul_impl(size_t a, size_t b, size_t *result) {
    6.36 +    if(a == 0 || b == 0) {
    6.37 +        *result = 0;
    6.38 +        return 0;
    6.39 +    }
    6.40 +    size_t r = a * b;
    6.41 +    if(r / b == a) {
    6.42 +        *result = r;
    6.43 +        return 0;
    6.44 +    } else {
    6.45 +        *result = 0;
    6.46 +        return 1;
    6.47 +    }
    6.48 +}
    6.49 +#endif

mercurial