1 /* This file is part of the Pangolin Project.
2  * http://github.com/stevenlovegrove/Pangolin
3  *
4  * Copyright (c) 2011-2013 Steven Lovegrove
5  *
6  * Permission is hereby granted, free of charge, to any person
7  * obtaining a copy of this software and associated documentation
8  * files (the "Software"), to deal in the Software without
9  * restriction, including without limitation the rights to use,
10  * copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following
13  * conditions:
14  *
15  * The above copyright notice and this permission notice shall be
16  * included in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25  * OTHER DEALINGS IN THE SOFTWARE.
26  */
27 
28 #pragma once
29 
30 #include <memory>
31 #include <vector>
32 #include <algorithm>
33 
34 #include <pangolin/utils/uri.h>
35 
36 namespace pangolin
37 {
38 
39 template<typename T>
40 struct FactoryInterface
41 {
42     typedef T FactoryItem;
43 
44     virtual ~FactoryInterface() = default;
45     virtual std::unique_ptr<T> Open(const Uri& uri) = 0;
46 };
47 
48 template<typename T>
49 class FactoryRegistry
50 {
51 public:
52     // IMPORTANT: Implement for each templated instantiation within a seperate compilation unit.
53     static FactoryRegistry<T>& I();
54 
~FactoryRegistry()55     ~FactoryRegistry()
56     {
57     }
58 
RegisterFactory(std::shared_ptr<FactoryInterface<T>> factory,uint32_t precedence,const std::string & scheme_name)59     void RegisterFactory(std::shared_ptr<FactoryInterface<T>> factory, uint32_t precedence, const std::string& scheme_name )
60     {
61         FactoryItem item = {precedence, scheme_name, factory};
62         factories.push_back( item );
63         std::sort(factories.begin(), factories.end());
64     }
65 
UnregisterFactory(FactoryInterface<T> * factory)66     void UnregisterFactory(FactoryInterface<T>* factory)
67     {
68         for( auto i = factories.end()-1; i != factories.begin(); --i)
69         {
70             if( i->factory.get() == factory ) {
71                 factories.erase(i);
72             }
73         }
74     }
75 
UnregisterAllFactories()76     void UnregisterAllFactories()
77     {
78         factories.clear();
79     }
80 
Open(const Uri & uri)81     std::unique_ptr<T> Open(const Uri& uri)
82     {
83         // Iterate over all registered factories in order of precedence.
84         for(auto& item : factories) {
85             if( item.scheme == uri.scheme) {
86                 std::unique_ptr<T> video = item.factory->Open(uri);
87                 if(video) {
88                     return video;
89                 }
90             }
91         }
92 
93         return std::unique_ptr<T>();
94     }
95 
96 private:
97     struct FactoryItem
98     {
99         uint32_t precedence;
100         std::string scheme;
101         std::shared_ptr<FactoryInterface<T>> factory;
102 
103         bool operator<(const FactoryItem& rhs) const {
104             return precedence < rhs.precedence;
105         }
106     };
107 
108     // Priority, Factory tuple
109     std::vector<FactoryItem> factories;
110 };
111 
112 #define PANGOLIN_REGISTER_FACTORY(x) void Register ## x ## Factory()
113 
114 }
115