-5

I have an file handler, that reads and writes custom binary files. To save myself work I've inherited multiple data from one base struct (base_p):

struct base_p{
  protected:
      uint32_t v0= 0;
      uint32_t v1= 0;
      uint32_t v2= 0;
  friend struct f_block;
  // other friends
};

Now during building of my internal blocks of that file, I've inherited that struct into multiple non POD type:

struct f_block:public base_p{
   f_block(){
      this->v0 = 0x3f580058; // an magic number of the block
      this->v1 = 0x1000004D; // version and use type
      this->v2 = 0;
   }
   f_block(uint32_t data){
      this->v0 = 0x3f580058; // an magic number of the block
      this->v1 = 0x1000004D; // version and usage type
      this->v2 = data;
   }

  operator uint8_t(){ return this->v1 & 0xff; }
  operator bool(){return this->v2 != 0 ;}
  friend std::ostream& operator<<( std::ostream& os, f_block& fb );
};
std::ostream& operator<<( std::ostream& os, f_block& fb ){
    union {
        uint32_t vrt;
        unsigned char parts[4];
    }temp;
    temp. vrt = fb. v2;
    return os << temp. parts[3] << temp. parts[2] << temp. parts[1] << temp. parts[0];
}

Inside my file handler, I have use for both structures. For example if I need to pass data somewhere, I need to extract data as base_p. But my block definition has an extra feature that usage serves and compression key and within data (v2) I have also stored some information such as bit offset from the end, length of featured blocks . . . and many others. So extracting function would look something along of lines:

struct file_handler{
   std::vector<base_p> data;
   file_handler():data(0){}
   virtual bool read(const char *filename) = 0; // to be overridden
   virtual bool write(const char *filename)= 0; // to be overridden  

   virtual bool set( base_p &data){
      // if data is base_p , push_back data as normal POD  
      // if data is f_block, push_back data as deflated version  
      // don't store anything in vector if none
   }
   virtual bool get( base_p &data){
      // if data is base_p, returns lasts 3 elements v2(data) fields
      // if data is f_block, returns last element as f_block - inflated, 
      // set data as 0 if none
   }
}

I've tried to catch an error of calling a function that doesn't exist in base_p, but it doesn't suit me since I am building multiple file handlers upon file_handler struct that should accept other data types. I am secure enough to start building other file types once I can successfully implement file_handler. What I need is something along of data type switch statement.

Since I come from python background, in it I could do something along of lines isinstance or something similar. But this is C++ so there isn't such implementation - that I am aware of.


I have searched and I've found some elements that seem to have potential to solve my problem, but most of them are for outdated versions or too abstract to wrap my head around to generate an logic solution.

  • SFINAE and void : mentions some sort of concept that SFINAEs follow, and compound concepts which is too abstract in question for me to successfully make valid implementation.
  • HasMember SFINAE : which seems feasible for constructor recognition, but best answer is written in c++03 with no mention if it translates to c++11 aka version I am currently using.

Is there a way to distinguish between PODs and non-PODs ?

