Coverage Report

Created: 2025-07-23 06:39

/src/brunsli/c/common/lehmer_code.h
Line
Count
Source (jump to first uncovered line)
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 <algorithm>
15
#include <utility>
16
#include <vector>
17
18
#include "./platform.h"
19
#include <brunsli/types.h>
20
21
namespace brunsli {
22
23
// Computes the Lehmer code of the permutation sigma[0..len) and puts the
24
// result into code[0..len).
25
void ComputeLehmerCode(const uint32_t* sigma, size_t len, uint32_t* code);
26
27
// Decodes the Lehmer code in code[0..len) and puts the resulting permutation
28
// into sigma[0..len).
29
bool DecodeLehmerCode(const uint32_t* code, size_t len, uint32_t* sigma);
30
31
// This class is an optimized Lehmer-like coder that takes the remaining
32
// number of possible values into account to reduce the bit usage.
33
// TODO(eustas): in worst case (always removing the first element), O(N^2)
34
// elements are moved; "Fenwick tree" is simple to implement and could reduce
35
// the complexity to O(N * log(N)).
36
class PermutationCoder {
37
 public:
38
42.2k
  PermutationCoder() {}
39
40
19.5k
  void Init(std::vector<uint8_t> values) {
41
19.5k
    values_ = std::move(values);
42
19.5k
  }
43
44
21.6k
  void Clear() {
45
21.6k
    std::vector<uint8_t>().swap(values_);
46
21.6k
  }
47
48
  // number of bits needed to represent the next code.
49
142k
  int num_bits() const {
50
142k
    uint32_t num_values = static_cast<uint32_t>(values_.size());
51
142k
    BRUNSLI_DCHECK(num_values > 0);
52
142k
    if (num_values <= 1) return 0;
53
142k
    return static_cast<int>(Log2FloorNonZero(num_values - 1) + 1);
54
142k
  }
55
56
  // Copy value at position 'code' and remove it. Returns false in
57
  // case of error (invalid slot).
58
128k
  bool Remove(size_t code, uint8_t* value) {
59
128k
    if (code >= values_.size()) {
60
9
      return false;
61
9
    }
62
128k
    *value = values_[code];
63
128k
    values_.erase(values_.begin() + code);
64
128k
    return true;
65
128k
  }
66
67
  // Removes 'value' from the list and assign a code + number-of-bits
68
  // for it. Returns false if value could not be encoded.
69
0
  bool RemoveValue(uint8_t value, int* code, int* nbits) {
70
0
    std::vector<uint8_t>::iterator it =
71
0
        std::find(values_.begin(), values_.end(), value);
72
0
    if (it == values_.end()) {
73
0
      return false;  // invalid/non-existing value was passed.
74
0
    }
75
0
    *code = static_cast<int>(it - values_.begin());
76
0
    *nbits = num_bits();
77
0
    values_.erase(it);
78
0
    return true;
79
0
  }
80
81
 private:
82
  std::vector<uint8_t> values_;
83
};
84
85
}  // namespace brunsli
86
87
#endif  // BRUNSLI_COMMON_LEHMER_CODE_H_