Add some smart pointers
parent
427ff72e42
commit
51622ba4d6
@ -0,0 +1,215 @@
|
|||||||
|
/*
|
||||||
|
* Created on Sun Jan 29 2023
|
||||||
|
*
|
||||||
|
* This file is a part of Skytable
|
||||||
|
* Skytable (formerly known as TerrabaseDB or Skybase) is a free and open-source
|
||||||
|
* NoSQL database written by Sayan Nandan ("the Author") with the
|
||||||
|
* vision to provide flexibility in data modelling without compromising
|
||||||
|
* on performance, queryability or scalability.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023, Sayan Nandan <ohsayan@outlook.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
use super::atm::{ORD_ACQ, ORD_REL, ORD_RLX};
|
||||||
|
use std::{
|
||||||
|
alloc::{dealloc, Layout},
|
||||||
|
borrow::Borrow,
|
||||||
|
fmt,
|
||||||
|
hash::{Hash, Hasher},
|
||||||
|
mem::{self, ManuallyDrop},
|
||||||
|
ops::Deref,
|
||||||
|
process,
|
||||||
|
ptr::{self, NonNull},
|
||||||
|
slice, str,
|
||||||
|
sync::atomic::{self, AtomicUsize},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub type BytesRC = SliceRC<u8>;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Hash)]
|
||||||
|
pub struct StrRC {
|
||||||
|
base: SliceRC<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StrRC {
|
||||||
|
fn new(base: SliceRC<u8>) -> Self {
|
||||||
|
Self { base }
|
||||||
|
}
|
||||||
|
pub fn from_bx(b: Box<str>) -> Self {
|
||||||
|
let mut md = ManuallyDrop::new(b);
|
||||||
|
Self::new(SliceRC::new(
|
||||||
|
unsafe {
|
||||||
|
// UNSAFE(@ohsayan): nullck + always aligned
|
||||||
|
NonNull::new_unchecked(md.as_mut_ptr())
|
||||||
|
},
|
||||||
|
md.len(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
pub fn as_str(&self) -> &str {
|
||||||
|
unsafe {
|
||||||
|
// UNSAFE(@ohsayan): Ctor guarantees correctness
|
||||||
|
str::from_utf8_unchecked(self.base.as_slice())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for StrRC {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.as_str() == other.as_str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<str> for StrRC {
|
||||||
|
fn eq(&self, other: &str) -> bool {
|
||||||
|
self.as_str() == other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for StrRC {
|
||||||
|
type Target = str;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.as_str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for StrRC {}
|
||||||
|
|
||||||
|
pub struct SliceRC<T> {
|
||||||
|
ptr: NonNull<T>,
|
||||||
|
len: usize,
|
||||||
|
rc: NonNull<AtomicUsize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> SliceRC<T> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn new(ptr: NonNull<T>, len: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
ptr,
|
||||||
|
len,
|
||||||
|
rc: unsafe {
|
||||||
|
// UNSAFE(@ohsayan): box would either fail or return a collect alloc
|
||||||
|
NonNull::new_unchecked(Box::into_raw(Box::new(AtomicUsize::new(0))))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn from_bx(b: Box<[T]>) -> Self {
|
||||||
|
let mut b = ManuallyDrop::new(b);
|
||||||
|
unsafe {
|
||||||
|
// UNSAFE(@ohsayan): non-null from the slice as usual
|
||||||
|
Self::new(NonNull::new_unchecked(b.as_mut_ptr()), b.len())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn as_slice(&self) -> &[T] {
|
||||||
|
unsafe {
|
||||||
|
// UNSAFE(@ohsayan): rc guard + ctor
|
||||||
|
slice::from_raw_parts(self.ptr.as_ptr(), self.len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline(always)]
|
||||||
|
fn _rc(&self) -> &AtomicUsize {
|
||||||
|
unsafe {
|
||||||
|
// UNSAFE(@ohsayan): rc + ctor
|
||||||
|
self.rc.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// SAFETY: Synchronize last man alive
|
||||||
|
#[inline(never)]
|
||||||
|
unsafe fn drop_slow(&self) {
|
||||||
|
// dtor
|
||||||
|
if mem::needs_drop::<T>() {
|
||||||
|
// UNSAFE(@ohsayan): dtor through, the ctor guarantees correct alignment and len
|
||||||
|
ptr::drop_in_place(ptr::slice_from_raw_parts_mut(self.ptr.as_ptr(), self.len));
|
||||||
|
}
|
||||||
|
// dealloc
|
||||||
|
// UNSAFE(@ohsayan): we allocated it
|
||||||
|
let layout = Layout::array::<T>(self.len).unwrap_unchecked();
|
||||||
|
// UNSAFE(@ohsayan): layout structure guaranteed by ctor
|
||||||
|
dealloc(self.ptr.as_ptr() as *mut u8, layout);
|
||||||
|
// UNSAFE(@ohsayan): well cmon, look for yourself
|
||||||
|
drop(Box::from_raw(self.rc.as_ptr()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Drop for SliceRC<T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if self._rc().fetch_sub(1, ORD_REL) != 1 {
|
||||||
|
// not the last man alive
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// emit a fence for sync with stores
|
||||||
|
atomic::fence(ORD_ACQ);
|
||||||
|
unsafe {
|
||||||
|
// UNSAFE(@ohsayan): Confirmed, we're the last one alive
|
||||||
|
self.drop_slow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Clone for SliceRC<T> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
let new_rc = self._rc().fetch_add(1, ORD_RLX);
|
||||||
|
if new_rc > (isize::MAX) as usize {
|
||||||
|
// some incredibly degenerate case; this won't ever happen but who knows if some fella decided to have atomic overflow fun?
|
||||||
|
process::abort();
|
||||||
|
}
|
||||||
|
Self { ..*self }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: fmt::Debug> fmt::Debug for SliceRC<T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_list().entries(self.as_slice()).finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Hash> Hash for SliceRC<T> {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.as_slice().hash(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PartialEq> PartialEq for SliceRC<T> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.as_slice() == other.as_slice()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PartialEq> PartialEq<[T]> for SliceRC<T> {
|
||||||
|
fn eq(&self, other: &[T]) -> bool {
|
||||||
|
self.as_slice() == other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Eq> Eq for SliceRC<T> {}
|
||||||
|
impl<T> Borrow<[T]> for SliceRC<T> {
|
||||||
|
fn borrow(&self) -> &[T] {
|
||||||
|
self.as_slice()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Deref for SliceRC<T> {
|
||||||
|
type Target = [T];
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.as_slice()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T: Send> Send for SliceRC<T> {}
|
||||||
|
unsafe impl<T: Sync> Sync for SliceRC<T> {}
|
Loading…
Reference in New Issue