// BlockyFroggy
// Copyright © 2019 John Ryland.
// All rights reserved.
#pragma once
#ifndef LOCK_FREE_H
#define LOCK_FREE_H
// Based on pseudo-code from here:
// https://www.infoq.com/news/2014/10/cpp-lock-free-programming
// Which is based on a Herb Sutter presentation
template <typename ObjectT>
class LockFreeList
{
public:
LockFreeList() = default;
~LockFreeList() = default;
class NodeReference
{
public:
NodeReference(SharedNodePtr aNode) : mNode{aNode} {}
ObjectT& operator*() { return mNode->mObject; }
ObjectT* operator->() { return &mNode->mObject; }
private:
SharedNodePtr mNode;
};
auto find(ObjectT aObject) const
{
auto node = mHead.load();
while (node && node->mObject != aObject)
node = node->mNext;
return NodeReference{std::move(node)};
}
void push_front(ObjectT aObject)
{
auto node = std::make_shared<Node>();
node->mObject = aObject;
node->mNext = mHead;
while (mHead.compare_exchange_weak(node->mNext, node))
/* do nothing */;
}
void pop_front()
{
auto node = mHead.load();
while (node && !mHead.compare_exchange_weak(node, node->mNext))
/* do nothing */;
}
private:
typedef std::shared_ptr<Node> SharedNodePtr;
typedef std::atomic<std::shared_ptr<ObjectT>> SharedAtomicObjectT;
struct Node
{
ObjectT mObject;
SharedNodePtr mNext;
};
std::atomic<SharedNodePtr> mHead;
};
#endif // LOCK_FREE_H