#![allow(dead_code)]
use parking_lot::Mutex;
use std::collections::VecDeque;
use std::sync::Arc;
pub struct ObjectPool<T> {
pool: Arc<Mutex<VecDeque<T>>>,
factory: Box<dyn Fn() -> T + Send + Sync>,
max_size: usize,
}
impl<T> ObjectPool<T>
where
T: Send + 'static,
{
pub fn new<F>(factory: F, max_size: usize) -> Self
where
F: Fn() -> T + Send + Sync + 'static,
{
Self {
pool: Arc::new(Mutex::new(VecDeque::new())),
factory: Box::new(factory),
max_size,
}
}
pub fn get(&self) -> PooledObject<T> {
let obj = {
let mut pool = self.pool.lock();
pool.pop_front().unwrap_or_else(|| (self.factory)())
};
PooledObject {
obj: Some(obj),
pool: Arc::clone(&self.pool),
max_size: self.max_size,
}
}
pub fn size(&self) -> usize {
self.pool.lock().len()
}
pub fn clear(&self) {
self.pool.lock().clear();
}
}
pub struct PooledObject<T> {
obj: Option<T>,
pool: Arc<Mutex<VecDeque<T>>>,
max_size: usize,
}
impl<T> PooledObject<T> {
pub fn as_ref(&self) -> &T {
self.obj.as_ref().expect("Object already taken")
}
pub fn as_mut(&mut self) -> &mut T {
self.obj.as_mut().expect("Object already taken")
}
pub fn take(mut self) -> T {
self.obj.take().expect("Object already taken")
}
}
impl<T> std::ops::Deref for PooledObject<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.as_ref()
}
}
impl<T> std::ops::DerefMut for PooledObject<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut()
}
}
impl<T> Drop for PooledObject<T> {
fn drop(&mut self) {
if let Some(obj) = self.obj.take() {
let mut pool = self.pool.lock();
if pool.len() < self.max_size {
pool.push_back(obj);
}
}
}
}
pub struct BufferPool {
pool: ObjectPool<Vec<u8>>,
default_capacity: usize,
}
impl BufferPool {
pub fn new(default_capacity: usize, max_pooled: usize) -> Self {
let pool = ObjectPool::new(move || Vec::with_capacity(default_capacity), max_pooled);
Self {
pool,
default_capacity,
}
}
pub fn get(&self) -> PooledBuffer {
let mut buffer = self.pool.get();
buffer.clear(); PooledBuffer { buffer }
}
pub fn get_with_capacity(&self, capacity: usize) -> PooledBuffer {
let mut buffer = self.pool.get();
buffer.clear();
let current_capacity = buffer.capacity();
if current_capacity < capacity {
buffer.reserve(capacity - current_capacity);
}
PooledBuffer { buffer }
}
}
pub struct PooledBuffer {
buffer: PooledObject<Vec<u8>>,
}
impl PooledBuffer {
pub fn len(&self) -> usize {
self.buffer.len()
}
pub fn is_empty(&self) -> bool {
self.buffer.is_empty()
}
pub fn capacity(&self) -> usize {
self.buffer.capacity()
}
pub fn clear(&mut self) {
self.buffer.as_mut().clear();
}
pub fn extend_from_slice(&mut self, data: &[u8]) {
self.buffer.as_mut().extend_from_slice(data);
}
pub fn as_slice(&self) -> &[u8] {
self.buffer.as_ref().as_slice()
}
pub fn into_vec(self) -> Vec<u8> {
self.buffer.take()
}
}
impl std::ops::Deref for PooledBuffer {
type Target = Vec<u8>;
fn deref(&self) -> &Self::Target {
&self.buffer
}
}
impl std::ops::DerefMut for PooledBuffer {
fn deref_mut(&mut self) -> &mut Self::Target {
self.buffer.as_mut()
}
}
pub struct OptimizedStringPool {
small_strings: ObjectPool<String>, medium_strings: ObjectPool<String>, large_strings: ObjectPool<String>, }
impl OptimizedStringPool {
pub fn new() -> Self {
Self {
small_strings: ObjectPool::new(|| String::with_capacity(64), 100),
medium_strings: ObjectPool::new(|| String::with_capacity(256), 50),
large_strings: ObjectPool::new(|| String::with_capacity(1024), 20),
}
}
pub fn get_string(&self, estimated_size: usize) -> PooledString {
let pooled = if estimated_size < 64 {
PooledStringType::Small(self.small_strings.get())
} else if estimated_size < 256 {
PooledStringType::Medium(self.medium_strings.get())
} else {
PooledStringType::Large(self.large_strings.get())
};
let mut string = PooledString { inner: pooled };
string.clear();
string
}
}
impl Default for OptimizedStringPool {
fn default() -> Self {
Self::new()
}
}
pub struct PooledString {
inner: PooledStringType,
}
enum PooledStringType {
Small(PooledObject<String>),
Medium(PooledObject<String>),
Large(PooledObject<String>),
}
impl PooledString {
pub fn clear(&mut self) {
match &mut self.inner {
PooledStringType::Small(s) => s.clear(),
PooledStringType::Medium(s) => s.clear(),
PooledStringType::Large(s) => s.clear(),
}
}
pub fn len(&self) -> usize {
match &self.inner {
PooledStringType::Small(s) => s.len(),
PooledStringType::Medium(s) => s.len(),
PooledStringType::Large(s) => s.len(),
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn push_str(&mut self, s: &str) {
match &mut self.inner {
PooledStringType::Small(string) => string.push_str(s),
PooledStringType::Medium(string) => string.push_str(s),
PooledStringType::Large(string) => string.push_str(s),
}
}
pub fn into_string(self) -> String {
match self.inner {
PooledStringType::Small(s) => s.take(),
PooledStringType::Medium(s) => s.take(),
PooledStringType::Large(s) => s.take(),
}
}
}
impl std::ops::Deref for PooledString {
type Target = str;
fn deref(&self) -> &Self::Target {
match &self.inner {
PooledStringType::Small(s) => s.as_str(),
PooledStringType::Medium(s) => s.as_str(),
PooledStringType::Large(s) => s.as_str(),
}
}
}
impl std::fmt::Display for PooledString {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.inner {
PooledStringType::Small(s) => write!(f, "{}", s.as_str()),
PooledStringType::Medium(s) => write!(f, "{}", s.as_str()),
PooledStringType::Large(s) => write!(f, "{}", s.as_str()),
}
}
}
use once_cell::sync::Lazy;
pub static BUFFER_POOL: Lazy<BufferPool> = Lazy::new(|| BufferPool::new(1024, 50));
pub static STRING_POOL: Lazy<OptimizedStringPool> = Lazy::new(OptimizedStringPool::new);
pub fn get_buffer() -> PooledBuffer {
BUFFER_POOL.get()
}
pub fn get_buffer_with_capacity(capacity: usize) -> PooledBuffer {
BUFFER_POOL.get_with_capacity(capacity)
}
pub fn get_string(estimated_size: usize) -> PooledString {
STRING_POOL.get_string(estimated_size)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_object_pool() {
let pool = ObjectPool::new(|| Vec::<i32>::new(), 2);
{
let mut obj1 = pool.get();
obj1.push(1);
assert_eq!(obj1.len(), 1);
}
assert_eq!(pool.size(), 1);
let obj2 = pool.get();
assert_eq!(obj2.len(), 0); }
#[test]
fn test_buffer_pool() {
let pool = BufferPool::new(64, 5);
{
let mut buffer = pool.get();
buffer.extend_from_slice(b"hello");
assert_eq!(buffer.len(), 5);
}
let buffer2 = pool.get();
assert_eq!(buffer2.len(), 0); }
#[test]
fn test_string_pool() {
let pool = OptimizedStringPool::new();
{
let mut string = pool.get_string(10);
string.push_str("hello");
assert_eq!(string.len(), 5);
}
let string2 = pool.get_string(10);
assert_eq!(string2.len(), 0); }
}