Seregon/ShadPKG

A tool for deriving PKG packet encryption keys for ps4 written in c++

C++/47.3 KB/No license
common/object_pool.h
ShadPKG / common / object_pool.h
1// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3 
4#pragma once
5 
6#include <memory>
7#include <type_traits>
8#include <utility>
9#include <vector>
10 
11namespace Common {
12 
13template <typename T>
14 requires std::is_destructible_v<T>
15class ObjectPool {
16public:
17 explicit ObjectPool(size_t chunk_size = 8192) : new_chunk_size{chunk_size} {
18 node = &chunks.emplace_back(new_chunk_size);
19 }
20 
21 template <typename... Args>
22 requires std::is_constructible_v<T, Args...>
23 [[nodiscard]] T* Create(Args&&... args) {
24 return std::construct_at(Memory(), std::forward<Args>(args)...);
25 }
26 
27 void ReleaseContents() {
28 if (chunks.empty()) {
29 return;
30 }
31 Chunk& root{chunks.front()};
32 if (root.used_objects == root.num_objects) {
33 // Root chunk has been filled, squash allocations into it
34 const size_t total_objects{root.num_objects + new_chunk_size * (chunks.size() - 1)};
35 chunks.clear();
36 chunks.emplace_back(total_objects);
37 } else {
38 root.Release();
39 chunks.resize(1);
40 }
41 chunks.shrink_to_fit();
42 node = &chunks.front();
43 }
44 
45private:
46 struct NonTrivialDummy {
47 NonTrivialDummy() noexcept {}
48 };
49 
50 union Storage {
51 Storage() noexcept {}
52 ~Storage() noexcept {}
53 
54 NonTrivialDummy dummy{};
55 T object;
56 };
57 
58 struct Chunk {
59 explicit Chunk() = default;
60 explicit Chunk(size_t size)
61 : num_objects{size}, storage{std::make_unique<Storage[]>(size)} {}
62 
63 Chunk& operator=(Chunk&& rhs) noexcept {
64 Release();
65 used_objects = std::exchange(rhs.used_objects, 0);
66 num_objects = std::exchange(rhs.num_objects, 0);
67 storage = std::move(rhs.storage);
68 return *this;
69 }
70 
71 Chunk(Chunk&& rhs) noexcept
72 : used_objects{std::exchange(rhs.used_objects, 0)},
73 num_objects{std::exchange(rhs.num_objects, 0)}, storage{std::move(rhs.storage)} {}
74 
75 ~Chunk() {
76 Release();
77 }
78 
79 void Release() {
80 std::destroy_n(storage.get(), used_objects);
81 used_objects = 0;
82 }
83 
84 size_t used_objects{};
85 size_t num_objects{};
86 std::unique_ptr<Storage[]> storage;
87 };
88 
89 [[nodiscard]] T* Memory() {
90 Chunk* const chunk{FreeChunk()};
91 return &chunk->storage[chunk->used_objects++].object;
92 }
93 
94 [[nodiscard]] Chunk* FreeChunk() {
95 if (node->used_objects != node->num_objects) {
96 return node;
97 }
98 node = &chunks.emplace_back(new_chunk_size);
99 return node;
100 }
101 
102 Chunk* node{};
103 std::vector<Chunk> chunks;
104 size_t new_chunk_size{};
105};
106 
107} // namespace Common
108