text:
use intrinsics;
use cast;
use std::kinds::marker;
use option::{Option,Some,None};
use ops::Drop;
use ty::Unsafe;

/// An atomic boolean type.
pub struct AtomicBool {
    priv v: Unsafe<uint>,
    priv nocopy: marker::NoCopy
}

/// A signed atomic integer type, supporting basic atomic arithmetic operations
pub struct AtomicInt {
    priv v: Unsafe<int>,
    priv nocopy: marker::NoCopy
}

/// An unsigned atomic integer type, supporting basic atomic arithmetic operations
pub struct AtomicUint {
    priv v: Unsafe<uint>,
    priv nocopy: marker::NoCopy
}

/// An unsafe atomic pointer. Only supports basic atomic operations
pub struct AtomicPtr<T> {
    priv p: Unsafe<uint>,
    priv nocopy: marker::NoCopy
}

/// An atomic, nullable unique pointer
///
/// This can be used as the concurrency primitive for operations that transfer
/// owned heap objects across tasks.
#[unsafe_no_drop_flag]
pub struct AtomicOption<T> {
    priv p: Unsafe<uint>,
}

/// Atomic memory orderings
///
/// Memory orderings limit the ways that both the compiler and CPU may reorder
/// instructions around atomic operations. At its most restrictive,
/// "sequentially consistent" atomics allow neither reads nor writes
/// to be moved either before or after the atomic operation; on the other end
/// "relaxed" atomics allow all reorderings.
///
/// Rust's memory orderings are the same as in C++[1].
///
/// [1]: http://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync
pub enum Ordering {
    /// No ordering constraints, only atomic operations
    Relaxed,
    /// When coupled with a store, all previous writes become visible
    /// to another thread that performs a load with `Acquire` ordering
    /// on the same value
    Release,
    /// When coupled with a load, all subsequent loads will see data
    /// written before a store with `Release` ordering on the same value
    /// in another thread
    Acquire,
    /// When coupled with a load, uses `Acquire` ordering, and with a store
    /// `Release` ordering
    AcqRel,
    /// Like `AcqRel` with the additional guarantee that all threads see all
    /// sequentially consistent operations in the same order.
    SeqCst
}

/// An `AtomicBool` initialized to `false`
pub static INIT_ATOMIC_BOOL : AtomicBool = AtomicBool { v: Unsafe{value: 0,
                                                                  marker1: marker::InvariantType},
                                                        nocopy: marker::NoCopy };
/// An `AtomicInt` initialized to `0`
pub static INIT_ATOMIC_INT  : AtomicInt  = AtomicInt  { v: Unsafe{value: 0,
                                                                  marker1: marker::InvariantType},
                                                        nocopy: marker::NoCopy };
/// An `AtomicUint` initialized to `0`
pub static INIT_ATOMIC_UINT : AtomicUint = AtomicUint { v: Unsafe{value: 0,
                                                                  marker1: marker::InvariantType},
                                                        nocopy: marker::NoCopy };

// NB: Needs to be -1 (0b11111111...) to make fetch_nand work correctly
static UINT_TRUE: uint = -1;

impl AtomicBool {
    /// Create a new `AtomicBool`
    pub fn new(v: bool) -> AtomicBool {
        let val = if v { UINT_TRUE } else { 0 };
        AtomicBool { v: Unsafe::new(val), nocopy: marker::NoCopy }
    }

    /// Load the value
    #[inline]
    pub fn load(&self, order: Ordering) -> bool {
        unsafe { atomic_load(self.v.get() as *uint, order) > 0 }
    }

    /// Store the value
    #[inline]
    pub fn store(&self, val: bool, order: Ordering) {
        let val = if val { UINT_TRUE } else { 0 };

        unsafe { atomic_store(self.v.get(), val, order); }
    }

    /// Store a value, returning the old value
    #[inline]
    pub fn swap(&self, val: bool, order: Ordering) -> bool {
        let val = if val { UINT_TRUE } else { 0 };

        unsafe { atomic_swap(self.v.get(), val, order) > 0 }
    }

    /// If the current value is the same as expected, store a new value
    ///
    /// Compare the current value with `old`; if they are the same then
    /// replace the current value with `new`. Return the previous value.
    /// If the return value is equal to `old` then the value was updated.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// # // FIXME: Needs PR #12430
    /// extern crate sync;
    ///
    /// use sync::Arc;
    /// use std::sync::atomics::{AtomicBool, SeqCst};
    ///
    /// fn main() {
    ///     let spinlock = Arc::new(AtomicBool::new(false));
    ///     let spinlock_clone = spin_lock.clone();
    ///
    ///     spawn(proc() {
    ///         with_lock(&spinlock, || println!("task 1 in lock"));
    ///     });
    ///
    ///     spawn(proc() {
    ///         with_lock(&spinlock_clone, || println!("task 2 in lock"));
    ///     });
    /// }
    ///
    /// fn with_lock(spinlock: &Arc<AtomicBool>, f: || -> ()) {
    ///     // CAS loop until we are able to replace `false` with `true`
    ///     while spinlock.compare_and_swap(false, true, SeqCst) == false {
    ///         // Since tasks may not be preemptive (if they are green threads)
    ///         // yield to the scheduler to let the other task run. Low level
    ///         // concurrent code needs to take into account Rust's two threading
    ///         // models.
    ///         deschedule();
    ///     }
    ///
    ///     // Now we have the spinlock
    ///     f();
    ///
    ///     // Release the lock
    ///     spinlock.store(false);
    /// }
    /// ```
    #[inline]
    pub fn compare_and_swap(&self, old: bool, new: bool, order: Ordering) -> bool {
        let old = if old { UINT_TRUE } else { 0 };
        let new = if new { UINT_TRUE } else { 0 };

        unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) > 0 }
    }

    /// A logical "and" operation
    ///
    /// Performs a logical "and" operation on the current value and the
    /// argument `val`, and sets the new value to the result.
    /// Returns the previous value.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::sync::atomics::{AtomicBool, SeqCst};
    ///
    /// let foo = AtomicBool::new(true);
    /// assert_eq!(true, foo.fetch_and(false, SeqCst));
    /// assert_eq!(false, foo.load(SeqCst));
    ///
    /// let foo = AtomicBool::new(true);
    /// assert_eq!(true, foo.fetch_and(true, SeqCst));
    /// assert_eq!(true, foo.load(SeqCst));
    ///
    /// let foo = AtomicBool::new(false);
    /// assert_eq!(false, foo.fetch_and(false, SeqCst));
    /// assert_eq!(false, foo.load(SeqCst));
    /// ```
    #[inline]
    pub fn fetch_and(&self, val: bool, order: Ordering) -> bool {
        let val = if val { UINT_TRUE } else { 0 };

        unsafe { atomic_and(self.v.get(), val, order) > 0 }
    }

    /// A logical "nand" operation
    ///
    /// Performs a logical "nand" operation on the current value and the
    /// argument `val`, and sets the new value to the result.
    /// Returns the previous value.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::sync::atomics::{AtomicBool, SeqCst};
    ///
    /// let foo = AtomicBool::new(true);
    /// assert_eq!(true, foo.fetch_nand(false, SeqCst));
    /// assert_eq!(true, foo.load(SeqCst));
    ///
    /// let foo = AtomicBool::new(true);
    /// assert_eq!(true, foo.fetch_nand(true, SeqCst));
    /// assert_eq!(0, foo.load(SeqCst) as int);
    /// assert_eq!(false, foo.load(SeqCst));
    ///
    /// let foo = AtomicBool::new(false);
    /// assert_eq!(false, foo.fetch_nand(false, SeqCst));
    /// assert_eq!(true, foo.load(SeqCst));
    /// ```
    #[inline]
    pub fn fetch_nand(&self, val: bool, order: Ordering) -> bool {
        let val = if val { UINT_TRUE } else { 0 };

        unsafe { atomic_nand(self.v.get(), val, order) > 0 }
    }

    /// A logical "or" operation
    ///
    /// Performs a logical "or" operation on the current value and the
    /// argument `val`, and sets the new value to the result.
    /// Returns the previous value.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::sync::atomics::{AtomicBool, SeqCst};
    ///
    /// let foo = AtomicBool::new(true);
    /// assert_eq!(true, foo.fetch_or(false, SeqCst));
    /// assert_eq!(true, foo.load(SeqCst));
    ///
    /// let foo = AtomicBool::new(true);
    /// assert_eq!(true, foo.fetch_or(true, SeqCst));
    /// assert_eq!(true, foo.load(SeqCst));
    ///
    /// let foo = AtomicBool::new(false);
    /// assert_eq!(false, foo.fetch_or(false, SeqCst));
    /// assert_eq!(false, foo.load(SeqCst));
    /// ```
    #[inline]
    pub fn fetch_or(&self, val: bool, order: Ordering) -> bool {
        let val = if val { UINT_TRUE } else { 0 };

        unsafe { atomic_or(self.v.get(), val, order) > 0 }
    }

    /// A logical "xor" operation
    ///
    /// Performs a logical "xor" operation on the current value and the
    /// argument `val`, and sets the new value to the result.
    /// Returns the previous value.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::sync::atomics::{AtomicBool, SeqCst};
    ///
    /// let foo = AtomicBool::new(true);
    /// assert_eq!(true, foo.fetch_xor(false, SeqCst));
    /// assert_eq!(true, foo.load(SeqCst));
    ///
    /// let foo = AtomicBool::new(true);
    /// assert_eq!(true, foo.fetch_xor(true, SeqCst));
    /// assert_eq!(false, foo.load(SeqCst));
    ///
    /// let foo = AtomicBool::new(false);
    /// assert_eq!(false, foo.fetch_xor(false, SeqCst));
    /// assert_eq!(false, foo.load(SeqCst));
    /// ```
    #[inline]
    pub fn fetch_xor(&self, val: bool, order: Ordering) -> bool {
        let val = if val { UINT_TRUE } else { 0 };

        unsafe { atomic_xor(self.v.get(), val, order) > 0 }
    }
}

impl AtomicInt {
    /// Create a new `AtomicInt`
    pub fn new(v: int) -> AtomicInt {
        AtomicInt {v: Unsafe::new(v), nocopy: marker::NoCopy}
    }

    /// Load the value
    #[inline]
    pub fn load(&self, order: Ordering) -> int {
        unsafe { atomic_load(self.v.get() as *int, order) }
    }

    /// Store the value
    #[inline]
    pub fn store(&self, val: int, order: Ordering) {
        unsafe { atomic_store(self.v.get(), val, order); }
    }

    /// Store a value, returning the old value
    #[inline]
    pub fn swap(&self, val: int, order: Ordering) -> int {
        unsafe { atomic_swap(self.v.get(), val, order) }
    }

    /// If the current value is the same as expected, store a new value
    ///
    /// Compare the current value with `old`; if they are the same then
    /// replace the current value with `new`. Return the previous value.
    /// If the return value is equal to `old` then the value was updated.
    #[inline]
    pub fn compare_and_swap(&self, old: int, new: int, order: Ordering) -> int {
        unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) }
    }

    /// Add to the current value, returning the previous
    ///
    /// # Examples
    ///
    /// ```
    /// use std::sync::atomics::{AtomicInt, SeqCst};
    ///
    /// let foo = AtomicInt::new(0);
    /// assert_eq!(0, foo.fetch_add(10, SeqCst));
    /// assert_eq!(10, foo.load(SeqCst));
    /// ```
    #[inline]
    pub fn fetch_add(&self, val: int, order: Ordering) -> int {
        unsafe { atomic_add(self.v.get(), val, order) }
    }

    /// Subtract from the current value, returning the previous
    ///
    /// # Examples
    ///
    /// ```
    /// use std::sync::atomics::{AtomicInt, SeqCst};
    ///
    /// let foo = AtomicInt::new(0);
    /// assert_eq!(0, foo.fetch_sub(10, SeqCst));
    /// assert_eq!(-10, foo.load(SeqCst));
    /// ```
    #[inline]
    pub fn fetch_sub(&self, val: int, order: Ordering) -> int {
        unsafe { atomic_sub(self.v.get(), val, order) }
    }
}

