Skip to main content

BufferPool

Struct BufferPool 

Source
pub struct BufferPool { /* private fields */ }
Expand description

Buffer pool for coordinate processing operations.

Manages a pool of reusable Vec<f64> buffers to minimize memory allocations during repeated coordinate calculations. This is particularly beneficial for iterative processing of large datasets or real-time applications.

§Performance Benefits

  • Reduced allocations: Reuses buffers instead of allocating new ones
  • Memory locality: Keeps buffer capacity to avoid repeated growth
  • Pool management: Limits pool size to prevent unbounded memory growth
  • RAII safety: Automatic buffer return via scoped operations

§Usage Patterns

The pool supports two usage patterns:

  1. Manual management: get_buffer() and return_buffer()
  2. Scoped operations: with_buffer() for automatic lifecycle management

§Examples

use rapidgeo_distance::format_batch::buffer_pool::BufferPool;
use rapidgeo_distance::LngLat;

// Create pool with initial buffer capacity of 1000 elements
let mut pool = BufferPool::new(1000);

// Scoped operation (recommended)
let result = pool.with_buffer(|buffer| {
    // Use buffer for calculations
    buffer.extend([1.0, 2.0, 3.0]);
    buffer.len()
}); // Buffer automatically returned to pool

assert_eq!(result, 3);
assert_eq!(pool.pool_size(), 1); // Buffer was returned

§Memory Management

  • Buffers are cleared (length set to 0) when returned, but capacity is preserved
  • Pool size is capped to prevent unbounded growth
  • Dropped buffers are not returned to the pool once capacity is reached

§Thread Safety

This pool is not thread-safe. Use separate pools per thread or add synchronization for concurrent access.

§See Also

Implementations§

Source§

impl BufferPool

Source

pub fn new(initial_capacity: usize) -> Self

Creates a new buffer pool with the specified initial buffer capacity.

§Arguments
  • initial_capacity - The initial capacity (in elements) for new buffers
§Examples
use rapidgeo_distance::format_batch::buffer_pool::BufferPool;

// Pool for processing up to 1000 coordinate pairs
let pool = BufferPool::new(1000);
assert_eq!(pool.pool_size(), 0); // No buffers initially
§Default Settings
  • Maximum pool size: 8 buffers
  • Initial pool size: 0 buffers (created on demand)
Source

pub fn with_max_size(initial_capacity: usize, max_pool_size: usize) -> Self

Creates a new buffer pool with custom capacity and pool size limits.

§Arguments
  • initial_capacity - The initial capacity (in elements) for new buffers
  • max_pool_size - Maximum number of buffers to keep in the pool
§Examples
use rapidgeo_distance::format_batch::buffer_pool::BufferPool;

// Pool for memory-constrained environments
let pool = BufferPool::with_max_size(500, 4);
assert_eq!(pool.pool_size(), 0);
§Pool Size Considerations
  • Small pools (1-4): Lower memory usage, more allocations
  • Large pools (8-16): Higher memory usage, fewer allocations
  • Very large pools (>16): Diminishing returns, potential memory waste
Source

pub fn get_buffer(&mut self) -> Vec<f64>

Gets a buffer from the pool, creating a new one if the pool is empty.

The returned buffer is empty (length 0) but may have existing capacity from previous use. You must call return_buffer when finished to return it to the pool.

§Returns

An empty Vec<f64> ready for use

§Examples
use rapidgeo_distance::format_batch::buffer_pool::BufferPool;

let mut pool = BufferPool::new(100);

let mut buffer = pool.get_buffer();
assert_eq!(buffer.len(), 0);
assert!(buffer.capacity() >= 100);

buffer.push(42.0);
pool.return_buffer(buffer);
§Performance Notes
  • Reused buffers retain their capacity from previous use
  • New buffers are allocated with the pool’s initial capacity
  • Consider using with_buffer for automatic management
Source

pub fn return_buffer(&mut self, buffer: Vec<f64>)

Returns a buffer to the pool for reuse.

The buffer is cleared (length set to 0) but capacity is preserved. If the pool is full, the buffer is dropped instead of being stored.

§Arguments
  • buffer - The buffer to return (will be cleared)
§Examples
use rapidgeo_distance::format_batch::buffer_pool::BufferPool;

let mut pool = BufferPool::new(50);

let mut buffer = pool.get_buffer();
buffer.extend([1.0, 2.0, 3.0]);

pool.return_buffer(buffer);
assert_eq!(pool.pool_size(), 1);

// Buffer is cleared but capacity preserved
let buffer2 = pool.get_buffer();
assert_eq!(buffer2.len(), 0);
§Pool Capacity

Buffers are only stored if there’s room in the pool:

use rapidgeo_distance::format_batch::buffer_pool::BufferPool;

let mut pool = BufferPool::with_max_size(50, 2); // Max 2 buffers

let buf1 = pool.get_buffer();
let buf2 = pool.get_buffer();
pool.return_buffer(buf1);
pool.return_buffer(buf2);
assert_eq!(pool.pool_size(), 2);

// Third buffer is dropped, not stored
let buf3 = pool.get_buffer();
pool.return_buffer(buf3);
assert_eq!(pool.pool_size(), 2); // Still 2
Source

pub fn with_buffer<F, R>(&mut self, f: F) -> R
where F: FnOnce(&mut Vec<f64>) -> R,

Executes a closure with a temporary buffer, automatically managing its lifecycle.

This is the recommended way to use the buffer pool as it ensures the buffer is always returned, even if the closure panics or returns early.

§Arguments
  • f - Closure that receives a mutable buffer reference
§Returns

The result of the closure

§Examples
use rapidgeo_distance::format_batch::buffer_pool::BufferPool;

