Coverage Report

Created: 2026-08-31 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/brunsli/c/common/lehmer_code.h
Line
Count
Source
1
// Copyright (c) Google LLC 2019
2
//
3
// Use of this source code is governed by an MIT-style
4
// license that can be found in the LICENSE file or at
5
// https://opensource.org/licenses/MIT.
6
7
// Library to compute the Lehmer code of a permutation and to reconstruct the
8
// permutation from its Lehmer code. For more details on Lehmer codes, see
9
// http://en.wikipedia.org/wiki/Lehmer_code
10
11
#ifndef BRUNSLI_COMMON_LEHMER_CODE_H_
12
#define BRUNSLI_COMMON_LEHMER_CODE_H_
13
14
#include <brunsli/types.h>
15
16
#include <algorithm>
17
#include <utility>
18
#include <vector>
19
20
#include "./platform.h"
21
22
namespace brunsli {
23
24
// Computes the Lehmer code of the permutation sigma[0..len) and puts the
25
// result into code[0..len).
26
void ComputeLehmerCode(const uint32_t* sigma, size_t len, uint32_t* code);
27
28
// Decodes the Lehmer code in code[0..len) and puts the resulting permutation
29
// into sigma[0..len).
30
bool DecodeLehmerCode(const uint32_t* code, size_t len, uint32_t* sigma);
31
32
// This class is an optimized Lehmer-like coder that takes the remaining
33
// number of possible values into account to reduce the bit usage.
34
// TODO(eustas): in worst case (always removing the first element), O(N^2)
35
// elements are moved; "Fenwick tree" is simple to implement and could reduce
36
// the complexity to O(N * log(N)).
37
class PermutationCoder {
38
 public:
39
39.9k
  PermutationCoder() {}
40
41
19.6k
  void Init(std::vector<uint8_t> values) { values_ = std::move(values); }
42
43
20.2k
  void Clear() { std::vector<uint8_t>().swap(values_); }
44
45
  // number of bits needed to represent the next code.
46
173k
  int num_bits() const {
47
173k
    uint32_t num_values = static_cast<uint32_t>(values_.size());
48
173k
    BRUNSLI_DCHECK(num_values > 0);
49
173k
    if (num_values <= 1) return 0;
50
173k
    return static_cast<int>(Log2FloorNonZero(num_values - 1) + 1);
51
173k
  }
52
53
  // Copy value at position 'code' and remove it. Returns false in
54
  // case of error (invalid slot).
55
156k
  bool Remove(size_t code, uint8_t* value) {
56
156k
    if (code >= values_.size()) {
57
20
      return false;
58
20
    }
59
156k
    *value = values_[code];
60
156k
    values_.erase(values_.begin() + code);
61
156k
    return true;
62
156k
  }
63
64
  // Removes 'value' from the list and assign a code + number-of-bits
65
  // for it. Returns false if value could not be encoded.
66
0
  bool RemoveValue(uint8_t value, int* code, int* nbits) {
67
0
    std::vector<uint8_t>::iterator it =
68
0
        std::find(values_.begin(), values_.end(), value);
69
0
    if (it == values_.end()) {
70
0
      return false;  // invalid/non-existing value was passed.
71
0
    }
72
0
    *code = static_cast<int>(it - values_.begin());
73
0
    *nbits = num_bits();
74
0
    values_.erase(it);
75
0
    return true;
76
0
  }
77
78
 private:
79
  std::vector<uint8_t> values_;
80
};
81
82
}  // namespace brunsli
83
84
#endif  // BRUNSLI_COMMON_LEHMER_CODE_H_