impl AtomicUint {
    /// Create a new `AtomicUint`
    pub fn new(v: uint) -> AtomicUint {
        AtomicUint { v: Unsafe::new(v), nocopy: marker::NoCopy }
    }

    /// Load the value
    #[inline]
    pub fn load(&self, order: Ordering) -> uint {
        unsafe { atomic_load(self.v.get() as *uint, order) }
    }

    /// Store the value
    #[inline]
    pub fn store(&self, val: uint, order: Ordering) {
        unsafe { atomic_store(self.v.get(), val, order); }
    }

    /// Store a value, returning the old value
    #[inline]
    pub fn swap(&self, val: uint, order: Ordering) -> uint {
        unsafe { atomic_swap(self.v.get(), val, order) }
    }

    /// If the current value is the same as expected, store a new value
    ///
    /// Compare the current value with `old`; if they are the same then
    /// replace the current value with `new`. Return the previous value.
    /// If the return value is equal to `old` then the value was updated.
    #[inline]
    pub fn compare_and_swap(&self, old: uint, new: uint, order: Ordering) -> uint {
        unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) }
    }

    /// Add to the current value, returning the previous
    ///
    /// # Examples
    ///
    /// ```
    /// use std::sync::atomics::{AtomicUint, SeqCst};
    ///
    /// let foo = AtomicUint::new(0);
    /// assert_eq!(0, foo.fetch_add(10, SeqCst));
    /// assert_eq!(10, foo.load(SeqCst));
    /// ```
    #[inline]
    pub fn fetch_add(&self, val: uint, order: Ordering) -> uint {
        unsafe { atomic_add(self.v.get(), val, order) }
    }

    /// Subtract from the current value, returning the previous
    ///
    /// # Examples
    ///
    /// ```
    /// use std::sync::atomics::{AtomicUint, SeqCst};
    ///
    /// let foo = AtomicUint::new(10);
    /// assert_eq!(10, foo.fetch_sub(10, SeqCst));
    /// assert_eq!(0, foo.load(SeqCst));
    /// ```
    #[inline]
    pub fn fetch_sub(&self, val: uint, order: Ordering) -> uint {
        unsafe { atomic_sub(self.v.get(), val, order) }
    }
}

impl<T> AtomicPtr<T> {
    /// Create a new `AtomicPtr`
    pub fn new(p: *mut T) -> AtomicPtr<T> {
        AtomicPtr { p: Unsafe::new(p as uint), nocopy: marker::NoCopy }
    }

    /// Load the value
    #[inline]
    pub fn load(&self, order: Ordering) -> *mut T {
        unsafe {
            atomic_load(self.p.get() as **mut T, order) as *mut T
        }
    }

    /// Store the value
    #[inline]
    pub fn store(&self, ptr: *mut T, order: Ordering) {
        unsafe { atomic_store(self.p.get(), ptr as uint, order); }
    }

    /// Store a value, returning the old value
    #[inline]
    pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T {
        unsafe { atomic_swap(self.p.get(), ptr as uint, order) as *mut T }
    }

    /// If the current value is the same as expected, store a new value
    ///
    /// Compare the current value with `old`; if they are the same then
    /// replace the current value with `new`. Return the previous value.
    /// If the return value is equal to `old` then the value was updated.
    #[inline]
    pub fn compare_and_swap(&self, old: *mut T, new: *mut T, order: Ordering) -> *mut T {
        unsafe {
            atomic_compare_and_swap(self.p.get(), old as uint,
                                    new as uint, order) as *mut T
        }
    }
}

impl<T> AtomicOption<T> {
    /// Create a new `AtomicOption`
    pub fn new(p: ~T) -> AtomicOption<T> {
        unsafe { AtomicOption { p: Unsafe::new(cast::transmute(p)) } }
    }

    /// Create a new `AtomicOption` that doesn't contain a value
    pub fn empty() -> AtomicOption<T> { AtomicOption { p: Unsafe::new(0) } }

    /// Store a value, returning the old value
    #[inline]
    pub fn swap(&self, val: ~T, order: Ordering) -> Option<~T> {
        unsafe {
            let val = cast::transmute(val);

            let p = atomic_swap(self.p.get(), val, order);
            if p as uint == 0 {
                None
            } else {
                Some(cast::transmute(p))
            }
        }
    }

    /// Remove the value, leaving the `AtomicOption` empty.
    #[inline]
    pub fn take(&self, order: Ordering) -> Option<~T> {
        unsafe { self.swap(cast::transmute(0), order) }
    }

    /// Replace an empty value with a non-empty value.
    ///
    /// Succeeds if the option is `None` and returns `None` if so. If
    /// the option was already `Some`, returns `Some` of the rejected
    /// value.
    #[inline]
    pub fn fill(&self, val: ~T, order: Ordering) -> Option<~T> {
        unsafe {
            let val = cast::transmute(val);
            let expected = cast::transmute(0);
            let oldval = atomic_compare_and_swap(self.p.get(), expected, val, order);
            if oldval == expected {
                None
            } else {
                Some(cast::transmute(val))
            }
        }
    }

    /// Returns `true` if the `AtomicOption` is empty.
    ///
    /// Be careful: The caller must have some external method of ensuring the
    /// result does not get invalidated by another task after this returns.
    #[inline]
    pub fn is_empty(&self, order: Ordering) -> bool {
        unsafe { atomic_load(self.p.get() as *uint, order) as uint == 0 }
    }
}

#[unsafe_destructor]
impl<T> Drop for AtomicOption<T> {
    fn drop(&mut self) {
        let _ = self.take(SeqCst);
    }
}

#[inline]
unsafe fn atomic_store<T>(dst: *mut T, val: T, order:Ordering) {
    match order {
        Release => intrinsics::atomic_store_rel(dst, val),
        Relaxed => intrinsics::atomic_store_relaxed(dst, val),
        _       => intrinsics::atomic_store(dst, val)
    }
}

#[inline]
unsafe fn atomic_load<T>(dst: *T, order:Ordering) -> T {
    match order {
        Acquire => intrinsics::atomic_load_acq(dst),
        Relaxed => intrinsics::atomic_load_relaxed(dst),
        _       => intrinsics::atomic_load(dst)
    }
}

#[inline]
unsafe fn atomic_swap<T>(dst: *mut T, val: T, order: Ordering) -> T {
    match order {
        Acquire => intrinsics::atomic_xchg_acq(dst, val),
        Release => intrinsics::atomic_xchg_rel(dst, val),
        AcqRel  => intrinsics::atomic_xchg_acqrel(dst, val),
        Relaxed => intrinsics::atomic_xchg_relaxed(dst, val),
        _       => intrinsics::atomic_xchg(dst, val)
    }
}

/// Returns the old value (like __sync_fetch_and_add).
#[inline]
unsafe fn atomic_add<T>(dst: *mut T, val: T, order: Ordering) -> T {
    match order {
        Acquire => intrinsics::atomic_xadd_acq(dst, val),
        Release => intrinsics::atomic_xadd_rel(dst, val),
        AcqRel  => intrinsics::atomic_xadd_acqrel(dst, val),
        Relaxed => intrinsics::atomic_xadd_relaxed(dst, val),
        _       => intrinsics::atomic_xadd(dst, val)
    }
}

/// Returns the old value (like __sync_fetch_and_sub).
#[inline]
unsafe fn atomic_sub<T>(dst: *mut T, val: T, order: Ordering) -> T {
    match order {
        Acquire => intrinsics::atomic_xsub_acq(dst, val),
        Release => intrinsics::atomic_xsub_rel(dst, val),
        AcqRel  => intrinsics::atomic_xsub_acqrel(dst, val),
        Relaxed => intrinsics::atomic_xsub_relaxed(dst, val),
        _       => intrinsics::atomic_xsub(dst, val)
    }
}

#[inline]
unsafe fn atomic_compare_and_swap<T>(dst: *mut T, old:T, new:T, order: Ordering) -> T {
    match order {
        Acquire => intrinsics::atomic_cxchg_acq(dst, old, new),
        Release => intrinsics::atomic_cxchg_rel(dst, old, new),
        AcqRel  => intrinsics::atomic_cxchg_acqrel(dst, old, new),
        Relaxed => intrinsics::atomic_cxchg_relaxed(dst, old, new),
        _       => intrinsics::atomic_cxchg(dst, old, new),
    }
}

#[inline]
unsafe fn atomic_and<T>(dst: *mut T, val: T, order: Ordering) -> T {
    match order {
        Acquire => intrinsics::atomic_and_acq(dst, val),
        Release => intrinsics::atomic_and_rel(dst, val),
        AcqRel  => intrinsics::atomic_and_acqrel(dst, val),
        Relaxed => intrinsics::atomic_and_relaxed(dst, val),
        _       => intrinsics::atomic_and(dst, val)
    }
}

#[inline]
unsafe fn atomic_nand<T>(dst: *mut T, val: T, order: Ordering) -> T {
    match order {
        Acquire => intrinsics::atomic_nand_acq(dst, val),
        Release => intrinsics::atomic_nand_rel(dst, val),
        AcqRel  => intrinsics::atomic_nand_acqrel(dst, val),
        Relaxed => intrinsics::atomic_nand_relaxed(dst, val),
        _       => intrinsics::atomic_nand(dst, val)
    }
}

#[inline]
unsafe fn atomic_or<T>(dst: *mut T, val: T, order: Ordering) -> T {
    match order {
        Acquire => intrinsics::atomic_or_acq(dst, val),
        Release => intrinsics::atomic_or_rel(dst, val),
        AcqRel  => intrinsics::atomic_or_acqrel(dst, val),
        Relaxed => intrinsics::atomic_or_relaxed(dst, val),
        _       => intrinsics::atomic_or(dst, val)
    }
}

#[inline]
unsafe fn atomic_xor<T>(dst: *mut T, val: T, order: Ordering) -> T {
    match order {
        Acquire => intrinsics::atomic_xor_acq(dst, val),
        Release => intrinsics::atomic_xor_rel(dst, val),
        AcqRel  => intrinsics::atomic_xor_acqrel(dst, val),
        Relaxed => intrinsics::atomic_xor_relaxed(dst, val),
        _       => intrinsics::atomic_xor(dst, val)
    }
}

/// An atomic fence.
///
/// A fence 'A' which has `Release` ordering semantics, synchronizes with a
/// fence 'B' with (at least) `Acquire` semantics, if and only if there exists
/// atomic operations X and Y, both operating on some atomic object 'M' such
/// that A is sequenced before X, Y is synchronized before B and Y observers
/// the change to M. This provides a happens-before dependence between A and B.
///
/// Atomic operations with `Release` or `Acquire` semantics can also synchronize
/// with a fence.
///
/// A fence with has `SeqCst` ordering, in addition to having both `Acquire` and
/// `Release` semantics, participates in the global program order of the other
/// `SeqCst` operations and/or fences.
///
/// Accepts `Acquire`, `Release`, `AcqRel` and `SeqCst` orderings.
///
/// # Failure
///
/// Fails if `order` is `Relaxed`
#[inline]
pub fn fence(order: Ordering) {
    unsafe {
        match order {
            Acquire => intrinsics::atomic_fence_acq(),
            Release => intrinsics::atomic_fence_rel(),
            AcqRel  => intrinsics::atomic_fence_acqrel(),
            SeqCst  => intrinsics::atomic_fence(),
            Relaxed => fail!("there is no such thing as a relaxed fence")
        }
    }
}

