1 /*========================== begin_copyright_notice ============================
2 
3 Copyright (C) 2017-2021 Intel Corporation
4 
5 SPDX-License-Identifier: MIT
6 
7 ============================= end_copyright_notice ===========================*/
8 
9 #pragma once
10 
11 #include <array>
12 
13 #include "cif/common/cif.h"
14 #include "cif/export/interface_creator.h"
15 
16 namespace CIF{
17 
18 template <template <Version_t> class Interface>
19 struct Multiversion
20 {
21     using ImplT = typename Interface<CIF::BaseVersion>::Impl;
22     using BaseInterfaceT = Interface<CIF::BaseVersion>;
23 
MultiversionMultiversion24     Multiversion(){
25         this->impl = nullptr;
26         std::fill(versions.begin(), versions.end(), nullptr);
27     }
28 
29     template<typename ArgT, typename ... ArgsT>
MultiversionMultiversion30     Multiversion(ArgT && arg, ArgsT && ... args)
31         : Multiversion(){
32         impl = new ImplT(std::forward<ArgT>(arg), std::forward<ArgsT>(args)...);
33         impl->retain(nullptr);
34     }
35 
MultiversionMultiversion36     Multiversion(ImplT *impl)
37         : Multiversion(){
38         this->impl = impl;
39         this->impl->retain(nullptr);
40     }
41 
42     template<typename ... ArgsT>
CreateImplMultiversion43     void CreateImpl(ArgsT && ... args){
44         // release interface tied-up to previous impl (if any)
45         for(BaseInterfaceT *&iVer : versions){
46             if(iVer == nullptr){
47                 continue;
48             }
49             iVer->Release();
50             iVer = nullptr;
51         }
52 
53         if(this->impl != nullptr){
54             this->impl->Release(nullptr);
55         }
56         this->impl = new ImplT(std::forward<ArgsT>(args)...);
57         this->impl->Retain(nullptr);
58     }
59 
~MultiversionMultiversion60     ~Multiversion(){
61         for(BaseInterfaceT * iVer : versions){
62             if(iVer == nullptr){
63                 continue;
64             }
65             iVer->Release();
66         }
67 
68         if(this->impl != nullptr){
69             impl->Release(nullptr);
70         }
71     }
72 
73     Multiversion(const Multiversion &) = delete;
74     Multiversion &operator=(const Multiversion &) = delete;
75     Multiversion(Multiversion &&) = delete;
76     Multiversion *operator=(Multiversion &&) = delete;
77 
78     ImplT *operator->() { return impl; }
79 
80     ImplT *operator->() const { return impl; }
81 
GetImplMultiversion82     ImplT *GetImpl(){
83         return impl;
84     }
85 
GetImplMultiversion86     const ImplT *GetImpl() const {
87         return impl;
88     }
89 
GetVersionMultiversion90     const BaseInterfaceT *GetVersion(Version_t v) const {
91         constexpr Version_t oldestSupportedVersion = Interface<CIF::TraitsSpecialVersion>::GetOldestSupportedVersion();
92         constexpr Version_t latestSupportedVersion = Interface<CIF::TraitsSpecialVersion>::GetLatestSupportedVersion();
93 
94         if((v < oldestSupportedVersion) || (v > latestSupportedVersion)){
95             return nullptr;
96         }
97 
98         size_t idx = static_cast<size_t>(v - oldestSupportedVersion);
99         BaseInterfaceT *curr = versions[idx];
100         if(curr != nullptr){
101             return curr;
102         }
103         versions[idx] = InterfaceCreator<Interface>::CreateInterfaceVer(v, impl);
104         return versions[idx];
105     }
106 
GetVersionMultiversion107     BaseInterfaceT *GetVersion(Version_t v) {
108         return const_cast<BaseInterfaceT*>(const_cast<const Multiversion<Interface>*>(this)->GetVersion(v));
109     }
110 protected:
111     mutable std::array<BaseInterfaceT*, Interface<CIF::TraitsSpecialVersion>::GetNumSupportedVersions()> versions = {};
112     ImplT *impl = nullptr;
113     bool ownsImpl = false;
114 };
115 
116 }
117