aboutsummaryrefslogtreecommitdiff
path: root/src/linda.h
blob: f3b1844028dd207eda0c03338a81fc6d1df96776 (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
#pragma once

#include "cancel.h"
#include "deep.h"
#include "keeper.h"
#include "universe.h"

#include <array>
#include <condition_variable>
#include <variant>

struct Keeper;

// #################################################################################################

using LindaGroup = Unique<int>;

class Linda : public DeepPrelude // Deep userdata MUST start with this header
{
    private:

    static constexpr size_t kEmbeddedNameLength = 24;
    using EmbeddedName = std::array<char, kEmbeddedNameLength>;
    struct AllocatedName
    {
        size_t len{ 0 };
        char* name{ nullptr };
    };
    // depending on the name length, it is either embedded inside the Linda, or allocated separately
    std::variant<AllocatedName, EmbeddedName> m_name;

    public:

    std::condition_variable m_read_happened;
    std::condition_variable m_write_happened;
    Universe* const U{ nullptr }; // the universe this linda belongs to
    int const m_keeper_index{ -1 }; // the keeper associated to this linda
    CancelRequest simulate_cancel{ CancelRequest::None };

    public:

    // a fifo full userdata has one uservalue, the table that holds the actual fifo contents
    [[nodiscard]] static void* operator new(size_t size_, Universe* U_) noexcept { return U_->internal_allocator.alloc(size_); }
    // always embedded somewhere else or "in-place constructed" as a full userdata
    // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception
    static void operator delete(void* p_, Universe* U_) { U_->internal_allocator.free(p_, sizeof(Linda)); }
    // this one is for us, to make sure memory is freed by the correct allocator
    static void operator delete(void* p_) { static_cast<Linda*>(p_)->U->internal_allocator.free(p_, sizeof(Linda)); }

    ~Linda();
    Linda(Universe* U_, LindaGroup group_, char const* name_, size_t len_);
    Linda() = delete;
    // non-copyable, non-movable
    Linda(Linda const&) = delete;
    Linda(Linda const&&) = delete;
    Linda& operator=(Linda const&) = delete;
    Linda& operator=(Linda const&&) = delete;

    static int ProtectedCall(lua_State* L, lua_CFunction f_);

    private :

    void setName(char const* name_, size_t len_);

    public:

    [[nodiscard]] char const* getName() const;
    [[nodiscard]] Keeper* whichKeeper() const { return U->keepers->nb_keepers ? &U->keepers->keeper_array[m_keeper_index] : nullptr; }
    [[nodiscard]] Keeper* acquireKeeper() const;
    void releaseKeeper(Keeper* keeper_) const;
};