#[cfg(test)]
mod test {
    use option::*;
    use super::*;

    #[test]
    fn bool_() {
        let a = AtomicBool::new(false);
        assert_eq!(a.compare_and_swap(false, true, SeqCst), false);
        assert_eq!(a.compare_and_swap(false, true, SeqCst), true);

        a.store(false, SeqCst);
        assert_eq!(a.compare_and_swap(false, true, SeqCst), false);
    }

    #[test]
    fn option_empty() {
        let option: AtomicOption<()> = AtomicOption::empty();
        assert!(option.is_empty(SeqCst));
    }

    #[test]
    fn option_swap() {
        let p = AtomicOption::new(~1);
        let a = ~2;

        let b = p.swap(a, SeqCst);

        assert_eq!(b, Some(~1));
        assert_eq!(p.take(SeqCst), Some(~2));
    }

    #[test]
    fn option_take() {
        let p = AtomicOption::new(~1);

        assert_eq!(p.take(SeqCst), Some(~1));
        assert_eq!(p.take(SeqCst), None);

        let p2 = ~2;
        p.swap(p2, SeqCst);

        assert_eq!(p.take(SeqCst), Some(~2));
    }

    #[test]
    fn option_fill() {
        let p = AtomicOption::new(~1);
        assert!(p.fill(~2, SeqCst).is_some()); // should fail; shouldn't leak!
        assert_eq!(p.take(SeqCst), Some(~1));

        assert!(p.fill(~2, SeqCst).is_none()); // shouldn't fail
        assert_eq!(p.take(SeqCst), Some(~2));
    }

    #[test]
    fn bool_and() {
        let a = AtomicBool::new(true);
        assert_eq!(a.fetch_and(false, SeqCst),true);
        assert_eq!(a.load(SeqCst),false);
    }

    static mut S_BOOL : AtomicBool = INIT_ATOMIC_BOOL;
    static mut S_INT  : AtomicInt  = INIT_ATOMIC_INT;
    static mut S_UINT : AtomicUint = INIT_ATOMIC_UINT;

    #[test]
    fn static_init() {
        unsafe {
            assert!(!S_BOOL.load(SeqCst));
            assert!(S_INT.load(SeqCst) == 0);
            assert!(S_UINT.load(SeqCst) == 0);
        }
    }

    #[test]
    fn different_sizes() {
        unsafe {
            let mut slot = 0u16;
            assert_eq!(super::atomic_swap(&mut slot, 1, SeqCst), 0);

            let mut slot = 0u8;
            assert_eq!(super::atomic_compare_and_swap(&mut slot, 1, 2, SeqCst), 0);

            let slot = 0u32;
            assert_eq!(super::atomic_load(&slot, SeqCst), 0);

            let mut slot = 0u64;
            super::atomic_store(&mut slot, 2, SeqCst);
        }
    }
}


text:
import List from '../components/common/container/list.vue'
import Article from '../components/common/container/details.vue'

//路由映射
var routes = [
    {
        path: "/",
        name: "/",
        component: List
    },
    {
        path: "/list",
        name: "/list",
        component: List
    },
    {
        path: "/article/:id",
        name: "article",
        component: Article
    }
];

module.exports = routes;

redpajama_set_name: RedPajamaGithub


text:
#include <assert.h>
#include "mk_events_objects.h"
#include "Common/config.h"
#include "Record/MP4Recorder.h"
#include "Http/HttpSession.h"
#include "Http/HttpBody.h"
#include "Http/HttpClient.h"
#include "Rtsp/RtspSession.h"
using namespace mediakit;

///////////////////////////////////////////RecordInfo/////////////////////////////////////////////
API_EXPORT uint64_t API_CALL mk_mp4_info_get_start_time(const mk_mp4_info ctx){
    assert(ctx);
    RecordInfo *info = (RecordInfo *)ctx;
    return info->start_time;
}

API_EXPORT float API_CALL mk_mp4_info_get_time_len(const mk_mp4_info ctx){
    assert(ctx);
    RecordInfo *info = (RecordInfo *)ctx;
    return info->time_len;
}

API_EXPORT uint64_t API_CALL mk_mp4_info_get_file_size(const mk_mp4_info ctx){
    assert(ctx);
    RecordInfo *info = (RecordInfo *)ctx;
    return info->file_size;
}

API_EXPORT const char* API_CALL mk_mp4_info_get_file_path(const mk_mp4_info ctx){
    assert(ctx);
    RecordInfo *info = (RecordInfo *)ctx;
    return info->file_path.c_str();
}

API_EXPORT const char* API_CALL mk_mp4_info_get_file_name(const mk_mp4_info ctx){
    assert(ctx);
    RecordInfo *info = (RecordInfo *)ctx;
    return info->file_name.c_str();
}

API_EXPORT const char* API_CALL mk_mp4_info_get_folder(const mk_mp4_info ctx){
    assert(ctx);
    RecordInfo *info = (RecordInfo *)ctx;
    return info->folder.c_str();
}

API_EXPORT const char* API_CALL mk_mp4_info_get_url(const mk_mp4_info ctx){
    assert(ctx);
    RecordInfo *info = (RecordInfo *)ctx;
    return info->url.c_str();
}

API_EXPORT const char* API_CALL mk_mp4_info_get_vhost(const mk_mp4_info ctx){
    assert(ctx);
    RecordInfo *info = (RecordInfo *)ctx;
    return info->vhost.c_str();
}

API_EXPORT const char* API_CALL mk_mp4_info_get_app(const mk_mp4_info ctx){
    assert(ctx);
    RecordInfo *info = (RecordInfo *)ctx;
    return info->app.c_str();
}

API_EXPORT const char* API_CALL mk_mp4_info_get_stream(const mk_mp4_info ctx){
    assert(ctx);
    RecordInfo *info = (RecordInfo *)ctx;
    return info->stream.c_str();
}

///////////////////////////////////////////Parser/////////////////////////////////////////////
API_EXPORT const char* API_CALL mk_parser_get_method(const mk_parser ctx){
    assert(ctx);
    Parser *parser = (Parser *)ctx;
    return parser->Method().c_str();
}
API_EXPORT const char* API_CALL mk_parser_get_url(const mk_parser ctx){
    assert(ctx);
    Parser *parser = (Parser *)ctx;
    return parser->Url().c_str();
}
API_EXPORT const char* API_CALL mk_parser_get_full_url(const mk_parser ctx){
    assert(ctx);
    Parser *parser = (Parser *)ctx;
    return parser->FullUrl().c_str();
}
API_EXPORT const char* API_CALL mk_parser_get_url_params(const mk_parser ctx){
    assert(ctx);
    Parser *parser = (Parser *)ctx;
    return parser->Params().c_str();
}
API_EXPORT const char* API_CALL mk_parser_get_url_param(const mk_parser ctx,const char *key){
    assert(ctx && key);
    Parser *parser = (Parser *)ctx;
    return parser->getUrlArgs()[key].c_str();
}
API_EXPORT const char* API_CALL mk_parser_get_tail(const mk_parser ctx){
    assert(ctx);
    Parser *parser = (Parser *)ctx;
    return parser->Tail().c_str();
}
API_EXPORT const char* API_CALL mk_parser_get_header(const mk_parser ctx,const char *key){
    assert(ctx && key);
    Parser *parser = (Parser *)ctx;
    return parser->getHeader()[key].c_str();
}
API_EXPORT const char* API_CALL mk_parser_get_content(const mk_parser ctx, int *length){
    assert(ctx);
    Parser *parser = (Parser *)ctx;
    if(length){
        *length = parser->Content().size();
    }
    return parser->Content().c_str();
}

///////////////////////////////////////////MediaInfo/////////////////////////////////////////////
API_EXPORT const char* API_CALL mk_media_info_get_params(const mk_media_info ctx){
    assert(ctx);
    MediaInfo *info = (MediaInfo *)ctx;
    return info->_param_strs.c_str();
}

API_EXPORT const char* API_CALL mk_media_info_get_schema(const mk_media_info ctx){
    assert(ctx);
    MediaInfo *info = (MediaInfo *)ctx;
    return info->_schema.c_str();
}

API_EXPORT const char* API_CALL mk_media_info_get_vhost(const mk_media_info ctx){
    assert(ctx);
    MediaInfo *info = (MediaInfo *)ctx;
    return info->_vhost.c_str();
}

API_EXPORT const char* API_CALL mk_media_info_get_host(const mk_media_info ctx){
    assert(ctx);
    MediaInfo *info = (MediaInfo *)ctx;
    return info->_host.c_str();
}

API_EXPORT uint16_t API_CALL mk_media_info_get_port(const mk_media_info ctx){
    assert(ctx);
    MediaInfo *info = (MediaInfo *)ctx;
    return std::stoi(info->_port);
}

API_EXPORT const char* API_CALL mk_media_info_get_app(const mk_media_info ctx){
    assert(ctx);
    MediaInfo *info = (MediaInfo *)ctx;
    return info->_app.c_str();
}

API_EXPORT const char* API_CALL mk_media_info_get_stream(const mk_media_info ctx){
    assert(ctx);
    MediaInfo *info = (MediaInfo *)ctx;
    return info->_streamid.c_str();
}

///////////////////////////////////////////MediaSource/////////////////////////////////////////////
API_EXPORT const char* API_CALL mk_media_source_get_schema(const mk_media_source ctx){
    assert(ctx);
    MediaSource *src = (MediaSource *)ctx;
    return src->getSchema().c_str();
}
API_EXPORT const char* API_CALL mk_media_source_get_vhost(const mk_media_source ctx){
    assert(ctx);
    MediaSource *src = (MediaSource *)ctx;
    return src->getVhost().c_str();
}
API_EXPORT const char* API_CALL mk_media_source_get_app(const mk_media_source ctx){
    assert(ctx);
    MediaSource *src = (MediaSource *)ctx;
    return src->getApp().c_str();
}
API_EXPORT const char* API_CALL mk_media_source_get_stream(const mk_media_source ctx){
    assert(ctx);
    MediaSource *src = (MediaSource *)ctx;
    return src->getId().c_str();
}
API_EXPORT int API_CALL mk_media_source_get_reader_count(const mk_media_source ctx){
    assert(ctx);
    MediaSource *src = (MediaSource *)ctx;
    return src->readerCount();
}

API_EXPORT int API_CALL mk_media_source_get_total_reader_count(const mk_media_source ctx){
    assert(ctx);
    MediaSource *src = (MediaSource *)ctx;
    return src->totalReaderCount();
}

API_EXPORT int API_CALL mk_media_source_close(const mk_media_source ctx,int force){
    assert(ctx);
    MediaSource *src = (MediaSource *)ctx;
    return src->close(force);
}
API_EXPORT int API_CALL mk_media_source_seek_to(const mk_media_source ctx,uint32_t stamp){
    assert(ctx);
    MediaSource *src = (MediaSource *)ctx;
    return src->seekTo(stamp);
}

API_EXPORT void API_CALL mk_media_source_find(const char *schema,
                                              const char *vhost,
                                              const char *app,
                                              const char *stream,
                                              void *user_data,
                                              on_mk_media_source_find_cb cb) {
    assert(schema && vhost && app && stream && cb);
    auto src = MediaSource::find(schema, vhost, app, stream);
    cb(user_data, src.get());
}

