2.12.2021, 9:00 - 11:00: Due to updates GitLab may be unavailable for some minutes between 09:00 and 11:00.

processorfactory.h 9.17 KB
Newer Older
Hossain Mahmud's avatar
Hossain Mahmud committed
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
29
30
31
32
33
34
35
// ================================================================================================
// 
// This file is part of the CAMPVis Software Framework.
// 
// If not explicitly stated otherwise: Copyright (C) 2012-2014, all rights reserved,
//      Christian Schulte zu Berge <christian.szb@in.tum.de>
//      Chair for Computer Aided Medical Procedures
//      Technische Universitaet Muenchen
//      Boltzmannstr. 3, 85748 Garching b. Muenchen, Germany
// 
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
// 
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 
// except in compliance with the License. You may obtain a copy of the License at
// 
// http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software distributed under the 
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
// either express or implied. See the License for the specific language governing permissions 
// and limitations under the License.
// 
// ================================================================================================

#ifndef PROCESSORFACTORY_H__
#define PROCESSORFACTORY_H__

#include "cgt/logmanager.h"
#include "cgt/singleton.h"

#include <tbb/atomic.h>
#include <tbb/spin_mutex.h>

#include "modules/modulesapi.h"

36
#include <functional>
Hossain Mahmud's avatar
Hossain Mahmud committed
37
38
#include <map>
#include <string>
39
#include <type_traits>
40
#include <typeindex>
Hossain Mahmud's avatar
Hossain Mahmud committed
41
#include <vector>
42
43

#include "core/pipeline/visualizationprocessor.h"
44
#include "core/pipeline/raycastingprocessor.h"
Hossain Mahmud's avatar
Hossain Mahmud committed
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

namespace campvis {
    class AbstractProcessor;
    class DataContainer;

    /**
     * Factory for creating processors by their name.
     * Using some template-magic, ProcessorFactory is able to register processors during static 
     * initialization in cooperation with the ProcessorRegistrar.
     * 
     * \note    ProcessorFactory is a thread-safe lazy-instantiated singleton.
     */
    class CAMPVIS_MODULES_API ProcessorFactory {
    public:
        /**
         * Returns a reference to the ProcessorFactory singleton.
         * Creates the singleton if necessary
         * \return  *_singleton
         */
        static ProcessorFactory& getRef();
    
        static void deinit();
        
68
69
70
71
        /**
         * Returns the list of all registered Processors.
         * \return  A std::vector of the string IDs of all registered processors.
         */
Hossain Mahmud's avatar
Hossain Mahmud committed
72
73
        std::vector<std::string> getRegisteredProcessors() const;

74
75
76
77
78
79
80
81
82
83
84
85
86
87
        /**
         * Returns the list of all registered raycasting processors (all registered processors 
         * inheriting from RaycastingProcessor).
         * \return  A std::vector of the string IDs of all registered raycasting processors.
         */
        std::vector<std::string> getRegisteredRaycastingProcessors() const;

        /**
         * Factory method to create a processor from the given string ID.
         * \param   id                  String ID of the processor to create.
         * \param   viewPortSizeProp    Pointer to the viewport size property that the created VisualizationProcessor should use. If the created processor is no VisualizationProcessor, then this argument is ignored. Defaults to nullptr.
         * \return  Pointer to the newly created processor, may be nullptr. Caller has to take ownership of the returned pointer.
         */
        AbstractProcessor* createProcessor(const std::string& id, IVec2Property* viewPortSizeProp = nullptr) const;
Hossain Mahmud's avatar
Hossain Mahmud committed
88

Hossain Mahmud's avatar
Hossain Mahmud committed
89
        
Hossain Mahmud's avatar
Hossain Mahmud committed
90
        /**
Hossain Mahmud's avatar
Hossain Mahmud committed
91
         * Statically registers the processor of type T with construction T() using \a callee as factory method.
Hossain Mahmud's avatar
Hossain Mahmud committed
92
93
94
95
         * \note    The template instantiation of ProcessorRegistrar takes care of calling this method.
         * \param   callee  Factory method to call to create an instance of type T
         * \return  The registration index.
         */
Hossain Mahmud's avatar
Hossain Mahmud committed
96
        template<typename T>
97
        size_t registerProcessorWithDefaultConstructor(std::function<AbstractProcessor*()> callee) {
98
99
            tbb::spin_mutex::scoped_lock lock(_mutex);

100
101
102
103
            // add to list of raycasting processors if needed
            if (std::is_base_of<RaycastingProcessor, T>::value)
                _raycastingProcessors.push_back(T::getId());

104
105
106
107
108
109
            auto it = _processorTypeMap.find(T::getId());
            if (it != _processorTypeMap.end()) {
                // check, whether the type is the same, then a double registration is okay since it
                // may occur due to having the ProcessorRegistrar being referenced in both 
                // campvis-application and campvis-modules.
                cgtAssert(std::type_index(typeid(T)) == it->second, "Tried to register two different processor types with the same ID.");
110
111
            }
            else {
112
                _processorTypeMap.insert(it, std::make_pair(T::getId(), std::type_index(typeid(T))));
113
114
            }

115
            _processorMapDefault[T::getId()] = callee;
116
            return _processorMapDefault.size();
117
118
        }

Hossain Mahmud's avatar
Hossain Mahmud committed
119
120
121
122
123
124
        /**
         * Statically registers the processor of type T with constructor T(IVec2Property) using \a callee as factory method.
         * \note    The template instantiation of ProcessorRegistrar takes care of calling this method.
         * \param   callee  Factory method to call to create an instance of type T
         * \return  The registration index.
         */
125
        template<typename T>
126
        size_t registerProcessorWithIVec2PropParam(std::function<AbstractProcessor*(IVec2Property*)> callee) {
Hossain Mahmud's avatar
Hossain Mahmud committed
127
128
            tbb::spin_mutex::scoped_lock lock(_mutex);

129
130
131
132
            // add to list of raycasting processors if needed
            if (std::is_base_of<RaycastingProcessor, T>::value)
                _raycastingProcessors.push_back(T::getId());

133
134
135
136
137
138
            auto it = _processorTypeMap.find(T::getId());
            if (it != _processorTypeMap.end()) {
                // check, whether the type is the same, then a double registration is okay since it
                // may occur due to having the ProcessorRegistrar being referenced in both 
                // campvis-application and campvis-modules.
                cgtAssert(std::type_index(typeid(T)) == it->second, "Tried to register two different processor types with the same ID.");
Hossain Mahmud's avatar
Hossain Mahmud committed
139
140
            }
            else {
141
                _processorTypeMap.insert(it, std::make_pair(T::getId(), std::type_index(typeid(T))));
Hossain Mahmud's avatar
Hossain Mahmud committed
142
            }
Hossain Mahmud's avatar
Hossain Mahmud committed
143

144
            _processorMapWithIVec2Param[T::getId()] = callee;
145
            return _processorMapWithIVec2Param.size();
Hossain Mahmud's avatar
Hossain Mahmud committed
146
        }
Hossain Mahmud's avatar
Hossain Mahmud committed
147

Hossain Mahmud's avatar
Hossain Mahmud committed
148
149
150
151
    private:
        mutable tbb::spin_mutex _mutex;
        static tbb::atomic<ProcessorFactory*> _singleton;    ///< the singleton object

152
153
154
        std::map< std::string, std::type_index> _processorTypeMap;
        std::map< std::string, std::function<AbstractProcessor*()> > _processorMapDefault;
        std::map< std::string, std::function<AbstractProcessor*(IVec2Property*)> > _processorMapWithIVec2Param;
155
156

