Created
June 29, 2019 13:20
-
-
Save Nihlus/0f96d12b8835d1ea2d2b339ef1d05068 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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