API_EXPORT void API_CALL mk_media_source_for_each(void *user_data, on_mk_media_source_find_cb cb){
    assert(cb);
    MediaSource::for_each_media([&](const MediaSource::Ptr &src){
        cb(user_data,src.get());
    });
}

///////////////////////////////////////////HttpBody/////////////////////////////////////////////
API_EXPORT mk_http_body API_CALL mk_http_body_from_string(const char *str,int len){
    assert(str);
    if(!len){
        len = strlen(str);
    }
    return new HttpBody::Ptr(new HttpStringBody(string(str,len)));
}

API_EXPORT mk_http_body API_CALL mk_http_body_from_file(const char *file_path){
    assert(file_path);
    return new HttpBody::Ptr(new HttpFileBody(file_path));
}

template <typename C = StrCaseMap>
static C get_http_header( const char *response_header[]){
    C header;
    for (int i = 0; response_header[i] != NULL;) {
        auto key = response_header[i];
        auto value = response_header[i + 1];
        if (key && value) {
            i += 2;
            header.emplace(key,value);
            continue;
        }
        break;
    }
    return header;
}

API_EXPORT mk_http_body API_CALL mk_http_body_from_multi_form(const char *key_val[],const char *file_path){
    assert(key_val && file_path);
    return new HttpBody::Ptr(new HttpMultiFormBody(get_http_header<HttpArgs>(key_val),file_path));
}

API_EXPORT void API_CALL mk_http_body_release(mk_http_body ctx){
    assert(ctx);
    HttpBody::Ptr *ptr = (HttpBody::Ptr *)ctx;
    delete ptr;
}

///////////////////////////////////////////HttpResponseInvoker/////////////////////////////////////////////
API_EXPORT void API_CALL mk_http_response_invoker_do_string(const mk_http_response_invoker ctx,
                                                            const char *response_code,
                                                            const char **response_header,
                                                            const char *response_content){
    assert(ctx && response_code && response_header && response_content);
    auto header = get_http_header(response_header);
    HttpSession::HttpResponseInvoker *invoker = (HttpSession::HttpResponseInvoker *)ctx;
    (*invoker)(response_code,header,response_content);
}

API_EXPORT void API_CALL mk_http_response_invoker_do_file(const mk_http_response_invoker ctx,
                                                          const mk_parser request_parser,
                                                          const char *response_header[],
                                                          const char *response_file_path){
    assert(ctx && request_parser && response_header && response_file_path);
    auto header = get_http_header(response_header);
    HttpSession::HttpResponseInvoker *invoker = (HttpSession::HttpResponseInvoker *)ctx;
    (*invoker).responseFile(((Parser *) (request_parser))->getHeader(), header, response_file_path);
}

API_EXPORT void API_CALL mk_http_response_invoker_do(const mk_http_response_invoker ctx,
                                                     const char *response_code,
                                                     const char **response_header,
                                                     const mk_http_body response_body){
    assert(ctx && response_code && response_header && response_body);
    auto header = get_http_header(response_header);
    HttpSession::HttpResponseInvoker *invoker = (HttpSession::HttpResponseInvoker *)ctx;
    HttpBody::Ptr *body = (HttpBody::Ptr*) response_body;
    (*invoker)(response_code,header,*body);
}

API_EXPORT mk_http_response_invoker API_CALL mk_http_response_invoker_clone(const mk_http_response_invoker ctx){
    assert(ctx);
    HttpSession::HttpResponseInvoker *invoker = (HttpSession::HttpResponseInvoker *)ctx;
    return new  HttpSession::HttpResponseInvoker (*invoker);
}

API_EXPORT void API_CALL mk_http_response_invoker_clone_release(const mk_http_response_invoker ctx){
    assert(ctx);
    HttpSession::HttpResponseInvoker *invoker = (HttpSession::HttpResponseInvoker *)ctx;
    delete invoker;
}

///////////////////////////////////////////HttpAccessPathInvoker/////////////////////////////////////////////
API_EXPORT void API_CALL mk_http_access_path_invoker_do(const mk_http_access_path_invoker ctx,
                                                        const char *err_msg,
                                                        const char *access_path,
                                                        int cookie_life_second){
    assert(ctx);
    HttpSession::HttpAccessPathInvoker *invoker = (HttpSession::HttpAccessPathInvoker *)ctx;
    (*invoker)(err_msg ? err_msg : "",
              access_path? access_path : "",
              cookie_life_second);
}

API_EXPORT mk_http_access_path_invoker API_CALL mk_http_access_path_invoker_clone(const mk_http_access_path_invoker ctx){
    assert(ctx);
    HttpSession::HttpAccessPathInvoker *invoker = (HttpSession::HttpAccessPathInvoker *)ctx;
    return new HttpSession::HttpAccessPathInvoker(*invoker);
}

API_EXPORT void API_CALL mk_http_access_path_invoker_clone_release(const mk_http_access_path_invoker ctx){
    assert(ctx);
    HttpSession::HttpAccessPathInvoker *invoker = (HttpSession::HttpAccessPathInvoker *)ctx;
    delete invoker;
}

///////////////////////////////////////////RtspSession::onGetRealm/////////////////////////////////////////////
API_EXPORT void API_CALL mk_rtsp_get_realm_invoker_do(const mk_rtsp_get_realm_invoker ctx,
                                                      const char *realm){
    assert(ctx);
    RtspSession::onGetRealm *invoker = (RtspSession::onGetRealm *)ctx;
    (*invoker)(realm ? realm : "");
}

API_EXPORT mk_rtsp_get_realm_invoker API_CALL mk_rtsp_get_realm_invoker_clone(const mk_rtsp_get_realm_invoker ctx){
    assert(ctx);
    RtspSession::onGetRealm *invoker = (RtspSession::onGetRealm *)ctx;
    return new RtspSession::onGetRealm (*invoker);
}

API_EXPORT void API_CALL mk_rtsp_get_realm_invoker_clone_release(const mk_rtsp_get_realm_invoker ctx){
    assert(ctx);
    RtspSession::onGetRealm *invoker = (RtspSession::onGetRealm *)ctx;
    delete invoker;
}

///////////////////////////////////////////RtspSession::onAuth/////////////////////////////////////////////
API_EXPORT void API_CALL mk_rtsp_auth_invoker_do(const mk_rtsp_auth_invoker ctx,
                                                 int encrypted,
                                                 const char *pwd_or_md5){
    assert(ctx);
    RtspSession::onAuth *invoker = (RtspSession::onAuth *)ctx;
    (*invoker)(encrypted, pwd_or_md5 ? pwd_or_md5 : "");
}

API_EXPORT mk_rtsp_auth_invoker API_CALL mk_rtsp_auth_invoker_clone(const mk_rtsp_auth_invoker ctx){
    assert(ctx);
    RtspSession::onAuth *invoker = (RtspSession::onAuth *)ctx;
    return new RtspSession::onAuth(*invoker);
}

API_EXPORT void API_CALL mk_rtsp_auth_invoker_clone_release(const mk_rtsp_auth_invoker ctx){
    assert(ctx);
    RtspSession::onAuth *invoker = (RtspSession::onAuth *)ctx;
    delete invoker;
}

///////////////////////////////////////////Broadcast::PublishAuthInvoker/////////////////////////////////////////////
API_EXPORT void API_CALL mk_publish_auth_invoker_do(const mk_publish_auth_invoker ctx,
                                                    const char *err_msg,
                                                    int enable_hls,
                                                    int enable_mp4){
    assert(ctx);
    Broadcast::PublishAuthInvoker *invoker = (Broadcast::PublishAuthInvoker *)ctx;
    (*invoker)(err_msg ? err_msg : "", enable_hls, enable_mp4);
}

API_EXPORT mk_publish_auth_invoker API_CALL mk_publish_auth_invoker_clone(const mk_publish_auth_invoker ctx){
    assert(ctx);
    Broadcast::PublishAuthInvoker *invoker = (Broadcast::PublishAuthInvoker *)ctx;
    return new Broadcast::PublishAuthInvoker(*invoker);
}

API_EXPORT void API_CALL mk_publish_auth_invoker_clone_release(const mk_publish_auth_invoker ctx){
    assert(ctx);
    Broadcast::PublishAuthInvoker *invoker = (Broadcast::PublishAuthInvoker *)ctx;
    delete invoker;
}

///////////////////////////////////////////Broadcast::AuthInvoker/////////////////////////////////////////////
API_EXPORT void API_CALL mk_auth_invoker_do(const mk_auth_invoker ctx, const char *err_msg){
    assert(ctx);
    Broadcast::AuthInvoker *invoker = (Broadcast::AuthInvoker *)ctx;
    (*invoker)(err_msg ? err_msg : "");
}

API_EXPORT mk_auth_invoker API_CALL mk_auth_invoker_clone(const mk_auth_invoker ctx){
    assert(ctx);
    Broadcast::AuthInvoker *invoker = (Broadcast::AuthInvoker *)ctx;
    return new Broadcast::AuthInvoker(*invoker);
}

API_EXPORT void API_CALL mk_auth_invoker_clone_release(const mk_auth_invoker ctx){
    assert(ctx);
    Broadcast::AuthInvoker *invoker = (Broadcast::AuthInvoker *)ctx;
    delete invoker;
}


text:
'use strict';

// MODULES //

var tape = require( 'tape' );
var noop = require( '@stdlib/utils/noop' );
var ctor = require( './../lib' );

// TESTS //

tape( 'main export is a function', function test( t ) {
	t.ok( true, __filename );
	t.strictEqual( typeof ctor, 'function', 'main export is a function' );
	t.end();
});

tape( 'an instance throws an error if provided an invalid `description` value', function test( t ) {
	var values;
	var i;

	values = [
		5,
		NaN,
		true,
		false,
		null,
		void 0,
		{},
		[],
		function noop() {}
	];

	for ( i = 0; i < values.length; i++ ) {
		t.throws( badValue( values[i] ), TypeError, 'throws an error when provided '+values[i] );
	}
	t.end();

	function badValue( value ) {
		return function badValue() {
			var sparkline = ctor();
			sparkline.description = value;
		};
	}
});

tape( 'an instance supports setting and getting the property value', function test( t ) {
	var sparkline;

	sparkline = ctor({
		'description': 'beep'
	});
	sparkline._render = noop; // eslint-disable-line no-underscore-dangle
	t.strictEqual( sparkline.description, 'beep', 'returns expected value' );

	sparkline.description = 'boop';
	t.strictEqual( sparkline.description, 'boop', 'returns expected value' );

	sparkline.description = 'foo';
	t.strictEqual( sparkline.description, 'foo', 'returns expected value' );

	t.end();
});

tape( 'setting the `description` property to a new value triggers a `change` event', function test( t ) {
	var sparkline;

	sparkline = ctor({
		'description': 'beep'
	});
	sparkline._render = noop; // eslint-disable-line no-underscore-dangle

	sparkline.on( 'change', onChange );
	sparkline.description = 'boop';

	function onChange() {
		t.ok( true, 'triggers event' );
		t.end();
	}
});

tape( 'setting the `description` property to its current value does not trigger a `change` event', function test( t ) {
	var sparkline;

	sparkline = ctor({
		'description': 'beep'
	});
	sparkline._render = noop; // eslint-disable-line no-underscore-dangle

	sparkline.on( 'change', onChange );
	sparkline.description = 'beep';

	t.ok( true, 'does not trigger event' );
	t.end();

	function onChange() {
		t.ok( false, 'should not trigger event' );
	}
});


text:
title: Kubernetes - Pod
mathjax: false
date: 2022-07-13 00:06:25
categories:
  - Cloud Native
  - Cloud Native Foundation
  - Kubernetes
