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#ifndef ECMASCRIPT_MEM_C_ADDRESS_ALLOCATOR_H
17#define ECMASCRIPT_MEM_C_ADDRESS_ALLOCATOR_H
18
19#include "ecmascript/mem/chunk.h"
20
21namespace panda::ecmascript {
22template<typename T>
23class CAddressAllocator {
24public:
25    // using by std allocator
26    using value_type = T;
27    using pointer = T *;
28    using reference = T &;
29    using const_pointer = const T *;
30    using const_reference = const T &;
31    using size_type = size_t;
32    using difference_type = ptrdiff_t;
33    using propagate_on_container_swap = std::true_type;
34
35    template<typename U>
36    struct Rebind {
37        using other = CAddressAllocator<U>;
38    };
39
40    template<typename U>
41    using rebind = Rebind<U>;
42
43    CAddressAllocator() = default;
44
45    template<typename U>
46    explicit CAddressAllocator(const CAddressAllocator<U> &other [[maybe_unused]])
47    {
48    }
49
50    CAddressAllocator(const CAddressAllocator &) = default;
51    CAddressAllocator &operator=(const CAddressAllocator &) = default;
52    CAddressAllocator(CAddressAllocator &&other) noexcept = default;
53    CAddressAllocator &operator=(CAddressAllocator &&other) noexcept = default;
54    ~CAddressAllocator() = default;
55
56    // NOLINTNEXTLINE(readability-identifier-naming)
57    size_type max_size() const
58    {
59        return static_cast<size_type>(-1) / sizeof(T);
60    }
61
62    bool operator==([[maybe_unused]] CAddressAllocator const &other) const
63    {
64        return false;
65    }
66
67    bool operator!=([[maybe_unused]] CAddressAllocator const &other) const
68    {
69        return true;
70    }
71
72    // NOLINTNEXTLINE(readability-identifier-naming)
73    pointer allocate(size_type n, [[maybe_unused]] const void *ptr = nullptr)
74    {
75        ASSERT(n <= max_size());
76        return static_cast<T *>(Allocate(n * sizeof(T)));
77    }
78
79    // NOLINTNEXTLINE(readability-identifier-naming)
80    void deallocate(pointer p, [[maybe_unused]] size_type n)
81    {
82        Free(static_cast<void *>(p));
83    }
84
85    template<typename U, typename... Args>
86    void construct(U *p, Args &&... args)  // NOLINT(readability-identifier-naming)
87    {
88        if (p == nullptr) {
89            return;
90        }
91        ::new (static_cast<void *>(p)) U(std::forward<Args>(args)...);
92    }
93    template<typename U>
94    void destroy(U *p)  // NOLINT(readability-identifier-naming)
95    {
96        if (p == nullptr) {
97            return;
98        }
99        p->~U();
100    }
101
102    [[nodiscard]] void *Allocate(size_t size)
103    {
104        if (size == 0) {
105            LOG_ECMA_MEM(FATAL) << "size must have a size bigger than 0";
106            UNREACHABLE();
107        }
108        // NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
109        void *ptr = malloc(size);
110        if (ptr == nullptr) {
111            LOG_ECMA_MEM(FATAL) << "malloc failed, size is: " << size;
112            UNREACHABLE();
113        }
114        return ptr;
115    }
116
117    template<typename S, typename... Args>
118    [[nodiscard]] S *New(Args &&... args)
119    {
120        auto p = reinterpret_cast<void *>(Allocate(sizeof(S)));
121        new (p) S(std::forward<Args>(args)...);
122        return reinterpret_cast<S *>(p);
123    }
124
125    template<class S>
126    void Finalize(S *ptr)
127    {
128        ASSERT(ptr != nullptr);
129        // NOLINTNEXTLINE(readability-braces-around-statements,bugprone-suspicious-semicolon)
130        if constexpr (std::is_class_v<S>) {
131            ptr->~S();
132        }
133        Free(ptr);
134    }
135
136    [[nodiscard]] T *AllocArray(size_t size)
137    {
138        return static_cast<T *>(Allocate(size * sizeof(T)));
139    }
140
141    void Delete(T *ptr)
142    {
143        if (ptr == nullptr) {
144            return;
145        }
146        // NOLINTNEXTLINE(readability-braces-around-statements,bugprone-suspicious-semicolon)
147        if constexpr (std::is_class_v<T>) {
148            ptr->~T();
149        }
150        Free(ptr);
151    }
152
153    void Free(void *mem)
154    {
155        if (mem == nullptr) {
156            return;
157        }
158        // NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
159        free(mem);
160    }
161};
162}  // namespace panda::ecmascript
163
164#endif  // ECMASCRIPT_MEM_C_ADDRESS_ALLOCATOR_H