1/*
2 * Copyright 2005 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdlib.h>
18#include <string.h>
19
20#include <cutils/atomic.h>
21
22#include "SharedBuffer.h"
23
24// ---------------------------------------------------------------------------
25
26namespace android {
27namespace tinyutils {
28
29SharedBuffer* SharedBuffer::alloc(size_t size)
30{
31    SharedBuffer* sb = static_cast<SharedBuffer *>(malloc(sizeof(SharedBuffer) + size));
32    if (sb) {
33        sb->mRefs = 1;
34        sb->mSize = size;
35    }
36    return sb;
37}
38
39
40ssize_t SharedBuffer::dealloc(const SharedBuffer* released)
41{
42    if (released->mRefs != 0) return -1; // XXX: invalid operation
43    free(const_cast<SharedBuffer*>(released));
44    return 0;
45}
46
47SharedBuffer* SharedBuffer::edit() const
48{
49    if (onlyOwner()) {
50        return const_cast<SharedBuffer*>(this);
51    }
52    SharedBuffer* sb = alloc(mSize);
53    if (sb) {
54        memcpy(sb->data(), data(), size());
55        release();
56    }
57    return sb;
58}
59
60SharedBuffer* SharedBuffer::editResize(size_t newSize) const
61{
62    if (onlyOwner()) {
63        SharedBuffer* buf = const_cast<SharedBuffer*>(this);
64        if (buf->mSize == newSize) return buf;
65        buf = (SharedBuffer*)realloc(buf, sizeof(SharedBuffer) + newSize);
66        if (buf != NULL) {
67            buf->mSize = newSize;
68            return buf;
69        }
70    }
71    SharedBuffer* sb = alloc(newSize);
72    if (sb) {
73        const size_t mySize = mSize;
74        memcpy(sb->data(), data(), newSize < mySize ? newSize : mySize);
75        release();
76    }
77    return sb;
78}
79
80SharedBuffer* SharedBuffer::attemptEdit() const
81{
82    if (onlyOwner()) {
83        return const_cast<SharedBuffer*>(this);
84    }
85    return 0;
86}
87
88SharedBuffer* SharedBuffer::reset(size_t new_size) const
89{
90    // cheap-o-reset.
91    SharedBuffer* sb = alloc(new_size);
92    if (sb) {
93        release();
94    }
95    return sb;
96}
97
98void SharedBuffer::acquire() const {
99    android_atomic_inc(&mRefs);
100}
101
102int32_t SharedBuffer::release(uint32_t flags) const
103{
104    int32_t prev = 1;
105    if (onlyOwner() || ((prev = android_atomic_dec(&mRefs)) == 1)) {
106        mRefs = 0;
107        if ((flags & eKeepStorage) == 0) {
108            free(const_cast<SharedBuffer*>(this));
109        }
110    }
111    return prev;
112}
113
114} // namespace tinyutils
115} // namespace android
116