let mut pool = BufferPool::new(100);

let sum = pool.with_buffer(|buffer| {
    buffer.extend([1.0, 2.0, 3.0, 4.0, 5.0]);
    buffer.iter().sum::<f64>()
});

assert_eq!(sum, 15.0);
assert_eq!(pool.pool_size(), 1); // Buffer was returned
§Error Safety

The buffer is returned to the pool even if the closure panics:

use rapidgeo_distance::format_batch::buffer_pool::BufferPool;

let mut pool = BufferPool::new(100);

pool.with_buffer(|_buffer| {
    panic!("Something went wrong!");
});
§Performance Benefits
  • No manual tracking: Impossible to forget buffer return
  • Exception safety: Buffer returned even on panic
  • Zero overhead: Inlined closure execution
Source

pub fn pairwise_haversine_iter<I>(&mut self, iter: I) -> Vec<f64>
where I: Iterator<Item = LngLat>,

Computes pairwise Haversine distances using a pooled buffer.

Calculates the distance between consecutive coordinate pairs using the Haversine formula. The result buffer is obtained from the pool but not returned automatically - you own the returned vector.

§Arguments
  • iter - Iterator over LngLat coordinates
§Returns

Vector of distances in meters between consecutive coordinate pairs

§Examples
use rapidgeo_distance::format_batch::buffer_pool::BufferPool;
use rapidgeo_distance::LngLat;

let mut pool = BufferPool::new(100);

let coords = [
    LngLat::new_deg(-122.4194, 37.7749), // San Francisco
    LngLat::new_deg(-74.0060, 40.7128),  // New York
    LngLat::new_deg(-87.6298, 41.8781),  // Chicago
];

let distances = pool.pairwise_haversine_iter(coords.iter().copied());
assert_eq!(distances.len(), 2); // n-1 distances for n points

// SF to NYC is approximately 4100km
assert!(distances[0] > 4_000_000.0 && distances[0] < 4_200_000.0);
§Performance
  • Buffer reuse: Uses pooled buffer for intermediate calculations
  • Single allocation: Result vector allocated once with appropriate capacity
  • Lazy evaluation: Iterator is consumed on-demand
§See Also
Source

pub fn pairwise_haversine_any<T: CoordSource>(&mut self, coords: &T) -> Vec<f64>

Computes pairwise Haversine distances from any coordinate source using a pooled buffer.

Accepts any type implementing CoordSource (tuples, arrays, etc.) and computes distances between consecutive coordinates. Automatically handles format detection and conversion as needed.

§Arguments
  • coords - Any coordinate source (Vec, Vec<(f64,f64)>, Vec, etc.)
§Returns

Vector of distances in meters between consecutive coordinate pairs

§Examples
use rapidgeo_distance::format_batch::buffer_pool::BufferPool;
use rapidgeo_distance::LngLat;

let mut pool = BufferPool::new(100);

// Works with various coordinate formats
let coords_lnglat = vec![
    LngLat::new_deg(-122.4194, 37.7749),
    LngLat::new_deg(-74.0060, 40.7128),
];
let distances1 = pool.pairwise_haversine_any(&coords_lnglat);

let coords_tuples = vec![
    (-122.4194, 37.7749),
    (-74.0060, 40.7128),
];
let distances2 = pool.pairwise_haversine_any(&coords_tuples);

// Results should be identical
assert!((distances1[0] - distances2[0]).abs() < 1e-10);
§Format Support

Supports all coordinate formats:

  • Vec<LngLat> - Native format
  • Vec<(f64, f64)> - Tuples with format detection
  • Vec<f64> - Flat arrays (chunked into pairs)
  • &[f64] - Array slices
§See Also
Source

pub fn pairwise_haversine_par_iter<I>(&mut self, iter: I) -> Vec<f64>
where I: Iterator<Item = LngLat>,

Source

pub fn pairwise_haversine_par_any<T: CoordSource + Sync>( &mut self, coords: &T, ) -> Vec<f64>

Source

pub fn pool_size(&self) -> usize

Returns the number of buffers currently stored in the pool.

This count represents available buffers ready for reuse. It will be between 0 and the maximum pool size configured during construction.

§Examples
use rapidgeo_distance::format_batch::buffer_pool::BufferPool;

let mut pool = BufferPool::new(100);
assert_eq!(pool.pool_size(), 0); // Initially empty

let buffer = pool.get_buffer();
assert_eq!(pool.pool_size(), 0); // Buffer checked out

pool.return_buffer(buffer);
assert_eq!(pool.pool_size(), 1); // Buffer returned
§Use Cases
  • Debugging: Verify buffers are being returned properly
  • Monitoring: Track pool utilization in long-running applications
  • Testing: Ensure proper resource management in tests
Source

pub fn clear_pool(&mut self)

Removes all buffers from the pool, freeing their memory.

This is useful for releasing memory when the pool won’t be used for an extended period, or for cleanup in tests and benchmarks.

§Examples
use rapidgeo_distance::format_batch::buffer_pool::BufferPool;

let mut pool = BufferPool::new(100);

// Use some buffers
let buf1 = pool.get_buffer();
let buf2 = pool.get_buffer();
pool.return_buffer(buf1);
pool.return_buffer(buf2);
assert_eq!(pool.pool_size(), 2);

// Clear all buffers
pool.clear_pool();
assert_eq!(pool.pool_size(), 0);
§Memory Impact

After clearing, subsequent get_buffer() calls will allocate new buffers with the pool’s configured initial capacity. This may cause temporary performance degradation until the pool is rebuilt.

§Use Cases
  • Memory pressure: Free memory when pool is idle
  • Test cleanup: Reset pool state between test cases
  • Capacity changes: Clear before changing buffer sizing strategy

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.