• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef DAWNWIRE_CLIENT_OBJECTALLOCATOR_H_
16 #define DAWNWIRE_CLIENT_OBJECTALLOCATOR_H_
17 
18 #include "common/Assert.h"
19 #include "common/Compiler.h"
20 #include "dawn_wire/WireCmd_autogen.h"
21 
22 #include <limits>
23 #include <memory>
24 #include <vector>
25 
26 namespace dawn_wire { namespace client {
27 
28     template <typename T>
29     class ObjectAllocator {
30       public:
31         struct ObjectAndSerial {
ObjectAndSerialObjectAndSerial32             ObjectAndSerial(std::unique_ptr<T> object, uint32_t generation)
33                 : object(std::move(object)), generation(generation) {
34             }
35             std::unique_ptr<T> object;
36             uint32_t generation;
37         };
38 
ObjectAllocator()39         ObjectAllocator() {
40             // ID 0 is nullptr
41             mObjects.emplace_back(nullptr, 0);
42         }
43 
44         template <typename Client>
New(Client * client)45         ObjectAndSerial* New(Client* client) {
46             uint32_t id = GetNewId();
47             auto object = std::make_unique<T>(client, 1, id);
48             client->TrackObject(object.get());
49 
50             if (id >= mObjects.size()) {
51                 ASSERT(id == mObjects.size());
52                 mObjects.emplace_back(std::move(object), 0);
53             } else {
54                 ASSERT(mObjects[id].object == nullptr);
55 
56                 mObjects[id].generation++;
57                 // The generation should never overflow. We don't recycle ObjectIds that would
58                 // overflow their next generation.
59                 ASSERT(mObjects[id].generation != 0);
60 
61                 mObjects[id].object = std::move(object);
62             }
63 
64             return &mObjects[id];
65         }
Free(T * obj)66         void Free(T* obj) {
67             ASSERT(obj->IsInList());
68             if (DAWN_LIKELY(mObjects[obj->id].generation != std::numeric_limits<uint32_t>::max())) {
69                 // Only recycle this ObjectId if the generation won't overflow on the next
70                 // allocation.
71                 FreeId(obj->id);
72             }
73             mObjects[obj->id].object = nullptr;
74         }
75 
GetObject(uint32_t id)76         T* GetObject(uint32_t id) {
77             if (id >= mObjects.size()) {
78                 return nullptr;
79             }
80             return mObjects[id].object.get();
81         }
82 
GetGeneration(uint32_t id)83         uint32_t GetGeneration(uint32_t id) {
84             if (id >= mObjects.size()) {
85                 return 0;
86             }
87             return mObjects[id].generation;
88         }
89 
90       private:
GetNewId()91         uint32_t GetNewId() {
92             if (mFreeIds.empty()) {
93                 return mCurrentId++;
94             }
95             uint32_t id = mFreeIds.back();
96             mFreeIds.pop_back();
97             return id;
98         }
FreeId(uint32_t id)99         void FreeId(uint32_t id) {
100             mFreeIds.push_back(id);
101         }
102 
103         // 0 is an ID reserved to represent nullptr
104         uint32_t mCurrentId = 1;
105         std::vector<uint32_t> mFreeIds;
106         std::vector<ObjectAndSerial> mObjects;
107     };
108 }}  // namespace dawn_wire::client
109 
110 #endif  // DAWNWIRE_CLIENT_OBJECTALLOCATOR_H_
111