datacontainer.h 9.29 KB
Newer Older
1
2
// ================================================================================================
// 
schultezub's avatar
schultezub committed
3
// This file is part of the CAMPVis Software Framework.
4
5
// 
// If not explicitly stated otherwise: Copyright (C) 2012, all rights reserved,
schultezub's avatar
schultezub committed
6
//      Christian Schulte zu Berge <christian.szb@in.tum.de>
7
8
9
//      Chair for Computer Aided Medical Procedures
//      Technische Universität München
//      Boltzmannstr. 3, 85748 Garching b. München, Germany
schultezub's avatar
schultezub committed
10
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 
// 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
30
31
#ifndef DATACONTAINER_H__
#define DATACONTAINER_H__
schultezub's avatar
schultezub committed
32

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

#include <string>
#include <map>
39
40
#include <utility>
#include <vector>
schultezub's avatar
schultezub committed
41

schultezub's avatar
schultezub committed
42
namespace campvis {
schultezub's avatar
schultezub committed
43
44
    class AbstractData;
    
schultezub's avatar
schultezub committed
45
46
47
48
    /**
     * 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 
49
     * lifetime is managed by the wrapping DataHandle instance and its reference counting mechanism.
schultezub's avatar
schultezub committed
50
     * Because the DataHandles are stored as const handles, the underlying data cannot be changed anymore. This
51
     * also ensures (hopefully) that nobody can do messy things, such as changing the data while some other 
52
53
     * thread is reading it. Theoretically this should be possible, but a correct implementation would require
     * some brain fuck.
schultezub's avatar
schultezub committed
54
     * 
55
     * \todo    Check thread-safety
schultezub's avatar
schultezub committed
56
57
58
     */
    class DataContainer {
    public:
59
60
        /**
         * Proxy class for scoped strongly-typed access to the data of a DataContainer.
61
         * From the outside DataContainer::ScopedTypedData<T> behaves exactly like a const T*, but internally it preserves the
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
         * 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)
            {
78
79
                if (dh.getData() != 0) {
                    data = dynamic_cast<const T*>(dh.getData());
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
                }
            };

            /**
             * 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;
            }

99
100
101
102
            /**
             * Gets the DataHandle.
             * \return dh
             */
103
            const DataHandle& getDataHandle() const {
104
105
106
                return dh;
            }

107
108
109
110
111
112
        private:
            /// Not copy-constructable
            ScopedTypedData(const ScopedTypedData& rhs);
            /// Not assignable
            ScopedTypedData& operator=(const ScopedTypedData& rhs);

113
114
            DataHandle dh;      ///< DataHandle
            const T* data;      ///< strongly-typed pointer to data, may be 0
115
116
117
        };


schultezub's avatar
schultezub committed
118
119
120
121
122
123
124
125
126
127
128
129
130
131
        /**
         * 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
132
         * and will manage its lifetime. So don't even think about deleting \a data yourself!
schultezub's avatar
schultezub committed
133
         *
134
135
         * \param   name    Key for accessing the DataHandle within this DataContainer.
         * \param   data    The data to wrap in a DataHandle and add to this DataContainer, must not be 0.
136
         * \return  A DataHandle containing \a data.
schultezub's avatar
schultezub committed
137
         */
138
        DataHandle addData(const std::string& name, AbstractData* data);
schultezub's avatar
schultezub committed
139
140
141
142
143
144
145
146

        /**
         * 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.
         */
147
        void addDataHandle(const std::string& name, const DataHandle& dh);
schultezub's avatar
schultezub committed
148
149
150
151
152
153
154
155
156
157
158

        /**
         * 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.
159
         * If no such DataHandle exists, this method returns an empty DataHandle.
schultezub's avatar
schultezub committed
160
161
         *
         * \param   name    Key of the DataHandle to search for
162
         * \return  The stored DataHandle with the given name, an empty DataHandle if no such DataHandle exists.
schultezub's avatar
schultezub committed
163
         */
164
        DataHandle getData(const std::string& name) const;
schultezub's avatar
schultezub committed
165

schultezub's avatar
schultezub committed
166
167
168
169
170
171
        /**
         * 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
172

173
174
175
176
177
178
        /**
         * Returns a copy of the current list of DataHandles.
         * \note    Use with caution, this method is to be considered as slow, as it includes several 
         *          copies and locks the whole DataContainer during execution.
         * \return  A list of pairs (name, DataHandle). The caller has to take ownership of the passed pointers!
         */
179
        std::vector< std::pair< std::string, DataHandle> > getDataHandlesCopy() const;
180

181
182
183
184
185
186
        /**
         * Returns a copy of the current map of DataHandles.
         * \note    Use with caution, this method is to be considered as slow, as it includes several 
         *          copies and locks the whole DataContainer during execution.
         * \return  A copy of the current handles map. The caller has to take ownership of the passed pointers!
         */
187
        std::map<std::string, DataHandle> getHandlesCopy() const;
188

schultezub's avatar
schultezub committed
189
190
191
192
        /**
         * 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.
         */
193
        sigslot::signal2<const std::string&, const DataHandle&> s_dataAdded;
schultezub's avatar
schultezub committed
194

195
196
197
        /// Signal emitted when list of DataHandles has changed.
        sigslot::signal0<> s_changed;

schultezub's avatar
schultezub committed
198
    private:
199
        /// Map of the DataHandles in this collection and their IDs. The DataHandles contain valid data.
200
        std::map<std::string, DataHandle> _handles;
201
        mutable tbb::spin_mutex _localMutex;
schultezub's avatar
schultezub committed
202
203
204
205
206

        static const std::string loggerCat_;
    };

}
schultezub's avatar
schultezub committed
207
208

#endif // DATACONTAINER_H__