summaryrefslogtreecommitdiff
path: root/AK/Buffer.h
blob: 3c1feb34c55962980f0acf3b70b77b7dee9e7f63 (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
#pragma once

#include "Assertions.h"
#include "Retainable.h"
#include "RetainPtr.h"
#include "StdLibExtras.h"
#include "kmalloc.h"

namespace AK {

template<typename T>
class Buffer : public Retainable<Buffer<T>> {
public:
    static RetainPtr<Buffer> create_uninitialized(size_t count);
    static RetainPtr<Buffer> copy(const T*, size_t count);
    static RetainPtr<Buffer> wrap(T*, size_t count);
    static RetainPtr<Buffer> adopt(T*, size_t count);

    ~Buffer() { clear(); }

    void clear()
    {
        if (!m_elements)
            return;
        if (m_owned)
            kfree(m_elements);
        m_elements = nullptr;
    }

    T& operator[](size_t i) { ASSERT(i < m_size); return m_elements[i]; }
    const T& operator[](size_t i) const { ASSERT(i < m_size); return m_elements[i]; }
    bool is_empty() const { return !m_size; }
    size_t size() const { return m_size; }

    T* pointer() { return m_elements; }
    const T* pointer() const { return m_elements; }

    T* offset_pointer(size_t offset) { return m_elements + offset; }
    const T* offset_pointer(size_t offset) const { return m_elements + offset; }

    const void* end_pointer() const { return m_elements + m_size; }

    // NOTE: trim() does not reallocate.
    void trim(size_t size)
    {
        ASSERT(size <= m_size);
        m_size = size;
    }

private:
    enum ConstructionMode { Uninitialized, Copy, Wrap, Adopt };
    explicit Buffer(size_t); // For ConstructionMode=Uninitialized
    Buffer(const T*, size_t, ConstructionMode); // For ConstructionMode=Copy
    Buffer(T*, size_t, ConstructionMode); // For ConstructionMode=Wrap/Adopt
    Buffer() { }

    T* m_elements { nullptr };
    size_t m_size { 0 };
    bool m_owned { false };
};

template<typename T>
inline Buffer<T>::Buffer(size_t size)
    : m_size(size)
{
    m_elements = static_cast<T*>(kmalloc(size * sizeof(T)));
    m_owned = true;
}

template<typename T>
inline Buffer<T>::Buffer(const T* elements, size_t size, ConstructionMode mode)
    : m_size(size)
{
    ASSERT(mode == Copy);
    m_elements = static_cast<T*>(kmalloc(size * sizeof(T)));
    memcpy(m_elements, elements, size * sizeof(T));
    m_owned = true;
}

template<typename T>
inline Buffer<T>::Buffer(T* elements, size_t size, ConstructionMode mode)
    : m_elements(elements)
    , m_size(size)
{
    if (mode == Adopt) {
        m_owned = true;
    } else if (mode == Wrap) {
        m_owned = false;
    }

}

template<typename T>
inline RetainPtr<Buffer<T>> Buffer<T>::create_uninitialized(size_t size)
{
    return ::adopt(*new Buffer<T>(size));
}

template<typename T>
inline RetainPtr<Buffer<T>> Buffer<T>::copy(const T* elements, size_t size)
{
    return ::adopt(*new Buffer<T>(elements, size, Copy));
}

template<typename T>
inline RetainPtr<Buffer<T>> Buffer<T>::wrap(T* elements, size_t size)
{
    return ::adopt(*new Buffer<T>(elements, size, Wrap));
}

template<typename T>
inline RetainPtr<Buffer<T>> Buffer<T>::adopt(T* elements, size_t size)
{
    return ::adopt(*new Buffer<T>(elements, size, Adopt));
}

}

using AK::Buffer;