EDIT: I think the version is known at run-time instead of compile-time so I'm not able to add it as a compile option to the gcc cmd. Which is why I have to support both versions based on whatever version the hardware reports back.
So I'm dealing with firmware where I am required to support multiple definitions for versions of the same C struct. We created our own header file as defined by the interface documentation of a memory controller based on the vendor's C struct definition.
// For simplicity lets pretend that this is the struct for version 1
typedef struct __attribute__((packed)) ver1 {
int x;
int y;
} ver1;
I also have an existing API that uses this interface already that needs to be replaced by some sort of class wrapper (I believe), e.g. or a wrapper that plays well with the existing API.
void function_call(ver1 v1);
Only once instance (ver 1 or ver 2) of the struct can exist at any time ver 1 for a certain fw version, and ver 2 after a certain fw version
ver2 is my extended version of ver1, I am naming it as ver2 for the hope of using some sort of factory to select the right C-style struct.
typedef struct __attribute__((packed)) ver2 {
int x;
int y;
int w; // new
int z; // new
} ver2;
Before creating a ver 2 I was looking into options such as the decorator or adaptor design pattern I could try a fancy CRTP template style I found on Hands-On Design Patterns but for simplicity, I'll illustrate with this scheme where I could possibly "add-on" to ver1:
struct ver2 : public ver1 {
int w;
int z;
}
But then I learned that C++ doesn't guarantee the same class layout C struct Inheritance vs C++ POD struct Inheritance and potential alignment issues (I'm not too familiar with it) so I don't think it is a real option for me to use.
I found this example on stackoverflow but I don't like the idea of adding include headers in the struct How to handle conflicting struct definitions in a C application. There is a similar example here using a similar base class C++ design for multiple versions of same interface (enumerations / structures in header files) which I don't think I can even use due to inheritance impact on the class layout.
Unless there is a valid reason to use the techniques of the links above, I was considering a wrapper class that returns the right version based on a selector. First I'll define a free function to leverage this.
int get_fw_version(int target);
I'm working on C++11 so I'm limited on auto return type deduction and below is just some draft code I'm trying to think up, not complete, doesn't compile, just illustrating my thought process. I haven't considered composition yet since IDK how that will quite work. Looking for ideas.
int main() {
// Roughly how I would like to use it...
const int fw_ver = get_fw_version(target);
ver_wrapper ver_inst(fw_ver);
// I would like to do reuse the existing API if possible
function_call(ver_inst.data());
// But I'm flexible enough to change the API if needed
function_call(ver_inst);
return 0;
}
typename <int R> // R for rev
struct ver_traits;
template <>
struct ver_traits<1> {
using type = ver1;
};
template <>
struct ver_traits<2> {
using type = ver2;
};
Am I limited to using a base class to create a factory pattern? Init ver1 and 2 differently. Not really a factory but a selector? - shrug
template<int I, typename TT = ver_traits<I>>
TT::type ver_factory(int fw_ver) {
return ...;
}
class ver_wrapper {
private:
int __fw_version;
T __data; // -> ?? need a good way to handle this, should be a template?
public:
ver_wrapper(int fw_ver):__fw_ver(fw_ver){
// could be switch statement
if(target == 1) {
// set up data with ver1 struct (probably w/memcpy)
data = ver_factory<1>(fw_ver)
}
else {
// init data with ver2 struct (probably w/memcpy)
data = ver_factory<2>(fw_ver)
}
}
// needs some sort of type deduction here
T data() {return __data;}
};
Aucun commentaire:
Enregistrer un commentaire