datacontainer.h 8.43 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// ================================================================================================
// 
// This file is part of the TUMVis Visualization Framework.
// 
// If not explicitly stated otherwise: Copyright (C) 2012, all rights reserved,
//      Christian Schulte zu Berge (christian.szb@in.tum.de)
//      Chair for Computer Aided Medical Procedures
//      Technische Universität München
//      Boltzmannstr. 3, 85748 Garching b. München, Germany
// 
// The licensing of this softare is not yet resolved. Until then, redistribution in source or
// binary forms outside the CAMP chair is not permitted, unless explicitly stated in legal form.
// However, the names of the original authors and the above copyright notice must retain in its
// original state in any case.
// 
// Legal disclaimer provided by the BSD license:
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
// 
// ================================================================================================

schultezub's avatar
schultezub committed
29
30
#ifndef DATACONTAINER_H__
#define DATACONTAINER_H__
schultezub's avatar
schultezub committed
31

schultezub's avatar
schultezub committed
32
#include "sigslot/sigslot.h"
33
#include "tbb/include/tbb/spin_mutex.h"
schultezub's avatar
schultezub committed
34
#include "core/datastructures/datahandle.h"
schultezub's avatar
schultezub committed
35
36
37
38
39

#include <string>
#include <map>

namespace TUMVis {
schultezub's avatar
schultezub committed
40
41
    class AbstractData;
    
schultezub's avatar
schultezub committed
42
43
44
45
    /**
     * A DataContainer manages instances of AbstractData and offers access to them via string identifiers (names/keys).
     * Therefore, it stores them in DataHandles which take ownership of the AbstractData instance. Hence,
     * as soon as an AbstractData instance is added to a DataContainer via DataContainer::addData(), its 
46
     * lifetime is managed by the wrapping DataHandle instance and its reference counting mechanism.
schultezub's avatar
schultezub committed
47
     * Because the DataHandles are stored as const handles, the underlying data cannot be changed anymore. This
48
     * also ensures (hopefully) that nobody can do messy things, such as changing the data while some other 
49
50
     * thread is reading it. Theoretically this should be possible, but a correct implementation would require
     * some brain fuck.
schultezub's avatar
schultezub committed
51
     * 
52
     * \todo    Check thread-safety
53
     * 
schultezub's avatar
schultezub committed
54
55
56
57
58
     * \todo    If the original data changes, the other objects accessing that very DataHandle might want to 
     *          get notified of the change. Hence, some observer pattern might be useful.
     */
    class DataContainer {
    public:
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
        /**
         * Proxy class for scoped strongly-typed access to the data of a DataContainer.
         * From the outside ScopedTypedData<T> behaves exactly like a const T*, but internally it preserves the
         * reference counting of a DataHandle. Use this class when you want temporary access to a strongly-typed
         * data item in a DataContainer but don't want to to the dynamic_cast yourself.
         *
         * \tparam  T   Base class of the DataHandle data to test for
         */
        template<typename T>
        struct ScopedTypedData {
            /**
             * Creates a new DataHandle to the data item with the key \a name in \a dc, that behaves like a T*.
             * \param   dc      DataContainer to grab data from
             * \param   name    Key of the DataHandle to search for
             */
            ScopedTypedData(const DataContainer& dc, const std::string& name)
                : dh(dc.getData(name))
                , data(0)
            {
                if (dh != 0 && dh->getData() != 0) {
                    data = dynamic_cast<const T*>(dh->getData());
                }
            };

            /**
             * Destructor, deletes the internal DataHandle.
             */
            ~ScopedTypedData() {
                if (dh) {
                    delete dh;
                }
            };

            /**
             * Implicit conversion operator to const T*.
             * \return  The data in the DataHandle, may be 0 when no DataHandle was found, or the data is of the wrong type.
             */
            operator const T*() {
                return data;
            }

            /**
             * Implicit arrow operator to const T*.
             * \return  The data in the DataHandle, may be 0 when no DataHandle was found, or the data is of the wrong type.
             */
            const T* operator->() const {
                return data;
            }

108
109
110
111
112
113
114
115
            /**
             * Gets the DataHandle.
             * \return dh
             */
            const DataHandle* getDataHandle() const {
                return dh;
            }

116
117
118
119
120
121
122
123
124
125
126
        private:
            /// Not copy-constructable
            ScopedTypedData(const ScopedTypedData& rhs);
            /// Not assignable
            ScopedTypedData& operator=(const ScopedTypedData& rhs);

            const DataHandle* dh;   ///< DataHandle, may be 0
            const T* data;          ///< strongly-typed pointer to data, may be 0
        };


schultezub's avatar
schultezub committed
127
128
129
130
131
132
133
134
135
136
137
138
139
140
        /**
         * Creates a new empty DataContainer
         */
        DataContainer();

        /**
         * Destructor of the DataContainer. Will disconnect all DataHandles from this container.
         */
        ~DataContainer();


        /**
         * Adds the given AbstractData instance \a data, accessible by the key \name, to this DataContainer.
         * In doing so, the DataContainer (respectively the created DataHandle) takes ownership of \a data
schultezub's avatar
schultezub committed
141
         * and will manage its lifetime. So don't even think about deleting \a data yourself!
schultezub's avatar
schultezub committed
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
         *
         * \param   name    Key for accessing the DataHandle within this DataContainer
         * \param   data    DataHandle to add.
         * \return  The DataHandle which was created for \a data.
         */
        const DataHandle* addData(const std::string& name, AbstractData* data);

        /**
         * Adds the given DataHandle \a data, accessible by the key \name, to this DataContainer.
         * Already existing DataHandles with the same key will be removed from this DataContainer.
         *
         * \param   name    Key for accessing the DataHandle within this DataContainer
         * \param   data    DataHandle to add.
         */
        void addDataHandle(const std::string& name, const DataHandle* dh);

        /**
         * Checks whether this DataContainer contains a DataHandle with the given name.
         *
         * \param   name    Key of the DataHandle to search for
         * \return  true, if this DataContainer contains a DataHandle with the given name.
         */
        bool hasData(const std::string& name) const;

        /**
         * Returns the DataHandle with the given name from this container.
         * If no such DataHandle exists, this method returns 0.
         *
         * \param   name    Key of the DataHandle to search for
         * \return  The stored DataHandle with the given name, 0 if no such DataHandle exists.
         */
        const DataHandle* getData(const std::string& name) const;

schultezub's avatar
schultezub committed
175
176
177
178
179
180
        /**
         * Removes the DataHandle with the given name from this container.
         * If no such DataHandle exists, nothing happens.
         * \param   name    Key of the DataHandle to remove.
         */
        void removeData(const std::string& name);
schultezub's avatar
schultezub committed
181

schultezub's avatar
schultezub committed
182
183
184
185
        /**
         * Signal emitted when data has been added to this DataContainer (this includes also data being replaced).
         * First parameter is the name of the added data, second parameter contains a DataHandle to the new data.
         */
schultezub's avatar
schultezub committed
186
187
        sigslot::signal2<const std::string&, const DataHandle*> s_dataAdded;

schultezub's avatar
schultezub committed
188
189
    private:
        std::map<std::string, const DataHandle*> _handles;
190
        mutable tbb::spin_mutex _localMutex;
schultezub's avatar
schultezub committed
191
192
193
194
195

        static const std::string loggerCat_;
    };

}
schultezub's avatar
schultezub committed
196
197

#endif // DATACONTAINER_H__