        std::vector<std::string> _raycastingProcessors;
Hossain Mahmud's avatar
Hossain Mahmud committed
157
158
159
160
161
    };


// ================================================================================================

162
163
164
165
    template<typename T, bool>
    class ProcessorRegistrarSwitch {
    };

Hossain Mahmud's avatar
Hossain Mahmud committed
166
    template<typename T>
167
168
    class ProcessorRegistrarSwitch<T, false> {
            public:
Hossain Mahmud's avatar
Hossain Mahmud committed
169
170
171
172
        /**
         * Static factory method for creating the processor of type T.
         * \return  A newly created processor of type T. Caller has to take ownership of the pointer.
         */
173
174
175
        static AbstractProcessor* create() {
            return new T();
        }
Hossain Mahmud's avatar
Hossain Mahmud committed
176

177
178
179
        /// static helper field to ensure registration at static initialization time.
        static const size_t _factoryId;
    };
180
181

    template<typename T>
182
    const size_t ProcessorRegistrarSwitch<T, false>::_factoryId = ProcessorFactory::getRef().registerProcessorWithDefaultConstructor<T>(&ProcessorRegistrarSwitch<T, false>::create);
183
184


185
    template<typename T>
186
    class ProcessorRegistrarSwitch<T, true> {
187
188
189
190
191
192
    public:
        /**
         * Static factory method for creating the processor of type T.
         * \param   viewPortSizeProp  viewPortSizeProp for the created processor to work on.
         * \return  A newly created processor of type T. Caller has to take ownership of the pointer.
         */
Hossain Mahmud's avatar
Hossain Mahmud committed
193
194
        static AbstractProcessor* create(IVec2Property* viewPortSizeProp) {
            return new T(viewPortSizeProp);
Hossain Mahmud's avatar
Hossain Mahmud committed
195
196
197
198
199
200
        }

        /// static helper field to ensure registration at static initialization time.
        static const size_t _factoryId;
    };

Hossain Mahmud's avatar
Hossain Mahmud committed
201
    template<typename T>
202
    const size_t ProcessorRegistrarSwitch<T, true>::_factoryId = ProcessorFactory::getRef().registerProcessorWithIVec2PropParam<T>(&ProcessorRegistrarSwitch<T, true>::create);
203

204
205
206
207
208
    
    /**
     * Smart processor registrar that uses type traits to deduce the base type of the processor to
     * register and forwards its registration to the corresponding ProcessorRegistrarSwitch<T, bool>.
     */
209
210
211
212
213
    template<typename T>
    class SmartProcessorRegistrar {
        static const size_t _helperField;
    };

214
    template<typename T>
215
    const size_t campvis::SmartProcessorRegistrar<T>::_helperField = ProcessorRegistrarSwitch< T, std::is_base_of<VisualizationProcessor, T>::value >::_factoryId;
Hossain Mahmud's avatar
Hossain Mahmud committed
216
217
218
219

}

#endif // PROCESSORFACTORY_H__