tags:
  - Cloud Native
  - Kubernetes
---

# 描述
![](https://cloud-native-kubernetes-1253868755.cos.ap-guangzhou.myqcloud.com/introduction/pod-desc.png)

<!-- more -->

# 操作
![](https://cloud-native-kubernetes-1253868755.cos.ap-guangzhou.myqcloud.com/introduction/pod-op.png)


text:
package org.twitterconsole.io;

import static java.text.MessageFormat.format;

import java.time.Duration;

public class SocialNetworkDuration {
    private static final String TIMESTAMP_PATTERN = "{0} {1} ago";
    private static final String UNIT_ONE_MINUTE = "minute";
    private static final String UNIT_MULTIPLE_MINUTES = "minutes";
    private static final String UNIT_ONE_SECOND = "second";
    private static final String UNIT_MULTIPLE_SECONDS = "seconds";

    private Duration timePassed;

    public SocialNetworkDuration(Duration timePassed) {
        this.timePassed = timePassed;
    }

    @Override
    public String toString() {
        if (timePassed.getSeconds() >= 60)
            return printTimestamp(timePassed.toMinutes());
        return printTimestampFromSeconds(timePassed.getSeconds());
    }

    private String printTimestampFromSeconds(long numberOfSeconds) {
        return format(TIMESTAMP_PATTERN, numberOfSeconds, getSecondsUnit(numberOfSeconds));
    }

    private Object getSecondsUnit(long numberOfSeconds) {
        if (numberOfSeconds > 1)
            return UNIT_MULTIPLE_SECONDS;
        return UNIT_ONE_SECOND;
    }

    private String printTimestamp(long numberOfMinutes) {
        return format(TIMESTAMP_PATTERN, numberOfMinutes, getUnit(numberOfMinutes));
    }

    private String getUnit(long numberOfMinutes) {
        if (numberOfMinutes > 1)
            return UNIT_MULTIPLE_MINUTES;
        return UNIT_ONE_MINUTE;
    }
}


text:
'use strict';
var assert = require('assert');
var typeutils = require('typeutils');
var domainRegex = /^[a-z0-9.-]+$/;

function isDomain(domain) {
  if (!typeutils.isString(domain)) {
    return false;
  }

  if (domain.length > 255) {
    return false;
  }

  if (!domainRegex.test(domain)) {
    return false;
  }

  var labels = domain.split('.');
  for (var i = 0; i < labels.length; ++i) {
    var label = labels[i];
    if (label.length < 1 || label.length > 63) {
      return false;
    }
  }

  return true;
}

module.exports = isDomain;


text:
namespace cc {
namespace {

class LayerTreeHostAnimationTest : public LayerTreeTest {
 public:
  void SetupTree() override {
    LayerTreeTest::SetupTree();
    layer_tree_host()->root_layer()->set_layer_animation_delegate(this);
  }
};

// Makes sure that SetNeedsAnimate does not cause the CommitRequested() state to
// be set.
class LayerTreeHostAnimationTestSetNeedsAnimateShouldNotSetCommitRequested
    : public LayerTreeHostAnimationTest {
 public:
  LayerTreeHostAnimationTestSetNeedsAnimateShouldNotSetCommitRequested()
      : num_commits_(0) {}

  void BeginTest() override { PostSetNeedsCommitToMainThread(); }

  void BeginMainFrame(const BeginFrameArgs& args) override {
    // We skip the first commit because its the commit that populates the
    // impl thread with a tree. After the second commit, the test is done.
    if (num_commits_ != 1)
      return;

    layer_tree_host()->SetNeedsAnimate();
    // Right now, CommitRequested is going to be true, because during
    // BeginFrame, we force CommitRequested to true to prevent requests from
    // hitting the impl thread. But, when the next DidCommit happens, we should
    // verify that CommitRequested has gone back to false.
  }

  void DidCommit() override {
    if (!num_commits_) {
      EXPECT_FALSE(layer_tree_host()->CommitRequested());
      layer_tree_host()->SetNeedsAnimate();
      EXPECT_FALSE(layer_tree_host()->CommitRequested());
    }

    // Verifies that the SetNeedsAnimate we made in ::Animate did not
    // trigger CommitRequested.
    EXPECT_FALSE(layer_tree_host()->CommitRequested());
    EndTest();
    num_commits_++;
  }

  void AfterTest() override {}

 private:
  int num_commits_;
};

MULTI_THREAD_TEST_F(
    LayerTreeHostAnimationTestSetNeedsAnimateShouldNotSetCommitRequested);

// Trigger a frame with SetNeedsCommit. Then, inside the resulting animate
// callback, request another frame using SetNeedsAnimate. End the test when
// animate gets called yet-again, indicating that the proxy is correctly
// handling the case where SetNeedsAnimate() is called inside the BeginFrame
// flow.
class LayerTreeHostAnimationTestSetNeedsAnimateInsideAnimationCallback
    : public LayerTreeHostAnimationTest {
 public:
  LayerTreeHostAnimationTestSetNeedsAnimateInsideAnimationCallback()
      : num_begin_frames_(0) {}

  void BeginTest() override { PostSetNeedsCommitToMainThread(); }

  void BeginMainFrame(const BeginFrameArgs& args) override {
    if (!num_begin_frames_) {
      layer_tree_host()->SetNeedsAnimate();
      num_begin_frames_++;
      return;
    }
    EndTest();
  }

  void AfterTest() override {}

 private:
  int num_begin_frames_;
};

SINGLE_AND_MULTI_THREAD_TEST_F(
    LayerTreeHostAnimationTestSetNeedsAnimateInsideAnimationCallback);

// Add a layer animation and confirm that
// LayerTreeHostImpl::UpdateAnimationState does get called.
class LayerTreeHostAnimationTestAddAnimation
    : public LayerTreeHostAnimationTest {
 public:
  LayerTreeHostAnimationTestAddAnimation()
      : update_animation_state_was_called_(false) {}

  void BeginTest() override {
    PostAddInstantAnimationToMainThread(layer_tree_host()->root_layer());
  }

  void UpdateAnimationState(LayerTreeHostImpl* host_impl,
                            bool has_unfinished_animation) override {
    EXPECT_FALSE(has_unfinished_animation);
    update_animation_state_was_called_ = true;
  }

  void NotifyAnimationStarted(base::TimeTicks monotonic_time,
                              Animation::TargetProperty target_property,
                              int group) override {
    EXPECT_LT(base::TimeTicks(), monotonic_time);

    LayerAnimationController* controller =
        layer_tree_host()->root_layer()->layer_animation_controller();
    Animation* animation = controller->GetAnimation(Animation::OPACITY);
    if (animation)
      controller->RemoveAnimation(animation->id());

    EndTest();
  }

  void AfterTest() override { EXPECT_TRUE(update_animation_state_was_called_); }

 private:
  bool update_animation_state_was_called_;
};

SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestAddAnimation);

// Add a layer animation to a layer, but continually fail to draw. Confirm that
// after a while, we do eventually force a draw.
class LayerTreeHostAnimationTestCheckerboardDoesNotStarveDraws
    : public LayerTreeHostAnimationTest {
 public:
  LayerTreeHostAnimationTestCheckerboardDoesNotStarveDraws()
      : started_animating_(false) {}

  void BeginTest() override {
    PostAddAnimationToMainThread(layer_tree_host()->root_layer());
  }

  void AnimateLayers(LayerTreeHostImpl* host_impl,
                     base::TimeTicks monotonic_time) override {
    started_animating_ = true;
  }

  void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
    if (started_animating_)
      EndTest();
  }

  DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
                                   LayerTreeHostImpl::FrameData* frame,
                                   DrawResult draw_result) override {
    return DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
  }

  void AfterTest() override {}

 private:
  bool started_animating_;
};

// Starvation can only be an issue with the MT compositor.
MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestCheckerboardDoesNotStarveDraws);

// Ensures that animations eventually get deleted.
class LayerTreeHostAnimationTestAnimationsGetDeleted
    : public LayerTreeHostAnimationTest {
 public:
  LayerTreeHostAnimationTestAnimationsGetDeleted()
      : started_animating_(false) {}

  void BeginTest() override {
    PostAddAnimationToMainThread(layer_tree_host()->root_layer());
  }

  void AnimateLayers(LayerTreeHostImpl* host_impl,
                     base::TimeTicks monotonic_time) override {
    bool have_animations = !host_impl->animation_registrar()
                                ->active_animation_controllers_for_testing()
                                .empty();
    if (!started_animating_ && have_animations) {
      started_animating_ = true;
      return;
    }

    if (started_animating_ && !have_animations)
      EndTest();
  }

  void NotifyAnimationFinished(base::TimeTicks monotonic_time,
                               Animation::TargetProperty target_property,
                               int group) override {
    // Animations on the impl-side controller only get deleted during a commit,
    // so we need to schedule a commit.
    layer_tree_host()->SetNeedsCommit();
  }

  void AfterTest() override {}

 private:
  bool started_animating_;
};

SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestAnimationsGetDeleted);

// Ensure that an animation's timing function is respected.
class LayerTreeHostAnimationTestAddAnimationWithTimingFunction
    : public LayerTreeHostAnimationTest {
 public:
  LayerTreeHostAnimationTestAddAnimationWithTimingFunction() {}

  void SetupTree() override {
    LayerTreeHostAnimationTest::SetupTree();
    picture_ = FakePictureLayer::Create(layer_settings(), &client_);
    picture_->SetBounds(gfx::Size(4, 4));
    layer_tree_host()->root_layer()->AddChild(picture_);
  }

  void BeginTest() override { PostAddAnimationToMainThread(picture_.get()); }

  void AnimateLayers(LayerTreeHostImpl* host_impl,
                     base::TimeTicks monotonic_time) override {
    LayerAnimationController* controller_impl =
        host_impl->active_tree()->root_layer()->children()[0]->
        layer_animation_controller();
    Animation* animation = controller_impl->GetAnimation(Animation::OPACITY);
    if (!animation)
      return;

    const FloatAnimationCurve* curve =
        animation->curve()->ToFloatAnimationCurve();
    float start_opacity = curve->GetValue(base::TimeDelta());
    float end_opacity = curve->GetValue(curve->Duration());
    float linearly_interpolated_opacity =
        0.25f * end_opacity + 0.75f * start_opacity;
    base::TimeDelta time = TimeUtil::Scale(curve->Duration(), 0.25f);
    // If the linear timing function associated with this animation was not
    // picked up, then the linearly interpolated opacity would be different
    // because of the default ease timing function.
    EXPECT_FLOAT_EQ(linearly_interpolated_opacity, curve->GetValue(time));

    EndTest();
  }

  void AfterTest() override {}

  FakeContentLayerClient client_;
  scoped_refptr<FakePictureLayer> picture_;
};

SINGLE_AND_MULTI_THREAD_TEST_F(
    LayerTreeHostAnimationTestAddAnimationWithTimingFunction);

