logging: fix compiler compatibility for one more constexpr function
[folly.git] / folly / experimental / LockFreeRingBuffer.h
index 87ed084e44cc1a6a9a6df9bb6035bc8bdbb2a05c..0e32e033ed716a22665c29e898b8f232672c1a22 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 #include <atomic>
 #include <boost/noncopyable.hpp>
-#include <iostream>
 #include <cmath>
+#include <memory>
 #include <string.h>
 #include <type_traits>
-#include <unistd.h>
 
-#include <folly/detail/TurnSequencer.h>
 #include <folly/Portability.h>
+#include <folly/detail/TurnSequencer.h>
+#include <folly/portability/TypeTraits.h>
+#include <folly/portability/Unistd.h>
 
 namespace folly {
 namespace detail {
@@ -69,16 +70,24 @@ public:
   struct Cursor {
     explicit Cursor(uint64_t initialTicket) noexcept : ticket(initialTicket) {}
 
-    void moveForward(uint64_t steps = 1) noexcept {
+    /// Returns true if this cursor now points to a different
+    /// write, false otherwise.
+    bool moveForward(uint64_t steps = 1) noexcept {
+      uint64_t prevTicket = ticket;
       ticket += steps;
+      return prevTicket != ticket;
     }
 
-    void moveBackward(uint64_t steps = 1) noexcept {
+    /// Returns true if this cursor now points to a previous
+    /// write, false otherwise.
+    bool moveBackward(uint64_t steps = 1) noexcept {
+      uint64_t prevTicket = ticket;
       if (steps > ticket) {
         ticket = 0;
       } else {
         ticket -= steps;
       }
+      return prevTicket != ticket;
     }
 
   protected: // for test visibility reasons
@@ -86,7 +95,7 @@ public:
     friend class LockFreeRingBuffer;
   };
 
-  explicit LockFreeRingBuffer(size_t capacity) noexcept
+  explicit LockFreeRingBuffer(uint32_t capacity) noexcept
     : capacity_(capacity)
     , slots_(new detail::RingBufferSlot<T,Atom>[capacity])
     , ticket_(0)
@@ -100,6 +109,16 @@ public:
     slots_[idx(ticket)].write(turn(ticket), value);
   }
 
+  /// Perform a single write of an object of type T.
+  /// Writes can block iff a previous writer has not yet completed a write
+  /// for the same slot (before the most recent wrap-around).
+  /// Returns a Cursor pointing to the just-written T.
+  Cursor writeAndGetCursor(T& value) noexcept {
+    uint64_t ticket = ticket_.fetch_add(1);
+    slots_[idx(ticket)].write(turn(ticket), value);
+    return Cursor(ticket);
+  }
+
   /// Read the value at the cursor.
   /// Returns true if the read succeeded, false otherwise. If the return
   /// value is false, dest is to be considered partially read and in an
@@ -129,7 +148,7 @@ public:
     assert(skipFraction >= 0.0 && skipFraction <= 1.0);
     uint64_t ticket = ticket_.load();
 
-    uint64_t backStep = std::llround((1.0 - skipFraction) * capacity_);
+    uint64_t backStep = llround((1.0 - skipFraction) * capacity_);
 
     // always try to move at least one step backward to something readable
     backStep = std::max<uint64_t>(1, backStep);
@@ -144,7 +163,7 @@ public:
   }
 
 private:
-  const size_t capacity_;
+  const uint32_t capacity_;
 
   const std::unique_ptr<detail::RingBufferSlot<T,Atom>[]> slots_;
 
@@ -155,7 +174,7 @@ private:
   }
 
   uint32_t turn(uint64_t ticket) noexcept {
-    return (ticket / capacity_);
+    return (uint32_t)(ticket / capacity_);
   }
 }; // LockFreeRingBuffer
 
@@ -184,7 +203,8 @@ public:
   bool waitAndTryRead(T& dest, uint32_t turn) noexcept {
     uint32_t desired_turn = (turn + 1) * 2;
     Atom<uint32_t> cutoff(0);
-    if(!sequencer_.tryWaitForTurn(desired_turn, cutoff, false)) {
+    if (sequencer_.tryWaitForTurn(desired_turn, cutoff, false) !=
+        TurnSequencer<Atom>::TryWaitResult::SUCCESS) {
       return false;
     }
     memcpy(&dest, &data, sizeof(T));