Skip to content

Commit

Permalink
Fix several warnings
Browse files Browse the repository at this point in the history
Of note:
- The flexible array `CNamePoolNodeInner::str` is now represented by a placeholder `char[1]` instead of an unsized array and can be accessed via `CNamePoolNodeInner::GetString()`
- Both `CNamePoolNode` and `CNamePoolNodeInner` are now packed to an alignment of 4, matching their behavior in the game
  • Loading branch information
googleben committed Jan 28, 2025
1 parent ac37971 commit f1995d1
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 7 deletions.
9 changes: 7 additions & 2 deletions include/RED4ext/CNamePool-inl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ RED4EXT_INLINE RED4ext::CNamePoolNode* RED4ext::CNamePoolNodeInner::Outer()
return reinterpret_cast<CNamePoolNode*>(reinterpret_cast<uintptr_t>(this) - offsetof(CNamePoolNode, inner));
}

RED4EXT_INLINE const char* RED4ext::CNamePoolNodeInner::GetString() const
{
return &*str;
}

RED4EXT_INLINE RED4ext::CNamePoolNodeInner* RED4ext::CNamePoolNodeInner::NextInList() const
{
return &const_cast<CNamePoolNodeInner*>(this)->Outer()->NextInList()->inner;
Expand Down Expand Up @@ -135,12 +140,12 @@ RED4EXT_INLINE RED4ext::CNamePoolHashmap::Iterator RED4ext::CNamePoolHashmap::Be
return Iterator((*this)[aKey]);
}

RED4EXT_INLINE RED4ext::CNamePoolHashmap::Iterator RED4ext::CNamePoolHashmap::End(const CName& aKey)
RED4EXT_INLINE RED4ext::CNamePoolHashmap::Iterator RED4ext::CNamePoolHashmap::End(const CName&)
{
return Iterator(nullptr);
}

RED4EXT_INLINE RED4ext::CNamePoolHashmap::Iterator RED4ext::CNamePoolHashmap::End(const uint64_t aKey)
RED4EXT_INLINE RED4ext::CNamePoolHashmap::Iterator RED4ext::CNamePoolHashmap::End(const uint64_t)
{
return Iterator(nullptr);
}
Expand Down
23 changes: 18 additions & 5 deletions include/RED4ext/CNamePool.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ namespace RED4ext
{
struct CNamePoolNode;

// CNamePoolNode and CNamePoolNodeInner are packed to a 4-byte alignment
#pragma pack(push, 4)
/**
* @brief The primary type for storing CNames in a CNamePool. This type is an implementation detail of CNamePool.
*
Expand All @@ -17,9 +19,11 @@ struct CNamePoolNode;
*/
struct CNamePoolNodeInner
{
// Only the game should allocate this struct
CNamePoolNodeInner() = delete;

/// @brief The CName corresponding to #str (in other words, the FNV1a64 hash of #str)
/// @brief The CName (key) corresponding to the string (value) of this node (in other words, the FNV1a64 hash of
/// #GetString())
const CName cname; // 00

/// @brief The next node in the hash bucket containing this node
Expand All @@ -31,10 +35,20 @@ struct CNamePoolNodeInner
/// @brief The index of this node in CNamePoolAllocator
const uint32_t cnameListIndex : 24; // 11

private:
/// @brief The corresponding string for #cname
const char str[]; // 14
/// This is a flexible array in the game, but because flexible arrays are a nonstandard extension, we use this
/// placeholder field plus #GetString() instead
const char str[1]; // 14
// if necessary, there is padding after this to align with a DWORD boundary

public:
/**
* @brief Gets the string (value) contained in this node, corresponding to the CName (key) contained in this node
* @return The string (value) contained in this node
*/
const char* GetString() const;

/**
* @brief Gets the next CNamePoolNodeInner that was allocated, chronologically speaking
*
Expand All @@ -59,7 +73,6 @@ RED4EXT_ASSERT_OFFSET(CNamePoolNodeInner, cname, 0x00);
RED4EXT_ASSERT_OFFSET(CNamePoolNodeInner, next, 0x08);
// we can't assert the offset of `len` and `cnameListIndex` because they're bitfields
// maybe switch to doing the bit manipulation ourselves?
RED4EXT_ASSERT_OFFSET(CNamePoolNodeInner, str, 0x14);

/**
* @brief The type of nodes allocated in a CNamePoolAllocator. This type is an implementation detail of
Expand All @@ -70,14 +83,13 @@ RED4EXT_ASSERT_OFFSET(CNamePoolNodeInner, str, 0x14);
*/
struct CNamePoolNode
{
// Only the game should allocate this struct
CNamePoolNode() = delete;

#pragma pack(push, 4)
/// @brief The size of #inner in bytes
const uint32_t len; // 00
/// @brief The actual allocated space
CNamePoolNodeInner inner; // 04
#pragma pack(pop)

/**
* @brief Gets the next CNamePoolNode that was allocated, chronologically speaking
Expand All @@ -94,6 +106,7 @@ struct CNamePoolNode
*/
CNamePoolNode* NextInHashBin();
};
#pragma pack(pop)
RED4EXT_ASSERT_OFFSET(CNamePoolNode, len, 0x00);
RED4EXT_ASSERT_OFFSET(CNamePoolNode, inner, 0x04);

Expand Down

0 comments on commit f1995d1

Please sign in to comment.