I would just use the straightforward operator overloading on a plainsyzygy wrote: What do you think of this:Code: Select all
/// Score enum stores a middlegame and an endgame value in a single integer /// (enum). The most significant 16 bits are used to store the endgame value /// and the lower 16 bits are used to store the middlegame value. Take some /// care to avoid undefined behavior (such as left-shifting a negative int) /// and relying on implementation-defined behavior (such as casting to signed /// ints). enum Score : uint32_t { SCORE_ZERO }; inline Score make_score(int mg, int eg) { return Score(((unsigned int)eg << 16) + mg); } /// Make sure the platform is reasonable. static_assert(uint16_t(INT16_MIN) == INT16_MAX + 1, "Range of int16_t is unsupported."); /// Helper function for correctly casting uint16_t to int16_t. /// The compiler will optimize this to a no-operation. inline int16_t cast_to_int16_t(uint16_t v) { return v <= INT16_MAX ? int16_t(v) : int16_t(v - INT16_MIN) + INT16_MIN; } inline Value eg_value(Score s) { return Value(cast_to_int16_t((s + 0x8000U) >> 16)); } inline Value mg_value(Score s) { return Value(cast_to_int16_t(s)); }
Code: Select all
struct Score { int mg, eg };