summaryrefslogtreecommitdiff
path: root/chromium/third_party/dawn/src/dawn_wire/server/ObjectStorage.h
blob: 0da9e7ca76e51bb95a0320462731844db1589c38 (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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef DAWNWIRE_SERVER_OBJECTSTORAGE_H_
#define DAWNWIRE_SERVER_OBJECTSTORAGE_H_

#include "dawn_wire/TypeTraits_autogen.h"
#include "dawn_wire/WireCmd_autogen.h"

#include <algorithm>
#include <map>

namespace dawn_wire { namespace server {

    template <typename T>
    struct ObjectDataBase {
        // The backend-provided handle and serial to this object.
        T handle;
        uint32_t serial = 0;

        // Used by the error-propagation mechanism to know if this object is an error.
        // TODO(cwallez@chromium.org): this is doubling the memory usage of
        // std::vector<ObjectDataBase> consider making it a special marker value in handle instead.
        bool valid;
        // Whether this object has been allocated, used by the KnownObjects queries
        // TODO(cwallez@chromium.org): make this an internal bit vector in KnownObjects.
        bool allocated;
    };

    // Stores what the backend knows about the type.
    template <typename T, bool IsBuilder = IsBuilderType<T>::value>
    struct ObjectData : public ObjectDataBase<T> {};

    template <typename T>
    struct ObjectData<T, true> : public ObjectDataBase<T> {
        ObjectHandle builtObject = ObjectHandle{0, 0};
    };

    template <>
    struct ObjectData<dawnBuffer, false> : public ObjectDataBase<dawnBuffer> {
        void* mappedData = nullptr;
        size_t mappedDataSize = 0;
    };

    // Keeps track of the mapping between client IDs and backend objects.
    template <typename T>
    class KnownObjects {
      public:
        using Data = ObjectData<T>;

        KnownObjects() {
            // Reserve ID 0 so that it can be used to represent nullptr for optional object values
            // in the wire format. However don't tag it as allocated so that it is an error to ask
            // KnownObjects for ID 0.
            Data reservation;
            reservation.handle = nullptr;
            reservation.valid = false;
            reservation.allocated = false;
            mKnown.push_back(reservation);
        }

        // Get a backend objects for a given client ID.
        // Returns nullptr if the ID hasn't previously been allocated.
        const Data* Get(uint32_t id) const {
            if (id >= mKnown.size()) {
                return nullptr;
            }

            const Data* data = &mKnown[id];

            if (!data->allocated) {
                return nullptr;
            }

            return data;
        }
        Data* Get(uint32_t id) {
            if (id >= mKnown.size()) {
                return nullptr;
            }

            Data* data = &mKnown[id];

            if (!data->allocated) {
                return nullptr;
            }

            return data;
        }

        // Allocates the data for a given ID and returns it.
        // Returns nullptr if the ID is already allocated, or too far ahead.
        // Invalidates all the Data*
        Data* Allocate(uint32_t id) {
            if (id > mKnown.size()) {
                return nullptr;
            }

            Data data;
            data.allocated = true;
            data.valid = false;
            data.handle = nullptr;

            if (id >= mKnown.size()) {
                mKnown.push_back(data);
                return &mKnown.back();
            }

            if (mKnown[id].allocated) {
                return nullptr;
            }

            mKnown[id] = data;
            return &mKnown[id];
        }

        // Marks an ID as deallocated
        void Free(uint32_t id) {
            ASSERT(id < mKnown.size());
            mKnown[id].allocated = false;
        }

        std::vector<T> AcquireAllHandles() {
            std::vector<T> objects;
            for (Data& data : mKnown) {
                if (data.allocated && data.handle != nullptr) {
                    objects.push_back(data.handle);
                    data.valid = false;
                    data.allocated = false;
                    data.handle = nullptr;
                }
            }

            return objects;
        }

      private:
        std::vector<Data> mKnown;
    };

    // ObjectIds are lost in deserialization. Store the ids of deserialized
    // objects here so they can be used in command handlers. This is useful
    // for creating ReturnWireCmds which contain client ids
    template <typename T>
    class ObjectIdLookupTable {
      public:
        void Store(T key, ObjectId id) {
            mTable[key] = id;
        }

        // Return the cached ObjectId, or 0 (null handle)
        ObjectId Get(T key) const {
            const auto it = mTable.find(key);
            if (it != mTable.end()) {
                return it->second;
            }
            return 0;
        }

        void Remove(T key) {
            auto it = mTable.find(key);
            if (it != mTable.end()) {
                mTable.erase(it);
            }
        }

      private:
        std::map<T, ObjectId> mTable;
    };

}}  // namespace dawn_wire::server

#endif  // DAWNWIRE_SERVER_OBJECTSTORAGE_H_