// Ensures that main thread animations have their start times synchronized with
// impl thread animations.
class LayerTreeHostAnimationTestSynchronizeAnimationStartTimes
    : public LayerTreeHostAnimationTest {
 public:
  LayerTreeHostAnimationTestSynchronizeAnimationStartTimes() {}

  void SetupTree() override {
    LayerTreeHostAnimationTest::SetupTree();
    picture_ = FakePictureLayer::Create(layer_settings(), &client_);
    picture_->SetBounds(gfx::Size(4, 4));
    picture_->set_layer_animation_delegate(this);
    layer_tree_host()->root_layer()->AddChild(picture_);
  }

  void BeginTest() override { PostAddAnimationToMainThread(picture_.get()); }

  void NotifyAnimationStarted(base::TimeTicks monotonic_time,
                              Animation::TargetProperty target_property,
                              int group) override {
    LayerAnimationController* controller =
        layer_tree_host()->root_layer()->children()[0]->
        layer_animation_controller();
    Animation* animation = controller->GetAnimation(Animation::OPACITY);
    main_start_time_ = animation->start_time();
    controller->RemoveAnimation(animation->id());
    EndTest();
  }

  void UpdateAnimationState(LayerTreeHostImpl* impl_host,
                            bool has_unfinished_animation) override {
    LayerAnimationController* controller =
        impl_host->active_tree()->root_layer()->children()[0]->
        layer_animation_controller();
    Animation* animation = controller->GetAnimation(Animation::OPACITY);
    if (!animation)
      return;

    impl_start_time_ = animation->start_time();
  }

  void AfterTest() override {
    EXPECT_EQ(impl_start_time_, main_start_time_);
    EXPECT_LT(base::TimeTicks(), impl_start_time_);
  }

 private:
  base::TimeTicks main_start_time_;
  base::TimeTicks impl_start_time_;
  FakeContentLayerClient client_;
  scoped_refptr<FakePictureLayer> picture_;
};

SINGLE_AND_MULTI_THREAD_TEST_F(
    LayerTreeHostAnimationTestSynchronizeAnimationStartTimes);

// Ensures that notify animation finished is called.
class LayerTreeHostAnimationTestAnimationFinishedEvents
    : public LayerTreeHostAnimationTest {
 public:
  LayerTreeHostAnimationTestAnimationFinishedEvents() {}

  void BeginTest() override {
    PostAddInstantAnimationToMainThread(layer_tree_host()->root_layer());
  }

  void NotifyAnimationFinished(base::TimeTicks monotonic_time,
                               Animation::TargetProperty target_property,
                               int group) override {
    LayerAnimationController* controller =
        layer_tree_host()->root_layer()->layer_animation_controller();
    Animation* animation = controller->GetAnimation(Animation::OPACITY);
    if (animation)
      controller->RemoveAnimation(animation->id());
    EndTest();
  }

  void AfterTest() override {}
};

SINGLE_AND_MULTI_THREAD_TEST_F(
    LayerTreeHostAnimationTestAnimationFinishedEvents);

// Ensures that when opacity is being animated, this value does not cause the
// subtree to be skipped.
class LayerTreeHostAnimationTestDoNotSkipLayersWithAnimatedOpacity
    : public LayerTreeHostAnimationTest {
 public:
  LayerTreeHostAnimationTestDoNotSkipLayersWithAnimatedOpacity()
      : update_check_layer_(
            FakePictureLayer::Create(layer_settings(), &client_)) {}

  void SetupTree() override {
    update_check_layer_->SetOpacity(0.f);
    layer_tree_host()->SetRootLayer(update_check_layer_);
    LayerTreeHostAnimationTest::SetupTree();
  }

  void BeginTest() override {
    PostAddAnimationToMainThread(update_check_layer_.get());
  }

  void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
    LayerAnimationController* controller_impl =
        host_impl->active_tree()->root_layer()->layer_animation_controller();
    Animation* animation_impl =
        controller_impl->GetAnimation(Animation::OPACITY);
    controller_impl->RemoveAnimation(animation_impl->id());
    EndTest();
  }

  void AfterTest() override {
    // Update() should have been called once, proving that the layer was not
    // skipped.
    EXPECT_EQ(1, update_check_layer_->update_count());

    // clear update_check_layer_ so LayerTreeHost dies.
    update_check_layer_ = NULL;
  }

 private:
  FakeContentLayerClient client_;
  scoped_refptr<FakePictureLayer> update_check_layer_;
};

SINGLE_AND_MULTI_THREAD_TEST_F(
    LayerTreeHostAnimationTestDoNotSkipLayersWithAnimatedOpacity);

// Layers added to tree with existing active animations should have the
// animation correctly recognized.
class LayerTreeHostAnimationTestLayerAddedWithAnimation
    : public LayerTreeHostAnimationTest {
 public:
  LayerTreeHostAnimationTestLayerAddedWithAnimation() {}

  void BeginTest() override { PostSetNeedsCommitToMainThread(); }

  void DidCommit() override {
    if (layer_tree_host()->source_frame_number() == 1) {
      scoped_refptr<Layer> layer = Layer::Create(layer_settings());
      layer->set_layer_animation_delegate(this);

      // Any valid AnimationCurve will do here.
      scoped_ptr<AnimationCurve> curve(new FakeFloatAnimationCurve());
      scoped_ptr<Animation> animation(
          Animation::Create(curve.Pass(), 1, 1, Animation::OPACITY));
      layer->layer_animation_controller()->AddAnimation(animation.Pass());

      // We add the animation *before* attaching the layer to the tree.
      layer_tree_host()->root_layer()->AddChild(layer);
    }
  }

  void AnimateLayers(LayerTreeHostImpl* impl_host,
                     base::TimeTicks monotonic_time) override {
    EndTest();
  }

  void AfterTest() override {}
};

SINGLE_AND_MULTI_THREAD_TEST_F(
    LayerTreeHostAnimationTestLayerAddedWithAnimation);

class LayerTreeHostAnimationTestCancelAnimateCommit
    : public LayerTreeHostAnimationTest {
 public:
  LayerTreeHostAnimationTestCancelAnimateCommit()
      : num_begin_frames_(0), num_commit_calls_(0), num_draw_calls_(0) {}

  void BeginTest() override { PostSetNeedsCommitToMainThread(); }

  void BeginMainFrame(const BeginFrameArgs& args) override {
    num_begin_frames_++;
    // No-op animate will cancel the commit.
    if (layer_tree_host()->source_frame_number() == 1) {
      EndTest();
      return;
    }
    layer_tree_host()->SetNeedsAnimate();
  }

  void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
    num_commit_calls_++;
    if (impl->active_tree()->source_frame_number() > 1)
      FAIL() << "Commit should have been canceled.";
  }

  void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
    num_draw_calls_++;
    if (impl->active_tree()->source_frame_number() > 1)
      FAIL() << "Draw should have been canceled.";
  }

  void AfterTest() override {
    EXPECT_EQ(2, num_begin_frames_);
    EXPECT_EQ(1, num_commit_calls_);
    EXPECT_EQ(1, num_draw_calls_);
  }

 private:
  int num_begin_frames_;
  int num_commit_calls_;
  int num_draw_calls_;
};

MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestCancelAnimateCommit);

class LayerTreeHostAnimationTestForceRedraw
    : public LayerTreeHostAnimationTest {
 public:
  LayerTreeHostAnimationTestForceRedraw()
      : num_animate_(0), num_draw_layers_(0) {}

  void BeginTest() override { PostSetNeedsCommitToMainThread(); }

  void BeginMainFrame(const BeginFrameArgs& args) override {
    if (++num_animate_ < 2)
      layer_tree_host()->SetNeedsAnimate();
  }

  void Layout() override { layer_tree_host()->SetNextCommitForcesRedraw(); }

  void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
    if (++num_draw_layers_ == 2)
      EndTest();
  }

  void AfterTest() override {
    // The first commit will always draw; make sure the second draw triggered
    // by the animation was not cancelled.
    EXPECT_EQ(2, num_draw_layers_);
    EXPECT_EQ(2, num_animate_);
  }

 private:
  int num_animate_;
  int num_draw_layers_;
};

MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestForceRedraw);

class LayerTreeHostAnimationTestAnimateAfterSetNeedsCommit
    : public LayerTreeHostAnimationTest {
 public:
  LayerTreeHostAnimationTestAnimateAfterSetNeedsCommit()
      : num_animate_(0), num_draw_layers_(0) {}

  void BeginTest() override { PostSetNeedsCommitToMainThread(); }

  void BeginMainFrame(const BeginFrameArgs& args) override {
    if (++num_animate_ <= 2) {
      layer_tree_host()->SetNeedsCommit();
      layer_tree_host()->SetNeedsAnimate();
    }
  }

  void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
    if (++num_draw_layers_ == 2)
      EndTest();
  }

  void AfterTest() override {
    // The first commit will always draw; make sure the second draw triggered
    // by the SetNeedsCommit was not cancelled.
    EXPECT_EQ(2, num_draw_layers_);
    EXPECT_GE(num_animate_, 2);
  }

 private:
  int num_animate_;
  int num_draw_layers_;
};

MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestAnimateAfterSetNeedsCommit);

// Animations should not be started when frames are being skipped due to
// checkerboard.
class LayerTreeHostAnimationTestCheckerboardDoesntStartAnimations
    : public LayerTreeHostAnimationTest {
  void SetupTree() override {
    LayerTreeHostAnimationTest::SetupTree();
    picture_ = FakePictureLayer::Create(layer_settings(), &client_);
    picture_->SetBounds(gfx::Size(4, 4));
    picture_->set_layer_animation_delegate(this);
    layer_tree_host()->root_layer()->AddChild(picture_);
  }

  void InitializeSettings(LayerTreeSettings* settings) override {
    // Make sure that drawing many times doesn't cause a checkerboarded
    // animation to start so we avoid flake in this test.
    settings->timeout_and_draw_when_animation_checkerboards = false;
  }

  void BeginTest() override {
    prevented_draw_ = 0;
    added_animations_ = 0;
    started_times_ = 0;

    PostSetNeedsCommitToMainThread();
  }

  DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
                                   LayerTreeHostImpl::FrameData* frame_data,
                                   DrawResult draw_result) override {
    if (added_animations_ < 2)
      return draw_result;
    if (TestEnded())
      return draw_result;
    // Act like there is checkerboard when the second animation wants to draw.
    ++prevented_draw_;
    if (prevented_draw_ > 2)
      EndTest();
    return DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
  }

  void DidCommitAndDrawFrame() override {
    switch (layer_tree_host()->source_frame_number()) {
      case 1:
        // The animation is longer than 1 BeginFrame interval.
        AddOpacityTransitionToLayer(picture_.get(), 0.1, 0.2f, 0.8f, false);
        added_animations_++;
        break;
      case 2:
        // This second animation will not be drawn so it should not start.
        AddAnimatedTransformToLayer(picture_.get(), 0.1, 5, 5);
        added_animations_++;
        break;
    }
  }

  void NotifyAnimationStarted(base::TimeTicks monotonic_time,
                              Animation::TargetProperty target_property,
                              int group) override {
    if (TestEnded())
      return;
    started_times_++;
  }

  void AfterTest() override {
    // Make sure we tried to draw the second animation but failed.
    EXPECT_LT(0, prevented_draw_);
    // The first animation should be started, but the second should not because
    // of checkerboard.
    EXPECT_EQ(1, started_times_);
  }

  int prevented_draw_;
  int added_animations_;
  int started_times_;
  FakeContentLayerClient client_;
  scoped_refptr<FakePictureLayer> picture_;
};

MULTI_THREAD_TEST_F(
    LayerTreeHostAnimationTestCheckerboardDoesntStartAnimations);

