The name of the initial branch for new projects is now "main" instead of "master". Existing projects remain unchanged. More information: https://doku.lrz.de/display/PUBLIC/GitLab

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__