Skip to content

Commit

Permalink
SingletonPattern
Browse files Browse the repository at this point in the history
  • Loading branch information
cppcloud committed Jun 30, 2024
1 parent 783ab76 commit 972fbbe
Show file tree
Hide file tree
Showing 8 changed files with 255 additions and 0 deletions.
31 changes: 31 additions & 0 deletions 6-8-SingletonPattern/6-8-SingletonPattern.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
QT -= gui

CONFIG += c++11 console
CONFIG -= app_bundle

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
main.cpp \
test.cpp \
widget.cpp

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

HEADERS += \
call_once.h \
singleton.h \
test.h \
widget.h
59 changes: 59 additions & 0 deletions 6-8-SingletonPattern/call_once.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// call_once.h

#ifndef CALL_ONCE_H
#define CALL_ONCE_H

#include <QtGlobal>
#include <QAtomicInt>
#include <QMutex>
#include <QWaitCondition>
#include <QThreadStorage>
#include <QThread>

namespace CallOnce {
enum ECallOnce {
CO_Request,
CO_InProgress,
CO_Finished
};

Q_GLOBAL_STATIC(QThreadStorage<QAtomicInt*>, once_flag)
}

template <class Function>
inline static void qCallOnce(Function func, QBasicAtomicInt& flag)
{
using namespace CallOnce;

#if QT_VERSION < 0x050000
int protectFlag = flag.fetchAndStoreAcquire(flag);
#elif QT_VERSION >= 0x050000
int protectFlag = flag.fetchAndStoreAcquire(flag.load());
#endif

if (protectFlag == CO_Finished)
return;
if (protectFlag == CO_Request && flag.testAndSetRelaxed(protectFlag,
CO_InProgress)) {
func();
flag.fetchAndStoreRelease(CO_Finished);
}
else {
do {
QThread::yieldCurrentThread();
}
while (!flag.testAndSetAcquire(CO_Finished, CO_Finished));
}
}

template <class Function>
inline static void qCallOncePerThread(Function func)
{
using namespace CallOnce;
if (!once_flag()->hasLocalData()) {
once_flag()->setLocalData(new QAtomicInt(CO_Request));
qCallOnce(func, *once_flag()->localData());
}
}

#endif // CALL_ONCE_H
31 changes: 31 additions & 0 deletions 6-8-SingletonPattern/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include <QCoreApplication>
#include <QDebug>
#include "test.h"
#include "widget.h"

//Singleton pattern
//https://wiki.qt.io/Qt_thread-safe_singleton
//Watch for bug in singleton.h line 31

/*
Need one and only one instance of a class
*/

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);

test::instance()->name = "Bryan";

qInfo() << test::instance()->name;

for(int i = 0; i < 5; i++) {
widget w;
w.makeChanges("Widget: " + QString::number(i));
}


qInfo() << test::instance()->name;

return a.exec();
}
66 changes: 66 additions & 0 deletions 6-8-SingletonPattern/singleton.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#ifndef SINGLETON_H
#define SINGLETON_H

#include <QtGlobal>
#include <QScopedPointer>
#include "call_once.h"

template <class T>
class Singleton
{
private:
typedef T* (*CreateInstanceFunction)();
public:
static T* instance(CreateInstanceFunction create);
private:
static void init();

Singleton();
~Singleton();
Q_DISABLE_COPY(Singleton)
static QBasicAtomicPointer<void> create;
static QBasicAtomicInt flag;
static QBasicAtomicPointer<void> tptr;
bool inited;
};

template <class T>
T* Singleton<T>::instance(CreateInstanceFunction create)
{
//Fracking Error!!!
//Singleton::create.store(create);
Singleton::create.store(((QBasicAtomicPointer<void>::Type)create));

qCallOnce(init, flag);
return (T*)tptr.load();
}

template <class T>
void Singleton<T>::init()
{
static Singleton singleton;
if (singleton.inited) {
CreateInstanceFunction createFunction = (CreateInstanceFunction)Singleton::create.load();
tptr.store(createFunction());
}
}

template <class T>
Singleton<T>::Singleton() {
inited = true;
};

template <class T>
Singleton<T>::~Singleton() {
T* createdTptr = (T*)tptr.fetchAndStoreOrdered(nullptr);
if (createdTptr) {
delete createdTptr;
}
create.store(nullptr);
}

template<class T> QBasicAtomicPointer<void> Singleton<T>::create = Q_BASIC_ATOMIC_INITIALIZER(nullptr);
template<class T> QBasicAtomicInt Singleton<T>::flag = Q_BASIC_ATOMIC_INITIALIZER(CallOnce::CO_Request);
template<class T> QBasicAtomicPointer<void> Singleton<T>::tptr = Q_BASIC_ATOMIC_INITIALIZER(nullptr);

#endif // SINGLETON_H
16 changes: 16 additions & 0 deletions 6-8-SingletonPattern/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include "test.h"

test *test::createInstance()
{
return new test();
}

test::test(QObject *parent) : QObject(parent)
{

}

test *test::instance()
{
return Singleton<test>::instance(test::createInstance);
}
23 changes: 23 additions & 0 deletions 6-8-SingletonPattern/test.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#ifndef TEST_H
#define TEST_H

#include <QObject>
#include "singleton.h"

class test : public QObject
{
Q_OBJECT
static test *createInstance();

public:
explicit test(QObject *parent = nullptr);

QString name;
static test* instance();

signals:

public slots:
};

#endif // TEST_H
11 changes: 11 additions & 0 deletions 6-8-SingletonPattern/widget.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include "widget.h"

widget::widget(QObject *parent) : QObject(parent)
{

}

void widget::makeChanges(QString value)
{
test::instance()->name = value;
}
18 changes: 18 additions & 0 deletions 6-8-SingletonPattern/widget.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#ifndef WIDGET_H
#define WIDGET_H

#include <QObject>
#include "test.h"

class widget : public QObject
{
Q_OBJECT
public:
explicit widget(QObject *parent = nullptr);
void makeChanges(QString value);
signals:

public slots:
};

#endif // WIDGET_H

0 comments on commit 972fbbe

Please sign in to comment.