/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// This is free and unencumbered software released into the public domain.
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
// In jurisdictions that recognize copyright laws, the author or authors
// of this software dedicate any and all copyright interest in the
// software to the public domain. We make this dedication for the benefit
// of the public at large and to the detriment of our heirs and
// successors. We intend this dedication to be an overt act of
// relinquishment in perpetuity of all present and future rights to this
// software under copyright law.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// For more information, please refer to
// Note:
// A combination of the algorithms described by the circular buffers
// documentation found in the Linux kernel, and the bounded MPMC queue
// by Dmitry Vyukov[1]. Implemented in pure C++11. Should work across
// most CPU architectures.
//
// [1] http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue
#ifndef __SPSC_BOUNDED_QUEUE_INCLUDED__
#define __SPSC_BOUNDED_QUEUE_INCLUDED__
#include
#include
namespace concqueue
{
template
class spsc_bounded_queue_t
{
public:
spsc_bounded_queue_t(size_t size)
: _size(size)
, _mask(size - 1)
, _buffer(reinterpret_cast(new aligned_t[_size + 1])) // need one extra element for a guard
, _head(0)
, _tail(0)
{
// make sure it's a power of 2
assert((_size != 0) && ((_size & (~_size + 1)) == _size));
}
~spsc_bounded_queue_t()
{
delete[] _buffer;
}
bool enqueue(T& input)
{
const size_t head = _head.load(std::memory_order_relaxed);
if (((_tail.load(std::memory_order_acquire) - (head + 1)) & _mask) >= 1)
{
_buffer[head & _mask] = input;
_head.store(head + 1, std::memory_order_release);
return true;
}
return false;
}
bool dequeue(T& output)
{
const size_t tail = _tail.load(std::memory_order_relaxed);
if (((_head.load(std::memory_order_acquire) - tail) & _mask) >= 1)
{
output = _buffer[_tail & _mask];
_tail.store(tail + 1, std::memory_order_release);
return true;
}
return false;
}
private:
typedef typename std::aligned_storage::value>::type aligned_t;
typedef char cache_line_pad_t[64];
cache_line_pad_t _pad0;
const size_t _size;
const size_t _mask;
T* const _buffer;
cache_line_pad_t _pad1;
std::atomic _head;
cache_line_pad_t _pad2;
std::atomic _tail;
spsc_bounded_queue_t(const spsc_bounded_queue_t&) {}
void operator=(const spsc_bounded_queue_t&) {}
};
}
#endif