aboutsummaryrefslogtreecommitdiff
path: root/thirdparty/tourist/foundation/src/allocator.cpp
blob: c6f021ad230f5a2fe2999e906646edf9ec01b7c3 (plain) (blame)
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
#include <foundation/buffer.h>
#include <foundation/malloc.h>

#include "slab.h"

//------------------------------------------------------------------------------
Allocator::~Allocator()
{
    if (_slab != nullptr)
        _slab->dec_ref();
}

//------------------------------------------------------------------------------
MutableBuffer Allocator::create_buffer(uint32 size)
{
    auto create_slab = [this] (uint32 slab_size) {
        auto* slab = tt_malloc<Slab>(slab_size + sizeof(Slab));
        slab->_allocator = this;
        slab->_size = slab_size;
        slab->_refs.store_relaxed(0);
        return slab;
    };

    enum {
        PACKET_PAGE_SIZE    = 4 << 10,
        PACKET_SLAB_SIZE    = 1 << 20,
        PACKET_ALIGN        = 32 - 1,
    };

    if (size > PACKET_PAGE_SIZE)
    {
        Slab* slab = create_slab(size);
        return MutableBuffer(slab, size, 0);
    }

    uint32 alloc_size = (size + PACKET_ALIGN) & ~PACKET_ALIGN;

    UniqueLock _(_lock);

    if (alloc_size > _slab_free && _slab != nullptr)
    {
        _slab->dec_ref();
        _slab = nullptr;
    }

    if (_slab == nullptr)
    {
        _slab_free = PACKET_SLAB_SIZE;
        _slab = create_slab(_slab_free);
        _slab->inc_ref();
    }

    uint32 offset = PACKET_SLAB_SIZE - _slab_free;
    _slab_free -= alloc_size;
    return MutableBuffer(_slab, size, offset);
}

//------------------------------------------------------------------------------
void Allocator::free_slab(Slab* slab)
{
    tt_free(slab);
}

//------------------------------------------------------------------------------
Allocator& Allocator::get_from(Buffer& buffer)      { return get_from(buffer._slab); }
Allocator& Allocator::get_from(BufferRef& ref)      { return get_from(ref.get_slab()); }
Allocator& Allocator::get_from(BufferStream& stream){ return get_from(stream.get_slab()); }
Allocator& Allocator::get_from(Pointer& pointer)    { return get_from(pointer.get_slab()); }
Allocator& Allocator::get_from(const Slab* slab)    { return slab->get_allocator(); }