1 /******************************************************************************
2  *
3  *  Copyright (C) 2014 Google, Inc.
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at:
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  ******************************************************************************/
18 #include <stdint.h>
19 #include "bt_common.h"
20 #include "osi/allocator.h"
21 #include "osi/buffer.h"
22 
23 struct buffer_t {
24     buffer_t *root;
25     size_t refcount;
26     size_t length;
27     uint8_t data[];
28 };
29 
buffer_new(size_t size)30 buffer_t *buffer_new(size_t size)
31 {
32     assert(size > 0);
33 
34     buffer_t *buffer = osi_malloc(sizeof(buffer_t) + size);
35     if (!buffer) {
36         OSI_TRACE_ERROR("%s unable to allocate buffer of %zu bytes.", __func__, size);
37         return NULL;
38     }
39 
40     buffer->root = buffer;
41     buffer->refcount = 1;
42     buffer->length = size;
43 
44     return buffer;
45 }
46 
buffer_new_ref(const buffer_t * buf)47 buffer_t *buffer_new_ref(const buffer_t *buf)
48 {
49     assert(buf != NULL);
50     return buffer_new_slice(buf, buf->length);
51 }
52 
buffer_new_slice(const buffer_t * buf,size_t slice_size)53 buffer_t *buffer_new_slice(const buffer_t *buf, size_t slice_size)
54 {
55     assert(buf != NULL);
56     assert(slice_size > 0);
57     assert(slice_size <= buf->length);
58 
59     buffer_t *ret = osi_calloc(sizeof(buffer_t));
60     if (!ret) {
61         OSI_TRACE_ERROR("%s unable to allocate new buffer for slice of length %zu.", __func__, slice_size);
62         return NULL;
63     }
64 
65     ret->root = buf->root;
66     ret->refcount = SIZE_MAX;
67     ret->length = slice_size;
68 
69     ++buf->root->refcount;
70 
71     return ret;
72 }
73 
buffer_free(buffer_t * buffer)74 void buffer_free(buffer_t *buffer)
75 {
76     if (!buffer) {
77         return;
78     }
79 
80     if (buffer->root != buffer) {
81         // We're a leaf node. Delete the root node if we're the last referent.
82         if (--buffer->root->refcount == 0) {
83             osi_free(buffer->root);
84         }
85         osi_free(buffer);
86     } else if (--buffer->refcount == 0) {
87         // We're a root node. Roots are only deleted when their refcount goes to 0.
88         osi_free(buffer);
89     }
90 }
91 
buffer_ptr(const buffer_t * buf)92 void *buffer_ptr(const buffer_t *buf)
93 {
94     assert(buf != NULL);
95     return buf->root->data + buf->root->length - buf->length;
96 }
97 
buffer_length(const buffer_t * buf)98 size_t buffer_length(const buffer_t *buf)
99 {
100     assert(buf != NULL);
101     return buf->length;
102 }
103