3

While it admittedly doesn't add much to my question, let me start by saying that my background is MUCH heavier in languages like Java and C# than C/C++ and much of my confusion undoubtedly comes from those gaps.

I have a C++ application which can load objects from up to 255 different data sources at any given time. Each of these shared data sources are assigned a GUID. Each object within one of these data sources is keyed with a 24bit index. I refer to these data objects as Resources.

Because each data source indexes it's resources sequentially, a reference to any resource includes the 24bit index and an additional byte to determine the data source within a given context. Thus eliminating ambiguity in the runtime environment.

If a data object contains a reference to a resource within the same data source, this byte will be loaded with a 0 value. If it references an object in another data source, the byte serves as an index into the data source's "dependency table" of up to 128 GUIDs for other data sources.

I'm inclined to define the C structure of these resource keys as:

typedef struct ResourceID {
    char DataSourceIndex;
    char[3] ResourceIndex;
} ResourceID;

The problem is that before the factory classes in my application can build a complete resource object, it must resolve the DataSourceIndex of each ResourceID to relate to application's own runtime context table (with up to 255 GUIDs). Not only for the ID of the resource it's building, but also for all references the resource may contain.

While the structure above is extremely easy to resolve in that manner, I don't know if it's as friendly or as efficient as a typical UINT32 would be for comparisons within a performance critical application. Though I am a bit worried of how endianness could become a sneaky problem in such a case.

Would this structure be implemented better with a single UINT32 member and methods which use bit operators to read/write the data source index byte?

Would a definition involving unions be a better strategy?

Is there an obvious common alternative which I'm missing?

RobStone
  • 187
  • 7

1 Answers1

3

You can define the structure using bitfields:

typedef struct ResourceID {
    unsigned int DataSourceIndex : 8;
    unsigned int ResourceIndex : 24;
} ResourceID;

If you want to be able to access the ID as a single 32-bit value, you can use a union like this:

typedef union ResourceID {
    struct
    {
        unsigned int DataSourceIndex : 8;
        unsigned int ResourceIndex : 24;
    };
    uint32_t ID;
} ResourceID;

Regarding thread-safety and bitfields, see this StackOverflow question. If it's a concern then don't use them.

Community
  • 1
  • 1
samgak
  • 23,944
  • 4
  • 60
  • 82
  • What would that add in terms of performance? (Plus you've just made the two "variables" part of the same memory location which has thread-safety implications.) – Mat Mar 03 '15 at 06:48
  • @Mat I wouldn't expect performance to be any worse than storing it in a UINT32 and doing the bit-shifting / masking operations yourself, but it is more readable. – samgak Mar 03 '15 at 06:57
  • What would be the fastest way to write the standard comparison operators for this structure without risking of undefined behavior on various platforms? – RobStone Mar 03 '15 at 07:34
  • 1
    You could create a union of this structure and a UINT32, and then compare the UINT32 values if you want to compare the whole structure at once. P.S. I don't want to make any conclusive statements about what is fastest or best, I just meant to answer your question of "Is there an obvious common alternative" to the other methods you presented – samgak Mar 03 '15 at 08:10
  • This is the answer I was looking for. Thank you. As soon as I have the appropriate rep, I'll mark it up. – RobStone Mar 03 '15 at 15:37
  • If you might agree that it's appropriate however, in case someone comes across this in the future, that you could update "unsigned int DataSourceIndex : 8;" to be of an unsigned char type. If only to allow for compiler warnings when an assigned value would be out of range. It would of course be dependent on an 8bit byte, but that's almost always a safe assumption and one which would be noticed by anyone who's working in such a problematic environment. – RobStone Mar 04 '15 at 06:50
  • 1
    @RobStone: unsigned int is more portable: http://stackoverflow.com/questions/17670436/in-case-of-bit-fields-which-one-is-better-to-use-unsigned-char-or-unsigned-int – samgak Mar 04 '15 at 07:40