Danilo
  • 1,017
  • 13
  • 32
  • 1
    Comments are not for extended discussion; this conversation has been [moved to chat](https://chat.stackoverflow.com/rooms/198805/discussion-on-question-by-danilo-programmatically-differentiate-between-pods-and). – Samuel Liew Sep 02 '19 at 00:09

2 Answers2

3

I come from python background

C++ is not Python.

If all you have is a void* and no idea where it came from or what object it points to, then there is nothing you can do. C++ is a statically-typed language. This means that objects do not automatically store within themselves anything which identifies them as being of a particular type. All of that typing information is done at compile-time based on the types the compiler sees in the code.

The type present here is void, which is the "not a type" type. So any typing information has been lost. And it cannot be recovered by looking at some bytes behind a void*.

As far as the contents of the first byte behind that void* is concerned, there is no difference between a pointer to subs and a pointer to a my_data.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
1

It sounds like you want to be able to take an arbitrary block of bytes, and determine whether those bytes constitute the underlying representation of an instance of the type my_data.

You can't. No such thing is meaningful. Those bytes do not have a type.

You will have to manually deserialise the bytes, using rules that you devise, picking out whether the values that lie therein (when so interpreted) match the preconditions for values in your my_data objects.

Usually we'd manage the data ourselves with some "header", indicating "this is an instance of a my_type" so that you at least know with some probability that it is so (don't forget this header may still be found in arbitrary data by pure chance). But you need to build that logic into the serialisation stage (on the way out) as well.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • Something along of that. I will try to explain my need for it in simplest terms. I have my data that i have handles that manage serialisation and deserialisation. But those data can be appended to PE or some other file. Appended bytes follow similar structure as any of my data custom blocks ( with that usage flags) I need a way for my program to say : "Yo this data that your offset is point out to is your data! and it holds 12 bytes of data and 3 bytes of magic with 4 bytes of checksuming - keep going". And then use deserialisation to subscript part of it and change part of it. – Danilo Sep 01 '19 at 18:01
  • But if i read an different part of PE or some other file, and my handle tries to deserialize it ( do some error or mistake) i need for my handle to say "this isn't your data, this are PODs or something similar... you get nothing". Handle should check how it should deserialize data by "usage" static member that governs it. So if i have an appended file that says it starts 50 bytes from the back, but it really starts in 51, and some corruption happen'd and magics are true. What i would be deserialized wouldn't be my data. – Danilo Sep 01 '19 at 18:02
  • 2
    Whatever "your handles that serialisation and deserialisation" do, it is up to them to do whatever is needed so that your code can identify that this "is your data". There is nothing in C++ that will do this for you. C++ does not work this way. All you have is a binary blob of data. You will have to decide how this binary blob should look so that it represents your "data", and then deserialize. Of course, if you guess wrong, your deserialization code will fail, and you will have to handle deserialization error in whatever manner you see fit. The other answer summarizes everything. – Sam Varshavchik Sep 01 '19 at 18:07
  • @Danilo You keep trying to make a distinction between "your data" and "PODs" and I can't work out what that distinction is. – Lightness Races in Orbit Sep 01 '19 at 18:14
  • So, the way i understood it , PODs are classes/structs/pointers... without constructor, virtual functions and etc... since wiki and other resources define POD by noun POD i am left to concise it as that is a structure of any kind where fields are used independently, they don't make an unique whole in terms of variable or functionality. Like when we need to return multiple values from an function and we make an struct for those types without constructor. That is how i understood it. If i am wrong please correct me. – Danilo Sep 02 '19 at 11:57
  • @SamVarshavchik My file handle manages what are essentially PODs, those 4 byte structures. My data types concise in binary form of 1 to multiple those PODs, and i need to be able to distinguish (in file form for this use) if that is some random POD that is leftover from another file type or is ti my object. I have managed to do this with serialised structures that hold their own magic number. But also handle needs to be able to distinguish between my data variables and 4 byte PODs so if 4 byte structure is passed to the handle it won't serialise it, and it will do something else. – Danilo Sep 02 '19 at 12:04
  • What i need is to figure out if structure of any kind has an specific underlying binary signature that i can then encode into my types. in order when i read that 4 byte memory as an whole integer i can do simple bitwise masking and say this is mine - serialise ( and or deserialise ) this isn't min - do something else (don't deserialize ) @LightnessRacesinOrbit – Danilo Sep 02 '19 at 12:06
  • 1
    You have described what you wanted to do over and over again. What you don't seem to understand is that there's nothing in the C++ language itself that will do all of this for you, and you have to implement all this work yourself. The most basic approach is to write some specific value to the file, before the contents of whatever POD, or whatever are written. When you read it back you read the value and know which particular POD, or whatever, follows, then you deserialize it. That's it. That's how Python, basically, does this, internally. C++ is not Python, and you have to do this yourself. – Sam Varshavchik Sep 02 '19 at 14:39