Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement standard traits for pointers and bump version to 0.2.0 #3

Merged
merged 8 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# 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).

---

## Version 0.2.0 - 2024-10-03
powergee marked this conversation as resolved.
Show resolved Hide resolved

### Features

* Added implementation of standard traits for pointers. ([#3](https://github.com/kaist-cp/circ/pull/3))
powergee marked this conversation as resolved.
Show resolved Hide resolved

### 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"
jeehoonkang marked this conversation as resolved.
Show resolved Hide resolved
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
Loading