Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 37140 - new getters and setters #37645

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

gabc-cpp
Copy link

Issue 37140 - Make metadata that combines flags and access privileges more compact

Changes to the following files:

src/app/WriteHandler.cpp
src/app/data-model-provider/MetadataTypes.h
src/app/reporting/Engine.cpp
src/data-model-providers/codegen/CodegenDataModelProvider.cpp

src/app/data-model-provider/MetadataTypes.h

Added bitmasks to handle the different values of Access::Privilege.
Added getters and setters for readPrivilige and writePrivilige.

src/app/WriteHandler.cpp
src/app/reporting/Engine.cpp
src/data-model-providers/codegen/CodegenDataModelProvider.cpp

Added several call for the new setters and getters.

Additional setters and getters are needed for the framework backend used for several unit tests. Work in progress.

Copy link

Review changes with  SemanticDiff

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


gabc-cpp seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@github-actions github-actions bot added the app label Feb 19, 2025
/**
* Checks if readPrivilege has a value.
*/
bool readPrivilegeHasValue() const { return (mask & ATTRIBUTE_MASK_READ_PRVLG_ANY_VALUE); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

drop these: one can use GetReadPrivilege().has_value() or similar.

//
// Read Privilege stored on the first trio of significant binary digits
//
// Attribute mask for any Read Privilege value set
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we doing this?
Privilege is already an almost bitflag object

// ProxyView, and Operate).
enum class Privilege : uint8_t
{
    kView       = 1 << 0,
    kProxyView  = 1 << 1,
    kOperate    = 1 << 2,
    kManage     = 1 << 3,
    kAdminister = 1 << 4
};

Set is simple |= privilege << WriteorReadOffset
unset is also simple &= ~(privilege << WriteorReadOffset)
Clear is &= ~0b11111 << WriteorReadOffset
all these elements will end up in the binary bloating
and an unnecesary jumptable

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI there is a template BitMask<> that gives you set and unset an check for these types of enum values

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Access privilege is a bitmask to support a set, however specifically for attributes and commands it is not a set. So the difference would be using 5-6 bits vs 3. however the point seems valid: if we have a bitset that already works even if we use more bits, maybe we could use 6 bits for read, 6 for write and that leaves us with 20 bits worth of extra flags (and we need about 5 only right now)

*/
Access::Privilege GetWritePrivilege() const
{
std::optional<Access::Privilege> writePrivilege;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why create an optional when you are returning Access::Privilege?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return should be an optional I believe - attributes may be read-only and we flag that via nullopt (no write privileges). Same for read.

For invoke however, commands always have some privileges so we return Access::Privilege instead of optional.

/**
* @brief Type for the attribute mask
*/
typedef uint32_t AttributeMask;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understood the ticket right, we want to compress everything into a smaller structure, 3 bit for W/R Access each and the rest to some other for the other flags in the structures
an example being AttributeQualityFlags in Attribute entry
CommandQualityFlags in AcceptedCommandEntry etc...

Right now it is 8 bits for ReadPrivileges and 8 for WritePrivileges, 16 with this change you go to 32, not compacting at all

/**
* Getter for readPrivilege.
*/
Access::Privilege GetReadPrivilege() const
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You want to return the full bit flag not am incomplete one, like if I have View | ProxyView | Manage I will get only View privilege with this function

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You never have more than one bit set here in practice.

/**
* Checks if writePrivilege has a value.
*/
bool writePrivilegeHasValue() const { return (mask & ATTRIBUTE_MASK_WRITE_PRVLG_ANY_VALUE); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Write is not a read

Copy link
Contributor

@bzbarsky-apple bzbarsky-apple left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like a lot more code complexity than we actually need here.

// Read Privilege stored on the first trio of significant binary digits
//
// Attribute mask for any Read Privilege value set
constexpr uint8_t ATTRIBUTE_MASK_READ_PRVLG_ANY_VALUE = 0x07; // == 0b00000111
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't duplicate Privilege values....

/**
* Checks if readPrivilege has a value.
*/
bool readPrivilegeHasValue() const { return (mask & ATTRIBUTE_MASK_READ_PRVLG_ANY_VALUE); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of doing manual bitops, have we considered just using a C++ bitfield here? So having:

   uint16_t readPrivilege : 5;
   uint16_t writePrivilege : 5;

and then just assign/read those members as normal?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It sounds like an excellent solution, might want the set/get though to abstract whatever bitfield mechanism is being used

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the API should not be those raw bitfields.

/**
* Getter for readPrivilege.
*/
Access::Privilege GetReadPrivilege() const
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You never have more than one bit set here in practice.

if ( (mask & ATTRIBUTE_MASK_READ_PRVLG_KADMINISTER_VALUE) == ATTRIBUTE_MASK_READ_PRVLG_KADMINISTER_VALUE )
return (Access::Privilege::kAdminister);

return(Access::Privilege::kView); // generally defaults to View if readable
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In theory we can have write-only attributes. None in the spec today, however unittestingcluster has one such thing. This is why we return optional here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants