188 lines
5.5 KiB
C
188 lines
5.5 KiB
C
#include "utils_generator.h"
|
|
|
|
/**
|
|
* @brief Reverse bits of 32-bit value
|
|
*
|
|
* @param[in] x Value to be reversed
|
|
*
|
|
* @return Reversed value
|
|
*/
|
|
static inline uint32_t bitreverse32(register uint32_t x)
|
|
{
|
|
x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
|
|
x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
|
|
x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
|
|
x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));
|
|
return((x >> 16) | (x << 16));
|
|
}
|
|
|
|
/**
|
|
* @brief Initialize bisect generator state
|
|
*
|
|
* @param[in] generator Pointer to generator structure
|
|
* @param[in] limit Limit of the value returned by generator (maximum value
|
|
* returned by the generator is limit - 1)
|
|
* @param[in] offset Offset at which generator should start
|
|
*
|
|
* @return Reversed value
|
|
*/
|
|
void ocf_generator_bisect_init(
|
|
struct ocf_generator_bisect_state *generator,
|
|
uint32_t limit, uint32_t offset)
|
|
{
|
|
unsigned clz;
|
|
uint32_t maplen;
|
|
|
|
clz = __builtin_clz(limit - 1);
|
|
maplen = 1 << (32 - clz);
|
|
|
|
generator->curr = (uint64_t)offset * maplen / limit;
|
|
generator->limit = limit;
|
|
}
|
|
|
|
/**
|
|
* @brief Generate next value of bisect generator
|
|
*
|
|
* This function calculates next value of the generator. The generator
|
|
* pattern is based on order of indexes in array visited with bisection
|
|
* algorithm, where always the left child is visited first at every depth.
|
|
* This can be imagined as a special implementation of BFS done on a full
|
|
* binary tree, where visiting nodes on each depth level is done the same
|
|
* order as original array (so the algorithm is recursive at each level).
|
|
*
|
|
* Example:
|
|
*
|
|
* 1. We generate array of all values for number of bits needed to express
|
|
* limit value - 1.
|
|
*
|
|
* For limit==14 (4 bits) it would be:
|
|
* [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
|
|
*
|
|
* 2. We take first element of the array, and then build full binary tree
|
|
* from other elements (it should always be possible to build a full
|
|
* binary tree, as number of remaining elements is always 2^n-1).
|
|
*
|
|
* The full binary tree for example array looks like this:
|
|
*
|
|
* Depth 0 -> 8
|
|
* / \
|
|
* / \
|
|
* / \
|
|
* / \
|
|
* / \
|
|
* / \
|
|
* / \
|
|
* / \
|
|
* Depth 1 -> 4 12
|
|
* / \ / \
|
|
* / \ / \
|
|
* / \ / \
|
|
* Depth 2 -> 2 6 10 14
|
|
* / \ / \ / \ / \
|
|
* Depth 3 -> 1 3 5 7 9 11 13 15
|
|
*
|
|
* 3. We traverse the tree:
|
|
* a) If depth level has one element, we take it.
|
|
* b) If depth level has two elements, we take left and then right.
|
|
* c) If depth level has more than two elements, we repeat steps
|
|
* from 2 on array built from elements on that level left to right.
|
|
*
|
|
* At level 0 we take 8, at level 1 we take 4 and 12, and at level 3 we
|
|
* take 2 and build tree like this one:
|
|
*
|
|
* 10
|
|
* / \
|
|
* 6 14
|
|
*
|
|
* Then at level 0 of that tree we take 10, at level 1 we take 6 and 14,
|
|
* and then we go back the original tree.
|
|
*
|
|
* At level 3 we take 1 and we build another tree from remaining elements
|
|
* of that level:
|
|
*
|
|
* 9
|
|
* / \
|
|
* / \
|
|
* / \
|
|
* 5 13
|
|
* / \ / \
|
|
* 3 7 11 15
|
|
*
|
|
* Repeating step 3 on that tree we get elements 9, then 5 and 13, and then
|
|
* by running steps from 2 on the lowest level of that tree we get elements
|
|
* in following order: 3, 11, 7 and 15.
|
|
*
|
|
* So the entire sequence would be as follows:
|
|
* [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]
|
|
*
|
|
* This algorithm is however quite complex, and it can be simplified
|
|
* significantly thanks to properties of the result sequence. Note that
|
|
* when this sequence is written in binary it looks like this:
|
|
*
|
|
* 0 0000
|
|
* 8 1000
|
|
* 4 0100
|
|
* 12 1100
|
|
* 2 0010
|
|
* 10 1010
|
|
* 6 0110
|
|
* 14 1110
|
|
* 1 0001
|
|
* 9 1001
|
|
* 5 0101
|
|
* 13 1101
|
|
* 3 0011
|
|
* 11 1011
|
|
* 7 0111
|
|
* 15 1111
|
|
*
|
|
* So in its binary representation it looks like a mirror image of binary
|
|
* representation of the original sequence:
|
|
*
|
|
* 0 0000 0000 0
|
|
* 8 1000 0001 1
|
|
* 4 0100 0010 2
|
|
* 12 1100 0011 3
|
|
* 2 0010 0100 4
|
|
* 10 1010 0101 5
|
|
* 6 0110 0110 6
|
|
* 14 1110 0111 7
|
|
* 1 0001 1000 8
|
|
* 9 1001 1001 9
|
|
* 5 0101 1010 10
|
|
* 13 1101 1011 11
|
|
* 3 0011 1100 12
|
|
* 11 1011 1101 13
|
|
* 7 0111 1110 14
|
|
* 15 1111 1111 15
|
|
*
|
|
* With that knowledge we can easily calculate the next result value by just
|
|
* reversing order of bits for each value in original sequence.
|
|
*
|
|
* As a result we are left with sequence that contains all the numbers that
|
|
* can be expressed with number of bits reqiured to express limit - 1. The only
|
|
* thing we need to do at that point is to just filter out values that do not
|
|
* fit within the limit.
|
|
*
|
|
* @param[in] generator Pointer to generator structure
|
|
*
|
|
* @return Generated value
|
|
*/
|
|
uint32_t ocf_generator_bisect_next(
|
|
struct ocf_generator_bisect_state *generator)
|
|
{
|
|
unsigned clz;
|
|
uint32_t maplen;
|
|
uint32_t value;
|
|
|
|
clz = __builtin_clz(generator->limit - 1);
|
|
maplen = 1 << (32 - clz);
|
|
|
|
do {
|
|
value = bitreverse32(generator->curr) >> clz;
|
|
generator->curr = (generator->curr + 1) % maplen;
|
|
} while (value >= generator->limit);
|
|
|
|
return value;
|
|
}
|