summaryrefslogtreecommitdiff
path: root/AK/Array.h
blob: 26c0a225b5060639d3a55e1e0afbe88bb6bce66e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
 * Copyright (c) 2020, the SerenityOS developers.
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#pragma once

#include <AK/Iterator.h>
#include <AK/Span.h>
#include <AK/StdLibExtras.h>
#include <AK/TypedTransfer.h>

namespace AK {

template<typename T, size_t Size>
struct Array {
    using ValueType = T;

    // This is a static function because constructors mess up Array's POD-ness.
    static Array from_span(Span<T> span)
    {
        Array array;
        VERIFY(span.size() == Size);
        TypedTransfer<T>::copy(array.data(), span.data(), Size);
        return array;
    }

    [[nodiscard]] constexpr T const* data() const { return __data; }
    [[nodiscard]] constexpr T* data() { return __data; }

    [[nodiscard]] constexpr size_t size() const { return Size; }

    [[nodiscard]] constexpr ReadonlySpan<T> span() const { return { __data, Size }; }
    [[nodiscard]] constexpr Span<T> span() { return { __data, Size }; }

    [[nodiscard]] constexpr T const& at(size_t index) const
    {
        VERIFY(index < size());
        return __data[index];
    }
    [[nodiscard]] constexpr T& at(size_t index)
    {
        VERIFY(index < size());
        return __data[index];
    }

    [[nodiscard]] constexpr T const& first() const { return at(0); }
    [[nodiscard]] constexpr T& first() { return at(0); }

    [[nodiscard]] constexpr T const& last() const
    requires(Size > 0)
    {
        return at(Size - 1);
    }
    [[nodiscard]] constexpr T& last()
    requires(Size > 0)
    {
        return at(Size - 1);
    }

    [[nodiscard]] constexpr bool is_empty() const { return size() == 0; }

    [[nodiscard]] constexpr T const& operator[](size_t index) const { return at(index); }
    [[nodiscard]] constexpr T& operator[](size_t index) { return at(index); }

    template<typename T2, size_t Size2>
    [[nodiscard]] constexpr bool operator==(Array<T2, Size2> const& other) const { return span() == other.span(); }

    using ConstIterator = SimpleIterator<Array const, T const>;
    using Iterator = SimpleIterator<Array, T>;

    [[nodiscard]] constexpr ConstIterator begin() const { return ConstIterator::begin(*this); }
    [[nodiscard]] constexpr Iterator begin() { return Iterator::begin(*this); }

    [[nodiscard]] constexpr ConstIterator end() const { return ConstIterator::end(*this); }
    [[nodiscard]] constexpr Iterator end() { return Iterator::end(*this); }

    [[nodiscard]] constexpr operator ReadonlySpan<T>() const { return span(); }
    [[nodiscard]] constexpr operator Span<T>() { return span(); }

    constexpr size_t fill(T const& value)
    {
        for (size_t idx = 0; idx < Size; ++idx)
            __data[idx] = value;

        return Size;
    }

    [[nodiscard]] constexpr T max() const
    requires(requires(T x, T y) { x < y; })
    {
        static_assert(Size > 0, "No values to max() over");

        T value = __data[0];
        for (size_t i = 1; i < Size; ++i)
            value = AK::max(__data[i], value);
        return value;
    }

    [[nodiscard]] constexpr T min() const
    requires(requires(T x, T y) { x > y; })
    {
        static_assert(Size > 0, "No values to min() over");

        T value = __data[0];
        for (size_t i = 1; i < Size; ++i)
            value = AK::min(__data[i], value);
        return value;
    }

    T __data[Size];
};

template<typename T, typename... Types>
Array(T, Types...) -> Array<T, sizeof...(Types) + 1>;

namespace Detail {
template<typename T, size_t... Is>
constexpr auto integer_sequence_generate_array([[maybe_unused]] T const offset, IntegerSequence<T, Is...>) -> Array<T, sizeof...(Is)>
{
    return { { (offset + Is)... } };
}
}

template<typename T, T N>
constexpr static auto iota_array(T const offset = {})
{
    static_assert(N >= T {}, "Negative sizes not allowed in iota_array()");
    return Detail::integer_sequence_generate_array<T>(offset, MakeIntegerSequence<T, N>());
}

}

#if USING_AK_GLOBALLY
using AK::Array;
using AK::iota_array;
#endif