1/*
2 * Copyright (C) 2023 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 API_BASE_CONTAINERS_ARRAYVIEW_H
17#define API_BASE_CONTAINERS_ARRAYVIEW_H
18
19#include <cassert>
20#include <cstdint>
21#include <iterator>
22#include <type_traits>
23
24/** @ingroup group_containers_arrayview */
25/** Array view */
26template<class T>
27class array_view {
28public:
29    struct Iterator {
30        using iterator_category = std::forward_iterator_tag;
31        using difference_type = std::ptrdiff_t;
32        using value_type = T;
33        using pointer = T*;
34        using reference = T&;
35
36        Iterator(pointer ptr) : m_ptr(ptr) {}
37
38        reference operator*() const
39        {
40            return *m_ptr;
41        }
42        pointer operator->()
43        {
44            return m_ptr;
45        }
46        Iterator& operator++()
47        {
48            m_ptr++;
49            return *this;
50        }
51        Iterator operator++(int)
52        {
53            Iterator tmp = *this;
54            ++(*this);
55            return tmp;
56        }
57        friend bool operator==(const Iterator& a, const Iterator& b)
58        {
59            return a.m_ptr == b.m_ptr;
60        };
61        friend bool operator!=(const Iterator& a, const Iterator& b)
62        {
63            return a.m_ptr != b.m_ptr;
64        };
65
66    private:
67        pointer m_ptr;
68    };
69    using value_type = T;
70    using difference_type = size_t;
71    using pointer = value_type*;
72    using reference = value_type&;
73
74    using size_type = size_t;
75    using const_reference = const value_type&;
76    using const_pointer = const value_type*;
77
78    using iterator = Iterator;
79    using const_iterator = Iterator;
80
81    constexpr array_view() noexcept : begin_(nullptr), size_(0), end_(nullptr) {}
82    constexpr array_view(pointer aBegin, pointer aEnd) noexcept : begin_(aBegin), size_(aEnd - aBegin), end_(aEnd)
83    {
84        assert(end_ >= begin_);
85    }
86    constexpr array_view(pointer aBegin, size_type aSize) noexcept : begin_(aBegin), size_(aSize), end_(aBegin + aSize)
87    {}
88    template<size_t N>
89    constexpr array_view(value_type (&arr)[N]) noexcept : begin_(arr), size_(N), end_(arr + N)
90    {}
91    template<class U, class = std::enable_if_t<std::is_same<std::remove_const_t<T>, U>::value>>
92    constexpr array_view(const array_view<U>& other) noexcept
93        : begin_(other.begin_), size_(other.size_), end_(other.end_)
94    {}
95    template<class U, class = std::enable_if_t<std::is_same<std::remove_const_t<T>, typename U::value_type>::value>>
96    constexpr array_view(U& container) noexcept : array_view(container.data(), container.size())
97    {}
98    template<class U, class = std::enable_if_t<std::is_same<std::remove_const_t<T>, typename U::value_type>::value>>
99    constexpr array_view(const U& container) noexcept : array_view(container.data(), container.size())
100    {}
101    ~array_view() = default;
102    constexpr size_type size() const noexcept
103    {
104        return size_;
105    }
106    constexpr size_type size_bytes() const noexcept
107    {
108        return size_ * sizeof(T);
109    }
110    constexpr bool empty() const noexcept
111    {
112        return size_ == 0;
113    }
114    constexpr const_pointer data() const noexcept
115    {
116        return begin_;
117    }
118    constexpr pointer data() noexcept
119    {
120        return begin_;
121    }
122    constexpr reference at(size_type aIndex) noexcept
123    {
124        // If index out-of-range, undefined behaviour on release builds, assert on debug builds.
125        assert(aIndex < size());
126        return begin_[aIndex];
127    }
128    constexpr const_reference at(size_type aIndex) const noexcept
129    {
130        // If index out-of-range, undefined behaviour on release builds, assert on debug builds.
131        assert(aIndex < size());
132        return begin_[aIndex];
133    }
134    constexpr reference operator[](size_type aIndex)
135    {
136        // If index out-of-range, undefined behaviour on release builds, assert on debug builds.
137        assert(aIndex < size());
138        return begin_[aIndex];
139    }
140    constexpr const_reference operator[](size_type aIndex) const
141    {
142        // If index out-of-range, undefined behaviour on release builds, assert on debug builds.
143        assert(aIndex < size());
144        return begin_[aIndex];
145    }
146    constexpr iterator begin() noexcept
147    {
148        return iterator(begin_);
149    }
150    constexpr iterator end() noexcept
151    {
152        return iterator(begin_ + size_);
153    }
154    constexpr const_iterator begin() const noexcept
155    {
156        return const_iterator(begin_);
157    }
158    constexpr const_iterator end() const noexcept
159    {
160        return const_iterator(begin_ + size_);
161    }
162    constexpr const_iterator cbegin() const noexcept
163    {
164        return begin();
165    }
166    constexpr const_iterator cend() const noexcept
167    {
168        return end();
169    }
170
171private:
172    template<class U>
173    friend class array_view;
174
175    pointer begin_;
176    size_type size_;
177    pointer end_;
178};
179
180template<typename T, size_t N>
181constexpr size_t countof(T (&)[N]) noexcept
182{
183    return N;
184}
185template<typename T, size_t N>
186constexpr array_view<T> arrayview(T (&arr)[N]) noexcept
187{
188    return array_view<T>(arr, N);
189}
190// Returns a const uint8_t array_view of any object.
191template<typename T>
192constexpr array_view<const uint8_t> arrayviewU8(const T& arr) noexcept
193{
194    return array_view(reinterpret_cast<const uint8_t*>(&arr), sizeof(arr));
195}
196
197#endif // API_BASE_CONTAINERS_ARRAYVIEW_H
198