/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /*************************************************************************** * atomic.h * * Wed Mar 23 09:15:05 CET 2016 * Copyright 2016 Christian Glöckner * cgloeckner@freenet.de ****************************************************************************/ /* * This file is part of DrumGizmo. * * DrumGizmo is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * DrumGizmo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with DrumGizmo; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #pragma once #include #include #include template class Atomic; // use std::atomic if possible template class Atomic::value>::type> : public std::atomic { public: // inherit methods using std::atomic::atomic; using std::atomic::operator=; }; // else work around it using a mutex template class Atomic::value>::type> { public: using self_type = Atomic::value>::type>; Atomic() : data{} , mutex{} { } Atomic(T data) : data{std::move(data)} , mutex{} { } Atomic(self_type const & other) : data{} , mutex{} { std::lock_guard lock{other.mutex}; data = other.data; } Atomic(self_type&& other) : data{} , mutex{} { std::lock_guard lock{other.mutex}; std::swap(data, other.data); } T operator=(T data) { std::lock_guard lock{mutex}; this->data = std::move(data); return this->data; } operator T() const { return load(); } bool is_lock_free() const { return false; } void store(T data) { std::lock_guard lock{mutex}; this->data = std::move(data); } T load() const { std::lock_guard lock{mutex}; return data; } T exchange(T data){ std::lock_guard lock{mutex}; std::swap(data, this->data); return data; } bool operator==(const T& other) const { std::lock_guard lock{mutex}; return other == data; } bool operator!=(const T& other) const { std::lock_guard lock{mutex}; return !(other == data); } bool operator==(const Atomic& other) const { std::lock_guard lock{mutex}; return other.load() == data; } bool operator!=(const Atomic& other) const { std::lock_guard lock{mutex}; return !(other.load() == data); } private: T data; mutable std::mutex mutex; }; //! Getter utility class. template class SettingRef { public: SettingRef(Atomic& value) : value(value) { // string isn't lock free either assert((std::is_same::value || value.is_lock_free())); } bool hasChanged() { T tmp = cache; cache.exchange(value); if(firstAccess) { firstAccess = false; return true; } return cache != tmp; } T getValue() const { return cache; } private: bool firstAccess{true}; Atomic& value; Atomic cache; };