// Verifies that scroll offset animations are only accepted when impl-scrolling
// is supported, and that when scroll offset animations are accepted,
// scroll offset updates are sent back to the main thread.
class LayerTreeHostAnimationTestScrollOffsetChangesArePropagated
    : public LayerTreeHostAnimationTest {
 public:
  LayerTreeHostAnimationTestScrollOffsetChangesArePropagated() {}

  void SetupTree() override {
    LayerTreeHostAnimationTest::SetupTree();

    scroll_layer_ = FakePictureLayer::Create(layer_settings(), &client_);
    scroll_layer_->SetScrollClipLayerId(layer_tree_host()->root_layer()->id());
    scroll_layer_->SetBounds(gfx::Size(1000, 1000));
    scroll_layer_->SetScrollOffset(gfx::ScrollOffset(10, 20));
    layer_tree_host()->root_layer()->AddChild(scroll_layer_);
  }

  void BeginTest() override { PostSetNeedsCommitToMainThread(); }

  void DidCommit() override {
    switch (layer_tree_host()->source_frame_number()) {
      case 1: {
        scoped_ptr<ScrollOffsetAnimationCurve> curve(
            ScrollOffsetAnimationCurve::Create(
                gfx::ScrollOffset(500.f, 550.f),
                EaseInOutTimingFunction::Create()));
        scoped_ptr<Animation> animation(
            Animation::Create(curve.Pass(), 1, 0, Animation::SCROLL_OFFSET));
        animation->set_needs_synchronized_start_time(true);
        bool animation_added = scroll_layer_->AddAnimation(animation.Pass());
        bool impl_scrolling_supported =
            layer_tree_host()->proxy()->SupportsImplScrolling();
        EXPECT_EQ(impl_scrolling_supported, animation_added);
        if (!impl_scrolling_supported)
          EndTest();
        break;
      }
      default:
        if (scroll_layer_->scroll_offset().x() > 10 &&
            scroll_layer_->scroll_offset().y() > 20)
          EndTest();
    }
  }

  void AfterTest() override {}

 private:
  FakeContentLayerClient client_;
  scoped_refptr<FakePictureLayer> scroll_layer_;
};

SINGLE_AND_MULTI_THREAD_TEST_F(
    LayerTreeHostAnimationTestScrollOffsetChangesArePropagated);

// Verifies that when the main thread removes a scroll animation and sets a new
// scroll position, the active tree takes on exactly this new scroll position
// after activation, and the main thread doesn't receive a spurious scroll
// delta.
class LayerTreeHostAnimationTestScrollOffsetAnimationRemoval
    : public LayerTreeHostAnimationTest {
 public:
  LayerTreeHostAnimationTestScrollOffsetAnimationRemoval()
      : final_postion_(50.0, 100.0) {}

  void SetupTree() override {
    LayerTreeHostAnimationTest::SetupTree();

    scroll_layer_ = FakePictureLayer::Create(layer_settings(), &client_);
    scroll_layer_->SetScrollClipLayerId(layer_tree_host()->root_layer()->id());
    scroll_layer_->SetBounds(gfx::Size(10000, 10000));
    scroll_layer_->SetScrollOffset(gfx::ScrollOffset(100.0, 200.0));
    layer_tree_host()->root_layer()->AddChild(scroll_layer_);

    scoped_ptr<ScrollOffsetAnimationCurve> curve(
        ScrollOffsetAnimationCurve::Create(gfx::ScrollOffset(6500.f, 7500.f),
                                           EaseInOutTimingFunction::Create()));
    scoped_ptr<Animation> animation(
        Animation::Create(curve.Pass(), 1, 0, Animation::SCROLL_OFFSET));
    animation->set_needs_synchronized_start_time(true);
    scroll_layer_->AddAnimation(animation.Pass());
  }

  void BeginTest() override { PostSetNeedsCommitToMainThread(); }

  void BeginMainFrame(const BeginFrameArgs& args) override {
    switch (layer_tree_host()->source_frame_number()) {
      case 0:
        break;
      case 1: {
        Animation* animation =
            scroll_layer_->layer_animation_controller()->GetAnimation(
                Animation::SCROLL_OFFSET);
        scroll_layer_->layer_animation_controller()->RemoveAnimation(
            animation->id());
        scroll_layer_->SetScrollOffset(final_postion_);
        break;
      }
      default:
        EXPECT_EQ(final_postion_, scroll_layer_->scroll_offset());
    }
  }

  void BeginCommitOnThread(LayerTreeHostImpl* host_impl) override {
    host_impl->BlockNotifyReadyToActivateForTesting(true);
  }

  void WillBeginImplFrameOnThread(LayerTreeHostImpl* host_impl,
                                  const BeginFrameArgs& args) override {
    if (!host_impl->pending_tree())
      return;

    if (!host_impl->active_tree()->root_layer()) {
      host_impl->BlockNotifyReadyToActivateForTesting(false);
      return;
    }

    LayerImpl* scroll_layer_impl =
        host_impl->active_tree()->root_layer()->children()[0];
    Animation* animation =
        scroll_layer_impl->layer_animation_controller()->GetAnimation(
            Animation::SCROLL_OFFSET);

    if (!animation || animation->run_state() != Animation::RUNNING) {
      host_impl->BlockNotifyReadyToActivateForTesting(false);
      return;
    }

    // Block activation until the running animation has a chance to produce a
    // scroll delta.
    gfx::Vector2dF scroll_delta = scroll_layer_impl->ScrollDelta();
    if (scroll_delta.x() < 1.f || scroll_delta.y() < 1.f)
      return;

    host_impl->BlockNotifyReadyToActivateForTesting(false);
  }

  void WillActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
    if (host_impl->pending_tree()->source_frame_number() != 1)
      return;
    LayerImpl* scroll_layer_impl =
        host_impl->pending_tree()->root_layer()->children()[0];
    EXPECT_EQ(final_postion_, scroll_layer_impl->CurrentScrollOffset());
  }

  void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
    if (host_impl->active_tree()->source_frame_number() != 1)
      return;
    LayerImpl* scroll_layer_impl =
        host_impl->active_tree()->root_layer()->children()[0];
    EXPECT_EQ(final_postion_, scroll_layer_impl->CurrentScrollOffset());
    EndTest();
  }

  void AfterTest() override {
    EXPECT_EQ(final_postion_, scroll_layer_->scroll_offset());
  }

 private:
  FakeContentLayerClient client_;
  scoped_refptr<FakePictureLayer> scroll_layer_;
  const gfx::ScrollOffset final_postion_;
};

MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestScrollOffsetAnimationRemoval);

// When animations are simultaneously added to an existing layer and to a new
// layer, they should start at the same time, even when there's already a
// running animation on the existing layer.
class LayerTreeHostAnimationTestAnimationsAddedToNewAndExistingLayers
    : public LayerTreeHostAnimationTest {
 public:
  LayerTreeHostAnimationTestAnimationsAddedToNewAndExistingLayers()
      : frame_count_with_pending_tree_(0) {}

  void BeginTest() override { PostSetNeedsCommitToMainThread(); }

  void DidCommit() override {
    if (layer_tree_host()->source_frame_number() == 1) {
      AddAnimatedTransformToLayer(layer_tree_host()->root_layer(), 4, 1, 1);
    } else if (layer_tree_host()->source_frame_number() == 2) {
      AddOpacityTransitionToLayer(
          layer_tree_host()->root_layer(), 1, 0.f, 0.5f, true);

      scoped_refptr<Layer> layer = Layer::Create(layer_settings());
      layer_tree_host()->root_layer()->AddChild(layer);
      layer->set_layer_animation_delegate(this);
      layer->SetBounds(gfx::Size(4, 4));
      AddOpacityTransitionToLayer(layer.get(), 1, 0.f, 0.5f, true);
    }
  }

  void BeginCommitOnThread(LayerTreeHostImpl* host_impl) override {
    host_impl->BlockNotifyReadyToActivateForTesting(true);
  }

  void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
    // For the commit that added animations to new and existing layers, keep
    // blocking activation. We want to verify that even with activation blocked,
    // the animation on the layer that's already in the active tree won't get a
    // head start.
    if (host_impl->pending_tree()->source_frame_number() != 2) {
      host_impl->BlockNotifyReadyToActivateForTesting(false);
    }
  }

  void WillBeginImplFrameOnThread(LayerTreeHostImpl* host_impl,
                                  const BeginFrameArgs& args) override {
    if (!host_impl->pending_tree() ||
        host_impl->pending_tree()->source_frame_number() != 2)
      return;

    frame_count_with_pending_tree_++;
    if (frame_count_with_pending_tree_ == 2) {
      host_impl->BlockNotifyReadyToActivateForTesting(false);
    }
  }

  void UpdateAnimationState(LayerTreeHostImpl* host_impl,
                            bool has_unfinished_animation) override {
    LayerAnimationController* root_controller_impl =
        host_impl->active_tree()->root_layer()->layer_animation_controller();
    Animation* root_animation =
        root_controller_impl->GetAnimation(Animation::OPACITY);
    if (!root_animation || root_animation->run_state() != Animation::RUNNING)
      return;

    LayerAnimationController* child_controller_impl =
        host_impl->active_tree()->root_layer()->children()
            [0]->layer_animation_controller();
    Animation* child_animation =
        child_controller_impl->GetAnimation(Animation::OPACITY);
    EXPECT_EQ(Animation::RUNNING, child_animation->run_state());
    EXPECT_EQ(root_animation->start_time(), child_animation->start_time());
    root_controller_impl->AbortAnimations(Animation::OPACITY);
    root_controller_impl->AbortAnimations(Animation::TRANSFORM);
    child_controller_impl->AbortAnimations(Animation::OPACITY);
    EndTest();
  }

  void AfterTest() override {}

 private:
  int frame_count_with_pending_tree_;
};

// This test blocks activation which is not supported for single thread mode.
MULTI_THREAD_BLOCKNOTIFY_TEST_F(
    LayerTreeHostAnimationTestAnimationsAddedToNewAndExistingLayers);

// When a layer with an animation is removed from the tree and later re-added,
// the animation should resume.
class LayerTreeHostAnimationTestAnimatedLayerRemovedAndAdded
    : public LayerTreeHostAnimationTest {
 public:
  LayerTreeHostAnimationTestAnimatedLayerRemovedAndAdded() {}

  void SetupTree() override {
    LayerTreeHostAnimationTest::SetupTree();
    layer_ = Layer::Create(layer_settings());
    layer_->SetBounds(gfx::Size(4, 4));
    layer_tree_host()->root_layer()->AddChild(layer_);
    AddOpacityTransitionToLayer(layer_.get(), 10000.0, 0.1f, 0.9f, true);
  }

  void BeginTest() override { PostSetNeedsCommitToMainThread(); }

  void DidCommit() override {
    switch (layer_tree_host()->source_frame_number()) {
      case 1:
        layer_->RemoveFromParent();
        break;
      case 2:
        layer_tree_host()->root_layer()->AddChild(layer_);
        break;
    }
  }

  void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
    switch (host_impl->active_tree()->source_frame_number()) {
      case 0:
        EXPECT_TRUE(host_impl->animation_registrar()->needs_animate_layers());
        break;
      case 1:
        EXPECT_FALSE(host_impl->animation_registrar()->needs_animate_layers());
        break;
      case 2:
        EXPECT_TRUE(host_impl->animation_registrar()->needs_animate_layers());
        EndTest();
        break;
    }
  }

  void AfterTest() override {}

 private:
  scoped_refptr<Layer> layer_;
};

SINGLE_AND_MULTI_THREAD_TEST_F(
    LayerTreeHostAnimationTestAnimatedLayerRemovedAndAdded);

