Skip to content

Instantly share code, notes, and snippets.

@Nihlus
Created June 29, 2019 13:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Nihlus/0f96d12b8835d1ea2d2b339ef1d05068 to your computer and use it in GitHub Desktop.
Save Nihlus/0f96d12b8835d1ea2d2b339ef1d05068 to your computer and use it in GitHub Desktop.
//
// AutoProperty.h
//
// Author:
// Jarl Gullberg <jarl.gullberg@gmail.com>
//
// Copyright (c) 2019 Jarl Gullberg
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
#ifndef QT_AUTO_PROPERTIES_AUTOPROPERTYIMPLEMENTATION_H
#define QT_AUTO_PROPERTIES_AUTOPROPERTYIMPLEMENTATION_H
#include <functional>
#include <QtCore>
/**
* Selects the first argument from the given parameter list.
* @param _1 The argument to select.
* @param ... The rest of the arguments, if any.
*/
#define ARG1(_1, ...) _1
/**
* Selects the second argument from the given parameter list.
* @param _1 Ignored.
* @param _2 The argument to select.
* @param ... The rest of the arguments, if any.
*/
#define ARG2(_1, _2, ...) _2
/**
* Selector for single-function auto properties (get-only and set-only, respectively). This macro, given a list of
* arguments, chooses the appropriate property implementation macro based on whether the user has provided their own
* get or set implementation.
* @param x An empty argument spacer. Ignored.
* @param TYPE The type of the property.
* @param NAME The name of the property.
* @param GETTERSETTER The getter or setter function that the user has provided.
* @param MACRO The macro to select.
* @remarks The only parameter that is actually used is the MACRO parameter - all of the other parameters serve to shift
* the macro to select forward in the argument list, such that it ends up at the correct position.
*/
#define AUTO_PROPERTY_FUNC_MACRO_CHOOSER(x, TYPE, NAME, GETTERSETTER, MACRO, ...) MACRO
/**
* Selector for dual-function auto properties (a get and set property). This macro, given a list of arguments, chooses
* the appropriate property implementation macro based on whether the user has provided their own get or set
* implementations.
* @param x An empty argument spacer. Ignored.
* @param TYPE The type of the property.
* @param NAME The name of the property.
* @param GETTER The getter function that the user has provided.
* @param SETTER The setter function that the user has provided.
* @param MACRO The macro to select.
* @remarks The only parameter that is actually used is the MACRO parameter - all of the other parameters serve to shift
* the macro to select forward in the argument list, such that it ends up at the correct position.
*/
#define AUTO_PROPERTY_2FUNC_MACRO_CHOOSER(x, TYPE, NAME, GETTER, SETTER, MACRO, ...) MACRO
/**
* Generates an auto-getter function that simply accesses the underlying value.
* @param TYPE The type of the property.
* @param NAME The name of the property.
*/
#define AUTO_GETTER(TYPE, NAME) \
[this]() -> TYPE& \
{ \
return this->NAME.getValueDirect();\
}
/**
* Generates an auto-setter function that simply assigns the underlying value.
*/
#define AUTO_SETTER(TYPE, NAME) \
[this](const TYPE& value) \
{ \
this->NAME.setValueDirect(value); \
}
/**
* Generates a member function that returns the value of the property.
* @param TYPE The type of the property.
* @param NAME The name of the property.
*/
#define Q_AUTO_PROPERTY_MEMBER_GETTER(TYPE, NAME) \
TYPE& __p_ ## NAME ##_get() \
{ \
return NAME; \
} \
/**
* Generates a member function that sets the value of the property.
* @param TYPE The type of the property.
* @param NAME The name of the property.
*/
#define Q_AUTO_PROPERTY_MEMBER_SETTER(TYPE, NAME) \
void __p_ ## NAME ## _set(TYPE value) \
{ \
NAME = value; \
} \
/**
* Generates the required members for an automatically implemented auto-property that allows reading and writing.
* A Qt signal is also generated, which is emitted whenever the value of the property changes.
* @param TYPE The type of the property.
* @param NAME The name of the property.
* @param USER_GETTER The user-provided getter function. Required.
* @param USER_SETTER The user-provided setter function. Required.
*/
#define Q_AUTO_PROPERTY_USERFUNC(TYPE, NAME, USER_GETTER, USER_SETTER) \
Q_PROPERTY(TYPE p_ ## NAME READ __p_ ## NAME ## _get WRITE __p_ ## NAME ## _set NOTIFY NAME ## Changed) \
ReadWriteAutoPropertyImplementation<TYPE> NAME = ReadWriteAutoPropertyImplementation<TYPE> \
( \
[this](TYPE value) \
{ \
emit NAME ## Changed(value); \
}, \
USER_GETTER, \
USER_SETTER \
); \
public: \
Q_SIGNAL void NAME ## Changed(TYPE value); \
private: \
Q_AUTO_PROPERTY_MEMBER_GETTER(TYPE, NAME) \
Q_AUTO_PROPERTY_MEMBER_SETTER(TYPE, NAME) \
/**
* Generates the required members for an automatically implemented auto-property that allows reading and writing.
* A Qt signal is also generated, which is emitted whenever the value of the property changes.
* @param TYPE The type of the property.
* @param NAME The name of the property.
*/
#define Q_AUTO_PROPERTY_AUTOFUNC(TYPE, NAME) \
Q_AUTO_PROPERTY_USERFUNC(TYPE, NAME, AUTO_GETTER(TYPE, NAME), AUTO_SETTER(TYPE,NAME))
/**
* Generates the required members for an automatically implemented auto-property that allows reading and writing.
* A Qt signal is also generated, which is emitted whenever the value of the property changes.
* @param TYPE The type of the property.
* @param NAME The name of the property.
* @param USER_GETTER The user-provided getter function. Optional.
* @param USER_SETTER The user-provided setter function. Optional.
*/
#define Q_AUTO_PROPERTY(...) \
AUTO_PROPERTY_2FUNC_MACRO_CHOOSER \
( \
,##__VA_ARGS__, \
Q_AUTO_PROPERTY_USERFUNC(__VA_ARGS__), /* type, name, getter,setter */ \
Q_AUTO_PROPERTY_USERFUNC(__VA_ARGS__, AUTO_SETTER(ARG1(__VA_ARGS__), ARG2(__VA_ARGS__))), /* type, name, getter */ \
Q_AUTO_PROPERTY_AUTOFUNC(__VA_ARGS__) /* type, name */ \
)
/**
* Generates the required members for an automatically implemented auto-property that allows reading.
* A Qt signal is also generated, which is emitted whenever the value of the property changes.
* @param TYPE The type of the property.
* @param NAME The name of the property.
* @param USER_GETTER The user-provided getter function. Required.
*/
#define Q_AUTO_READONLY_PROPERTY_USERFUNC(TYPE, NAME, USER_GETTER) \
Q_PROPERTY(TYPE p_NAME READ __p_ ## NAME ## _get) \
ReadOnlyAutoPropertyImplementation<TYPE> NAME = ReadOnlyAutoPropertyImplementation<TYPE> \
( \
USER_GETTER \
); \
private: \
Q_AUTO_PROPERTY_MEMBER_GETTER(TYPE, NAME) \
/**
* Generates the required members for an automatically implemented auto-property that allows reading.
* A Qt signal is also generated, which is emitted whenever the value of the property changes.
* @param TYPE The type of the property.
* @param NAME The name of the property.
*/
#define Q_AUTO_READONLY_PROPERTY_AUTOFUNC(TYPE, NAME) \
Q_AUTO_READONLY_PROPERTY_USERFUNC(TYPE, NAME, AUTO_GETTER(TYPE, NAME))
/**
* Generates the required members for an automatically implemented auto-property that allows reading.
* A Qt signal is also generated, which is emitted whenever the value of the property changes.
* @param TYPE The type of the property.
* @param NAME The name of the property.
* @param USER_GETTER The user-provided getter function. Optional.
*/
#define Q_AUTO_READONLY_PROPERTY(...) \
AUTO_PROPERTY_FUNC_MACRO_CHOOSER \
( \
,##__VA_ARGS__, \
Q_AUTO_READONLY_PROPERTY_USERFUNC(__VA_ARGS__), \
Q_AUTO_READONLY_PROPERTY_AUTOFUNC(__VA_ARGS__) \
)
/**
* Generates the required members for an automatically implemented auto-property that allows writing.
* A Qt signal is also generated, which is emitted whenever the value of the property changes.
* @param TYPE The type of the property.
* @param NAME The name of the property.
* @param USER_SETTER The user-provided setter function. Required.
*/
#define Q_AUTO_WRITEONLY_PROPERTY_USERFUNC(TYPE, NAME, USER_SETTER) \
Q_PROPERTY(TYPE p_ ## NAME WRITE __p_ ## NAME ## _set NOTIFY NAME ## Changed) \
WriteOnlyAutoPropertyImplementation<TYPE> NAME = WriteOnlyAutoPropertyImplementation<TYPE> \
( \
[this](TYPE value) \
{ \
emit NAME ## Changed(value); \
}, \
USER_SETTER \
); \
public: \
Q_SIGNAL void NAME ## Changed(TYPE value); \
private: \
Q_AUTO_PROPERTY_MEMBER_SETTER(TYPE, NAME) \
/**
* Generates the required members for an automatically implemented auto-property that allows writing.
* A Qt signal is also generated, which is emitted whenever the value of the property changes.
* @param TYPE The type of the property.
* @param NAME The name of the property.
*/
#define Q_AUTO_WRITEONLY_PROPERTY_AUTOFUNC(TYPE, NAME) \
Q_AUTO_WRITEONLY_PROPERTY_USERFUNC(TYPE, NAME, AUTO_SETTER(TYPE ,NAME))
/**
* Generates the required members for an automatically implemented auto-property that allows writing.
* A Qt signal is also generated, which is emitted whenever the value of the property changes.
* @param TYPE The type of the property.
* @param NAME The name of the property.
* @param USER_SETTER The user-provided Setter function. Optional.
*/
#define Q_AUTO_WRITEONLY_PROPERTY(...) \
AUTO_PROPERTY_FUNC_MACRO_CHOOSER \
( \
,##__VA_ARGS__, \
Q_AUTO_WRITEONLY_PROPERTY_USERFUNC(__VA_ARGS__), \
Q_AUTO_WRITEONLY_PROPERTY_AUTOFUNC(__VA_ARGS__) \
)
/**
* Generates the member implementation for an auto-property type that allows reading.
* @param TYPE The type of the property.
*/
#define AUTO_PROPERTY_READ_IMPL(TYPE) \
private: \
std::function<T&()> _getFunc; \
public: \
T& getValue() const \
{ \
return _getFunc(); \
} \
\
T& getValueDirect() \
{ \
return _value; \
} \
\
operator T&() \
{ \
return _getFunc(); \
} \
/**
* Generates the member implementation for an auto-property type that allows writing.
* @param TYPE The type of the property.
* @param IMPLEMENTING_TYPE The type that implements the members.
*/
#define AUTO_PROPERTY_WRITE_IMPL(TYPE, IMPLEMENTING_TYPE) \
private: \
std::function<void(const T&)> _changedSignal; \
std::function<void(const T& value)> _setFunc; \
public: \
void setValue(const T& value) \
{ \
_setFunc(value); \
} \
\
void setValueDirect(const T& value) \
{ \
_value = value; \
} \
\
IMPLEMENTING_TYPE& operator=(const IMPLEMENTING_TYPE& other) \
{ \
if (this == &other) \
{ \
return *this; \
} \
\
this->operator=(other._value); \
} \
\
IMPLEMENTING_TYPE& operator=(const T& value) \
{ \
if (this->_value == value) \
{ \
return *this; \
} \
\
_setFunc(value); \
this->_changedSignal(value); \
} \
/**
* Represents an auto-property that allows reading and writing.
* @tparam T The underlying property type.
*/
template <typename T>
class ReadWriteAutoPropertyImplementation
{
protected:
/*
* Holds the underlying value.
*/
T _value;
public:
AUTO_PROPERTY_READ_IMPL(T)
AUTO_PROPERTY_WRITE_IMPL(T, ReadWriteAutoPropertyImplementation<T>)
/**
* Initializes a new instance of the @see ReadWriteAutoPropertyImplementation class.
* @param changedSignal The function that notifies subscribers that the value has changed.
* @param getFunc The function that gets the value of the property.
* @param setFunc The function that sets the value of the property.
*/
explicit ReadWriteAutoPropertyImplementation
(
std::function<void(T)> changedSignal,
std::function<T&()> getFunc,
std::function<void(const T&)> setFunc
) : _value()
{
_changedSignal = changedSignal;
_getFunc = getFunc;
_setFunc = setFunc;
}
};
/**
* Represents a read-only auto-property.
* @tparam T The underlying property type.
*/
template <typename T>
class ReadOnlyAutoPropertyImplementation
{
protected:
/*
* Holds the underlying value.
*/
T _value;
public:
AUTO_PROPERTY_READ_IMPL(T)
/**
* Initializes a new instance of the @see ReadOnlyAutoPropertyImplementation class.
* @param getFunc The function that gets the value of the property.
*/
explicit ReadOnlyAutoPropertyImplementation(std::function<T&()> getFunc) : _value()
{
_getFunc = getFunc;
}
};
/**
* Represents a write-only auto-property.
* @tparam T The underlying property type.
*/
template <typename T>
class WriteOnlyAutoPropertyImplementation
{
protected:
/*
* Holds the underlying value.
*/
T _value;
public:
AUTO_PROPERTY_WRITE_IMPL(T, WriteOnlyAutoPropertyImplementation<T>)
/**
* Initializes a new instance of the @see WriteOnlyAutoPropertyImplementation class.
* @param changedSignal The function that notifies subscribers that the value has changed.
* @param setFunc The function that sets the value of the property.
*/
explicit WriteOnlyAutoPropertyImplementation
(
std::function<void(T)> changedSignal,
std::function<void(const T&)> setFunc
) : _value()
{
_setFunc = setFunc;
_changedSignal = changedSignal;
}
};
#endif //QT_AUTO_PROPERTIES_AUTOPROPERTYIMPLEMENTATION_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment