39d8477c创建于 2023年6月27日历史提交
/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "buffer.h"
#include <stdlib.h>
#include <memory.h>
#include <stdatomic.h>
#include "platform/include/platform_def.h"

typedef struct Buffer {
    uint32_t size;
    atomic_uint_least32_t refcount;
    Buffer *rootbuf;
    uint8_t *data;
} BufferInternal;

Buffer *BufferMalloc(uint32_t size)
{
    if (size == 0) {
        return NULL;
    }

    Buffer *buf = (Buffer *)calloc(1, (sizeof(Buffer) + size));
    if (buf == NULL) {
        return NULL;
    }

    buf->size = size;
    buf->refcount = 1;
    buf->rootbuf = buf;
    buf->data = (uint8_t *)buf + sizeof(Buffer);
    return buf;
}

Buffer *BufferRefMalloc(const Buffer *buf)
{
    if (buf == NULL) {
        return NULL;
    }

    Buffer *ref = (Buffer *)calloc(1, sizeof(Buffer));
    if (ref == NULL) {
        return NULL;
    }

    ref->data = buf->data;
    ref->size = buf->size;
    ref->rootbuf = buf->rootbuf;
    atomic_fetch_add_explicit(&ref->rootbuf->refcount, 1, memory_order_seq_cst);

    return ref;
}

Buffer *BufferSliceMalloc(const Buffer *buf, uint32_t offset, uint32_t size)
{
    if (buf == NULL) {
        return NULL;
    }

    if ((size + offset > buf->size) || (size == 0)) {
        LOG_ERROR("Size too small or too big");
        return NULL;
    }

    if (offset > buf->size) {
        LOG_ERROR("BufferSliceMalloc##Buffer offset out of bound");
        return NULL;
    }

    Buffer *slice = BufferRefMalloc(buf);
    slice = BufferResize(slice, offset, size);

    return slice;
}

Buffer *BufferResize(Buffer *buf, uint32_t offset, uint32_t size)
{
    if (buf == NULL) {
        return NULL;
    }
    if (size + offset > buf->size) {
        LOG_ERROR("Size too small or too big");
        return buf;
    }

    if (buf->rootbuf == buf) {
        Buffer *ref = BufferRefMalloc(buf);
        atomic_fetch_add_explicit(&ref->rootbuf->refcount, -1, memory_order_seq_cst);
        ref->data += offset;
        ref->size = size;
        return ref;
    } else {
        buf->data += offset;
        buf->size = size;
        return buf;
    }
}

void BufferFree(Buffer *buf)
{
    if (buf == NULL) {
        return;
    }

    if (buf->rootbuf != buf) {
        if (atomic_fetch_add_explicit(&buf->rootbuf->refcount, -1, memory_order_seq_cst) == 1) {
            free(buf->rootbuf);
        }
        free(buf);
    } else if (atomic_fetch_add_explicit(&buf->refcount, -1, memory_order_seq_cst) == 1) {
        free(buf->rootbuf);
    }
}

void *BufferPtr(const Buffer *buf)
{
    if (buf == NULL) {
        return NULL;
    }

    return buf->data;
}

uint32_t BufferGetSize(const Buffer *buf)
{
    if (buf == NULL) {
        return 0;
    }

    return buf->size;
}