1b1994897Sopenharmony_ci/**
2b1994897Sopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3b1994897Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4b1994897Sopenharmony_ci * you may not use this file except in compliance with the License.
5b1994897Sopenharmony_ci * You may obtain a copy of the License at
6b1994897Sopenharmony_ci *
7b1994897Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8b1994897Sopenharmony_ci *
9b1994897Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10b1994897Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11b1994897Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12b1994897Sopenharmony_ci * See the License for the specific language governing permissions and
13b1994897Sopenharmony_ci * limitations under the License.
14b1994897Sopenharmony_ci */
15b1994897Sopenharmony_ci
16b1994897Sopenharmony_ci#ifndef LIBPANDABASE_UTILS_BIT_FIELD_H
17b1994897Sopenharmony_ci#define LIBPANDABASE_UTILS_BIT_FIELD_H
18b1994897Sopenharmony_ci
19b1994897Sopenharmony_ci#include <limits>
20b1994897Sopenharmony_ci#include "macros.h"
21b1994897Sopenharmony_ci
22b1994897Sopenharmony_cinamespace panda {
23b1994897Sopenharmony_ci
24b1994897Sopenharmony_ci/*
25b1994897Sopenharmony_ci * Auxiliary static class that provides access to bits range within an integer value.
26b1994897Sopenharmony_ci */
27b1994897Sopenharmony_citemplate <typename T, size_t start, size_t bits_num = 1>
28b1994897Sopenharmony_ciclass BitField {
29b1994897Sopenharmony_ci    static constexpr unsigned BITS_PER_BYTE = 8;
30b1994897Sopenharmony_ci
31b1994897Sopenharmony_ci    static_assert(start < sizeof(uint64_t) * BITS_PER_BYTE, "Invalid position");
32b1994897Sopenharmony_ci    static_assert(bits_num != 0U, "Invalid size");
33b1994897Sopenharmony_ci    static_assert(bits_num <= sizeof(uint64_t) * BITS_PER_BYTE, "Invalid size");
34b1994897Sopenharmony_ci    static_assert(bits_num + start <= sizeof(uint64_t) * BITS_PER_BYTE, "Invalid position + size");
35b1994897Sopenharmony_ci
36b1994897Sopenharmony_cipublic:
37b1994897Sopenharmony_ci    using ValueType = T;
38b1994897Sopenharmony_ci    static constexpr unsigned START_BIT = start;
39b1994897Sopenharmony_ci    static constexpr unsigned END_BIT = start + bits_num;
40b1994897Sopenharmony_ci    static constexpr unsigned SIZE = bits_num;
41b1994897Sopenharmony_ci
42b1994897Sopenharmony_ci    /*
43b1994897Sopenharmony_ci     * This is static class and should not be instantiated.
44b1994897Sopenharmony_ci     */
45b1994897Sopenharmony_ci    BitField() = delete;
46b1994897Sopenharmony_ci
47b1994897Sopenharmony_ci    virtual ~BitField() = delete;
48b1994897Sopenharmony_ci
49b1994897Sopenharmony_ci    NO_COPY_SEMANTIC(BitField);
50b1994897Sopenharmony_ci    NO_MOVE_SEMANTIC(BitField);
51b1994897Sopenharmony_ci
52b1994897Sopenharmony_ci    /*
53b1994897Sopenharmony_ci     * Make BitField type that follows right after current bit range.
54b1994897Sopenharmony_ci     *
55b1994897Sopenharmony_ci     *  If we have
56b1994897Sopenharmony_ci     *   BitField<T, 0, 9>
57b1994897Sopenharmony_ci     * then
58b1994897Sopenharmony_ci     *   BitField<T, 0, 9>::NextField<T,3>
59b1994897Sopenharmony_ci     * will be equal to
60b1994897Sopenharmony_ci     *   BitField<T, 9, 3>
61b1994897Sopenharmony_ci     *
62b1994897Sopenharmony_ci     * It is helpful when we need to specify chain of fields.
63b1994897Sopenharmony_ci     */
64b1994897Sopenharmony_ci    template <typename T2, unsigned bits_num2>
65b1994897Sopenharmony_ci    using NextField = BitField<T2, start + bits_num, bits_num2>;
66b1994897Sopenharmony_ci
67b1994897Sopenharmony_ci    /*
68b1994897Sopenharmony_ci     * Make Flag field that follows right after current bit range.
69b1994897Sopenharmony_ci     * Same as NextField, but no need to specify number of bits, it is always 1.
70b1994897Sopenharmony_ci     */
71b1994897Sopenharmony_ci    using NextFlag = BitField<bool, start + bits_num, 1>;
72b1994897Sopenharmony_ci
73b1994897Sopenharmony_cipublic:
74b1994897Sopenharmony_ci    /*
75b1994897Sopenharmony_ci     * Return maximum value that fits bit range [START_BIT : START_BIT+END_BIT]
76b1994897Sopenharmony_ci     */
77b1994897Sopenharmony_ci    static constexpr uint64_t MaxValue()
78b1994897Sopenharmony_ci    {
79b1994897Sopenharmony_ci        return (1LLU << bits_num) - 1;
80b1994897Sopenharmony_ci    }
81b1994897Sopenharmony_ci
82b1994897Sopenharmony_ci    /*
83b1994897Sopenharmony_ci     * Return mask of bit range, f.e. 0b1110 for BitField<T, 1, 3>
84b1994897Sopenharmony_ci     */
85b1994897Sopenharmony_ci    static constexpr uint64_t Mask()
86b1994897Sopenharmony_ci    {
87b1994897Sopenharmony_ci        return MaxValue() << start;
88b1994897Sopenharmony_ci    }
89b1994897Sopenharmony_ci
90b1994897Sopenharmony_ci    /*
91b1994897Sopenharmony_ci     * Check if given value fits into the bit field
92b1994897Sopenharmony_ci     */
93b1994897Sopenharmony_ci    static constexpr bool IsValid(T value)
94b1994897Sopenharmony_ci    {
95b1994897Sopenharmony_ci        return (static_cast<uint64_t>(value) & ~MaxValue()) == 0;
96b1994897Sopenharmony_ci    }
97b1994897Sopenharmony_ci
98b1994897Sopenharmony_ci    /*
99b1994897Sopenharmony_ci     * Set 'value' to current bit range [START_BIT : START_BIT+END_BIT] within the 'stor' parameter.
100b1994897Sopenharmony_ci     */
101b1994897Sopenharmony_ci    template <typename Stor>
102b1994897Sopenharmony_ci    static constexpr void Set(T value, Stor *stor)
103b1994897Sopenharmony_ci    {
104b1994897Sopenharmony_ci        static_assert(END_BIT <= std::numeric_limits<Stor>::digits);
105b1994897Sopenharmony_ci        *stor = (*stor & ~Mask()) | Encode(value);
106b1994897Sopenharmony_ci    }
107b1994897Sopenharmony_ci
108b1994897Sopenharmony_ci    /*
109b1994897Sopenharmony_ci     * Return bit range [START_BIT : START_BIT+END_BIT] value from given integer 'value'
110b1994897Sopenharmony_ci     */
111b1994897Sopenharmony_ci    static constexpr T Get(uint64_t value)
112b1994897Sopenharmony_ci    {
113b1994897Sopenharmony_ci        return static_cast<T>((value >> start) & MaxValue());
114b1994897Sopenharmony_ci    }
115b1994897Sopenharmony_ci
116b1994897Sopenharmony_ci    /*
117b1994897Sopenharmony_ci     * Encode 'value' to current bit range [START_BIT : START_BIT+END_BIT] and return it
118b1994897Sopenharmony_ci     */
119b1994897Sopenharmony_ci    static constexpr uint64_t Encode(T value)
120b1994897Sopenharmony_ci    {
121b1994897Sopenharmony_ci        ASSERT(IsValid(value));
122b1994897Sopenharmony_ci        return (static_cast<uint64_t>(value) << start);
123b1994897Sopenharmony_ci    }
124b1994897Sopenharmony_ci
125b1994897Sopenharmony_ci    /*
126b1994897Sopenharmony_ci     * Update 'value' to current bit range [START_BIT : START_BIT+END_BIT] and return it
127b1994897Sopenharmony_ci     */
128b1994897Sopenharmony_ci    static constexpr uint64_t Update(uint64_t old_value, T value)
129b1994897Sopenharmony_ci    {
130b1994897Sopenharmony_ci        return (old_value & ~Mask()) | Encode(value);
131b1994897Sopenharmony_ci    }
132b1994897Sopenharmony_ci
133b1994897Sopenharmony_ci    /*
134b1994897Sopenharmony_ci     * Decode from value
135b1994897Sopenharmony_ci     */
136b1994897Sopenharmony_ci    static constexpr T Decode(uint64_t value)
137b1994897Sopenharmony_ci    {
138b1994897Sopenharmony_ci        return Get(value);
139b1994897Sopenharmony_ci    }
140b1994897Sopenharmony_ci};
141b1994897Sopenharmony_ci
142b1994897Sopenharmony_ci}  // namespace panda
143b1994897Sopenharmony_ci
144b1994897Sopenharmony_ci#endif  // LIBPANDABASE_UTILS_BIT_FIELD_H
145