Advertisement
Guest User

Untitled

a guest
Apr 22nd, 2019
92
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.89 KB | None | 0 0
  1. use std::sync::atomic::{ self, AtomicUsize };
  2. use std::ptr;
  3. use std::mem;
  4. use std::slice;
  5. use std::ops;
  6. use std::fmt;
  7.  
  8. struct CowStringMeta {
  9. refctr: AtomicUsize,
  10. allocd: usize,
  11. }
  12.  
  13. pub struct CowString {
  14. begn: ptr::NonNull<u8>,
  15. leng: usize,
  16. meta: *mut CowStringMeta,
  17. }
  18.  
  19. const SOM: usize = mem::size_of::<CowStringMeta>();
  20.  
  21. static NULLBYTE: u8 = 0;
  22.  
  23.  
  24. // Invariants:
  25. //
  26. // (self.meta.is_null() && self.leng == 0) || !self.meta.is_null()
  27. //
  28. // !meta.is_null() = we allocated and own some memory (shared ownership)
  29. //
  30. // meta.is_null() || (*meta.refctr > 1) implies sharing, in which case
  31. // the data is only accessed in read-only fasion with the exception of
  32. // the atomic reference counter.
  33.  
  34. impl CowString {
  35. pub fn new() -> Self {
  36. // Using *mut here is fine because we guarantee never to
  37. // write to the byte buffer if it is shared. And it's considered
  38. // shared because we initialize meta as null pointer.
  39. let t = unsafe { ptr::NonNull::new_unchecked(&NULLBYTE as *const _ as *mut _) };
  40. CowString {
  41. begn: t,
  42. leng: 0,
  43. meta: ptr::null_mut(),
  44. }
  45. }
  46.  
  47. pub fn capacity(&self) -> usize {
  48. let m: *const CowStringMeta = self.meta;
  49. if m.is_null() {
  50. 0
  51. } else {
  52. unsafe { &*m }.allocd
  53. }
  54. }
  55. }
  56.  
  57. impl Clone for CowString {
  58. fn clone(&self) -> Self {
  59. let m: *const CowStringMeta = self.meta;
  60. if !m.is_null() {
  61. unsafe { &*m }.refctr.fetch_add(1, atomic::Ordering::AcqRel);
  62. println!("Increased reference counter");
  63. }
  64. CowString {
  65. begn: self.begn,
  66. leng: self.leng,
  67. meta: self.meta,
  68. }
  69. }
  70. }
  71.  
  72. impl Drop for CowString {
  73. fn drop(&mut self) {
  74. let m: *const CowStringMeta = self.meta;
  75. if !m.is_null() { // allocation with reference counter
  76. let old = unsafe { &*m }.refctr.fetch_sub(1, atomic::Ordering::AcqRel);
  77. println!("Lowered reference counter");
  78. if old == 1 { // we are the sole owner
  79. drop( unsafe {
  80. Vec::from_raw_parts(
  81. self.meta,
  82. 1,
  83. 1 + (*self.meta).allocd / SOM)
  84. } );
  85. println!("Deallocated buffer");
  86. }
  87. }
  88. }
  89. }
  90.  
  91. impl ops::Deref for CowString {
  92. type Target = str;
  93.  
  94. fn deref(&self) -> &str {
  95. unsafe {
  96. std::str::from_utf8_unchecked(
  97. slice::from_raw_parts(self.begn.as_ptr(), self.leng)
  98. )
  99. }
  100. }
  101. }
  102.  
  103. impl ops::DerefMut for CowString {
  104. fn deref_mut(&mut self) -> &mut str {
  105. unsafe {
  106. std::str::from_utf8_unchecked_mut(
  107. slice::from_raw_parts_mut(self.begn.as_ptr(), self.leng)
  108. )
  109. }
  110. }
  111. }
  112.  
  113. impl<'a> From<&'a str> for CowString {
  114. fn from(s: &'a str) -> Self {
  115. let capa_metas = (s.len() + SOM - 1) / SOM;
  116. let capa_bytes = capa_metas * SOM;
  117. let mut v: Vec<CowStringMeta> = Vec::with_capacity(1 + capa_metas);
  118. println!("Allocated buffer");
  119. v.push( CowStringMeta {
  120. refctr: AtomicUsize::new(1),
  121. allocd: capa_bytes,
  122. } );
  123. let meta_p = v.as_mut_ptr();
  124. let byte_p = unsafe { meta_p.add(1) as *mut u8 };
  125. if s.len() > 0 { unsafe {
  126. ptr::copy_nonoverlapping(s.as_ptr(), byte_p, s.len());
  127. } }
  128. println!("I copied data");
  129. mem::forget(v);
  130. CowString {
  131. begn: unsafe { ptr::NonNull::new_unchecked(byte_p) },
  132. leng: s.len(),
  133. meta: meta_p,
  134. }
  135. }
  136. }
  137.  
  138. impl fmt::Display for CowString {
  139. fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
  140. <str as fmt::Display>::fmt(self, f)
  141. }
  142. }
  143.  
  144. fn main() {
  145. let cs = CowString::from("Hello, World!");
  146. let y = cs.clone();
  147. println!("{}\n{}", cs, y);
  148. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement