unilink  0.4.3
A simple C++ library for unified async communication
memory_pool.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2025 Jinwoo Sung
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <array>
20 #include <atomic>
21 #include <chrono>
22 #include <cstddef>
23 #include <memory>
24 #include <mutex>
25 #include <string>
26 #include <unordered_map>
27 #include <vector>
28 
30 
31 namespace unilink {
32 namespace memory {
33 
44  public:
45  // Basic statistics
46  struct PoolStats {
47  size_t total_allocations{0};
48  size_t pool_hits{0};
49  };
50 
51  // Basic health metrics
52  struct HealthMetrics {
53  double hit_rate{0.0};
54  };
55 
56  // Predefined buffer sizes for common use cases
57  enum class BufferSize : size_t {
58  SMALL = 1024, // 1KB - small messages
59  MEDIUM = 4096, // 4KB - typical network packets
60  LARGE = 16384, // 16KB - large data transfers
61  XLARGE = 65536 // 64KB - bulk operations
62  };
63 
64  explicit MemoryPool(size_t initial_pool_size = 400, size_t max_pool_size = 2000);
65  ~MemoryPool() = default;
66 
67  // Non-copyable, non-movable
68  MemoryPool(const MemoryPool&) = delete;
69  MemoryPool& operator=(const MemoryPool&) = delete;
70  MemoryPool(MemoryPool&&) = delete;
72 
73  std::unique_ptr<uint8_t[]> acquire(size_t size);
74  std::unique_ptr<uint8_t[]> acquire(BufferSize buffer_size);
75  void release(std::unique_ptr<uint8_t[]> buffer, size_t size);
76  PoolStats get_stats() const;
77  double get_hit_rate() const;
78  void cleanup_old_buffers(std::chrono::milliseconds max_age = std::chrono::minutes(5));
79  std::pair<size_t, size_t> get_memory_usage() const;
80  void resize_pool(size_t new_size);
81  void auto_tune();
82  HealthMetrics get_health_metrics() const;
83 
84  private:
85  // Simple pool bucket
86  struct PoolBucket {
87  std::vector<std::unique_ptr<uint8_t[]>> buffers_;
88  mutable std::mutex mutex_;
89  size_t size_;
90  size_t capacity_;
91 
92  PoolBucket() : size_{0}, capacity_{0} {}
93  PoolBucket(PoolBucket&& other) noexcept;
94  PoolBucket& operator=(PoolBucket&& other) noexcept;
95  PoolBucket(const PoolBucket&) = delete;
96  PoolBucket& operator=(const PoolBucket&) = delete;
97  };
98 
99  std::array<PoolBucket, 4> buckets_; // For SMALL, MEDIUM, LARGE, XLARGE
100 
101  // Internal statistics (atomic for thread safety)
102  std::atomic<size_t> total_allocations_{0};
103  std::atomic<size_t> pool_hits_{0};
104 
105  // Helper functions
106  PoolBucket& get_bucket(size_t size);
107  size_t get_bucket_index(size_t size) const;
108 
109  // Allocation functions
110  std::unique_ptr<uint8_t[]> acquire_from_bucket(PoolBucket& bucket);
111  std::unique_ptr<uint8_t[]> create_buffer(size_t size);
112 
113  // Release functions
114  void release_to_bucket(PoolBucket& bucket, std::unique_ptr<uint8_t[]> buffer);
115 
116  // Utility functions
117  void validate_size(size_t size) const;
118 };
119 
124  public:
125  static MemoryPool& instance() {
126  static MemoryPool pool;
127  return pool;
128  }
129 
130  // Factory method to create optimized memory pool
131  static std::unique_ptr<MemoryPool> create_optimized() {
132  return std::make_unique<MemoryPool>(800, 4000); // Optimized default sizes
133  }
134 
135  // Factory method to create size-optimized memory pool
136  static std::unique_ptr<MemoryPool> create_size_optimized() {
137  return std::make_unique<MemoryPool>(1200, 6000); // Even larger for better concurrency
138  }
139 
140  // Non-copyable, non-movable
141  GlobalMemoryPool() = delete;
144 };
145 
150  public:
151  explicit PooledBuffer(size_t size);
152  explicit PooledBuffer(MemoryPool::BufferSize buffer_size);
153  ~PooledBuffer();
154 
155  // Non-copyable, movable
156  PooledBuffer(const PooledBuffer&) = delete;
158  PooledBuffer(PooledBuffer&& other) noexcept;
159  PooledBuffer& operator=(PooledBuffer&& other) noexcept;
160 
161  // Safe access methods
162  uint8_t* data() const;
163  size_t size() const;
164  bool valid() const;
165 
166  // Safe array access with bounds checking
167  uint8_t& operator[](size_t index);
168  const uint8_t& operator[](size_t index) const;
169 
170  // Safe array access with bounds checking
171  uint8_t& at(size_t index);
172  const uint8_t& at(size_t index) const;
173 
174  // Explicit conversion methods (no implicit conversion)
175  uint8_t* get() const { return data(); }
176  explicit operator bool() const { return valid(); }
177 
178  private:
179  std::unique_ptr<uint8_t[]> buffer_;
180  size_t size_;
181  MemoryPool* pool_;
182 
183  // Helper for bounds checking
184  void check_bounds(size_t index) const;
185 };
186 
187 } // namespace memory
188 } // namespace unilink
#define UNILINK_API
Definition: visibility.hpp:37