README.md 4.9 KB

XArray

XArray is an abstract data type functioning like an expansive array of items where each item must be an 8-byte object, such as Arc<T> or Box<T>. User-stored pointers must have a minimum alignment of 4 bytes. XArray facilitates efficient sequential access to adjacent entries, supporting multiple concurrent reads and exclusively allowing one write operation at a time.

Features

  • Cursors: Provide cursors for precise and efficient iteration over the array. Cursors have both immutable and mutable versions. One can hold multiple immutable cursors or hold a mutable cursor exclusively at a time.
  • Marking: Provide ability to mark entries and the XArray itself for easy state tracking.
  • Generics: Generic implementation that can work with any entry type and any inner locks that fits the use case.
  • Copy-on-Write (COW): Efficient cloning of XArrays with shared structure until mutation.

Installation

Add this to your Cargo.toml:

[dependencies]
xarray = "0.1.0"

Usage

This crate is developed in no_std environment, but std users can still use this crate with --feature="std":

The following section covers how to interact with XArray including creating an XArray, using cursors, marking, cloning, and more.

Creating an XArray:

  • Users should declare the type of items (Arc) stored in the XArray and the lock (StdMutex) used inside the XArray. Note that StdMutex is an abstraction for std::sync::Mutex.
  • The type of stored item must implement ItemEntry trait and the used lock abstraction must be generated by the macro abstract_lock_to!. The real lock type that be abstracted should implement ValidLock trait.
  • We implement ItemEntry for alloc::sync::Arc and alloc::sync::Box by default, and abstract std::sync::Mutex and std::sync::RwLock as StdMutex and StdRwLock for std users, respectively

    extern crate alloc;
    
    use alloc::sync::Arc;
    use xarray::{XArray, StdMutex};
    
    // Create a new XArray instance
    let mut xarray: XArray<Arc<i32>, StdMutex> = XArray::new();
    
  • Using Cursor

    extern crate alloc;
    
    use alloc::sync::Arc;
    use xarray::{XArray, StdMutex};
    
    let mut xarray_arc: XArray<Arc<i32>, StdMutex> = XArray::new();
    
    let mut cursor = xarray_arc.cursor_mut(0);
    // Store the Arc at the index range 0~10000.
    for i in 0..10000 {
        let value = Arc::new(i * 2);
        cursor.store(value);
        cursor.next();
    }
    
    cursor.reset_to(0);
    for i in 0..10000 {
        let value = cursor.load().unwrap();
        assert!(*value.as_ref() == i * 2);
        cursor.next();
    }
    

    Using Marks

    • Items and the XArray can have up to three distinct marks by default, with each mark independently maintained.
    • Users need to use a struct to represent the marks that need to be used. For the situation where multiple marks are required, these marks are typically encapsulated within an enumeration class.
    • This struct for marks should implement Into<XMark> trait and be declared in the generics list of XArray.

      extern crate alloc;
      
      use alloc::sync::Arc;
      use xarray::{XArray, XMark, StdMutex};
      
      #[derive(Clone, Copy)]
      enum MarkDemo {
      Mark0,
      Mark1,
      Mark2,
      }
      
      impl Into<XMark> for MarkDemo {
      fn into(self) -> XMark {
          match self {
              MarkDemo::Mark0 => XMark::Mark0,
              MarkDemo::Mark1 => XMark::Mark1,
              MarkDemo::Mark2 => XMark::Mark2,
          }
      }
      }
      
      let mut xarray_arc: XArray<Arc<i32>, StdMutex, MarkDemo> = XArray::new();
      // Mark the xarray with Mark1.
      xarray_arc.set_mark(MarkDemo::Mark0);
      assert!(xarray_arc.is_marked(MarkDemo::Mark0));
      
      let mut cursor = xarray_arc.cursor_mut(1000);
      let value = Arc::new(i * 2);
      cursor.store(value);
      
      // Mark the item with Mark1.
      cursor.set_mark(MarkDemo::Mark1).unwrap();
      assert!(cursor.is_marked(MarkDemo::Mark1));
      

    Copy-On-Write (COW) Clone

    use std::sync::Arc;
    use xarray::{XArray, StdMutex};
    
    let mut xarray: XArray<Arc<i32>, StdMutex> = XArray::new();
    
    // Store values
    let value = Arc::new(10);
    xarray.store(333, value.clone());
    assert_eq!(*xarray.load(333).unwrap().as_ref(), 10);
    
    // Clone the XArray
    let mut xarray_clone = xarray.clone();
    assert_eq!(*xarray_clone.load(333).unwrap().as_ref(), 10);
    
    // Store a new value in the clone
    let new_value = Arc::new(100);
    xarray_clone.store(333, new_value);
    
    // The original XArray is unaffected by changes in the clone
    assert_eq!(*xarray.load(333).unwrap().as_ref(), 10);
    assert_eq!(*xarray_clone.load(333).unwrap().as_ref(), 100);
    

    Iteration

    use std::sync::Arc;
    use xarray::{XArray, StdMutex};
    
    let mut xarray: XArray<Arc<i32>, StdMutex> = XArray::new();
    
    // Store item to even index in the range 100~200.
    for i in 100..200 {
        if i % 2 == 0 {
            let value = Arc::new(i * 2);
            cursor.store(value);
        }
        cursor.next();
    }
    
    // Iterate at the range 100~200.
    let mut count = 0;
    for item in xarray.range(100..200) {
        count += 1;
    }
    assert_eq!(count == 50);
    

    License