Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- use std::sync::atomic::{ self, AtomicUsize };
- use std::ptr;
- use std::mem;
- use std::slice;
- use std::ops;
- use std::fmt;
- struct CowStringMeta {
- refctr: AtomicUsize,
- allocd: usize,
- }
- pub struct CowString {
- begn: ptr::NonNull<u8>,
- leng: usize,
- meta: *mut CowStringMeta,
- }
- const SOM: usize = mem::size_of::<CowStringMeta>();
- static NULLBYTE: u8 = 0;
- // Invariants:
- //
- // (self.meta.is_null() && self.leng == 0) || !self.meta.is_null()
- //
- // !meta.is_null() = we allocated and own some memory (shared ownership)
- //
- // meta.is_null() || (*meta.refctr > 1) implies sharing, in which case
- // the data is only accessed in read-only fasion with the exception of
- // the atomic reference counter.
- impl CowString {
- pub fn new() -> Self {
- // Using *mut here is fine because we guarantee never to
- // write to the byte buffer if it is shared. And it's considered
- // shared because we initialize meta as null pointer.
- let t = unsafe { ptr::NonNull::new_unchecked(&NULLBYTE as *const _ as *mut _) };
- CowString {
- begn: t,
- leng: 0,
- meta: ptr::null_mut(),
- }
- }
- pub fn capacity(&self) -> usize {
- let m: *const CowStringMeta = self.meta;
- if m.is_null() {
- 0
- } else {
- unsafe { &*m }.allocd
- }
- }
- }
- impl Clone for CowString {
- fn clone(&self) -> Self {
- let m: *const CowStringMeta = self.meta;
- if !m.is_null() {
- unsafe { &*m }.refctr.fetch_add(1, atomic::Ordering::AcqRel);
- println!("Increased reference counter");
- }
- CowString {
- begn: self.begn,
- leng: self.leng,
- meta: self.meta,
- }
- }
- }
- impl Drop for CowString {
- fn drop(&mut self) {
- let m: *const CowStringMeta = self.meta;
- if !m.is_null() { // allocation with reference counter
- let old = unsafe { &*m }.refctr.fetch_sub(1, atomic::Ordering::AcqRel);
- println!("Lowered reference counter");
- if old == 1 { // we are the sole owner
- drop( unsafe {
- Vec::from_raw_parts(
- self.meta,
- 1,
- 1 + (*self.meta).allocd / SOM)
- } );
- println!("Deallocated buffer");
- }
- }
- }
- }
- impl ops::Deref for CowString {
- type Target = str;
- fn deref(&self) -> &str {
- unsafe {
- std::str::from_utf8_unchecked(
- slice::from_raw_parts(self.begn.as_ptr(), self.leng)
- )
- }
- }
- }
- impl ops::DerefMut for CowString {
- fn deref_mut(&mut self) -> &mut str {
- unsafe {
- std::str::from_utf8_unchecked_mut(
- slice::from_raw_parts_mut(self.begn.as_ptr(), self.leng)
- )
- }
- }
- }
- impl<'a> From<&'a str> for CowString {
- fn from(s: &'a str) -> Self {
- let capa_metas = (s.len() + SOM - 1) / SOM;
- let capa_bytes = capa_metas * SOM;
- let mut v: Vec<CowStringMeta> = Vec::with_capacity(1 + capa_metas);
- println!("Allocated buffer");
- v.push( CowStringMeta {
- refctr: AtomicUsize::new(1),
- allocd: capa_bytes,
- } );
- let meta_p = v.as_mut_ptr();
- let byte_p = unsafe { meta_p.add(1) as *mut u8 };
- if s.len() > 0 { unsafe {
- ptr::copy_nonoverlapping(s.as_ptr(), byte_p, s.len());
- } }
- println!("I copied data");
- mem::forget(v);
- CowString {
- begn: unsafe { ptr::NonNull::new_unchecked(byte_p) },
- leng: s.len(),
- meta: meta_p,
- }
- }
- }
- impl fmt::Display for CowString {
- fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- <str as fmt::Display>::fmt(self, f)
- }
- }
- fn main() {
- let cs = CowString::from("Hello, World!");
- let y = cs.clone();
- println!("{}\n{}", cs, y);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement