Rajeshwar
Rajeshwar

Reputation: 11681

Suggestion for a pattern involving bits using bit manipulation

I currently have a structure like this

struct foo
{
  UINT64 optionA = 0;
  UINT64 optionB = 0;
  UINT64 optionC = 0;
}

I am attempting to write a function for comparing two objects of foo based on optionA , optionB and optionC. Essentially what I would like the function to do is check if optionA is the same in both if no then return the lowest object back. If the optionA in both objects are the same then it will check optionB in both objects and would return the lowest one. If optionB are the same in both then it will look at optionC and return the lowest.

I am thinking that this could be accomplished by assigning a UINT64 no to each object. Then assigning bits based on priority to that no and then comparing each and returning back the lesser one. I am not sure how to go about that approach any suggestions to do this would be appreciated.

Upvotes: 0

Views: 84

Answers (3)

Jerry Jeremiah
Jerry Jeremiah

Reputation: 9643

It would be simpler and more readable to just have a comparison function that directly compares the data members in the right order, but if having bit masks that store which data members are bigger is helpful for some other reason then here is how I would do it:

foo compare(foo x, foo y)
{
    // needs to hold status for 3 data members (one bit each)
    int x_status = 0, y_status = 0;

    // each bit is 1 if this member is bigger, 0 if smaller
    x_status |= (x.optionC > y.optionC)<<0;
    x_status |= (x.optionB > y.optionB)<<1;
    x_status |= (x.optionA > y.optionA)<<2;

    // each bit is 1 if this member is bigger, 0 if smaller
    y_status |= (x.optionC < y.optionC)<<0;
    y_status |= (x.optionB < y.optionB)<<1;
    y_status |= (x.optionA < y.optionA)<<2;

    // so now we can compare the values
    // if all the data members were bigger the value will be 7 (0b111)
    // if all the data members were smaller the value will be 0 (0b000)
    if (x_status < y_status) return x; else return y;
}

Try it online here: https://onlinegdb.com/XpdOSFLFa

Upvotes: 1

Jarod42
Jarod42

Reputation: 218288

With C++20, default operator <=> and operator == would do the job.

struct foo
{
  UINT64 optionA = 0;
  UINT64 optionB = 0;
  UINT64 optionC = 0;

  auto operator <=>(const foo&) const = default;
  bool operator ==(const foo&) const = default;
};

else, std::tuple might help:

bool operator ==(const foo& lhs, const foo& rhs)
{
   return std::tie(lhs.optionA, lhs.optionB, lhs.optionC)
       == std::tie(rhs.optionA, rhs.optionB, rhs.optionC);
}

bool operator <(const foo& lhs, const foo& rhs)
{
   return std::tie(lhs.optionA, lhs.optionB, lhs.optionC)
        < std::tie(rhs.optionA, rhs.optionB, rhs.optionC);
}

Upvotes: 2

Ted Lyngmo
Ted Lyngmo

Reputation: 118047

The code is currently missing an operator that checks for equallity.

Example:

constexpr bool operator==(const foo& a, const foo& b) {
    return
        a.optionA == b.optionA &&
        a.optionB == b.optionB &&
        a.optionC == b.optionC;
}

With that, the below would compile (meaningfully):

using UINT64 = /* unsigned long long */; // usually

struct foo {
    UINT64 optionA = 0;
    UINT64 optionB = 0;
    UINT64 optionC = 0;
};

constexpr bool operator==(const foo& a, const foo& b) {
    return
        a.optionA == b.optionA &&
        a.optionB == b.optionB &&
        a.optionC == b.optionC;
}

int main() {
    constexpr foo a, b;
    static_assert(a == b);
}

Upvotes: 1

Related Questions