class LayerTreeHostAnimationTestAddAnimationAfterAnimating
    : public LayerTreeHostAnimationTest {
 public:
  void SetupTree() override {
    LayerTreeHostAnimationTest::SetupTree();
    layer_ = Layer::Create(layer_settings());
    layer_->SetBounds(gfx::Size(4, 4));
    layer_tree_host()->root_layer()->AddChild(layer_);
  }

  void BeginTest() override { PostSetNeedsCommitToMainThread(); }

  void DidCommit() override {
    switch (layer_tree_host()->source_frame_number()) {
      case 1:
        // First frame: add an animation to the root layer.
        AddAnimatedTransformToLayer(layer_tree_host()->root_layer(), 0.1, 5, 5);
        break;
      case 2:
        // Second frame: add an animation to the content layer. The root layer
        // animation has caused us to animate already during this frame.
        AddOpacityTransitionToLayer(layer_.get(), 0.1, 5, 5, false);
        break;
    }
  }

  void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, bool result) override {
    // After both animations have started, verify that they have valid
    // start times.
    if (host_impl->active_tree()->source_frame_number() < 2)
      return;
    AnimationRegistrar::AnimationControllerMap controllers_copy =
        host_impl->animation_registrar()
            ->active_animation_controllers_for_testing();
    EXPECT_EQ(2u, controllers_copy.size());
    for (auto& it : controllers_copy) {
      int id = it.first;
      if (id == host_impl->RootLayer()->id()) {
        Animation* anim = it.second->GetAnimation(Animation::TRANSFORM);
        EXPECT_GT((anim->start_time() - base::TimeTicks()).InSecondsF(), 0);
      } else if (id == host_impl->RootLayer()->children()[0]->id()) {
        Animation* anim = it.second->GetAnimation(Animation::OPACITY);
        EXPECT_GT((anim->start_time() - base::TimeTicks()).InSecondsF(), 0);
      }
      EndTest();
    }
  }

  void AfterTest() override {}

 private:
  scoped_refptr<Layer> layer_;
};

SINGLE_AND_MULTI_THREAD_TEST_F(
    LayerTreeHostAnimationTestAddAnimationAfterAnimating);

class LayerTreeHostAnimationTestRemoveAnimation
    : public LayerTreeHostAnimationTest {
 public:
  void SetupTree() override {
    LayerTreeHostAnimationTest::SetupTree();
    layer_ = FakePictureLayer::Create(layer_settings(), &client_);
    layer_->SetBounds(gfx::Size(4, 4));
    layer_tree_host()->root_layer()->AddChild(layer_);
  }

  void BeginTest() override { PostSetNeedsCommitToMainThread(); }

  void DidCommit() override {
    switch (layer_tree_host()->source_frame_number()) {
      case 1:
        AddAnimatedTransformToLayer(layer_.get(), 1.0, 5, 5);
        break;
      case 2:
        LayerAnimationController* controller =
            layer_->layer_animation_controller();
        Animation* animation = controller->GetAnimation(Animation::TRANSFORM);
        controller->RemoveAnimation(animation->id());
        gfx::Transform transform;
        transform.Translate(10.f, 10.f);
        layer_->SetTransform(transform);

        // Do something that causes property trees to get rebuilt.
        layer_->AddChild(Layer::Create(layer_settings()));
        break;
    }
  }

  void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
    if (host_impl->active_tree()->source_frame_number() < 2)
      return;
    gfx::Transform expected_transform;
    expected_transform.Translate(10.f, 10.f);
    EXPECT_EQ(expected_transform, host_impl->active_tree()
                                      ->root_layer()
                                      ->children()[0]
                                      ->draw_transform());
    EndTest();
  }

  void AfterTest() override {}

 private:
  scoped_refptr<Layer> layer_;
  FakeContentLayerClient client_;
};

SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestRemoveAnimation);

class LayerTreeHostAnimationTestAnimationFinishesDuringCommit
    : public LayerTreeHostAnimationTest {
 public:
  void SetupTree() override {
    LayerTreeHostAnimationTest::SetupTree();
    layer_ = FakePictureLayer::Create(layer_settings(), &client_);
    layer_->SetBounds(gfx::Size(4, 4));
    layer_tree_host()->root_layer()->AddChild(layer_);
  }

  void BeginTest() override { PostSetNeedsCommitToMainThread(); }

  void DidCommit() override {
    if (layer_tree_host()->source_frame_number() == 1)
      AddAnimatedTransformToLayer(layer_.get(), 0.04, 5, 5);
  }

  void WillCommit() override {
    if (layer_tree_host()->source_frame_number() == 2) {
      // Block until the animation finishes on the compositor thread. Since
      // animations have already been ticked on the main thread, when the commit
      // happens the state on the main thread will be consistent with having a
      // running animation but the state on the compositor thread will be
      // consistent with having only a finished animation.
      completion_.Wait();
    }
  }

  void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
    switch (host_impl->sync_tree()->source_frame_number()) {
      case 1:
        PostSetNeedsCommitToMainThread();
        break;
      case 2:
        gfx::Transform expected_transform;
        expected_transform.Translate(5.f, 5.f);
        LayerImpl* layer_impl =
            host_impl->sync_tree()->root_layer()->children()[0];
        EXPECT_EQ(expected_transform, layer_impl->draw_transform());
        EndTest();
        break;
    }
  }

  void UpdateAnimationState(LayerTreeHostImpl* host_impl,
                            bool has_unfinished_animation) override {
    if (host_impl->active_tree()->source_frame_number() == 1 &&
        !has_unfinished_animation) {
      // The animation has finished, so allow the main thread to commit.
      completion_.Signal();
    }
  }

  void AfterTest() override {}

 private:
  scoped_refptr<Layer> layer_;
  FakeContentLayerClient client_;
  CompletionEvent completion_;
};

// An animation finishing during commit can only happen when we have a separate
// compositor thread.
MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestAnimationFinishesDuringCommit);

class LayerTreeHostAnimationTestNotifyAnimationFinished
    : public LayerTreeHostAnimationTest {
 public:
  LayerTreeHostAnimationTestNotifyAnimationFinished()
      : called_animation_started_(false), called_animation_finished_(false) {}

  void SetupTree() override {
    LayerTreeHostAnimationTest::SetupTree();
    picture_ = FakePictureLayer::Create(layer_settings(), &client_);
    picture_->SetBounds(gfx::Size(4, 4));
    picture_->set_layer_animation_delegate(this);
    layer_tree_host()->root_layer()->AddChild(picture_);
  }

  void BeginTest() override {
    PostAddLongAnimationToMainThread(picture_.get());
  }

  void NotifyAnimationStarted(base::TimeTicks monotonic_time,
                              Animation::TargetProperty target_property,
                              int group) override {
    called_animation_started_ = true;
    layer_tree_host()->AnimateLayers(
        base::TimeTicks::FromInternalValue(std::numeric_limits<int64>::max()));
    PostSetNeedsCommitToMainThread();
  }

  void NotifyAnimationFinished(base::TimeTicks monotonic_time,
                               Animation::TargetProperty target_property,
                               int group) override {
    called_animation_finished_ = true;
    EndTest();
  }

  void AfterTest() override {
    EXPECT_TRUE(called_animation_started_);
    EXPECT_TRUE(called_animation_finished_);
  }

 private:
  bool called_animation_started_;
  bool called_animation_finished_;
  FakeContentLayerClient client_;
  scoped_refptr<FakePictureLayer> picture_;
};

SINGLE_AND_MULTI_THREAD_TEST_F(
    LayerTreeHostAnimationTestNotifyAnimationFinished);

}  // namespace
}  // namespace cc


text:
ROOT="/data/devo/current"

PHP_CS_FIXER="vendor/bin/php-cs-fixer"
HAS_PHP_CS_FIXER=false

if [ -x vendor/bin/php-cs-fixer ]; then
HAS_PHP_CS_FIXER=true
fi

if $HAS_PHP_CS_FIXER; then
git status --porcelain | grep -e '^[AM]\(.*\).php$' | cut -c 3- | while read line; do
        $PHP_CS_FIXER fix --verbose "$line";
        git add "$line";
    done
else
echo ""
    echo "Please install php-cs-fixer, e.g.:"
    echo ""
    echo " composer require --dev fabpot/php-cs-fixer:dev-master"
    echo ""
fi

echo "pre commit hook finish"


text:
class ComfortableMexicanSofa::Tag::Collection
  include ComfortableMexicanSofa::Tag

  # Here's a full tag signature:
  #   {{ cms:collection:label:collection_class:collection_partial:collection_title:collection_identifier:collection_params }}
  # Most minimal tag can look like this:
  #   {{ cms:collection:album:foo/my_album }}
  # A more complete example of the above:
  #   {{ cms:collection:album:foo/my_album:albums/show:title:slug:param_a:param_b }}
  def self.regex_tag_signature(identifier = nil)
    identifier ||= IDENTIFIER_REGEX
    /\{\{\s*cms:collection:(#{identifier}):(.*?)\s*\}\}/
  end

  # Class definitition. It's basically `Herp::DerpityDerp.undescore` so an example
  # of valid definition is: `herp/derpity_derp`
  def collection_class
    self.params[0].classify
  end

  # Path to the partial. Example: `path/to/partial`
  def collection_partial
    self.params[1] || "partials/#{self.collection_class.underscore.pluralize}"
  end

  # Title method for the Collection objects. Default is `label`
  def collection_title
    self.params[2] || 'label'
  end

  # Identifier that will be used to find selected collection object. Defaults to `id`
  def collection_identifier
    self.params[3] || 'id'
  end

  # Extra params that will be passed to the partial AND ALSO will be passed as parameters
  # for the `cms_collection` scope you can define for your Collection object
  def collection_params
    self.params[4..-1] || []
  end

  # Array of objects used in the collection
  # You may set up a scope on the model `scope :cms_collection, lambda|*args| do ... end `
  # `args` will be the set of `collection_params`
  def collection_objects
    klass = self.collection_class.constantize
    klass.respond_to?(:cms_collection) ? klass.cms_collection(*collection_params) : klass.all
  end

  def content
    block.content
  end

  def render
    if self.content.present?
      ps = collection_params.collect_with_index{|p, i| ":param_#{i+1} => '#{p}'"}.join(', ')
      ps = ps.present?? ", #{ps}" : ''
      "<%= render :partial => '#{collection_partial}', :locals => {:model => '#{collection_class}', :identifier => '#{content}'#{ps}} %>"
    else
      ''
    end
  end

end


text:
from unittest import TestCase
from unittest.mock import MagicMock

from pyga import Random, CandidateFactory

class CandidateFactoryTestCase(TestCase):
    def test_create_population(self):
        random = Random()
        size = 4
        candidate_factory = CandidateFactory(random)
        candidate_factory.create_candidate = MagicMock()
        result = candidate_factory.create_population(size)
        self.assertEqual(candidate_factory.create_candidate.call_count, size)
        self.assertEqual(len(result), size)


text:
import React from 'react';
import {Router, Route, browserHistory, IndexRoute} from 'react-router';

// Import high-level components.
import Main from '../components/Main';
import Dashboard from '../components/Dashboard';
import Login from '../components/Login';
import Calendar from '../components/dashboard/calendar/Calendar';
import New from '../components/dashboard/entries/New';
import Home from '../components/dashboard/home/Home';
import TagView from '../components/dashboard/home/TagView';
import Settings from '../components/dashboard/settings/Settings';
import Edit from '../components/dashboard/entries/Edit';
import About from '../components/dashboard/about/About';

// Create routes.
export default (
    <Router history={browserHistory}>
        <Route path="/" component={Main}>
            <Route path="dashboard" component={Dashboard}>
                <Route path="calendar" component={Calendar} />
                <Route path="home" component={Home} />
                <Route path="tags/:tagText" component={TagView} />
                <Route path="new(/:date)" component={New}/>
                <Route path="about" component={About} />
                <Route path="users/:googleId/entries/:entryId/edit" component={Edit} />
                <Route path="settings" component={Settings} />
                <IndexRoute component={Home} />
            </Route>
            <Route path="login" component={Login} />
            <Route path="logged-out" component={Login} />
            <IndexRoute component={Dashboard} />
        </Route>
    </Router>
);