append-only-vec
Advanced tools
| { | ||
| "git": { | ||
| "sha1": "a1b865a8bdf688120b1ddbe328226fe74f3de964" | ||
| "sha1": "1d2940c9ca84bcd2101091ba48f5a4b41e591443" | ||
| }, | ||
| "path_in_vcs": "" | ||
| } |
+7
-7
@@ -1,2 +0,2 @@ | ||
| use std::{sync::RwLock, ops::Index}; | ||
| use std::{ops::Index, sync::RwLock}; | ||
@@ -13,3 +13,3 @@ use append_only_vec::AppendOnlyVec; | ||
| RwVec { | ||
| data: RwLock::new(Vec::new()) | ||
| data: RwLock::new(Vec::new()), | ||
| } | ||
@@ -35,3 +35,3 @@ } | ||
| ParkVec { | ||
| data: parking_lot::RwLock::new(Vec::new()) | ||
| data: parking_lot::RwLock::new(Vec::new()), | ||
| } | ||
@@ -281,3 +281,3 @@ } | ||
| for i in 0..n { | ||
| sum += vec[n-1-i]; | ||
| sum += vec[n - 1 - i]; | ||
| } | ||
@@ -303,3 +303,3 @@ sum | ||
| for i in 0..n { | ||
| sum += vec.get(n-1-i); | ||
| sum += vec.get(n - 1 - i); | ||
| } | ||
@@ -325,3 +325,3 @@ sum | ||
| for i in 0..n { | ||
| sum += vec.get(n-1-i); | ||
| sum += vec.get(n - 1 - i); | ||
| } | ||
@@ -347,3 +347,3 @@ sum | ||
| for i in 0..n { | ||
| sum += vec[n-1-i]; | ||
| sum += vec[n - 1 - i]; | ||
| } | ||
@@ -350,0 +350,0 @@ sum |
+11
-1
@@ -15,4 +15,9 @@ # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO | ||
| name = "append-only-vec" | ||
| version = "0.1.6" | ||
| version = "0.1.7" | ||
| authors = ["David Roundy <daveroundy@gmail.com>"] | ||
| build = false | ||
| autobins = false | ||
| autoexamples = false | ||
| autotests = false | ||
| autobenches = false | ||
| description = "Append-only, concurrent vector" | ||
@@ -31,4 +36,9 @@ readme = "README.md" | ||
| [lib] | ||
| name = "append_only_vec" | ||
| path = "src/lib.rs" | ||
| [[bench]] | ||
| name = "bench" | ||
| path = "benches/bench.rs" | ||
| harness = false | ||
@@ -35,0 +45,0 @@ |
+66
-4
@@ -117,7 +117,8 @@ //! AppendOnlyVec | ||
| } | ||
| /// Append an element to the array | ||
| /// Internal-only function requests a slot and puts data into it. | ||
| /// | ||
| /// This is notable in that it doesn't require a `&mut self`, because it | ||
| /// does appropriate atomic synchronization. | ||
| pub fn push(&self, val: T) -> usize { | ||
| /// However this does not update the size of the vec, which *must* be done | ||
| /// in order for either the value to be readable *or* for future pushes to | ||
| /// actually terminate. | ||
| fn pre_push(&self, val: T) -> usize { | ||
| let idx = self.reserved.fetch_add(1, Ordering::Relaxed); | ||
@@ -159,2 +160,12 @@ let (array, offset) = indices(idx); | ||
| unsafe { (ptr.add(offset)).write(val) }; | ||
| idx | ||
| } | ||
| /// Append an element to the array | ||
| /// | ||
| /// This is notable in that it doesn't require a `&mut self`, because it | ||
| /// does appropriate atomic synchronization. | ||
| /// | ||
| /// The return value is the index tha was pushed to. | ||
| pub fn push(&self, val: T) -> usize { | ||
| let idx = self.pre_push(val); | ||
@@ -183,2 +194,25 @@ // Now we need to increase the size of the vec, so it can get read. We | ||
| } | ||
| /// Extend the vec with the contents of an iterator. | ||
| /// | ||
| /// Note: this is currently no more efficient than calling `push` for each | ||
| /// element of the iterator. | ||
| pub fn extend(&self, iter: impl IntoIterator<Item = T>) { | ||
| for val in iter { | ||
| self.push(val); | ||
| } | ||
| } | ||
| /// Append an element to the array with exclusive access | ||
| /// | ||
| /// This is slightly more efficient than [`AppendOnlyVec::push`] since it | ||
| /// doesn't need to worry about concurrent access. | ||
| /// | ||
| /// The return value is the new size of the array. | ||
| pub fn push_mut(&mut self, val: T) -> usize { | ||
| let idx = self.pre_push(val); | ||
| // We do not need synchronization here because no one else has access to | ||
| // this data, and if it is passed to another thread that will involve | ||
| // the appropriate memory barrier. | ||
| self.count.store(idx, Ordering::Relaxed); | ||
| idx | ||
| } | ||
| const EMPTY: UnsafeCell<*mut T> = UnsafeCell::new(std::ptr::null_mut()); | ||
@@ -347,2 +381,22 @@ /// Allocate a new empty array | ||
| impl<T> FromIterator<T> for AppendOnlyVec<T> { | ||
| fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self { | ||
| let out = Self::new(); | ||
| for x in iter { | ||
| let idx = out.pre_push(x); | ||
| // We can be relaxed here because no one else has access to | ||
| // this data, and if it is passed to another thread that will involve | ||
| // the appropriate memory barrier. | ||
| out.count.store(idx + 1, Ordering::Relaxed); | ||
| } | ||
| out | ||
| } | ||
| } | ||
| impl<T> From<Vec<T>> for AppendOnlyVec<T> { | ||
| fn from(value: Vec<T>) -> Self { | ||
| value.into_iter().collect() | ||
| } | ||
| } | ||
| #[test] | ||
@@ -424,1 +478,9 @@ fn test_pushing_and_indexing() { | ||
| } | ||
| #[test] | ||
| fn test_from_vec() { | ||
| for v in [vec![5_i32, 4, 3, 2, 1], Vec::new(), vec![1]] { | ||
| let aov: AppendOnlyVec<i32> = v.clone().into(); | ||
| assert_eq!(v, aov.into_vec()); | ||
| } | ||
| } |
Sorry, the diff of this file is not supported yet