lehmer_code_test.cc (2902B)
1 // Copyright (c) the JPEG XL Project Authors. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 #include "lib/jxl/lehmer_code.h" 7 8 #include <cstdint> 9 #include <cstring> 10 #include <numeric> 11 #include <vector> 12 13 #include "lib/jxl/base/bits.h" 14 #include "lib/jxl/base/data_parallel.h" 15 #include "lib/jxl/base/random.h" 16 #include "lib/jxl/base/status.h" 17 #include "lib/jxl/test_utils.h" 18 #include "lib/jxl/testing.h" 19 20 namespace jxl { 21 namespace { 22 23 template <typename PermutationT> 24 struct WorkingSet { 25 explicit WorkingSet(size_t max_n) 26 : padded_n(1ull << CeilLog2Nonzero(max_n + 1)), 27 permutation(max_n), 28 temp(padded_n), 29 lehmer(max_n), 30 decoded(max_n) {} 31 32 size_t padded_n; 33 std::vector<PermutationT> permutation; 34 std::vector<uint32_t> temp; 35 std::vector<LehmerT> lehmer; 36 std::vector<PermutationT> decoded; 37 }; 38 39 template <typename PermutationT> 40 void Roundtrip(uint32_t n, WorkingSet<PermutationT>* ws) { 41 EXPECT_TRUE(n != 0); 42 const size_t padded_n = 1ull << CeilLog2Nonzero(n); 43 44 Rng rng(static_cast<uint64_t>(n) * 65537 + 13); 45 46 // Ensure indices fit into PermutationT 47 EXPECT_LE(n, 1ULL << (sizeof(PermutationT) * 8)); 48 49 std::iota(ws->permutation.begin(), ws->permutation.begin() + n, 0); 50 51 // For various random permutations: 52 for (size_t rep = 0; rep < 3; ++rep) { 53 rng.Shuffle(ws->permutation.data(), n); 54 55 // Must decode to the same permutation 56 EXPECT_TRUE(ComputeLehmerCode(ws->permutation.data(), ws->temp.data(), n, 57 ws->lehmer.data())); 58 memset(ws->temp.data(), 0, padded_n * 4); 59 EXPECT_TRUE(DecodeLehmerCode(ws->lehmer.data(), ws->temp.data(), n, 60 ws->decoded.data())); 61 62 for (size_t i = 0; i < n; ++i) { 63 EXPECT_EQ(ws->permutation[i], ws->decoded[i]); 64 } 65 } 66 } 67 68 // Preallocates arrays and tests n = [begin, end). 69 template <typename PermutationT> 70 void RoundtripSizeRange(ThreadPool* pool, uint32_t begin, uint32_t end) { 71 ASSERT_NE(0u, begin); // n = 0 not allowed. 72 std::vector<WorkingSet<PermutationT>> working_sets; 73 74 const auto init = [&working_sets, end](const size_t num_threads) -> Status { 75 for (size_t i = 0; i < num_threads; i++) { 76 working_sets.emplace_back(end - 1); 77 } 78 return true; 79 }; 80 const auto do_roundtrip = [&working_sets](const uint32_t n, 81 const size_t thread) -> Status { 82 Roundtrip(n, &working_sets[thread]); 83 return true; 84 }; 85 ASSERT_TRUE(RunOnPool(pool, begin, end, init, do_roundtrip, "lehmer test")); 86 } 87 88 TEST(LehmerCodeTest, TestRoundtrips) { 89 test::ThreadPoolForTests pool(8); 90 91 RoundtripSizeRange<uint16_t>(pool.get(), 1, 1026); 92 93 // Ensures PermutationT can fit > 16 bit values. 94 RoundtripSizeRange<uint32_t>(pool.get(), 65536, 65540); 95 } 96 97 } // namespace 98 } // namespace jxl