From bac3da61644515f05663789b122554dc77549286 Mon Sep 17 00:00:00 2001 From: Luca Muscariello Date: Thu, 17 Jan 2019 13:47:57 +0100 Subject: This is the first commit of the hicn project Change-Id: I6f2544ad9b9f8891c88cc4bcce3cf19bd3cc863f Signed-off-by: Luca Muscariello --- .../src/hicn/transport/utils/ring_buffer.h | 129 +++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100755 libtransport/src/hicn/transport/utils/ring_buffer.h (limited to 'libtransport/src/hicn/transport/utils/ring_buffer.h') diff --git a/libtransport/src/hicn/transport/utils/ring_buffer.h b/libtransport/src/hicn/transport/utils/ring_buffer.h new file mode 100755 index 000000000..52bcd81c4 --- /dev/null +++ b/libtransport/src/hicn/transport/utils/ring_buffer.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2017-2019 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace utils { + +/** + * NOTE: Single consumer single producer ring buffer + */ +template +class CircularFifo { + public: + enum { Capacity = Size + 1 }; + + CircularFifo() : tail_(0), head_(0), size_(0) {} + virtual ~CircularFifo() {} + + bool push(const Element& item); + bool push(Element&& item); + bool pop(Element& item); + + bool wasEmpty() const; + bool wasFull() const; + bool isLockFree() const; + std::size_t size() const; + + private: + std::size_t increment(std::size_t idx) const; + std::atomic tail_; // tail(input) index + Element array_[Capacity]; + std::atomic head_; // head(output) index + std::atomic size_; +}; + +template +bool CircularFifo::push(const Element& item) { + const auto current_tail = tail_.load(std::memory_order_relaxed); + const auto next_tail = increment(current_tail); + if (next_tail != head_.load(std::memory_order_acquire)) { + array_[current_tail] = item; + tail_.store(next_tail, std::memory_order_release); + size_++; + return true; + } + + // full queue + return false; +} + +/** + * Push by move + */ +template +bool CircularFifo::push(Element&& item) { + const auto current_tail = tail_.load(std::memory_order_relaxed); + const auto next_tail = increment(current_tail); + if (next_tail != head_.load(std::memory_order_acquire)) { + array_[current_tail] = std::move(item); + tail_.store(next_tail, std::memory_order_release); + size_++; + return true; + } + + // full queue + return false; +} + +// Pop by Consumer can only update the head +// (load with relaxed, store with release) +// the tail must be accessed with at least acquire +template +bool CircularFifo::pop(Element& item) { + const auto current_head = head_.load(std::memory_order_relaxed); + if (current_head == tail_.load(std::memory_order_acquire)) { + return false; // empty queue + } + + item = std::move(array_[current_head]); + head_.store(increment(current_head), std::memory_order_release); + size_--; + return true; +} + +template +bool CircularFifo::wasEmpty() const { + // snapshot with acceptance of that this comparison operation is not atomic + return (head_.load() == tail_.load()); +} + +// snapshot with acceptance that this comparison is not atomic +template +bool CircularFifo::wasFull() const { + const auto next_tail = + increment(tail_.load()); // acquire, we dont know who call + return (next_tail == head_.load()); +} + +template +bool CircularFifo::isLockFree() const { + return (tail_.is_lock_free() && head_.is_lock_free()); +} + +template +std::size_t CircularFifo::increment(std::size_t idx) const { + return (idx + 1) % Capacity; +} + +template +std::size_t CircularFifo::size() const { + return size_.load(std::memory_order_relaxed); +} + +} // namespace utils \ No newline at end of file -- cgit 1.2.3-korg