diff --git a/Cargo.toml b/Cargo.toml index 937246b8..ef73007f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ fnv = "1.0.3" lazy_static = "0.2.1" libc = "0.2" regex = "0.1" +cfg-if = "0.1" [dependencies.hyper] version = "0.9" diff --git a/src/atomic64.rs b/src/atomic64.rs deleted file mode 100644 index e0c109f2..00000000 --- a/src/atomic64.rs +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2014 The Prometheus Authors -// Copyright 2016 PingCAP, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -#[cfg(not(feature = "nightly"))] -pub use self::rwlock::{RwlockF64 as AtomicF64, RwlockU64 as AtomicU64}; - -#[cfg(feature = "nightly")] -pub use self::atomic::{AtomicF64, AtomicU64}; - -#[cfg(not(feature = "nightly"))] -mod rwlock { - use std::sync::RwLock; - - pub struct RwlockF64 { - inner: RwLock, - } - - impl RwlockF64 { - pub fn new(val: f64) -> RwlockF64 { - RwlockF64 { inner: RwLock::new(val) } - } - - #[inline] - pub fn set(&self, val: f64) { - *self.inner.write().unwrap() = val; - } - - #[inline] - pub fn get(&self) -> f64 { - *self.inner.read().unwrap() - } - - #[inline] - pub fn inc_by(&self, delta: f64) { - *self.inner.write().unwrap() += delta; - } - } - - pub struct RwlockU64 { - inner: RwLock, - } - - impl RwlockU64 { - pub fn new(val: u64) -> RwlockU64 { - RwlockU64 { inner: RwLock::new(val) } - } - - #[inline] - pub fn get(&self) -> u64 { - *self.inner.read().unwrap() - } - - #[inline] - pub fn inc_by(&self, delta: u64) { - *self.inner.write().unwrap() += delta; - } - } -} - -#[cfg(feature = "nightly")] -mod atomic { - use std::sync::atomic::{AtomicU64 as StdAtomicU64, Ordering}; - use std::mem::transmute; - - pub struct AtomicF64 { - inner: StdAtomicU64, - } - - impl AtomicF64 { - pub fn new(val: f64) -> AtomicF64 { - AtomicF64 { inner: StdAtomicU64::new(f64_to_u64(val)) } - } - - #[inline] - pub fn get(&self) -> f64 { - u64_to_f64(self.inner.load(Ordering::Relaxed)) - } - - #[inline] - pub fn set(&self, val: f64) { - self.inner.store(f64_to_u64(val), Ordering::Relaxed) - } - - #[inline] - pub fn inc_by(&self, delta: f64) { - loop { - let current = self.inner.load(Ordering::Acquire); - let new = u64_to_f64(current) + delta; - let swapped = self.inner - .compare_and_swap(current, f64_to_u64(new), Ordering::Release); - if swapped == current { - return; - } - } - } - } - - fn u64_to_f64(val: u64) -> f64 { - unsafe { transmute(val) } - } - - fn f64_to_u64(val: f64) -> u64 { - unsafe { transmute(val) } - } - - pub struct AtomicU64 { - inner: StdAtomicU64, - } - - impl AtomicU64 { - pub fn new(val: u64) -> AtomicU64 { - AtomicU64 { inner: StdAtomicU64::new(val) } - } - - #[inline] - pub fn get(&self) -> u64 { - self.inner.load(Ordering::Acquire) - } - - #[inline] - pub fn inc_by(&self, delta: u64) { - self.inner.fetch_add(delta, Ordering::Release); - } - } -} - -#[cfg(test)] -mod test { - use std::f64::consts::PI; - use std::f64::{self, EPSILON}; - - use super::*; - - #[test] - fn test_atomicf64() { - let table: Vec = vec![0.0, 1.0, PI, f64::MIN, f64::MAX]; - - for f in table { - assert!((f - AtomicF64::new(f).get()).abs() < EPSILON); - } - } - - #[test] - fn test_atomicu64() { - let au64 = AtomicU64::new(0); - assert_eq!(au64.get(), 0); - - au64.inc_by(1); - assert_eq!(au64.get(), 1); - } -} diff --git a/src/atomic64/atomic.rs b/src/atomic64/atomic.rs new file mode 100644 index 00000000..b061629d --- /dev/null +++ b/src/atomic64/atomic.rs @@ -0,0 +1,63 @@ +use std::sync::atomic::Ordering; +use std::mem::transmute; + +pub struct F64 { + inner: super::AtomicU64Type, +} + +impl F64 { + pub fn new(val: f64) -> F64 { + F64 { inner: super::AtomicU64Type::new(f64_to_u64(val)) } + } + + #[inline] + pub fn get(&self) -> f64 { + u64_to_f64(self.inner.load(Ordering::Relaxed)) + } + + #[inline] + pub fn set(&self, val: f64) { + self.inner.store(f64_to_u64(val), Ordering::Relaxed) + } + + #[inline] + pub fn inc_by(&self, delta: f64) { + loop { + let current = self.inner.load(Ordering::Acquire); + let new = u64_to_f64(current) + delta; + let swapped = self.inner + .compare_and_swap(current, f64_to_u64(new), Ordering::Release); + if swapped == current { + return; + } + } + } +} + +fn u64_to_f64(val: super::U64Type) -> f64 { + unsafe { transmute(val) } +} + +fn f64_to_u64(val: f64) -> super::U64Type { + unsafe { transmute(val) } +} + +pub struct U64 { + inner: super::AtomicU64Type, +} + +impl U64 { + pub fn new(val: u64) -> U64 { + U64 { inner: super::AtomicU64Type::new(val as super::U64Type) } + } + + #[inline] + pub fn get(&self) -> u64 { + self.inner.load(Ordering::Acquire) as u64 + } + + #[inline] + pub fn inc_by(&self, delta: u64) { + self.inner.fetch_add(delta as super::U64Type, Ordering::Release); + } +} diff --git a/src/atomic64/mod.rs b/src/atomic64/mod.rs new file mode 100644 index 00000000..9b98200a --- /dev/null +++ b/src/atomic64/mod.rs @@ -0,0 +1,117 @@ +// Copyright 2014 The Prometheus Authors +// Copyright 2016 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// See the License for the specific language governing permissions and +// limitations under the License. + + +cfg_if! { + if #[cfg(feature = "nightly")] { + // Prefer AtomicU64 if available. + type AtomicU64Type = ::std::sync::atomic::AtomicU64; + type U64Type = u64; + + #[path = "atomic.rs"] + mod imp; + } else if #[cfg(target_pointer_width = "64")] { + // Use AtomicUsize if pointer width is 64 bit. This *may* have issues if + // a target has 64 bit pointer width but no atomic pointer-sized type, + // but that is not the case for any of the major architectures. + type AtomicU64Type = ::std::sync::atomic::AtomicUsize; + type U64Type = usize; + + #[path = "atomic.rs"] + mod imp; + } else { + // Fall back to RwLock based version. + #[path = "rwlock.rs"] + mod imp; + } +} + + +pub struct AtomicF64 { + inner: imp::F64, +} + + +impl AtomicF64 { + pub fn new(val: f64) -> AtomicF64 { + AtomicF64 { + inner: imp::F64::new(val), + } + } + + #[inline] + pub fn get(&self) -> f64 { + self.inner.get() + } + + #[inline] + pub fn set(&self, val: f64) { + self.inner.set(val) + } + + #[inline] + pub fn inc_by(&self, delta: f64) { + self.inner.inc_by(delta) + } +} + + +pub struct AtomicU64 { + inner: imp::U64, +} + +impl AtomicU64 { + pub fn new(val: u64) -> AtomicU64 { + AtomicU64 { + inner: imp::U64::new(val), + } + } + + #[inline] + pub fn get(&self) -> u64 { + self.inner.get() + } + + #[inline] + pub fn inc_by(&self, delta: u64) { + self.inner.inc_by(delta) + } +} + + +#[cfg(test)] +mod test { + use std::f64::consts::PI; + use std::f64::{self, EPSILON}; + + use super::*; + + #[test] + fn test_atomicf64() { + let table: Vec = vec![0.0, 1.0, PI, f64::MIN, f64::MAX]; + + for f in table { + assert!((f - AtomicF64::new(f).get()).abs() < EPSILON); + } + } + + #[test] + fn test_atomicu64() { + let au64 = AtomicU64::new(0); + assert_eq!(au64.get(), 0); + + au64.inc_by(1); + assert_eq!(au64.get(), 1); + } +} diff --git a/src/atomic64/rwlock.rs b/src/atomic64/rwlock.rs new file mode 100644 index 00000000..56ac3ba9 --- /dev/null +++ b/src/atomic64/rwlock.rs @@ -0,0 +1,46 @@ +use std::sync::RwLock; + +pub struct F64 { + inner: RwLock, +} + +impl F64 { + pub fn new(val: f64) -> F64 { + F64 { inner: RwLock::new(val) } + } + + #[inline] + pub fn set(&self, val: f64) { + *self.inner.write().unwrap() = val; + } + + #[inline] + pub fn get(&self) -> f64 { + *self.inner.read().unwrap() + } + + #[inline] + pub fn inc_by(&self, delta: f64) { + *self.inner.write().unwrap() += delta; + } +} + +pub struct U64 { + inner: RwLock, +} + +impl U64 { + pub fn new(val: u64) -> U64 { + U64 { inner: RwLock::new(val) } + } + + #[inline] + pub fn get(&self) -> u64 { + *self.inner.read().unwrap() + } + + #[inline] + pub fn inc_by(&self, delta: u64) { + *self.inner.write().unwrap() += delta; + } +} diff --git a/src/lib.rs b/src/lib.rs index f9a07995..f3de43ad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,6 +15,8 @@ #![cfg_attr(feature="dev", plugin(clippy))] #![cfg_attr(feature="nightly", feature(integer_atomics))] +#[macro_use] +extern crate cfg_if; #[macro_use] extern crate quick_error; extern crate protobuf;