The expiration time for new job artifacts in CI/CD pipelines is now 30 days (GitLab default). Previously generated artifacts in already completed jobs will not be affected by the change. The latest artifacts for all jobs in the latest successful pipelines will be kept. More information: https://gitlab.lrz.de/help/user/admin_area/settings/continuous_integration.html#default-artifacts-expiration

genericproperty.h 6.84 KB
Newer Older
schultezub's avatar
   
schultezub committed
1
2
3
#ifndef GENERICPROPERTY_H__
#define GENERICPROPERTY_H__

4
#include "tbb/include/tbb/spin_mutex.h"
schultezub's avatar
   
schultezub committed
5
#include "tgt/logmanager.h"
schultezub's avatar
schultezub committed
6
#include "core/properties/abstractproperty.h"
schultezub's avatar
   
schultezub committed
7
8
9
10

namespace TUMVis {

    /**
schultezub's avatar
schultezub committed
11
12
13
     * Generic class for value-based properties.
     *
     * \tparam  T   Base type of the property's value.
14
     * \todo    Add PropertyWidgets, review use of mutex
schultezub's avatar
   
schultezub committed
15
16
     */
    template<typename T>
schultezub's avatar
schultezub committed
17
    class GenericProperty : public AbstractProperty {
schultezub's avatar
   
schultezub committed
18
19
    public:
        /**
schultezub's avatar
schultezub committed
20
21
22
23
24
         * Creates a new GenericProperty.
         * \param name      Property name
         * \param title     Property title (e.g. used for GUI)
         * \param value     Initial value of the property
         * \param il        Invalidation level that this property triggers
schultezub's avatar
   
schultezub committed
25
         */
schultezub's avatar
schultezub committed
26
27
28
29
30
        GenericProperty(
            const std::string& name,
            const std::string& title,
            const T& value,
            InvalidationLevel il = InvalidationLevel::INVALID_RESULT);
schultezub's avatar
   
schultezub committed
31
32
33
34
35
36
37

        /**
         * Virtual Destructor
         **/
        virtual ~GenericProperty();


38
39
40
41
42
43
44
45
        /**
         * Adds the given property \a prop to the set of shared properties.
         * All shared properties will be changed when this property changes.
         * \note        Make sure not to build circular sharing or you will encounter endless loops!
         * \param prop  Property to add, must be of the same type as this property.
         */
        virtual void addSharedProperty(AbstractProperty* prop);

schultezub's avatar
schultezub committed
46
47
48
49
        /**
         * Returns the current value of this property.
         * \return _value
         */
schultezub's avatar
schultezub committed
50
        const T& getValue() const;
schultezub's avatar
   
schultezub committed
51

schultezub's avatar
schultezub committed
52
        /**
53
         * On successful validation it sets the property value to \a value and notifies all observers.
54
         * Depending on the current lock state of the property, the value will either be written to the front or back buffer.
55
         * \sa GenericProperty::validateValue
schultezub's avatar
schultezub committed
56
57
         * \param value     New value for this property.
         */
58
        virtual void setValue(const T& value);
schultezub's avatar
   
schultezub committed
59
60


61
62
63
64
65
        /**
         * Locks the property and marks it as "in use". All changes to its value will be written to
         * the back buffer. The buffers will be swapped on unlocking the property.
         * \sa  GenericProperty::unlock
         */
schultezub's avatar
schultezub committed
66
        virtual void lock();
67
68
69
70
71
72

        /**
         * Unlocks the property. If the back buffer has changed, the changes will be written to the front
         * buffer and all observers will be notified.
         * \sa  GenericProperty::lock
         */
schultezub's avatar
schultezub committed
73
        virtual void unlock();
74
75


schultezub's avatar
schultezub committed
76
    protected:
77
78
79
80
81
82
83
84

        /**
         * Adapts \a value, so that is is a valid value for this property.
         * Default implementation does nothing and always returns \a value, subclasses can overwrite this method to fit their needs.
         * \param   value   value to validate.
         */
        virtual T validateValue(const T& value);

85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
        /**
         * Sets the property value to \a value and notifies all observers.
         * \note    _localMutex has to be acquired before calling!
         * \param   value   New value for _value.
         */
        void setFrontValue(const T& value);

        /**
         * Sets the property's back buffer value to \a value.
         * \note    _localMutex has to be acquired before calling!
         * \param   value   New value for _backBuffer.
         */
        void setBackValue(const T& value);

        
        T _value;                               ///< value of the property
        T _backBuffer;                          ///< back buffer for values when property is in use
102

schultezub's avatar
schultezub committed
103
104
        static const std::string loggerCat_;
    };
schultezub's avatar
   
schultezub committed
105

schultezub's avatar
schultezub committed
106
107
108
109
110
// = Typedefs =====================================================================================

