Skip to content

Commit

Permalink
Merge pull request #3 from powergee/trait
Browse files Browse the repository at this point in the history
Implement standard traits for pointers and bump version to 0.2.0
  • Loading branch information
powergee authored Oct 4, 2024
2 parents f7825ba + 5f1ab7c commit e9e8574
Show file tree
Hide file tree
Showing 7 changed files with 303 additions and 51 deletions.
34 changes: 34 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Change Log

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog and this project adheres to Semantic Versioning.

For all future releases, please manage versions as follows:

1. Briefly summarize notable changes in this file (`CHANGELOG.md`). If the release includes *breaking changes*, provide clear migration instructions.
2. Publish the new version on crates.io and create a new release on [GitHub Releases](https://github.com/kaist-cp/circ/releases).

---

## Unreleased
<!-- TODO -->

## Version 0.2.0 - 2024-10-03

### Features

* Added implementation of standard traits for pointers. ([#3](https://github.com/kaist-cp/circ/pull/3))

### Bug Fixes

* `PartialEq` for `Rc` and `Snapshot` now compares the objects they point to, rather than the pointers themselves. ([#3](https://github.com/kaist-cp/circ/pull/3)) (See compatibility note below.)

### Compatibility Notes

* `Rc::eq` and `Snapshot::eq` now compare the objects they point to instead of their pointer values. This change aligns with the behavior of `PartialEq` for other smart pointer types (e.g., `std::rc::Rc`), where equality is based on the objects being pointed to. The original pointer-based comparison is still available via the `ptr_eq` method.
* **Migration**: To compare pointer values, use the `ptr_eq` method.

## Version 0.1.0 - 2024-06-12

* Initial release.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "circ"
version = "0.1.0"
version = "0.2.0"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "Efficient referenced counted pointers for non-blocking concurrency"
Expand Down
48 changes: 34 additions & 14 deletions src/ebr_impl/pointers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use core::marker::PhantomData;
use core::mem::align_of;
use core::ptr::null_mut;
use core::sync::atomic::AtomicUsize;
use std::fmt::{Debug, Formatter, Pointer};

use atomic::{Atomic, Ordering};

Expand All @@ -12,6 +13,18 @@ pub struct Tagged<T: ?Sized> {
ptr: *mut T,
}

impl<T> Debug for Tagged<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Pointer::fmt(&self.as_raw(), f)
}
}

impl<T> Pointer for Tagged<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Pointer::fmt(&self.as_raw(), f)
}
}

impl<T> Default for Tagged<T> {
fn default() -> Self {
Self { ptr: null_mut() }
Expand All @@ -26,14 +39,6 @@ impl<T> Clone for Tagged<T> {

impl<T> Copy for Tagged<T> {}

impl<T> PartialEq for Tagged<T> {
fn eq(&self, other: &Self) -> bool {
self.with_high_tag(0).ptr == other.with_high_tag(0).ptr
}
}

impl<T> Eq for Tagged<T> {}

impl<T> Hash for Tagged<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.ptr.hash(state)
Expand Down Expand Up @@ -125,6 +130,16 @@ impl<T> Tagged<T> {
Some(self.deref())
}
}

/// Returns `true` if the two pointer values, including the tag values set by `with_tag`,
/// are identical.
pub fn ptr_eq(self, other: Self) -> bool {
// Instead of using a direct equality comparison (`==`), we use `ptr_eq`, which ignores
// the epoch tag in the high bits. This is because the epoch tags hold no significance
// for clients; they are only used internally by the CIRC engine to track the last
// accessed epoch for the pointer.
self.with_high_tag(0).ptr == other.with_high_tag(0).ptr
}
}

/// Returns a bitmask containing the unused least significant bits of an aligned pointer to `T`.
Expand Down Expand Up @@ -196,6 +211,7 @@ impl<T> RawAtomic<T> {
}
}

// A shared pointer type only for the internal EBR implementation.
pub(crate) struct RawShared<'g, T> {
inner: Tagged<T>,
_marker: PhantomData<&'g T>,
Expand Down Expand Up @@ -236,12 +252,6 @@ impl<'g, T> From<Tagged<T>> for RawShared<'g, T> {
}
}

impl<'g, T> PartialEq for RawShared<'g, T> {
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner
}
}

impl<'g, T> RawShared<'g, T> {
pub fn null() -> Self {
Self {
Expand Down Expand Up @@ -288,4 +298,14 @@ impl<'g, T> RawShared<'g, T> {
pub fn is_null(self) -> bool {
self.inner.is_null()
}

/// Returns `true` if the two pointer values, including the tag values set by `with_tag`,
/// are identical.
pub fn ptr_eq(&self, other: Self) -> bool {
// Instead of using a direct equality comparison (`==`), we use `ptr_eq`, which ignores
// the epoch tag in the high bits. This is because the epoch tags hold no significance
// for clients; they are only used internally by the CIRC engine to track the last
// accessed epoch for the pointer.
self.inner.ptr_eq(other.inner)
}
}
4 changes: 2 additions & 2 deletions src/ebr_impl/sync/queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ impl<T> Queue<T> {
.map(|_| {
let tail = self.tail.load(Relaxed, guard);
// Advance the tail so that we don't retire a pointer to a reachable node.
if head == tail {
if head.ptr_eq(tail) {
let _ = self
.tail
.compare_exchange(tail, next, Release, Relaxed, guard);
Expand Down Expand Up @@ -154,7 +154,7 @@ impl<T> Queue<T> {
.map(|_| {
let tail = self.tail.load(Relaxed, guard);
// Advance the tail so that we don't retire a pointer to a reachable node.
if head == tail {
if head.ptr_eq(tail) {
let _ = self
.tail
.compare_exchange(tail, next, Release, Relaxed, guard);
Expand Down
Loading

0 comments on commit e9e8574

Please sign in to comment.