1 /*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "buffer.h"
17 #include <stdlib.h>
18 #include <memory.h>
19 #include <stdatomic.h>
20 #include "platform/include/platform_def.h"
21
22 typedef struct Buffer {
23 uint32_t size;
24 atomic_uint_least32_t refcount;
25 Buffer *rootbuf;
26 uint8_t *data;
27 } BufferInternal;
28
BufferMalloc(uint32_t size)29 Buffer *BufferMalloc(uint32_t size)
30 {
31 if (size == 0) {
32 return NULL;
33 }
34
35 Buffer *buf = (Buffer *)calloc(1, (sizeof(Buffer) + size));
36 if (buf == NULL) {
37 return NULL;
38 }
39
40 buf->size = size;
41 buf->refcount = 1;
42 buf->rootbuf = buf;
43 buf->data = (uint8_t *)buf + sizeof(Buffer);
44 return buf;
45 }
46
BufferRefMalloc(const Buffer * buf)47 Buffer *BufferRefMalloc(const Buffer *buf)
48 {
49 if (buf == NULL) {
50 return NULL;
51 }
52
53 Buffer *ref = (Buffer *)calloc(1, sizeof(Buffer));
54 if (ref == NULL) {
55 return NULL;
56 }
57
58 ref->data = buf->data;
59 ref->size = buf->size;
60 ref->rootbuf = buf->rootbuf;
61 atomic_fetch_add_explicit(&ref->rootbuf->refcount, 1, memory_order_seq_cst);
62
63 return ref;
64 }
65
BufferSliceMalloc(const Buffer * buf,uint32_t offset,uint32_t size)66 Buffer *BufferSliceMalloc(const Buffer *buf, uint32_t offset, uint32_t size)
67 {
68 if (buf == NULL) {
69 return NULL;
70 }
71
72 if ((size + offset > buf->size) || (size == 0)) {
73 LOG_ERROR("Size too small or too big");
74 return NULL;
75 }
76
77 if (offset > buf->size) {
78 LOG_ERROR("BufferSliceMalloc##Buffer offset out of bound");
79 return NULL;
80 }
81
82 Buffer *slice = BufferRefMalloc(buf);
83 slice = BufferResize(slice, offset, size);
84
85 return slice;
86 }
87
BufferResize(Buffer * buf,uint32_t offset,uint32_t size)88 Buffer *BufferResize(Buffer *buf, uint32_t offset, uint32_t size)
89 {
90 if (buf == NULL) {
91 return NULL;
92 }
93 if (size + offset > buf->size) {
94 LOG_ERROR("Size too small or too big");
95 return buf;
96 }
97
98 if (buf->rootbuf == buf) {
99 Buffer *ref = BufferRefMalloc(buf);
100 atomic_fetch_add_explicit(&ref->rootbuf->refcount, -1, memory_order_seq_cst);
101 ref->data += offset;
102 ref->size = size;
103 return ref;
104 } else {
105 buf->data += offset;
106 buf->size = size;
107 return buf;
108 }
109 }
110
BufferFree(Buffer * buf)111 void BufferFree(Buffer *buf)
112 {
113 if (buf == NULL) {
114 return;
115 }
116
117 if (buf->rootbuf != buf) {
118 if (atomic_fetch_add_explicit(&buf->rootbuf->refcount, -1, memory_order_seq_cst) == 1) {
119 free(buf->rootbuf);
120 }
121 free(buf);
122 } else if (atomic_fetch_add_explicit(&buf->refcount, -1, memory_order_seq_cst) == 1) {
123 free(buf->rootbuf);
124 }
125 }
126
BufferPtr(const Buffer * buf)127 void *BufferPtr(const Buffer *buf)
128 {
129 if (buf == NULL) {
130 return NULL;
131 }
132
133 return buf->data;
134 }
135
BufferGetSize(const Buffer * buf)136 uint32_t BufferGetSize(const Buffer *buf)
137 {
138 if (buf == NULL) {
139 return 0;
140 }
141
142 return buf->size;
143 }