    typedef GenericProperty<std::string> StringProperty;

// = Template Implementation ======================================================================
schultezub's avatar
   
schultezub committed
111

schultezub's avatar
schultezub committed
112
113
114
115
    template<typename T>
    TUMVis::GenericProperty<T>::GenericProperty(const std::string& name, const std::string& title, const T& value, InvalidationLevel il /*= InvalidationLevel::INVALID_RESULT*/) 
        : AbstractProperty(name, title, il)
        , _value(value)
116
        , _backBuffer(value)
schultezub's avatar
schultezub committed
117
118
    {
    }
schultezub's avatar
   
schultezub committed
119

schultezub's avatar
schultezub committed
120
121
    template<typename T>
    TUMVis::GenericProperty<T>::~GenericProperty() {
schultezub's avatar
   
schultezub committed
122

schultezub's avatar
schultezub committed
123
    }
schultezub's avatar
   
schultezub committed
124

125
126
127
128
    template<typename T>
    void TUMVis::GenericProperty<T>::addSharedProperty(AbstractProperty* prop) {
        // make type check first, then call base method.
        tgtAssert(prop != 0, "Shared property must not be 0!");
schultezub's avatar
schultezub committed
129
130
131
        if (GenericProperty<T>* tmp = dynamic_cast< GenericProperty<T>* >(prop)) {
            AbstractProperty::addSharedProperty(prop);
            tmp->setValue(getValue());
132
133
            return;
        }
schultezub's avatar
schultezub committed
134
        tgtAssert(false, "Shared property must be of the same type as this property!");
135
136
    }

schultezub's avatar
schultezub committed
137
    template<typename T>
schultezub's avatar
schultezub committed
138
    const T& TUMVis::GenericProperty<T>::getValue() const {
schultezub's avatar
schultezub committed
139
140
        return _value;
    }
schultezub's avatar
   
schultezub committed
141

schultezub's avatar
schultezub committed
142
143
    template<typename T>
    void TUMVis::GenericProperty<T>::setValue(const T& value) {
144
        T vv = validateValue(value);
schultezub's avatar
schultezub committed
145
        tbb::spin_mutex::scoped_lock lock(_localMutex);
146
147

        if (_inUse)
148
            setBackValue(vv);
schultezub's avatar
schultezub committed
149
        else {
150
151
            setFrontValue(vv);
            setBackValue(vv);
schultezub's avatar
schultezub committed
152
        }
153
154
155
156
    }

    template<typename T>
    void TUMVis::GenericProperty<T>::lock() {
schultezub's avatar
schultezub committed
157
        tbb::spin_mutex::scoped_lock lock(_localMutex);
158
159
160
161
162
        _inUse = true;
    }

    template<typename T>
    void TUMVis::GenericProperty<T>::unlock() {
schultezub's avatar
schultezub committed
163
        tbb::spin_mutex::scoped_lock lock(_localMutex);
164
165
166
167
168
169
170
171

        if (_backBuffer != _value)
            setFrontValue(_backBuffer);
        _inUse = false;
    }

    template<typename T>
    void TUMVis::GenericProperty<T>::setFrontValue(const T& value) {
schultezub's avatar
schultezub committed
172
        _value = value;
173
174
175
176
177
178
179
180
        // TODO:    think about the correct/reasonable order of observer notification
        //          thread-safety might play a role thereby...
        for (std::set<AbstractProperty*>::iterator it = _sharedProperties.begin(); it != _sharedProperties.end(); ++it) {
            // We ensure all shared properties to be of type GenericProperty<T> in the addSharedProperty overload.
            // Hence, static_cast ist safe.
            GenericProperty<T>* child = static_cast< GenericProperty<T>* >(*it);
            child->setValue(value);
        }
schultezub's avatar
schultezub committed
181
        s_changed(this);
schultezub's avatar
schultezub committed
182
    }
schultezub's avatar
   
schultezub committed
183

184
185
186
187
188
    template<typename T>
    void TUMVis::GenericProperty<T>::setBackValue(const T& value) {
        _backBuffer = value;
    }

189
190
191
192
193
    template<typename T>
    T TUMVis::GenericProperty<T>::validateValue(const T& value) {
        return value;
    }

schultezub's avatar
schultezub committed
194
195
    template<typename T>
    const std::string TUMVis::GenericProperty<T>::loggerCat_ = "TUMVis.core.datastructures.GenericProperty";
schultezub's avatar
   
schultezub committed
196
197
198
}

#endif // GENERICPROPERTY_H__