1/*
2 * Copyright (c) 2022 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 "util/string_pool.h"
17#include "securec.h"
18#include "util/logger.h"
19
20namespace OHOS {
21namespace Idl {
22const char* StringPool::TAG = "StringPool";
23
24StringPool::StringPool()
25{
26    data_ = reinterpret_cast<char*>(calloc(1, dataCapacity_));
27    if (data_ == nullptr) {
28        Logger::E(TAG, "Out of memory.");
29    }
30}
31
32StringPool::~StringPool()
33{
34    if (data_ != nullptr) {
35        free(data_);
36    }
37}
38
39void StringPool::Add(const String& string)
40{
41    if (string.IsEmpty() || stringOffsets_.find(string) != stringOffsets_.end()) {
42        return;
43    }
44
45    ptrdiff_t offset = AddInternal(string);
46    if (offset != -1) {
47        stringOffsets_[string] = offset;
48    }
49}
50
51ptrdiff_t StringPool::GetOffset(const String& string)
52{
53    return stringOffsets_[string];
54}
55
56ptrdiff_t StringPool::AddInternal(const String& string)
57{
58    if (!Grow(string.GetLength() + 1)) {
59        return -1;
60    }
61
62    char* addr = data_ + dataOffset_;
63    if (strcpy_s(addr, dataCapacity_ - dataOffset_, string.string())) {
64        Logger::E(TAG, "Error to copy str");
65        return -1;
66    }
67    dataOffset_ += string.GetLength() + 1;
68    return addr - data_;
69}
70
71bool StringPool::Grow(size_t expand)
72{
73    size_t newSize = static_cast<size_t>(dataOffset_) + expand;
74    if (newSize < dataCapacity_) {
75        return true;
76    }
77    // 3->3x capacity expansion
78    size_t step = dataCapacity_ * 3;
79    newSize = step > newSize ? step : step + newSize;
80    char* newData = reinterpret_cast<char*>(calloc(1, newSize));
81    if (newData == nullptr) {
82        Logger::E(TAG, "Out of memory.");
83        return false;
84    }
85    errno_t ret = memcpy_s(newData, newSize, data_, dataOffset_);
86    if (ret != EOK) {
87        free(newData);
88        newData = nullptr;
89        return false;
90    }
91    free(data_);
92    data_ = newData;
93    dataCapacity_ = newSize;
94    return true;
95}
96}
97}
98