blob: ed7c1ffbd1afcd3979df84d50e3baef7973b0070 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <stdint.h>
#include <type_traits>
namespace fbl {
namespace tests {
namespace internal {
// A templated implementation of a linear feedback shift register for various
// core state sizes. With proper selection of the generator, the LFSR will be a
// maximum-cycle LFSR meaning that it will cycle through all of its core states
// (except for all zeros) exactly once before repeating.
template <typename CoreType, CoreType generator>
class Lfsr {
public:
static_assert(std::is_unsigned_v<CoreType>, "LFSR core type must be an unsigned integer!");
constexpr explicit Lfsr(CoreType initial_core) : core_(initial_core) {}
template <typename T>
void SetCore(T val) {
static_assert(std::is_unsigned_v<T>, "LFSR initializer type must be an unsigned integer!");
core_ = static_cast<CoreType>(val);
}
CoreType PeekCore() const { return core_; }
CoreType GetNext() {
CoreType ret = 0u;
CoreType flag = 1u;
for (size_t i = 0; i < (sizeof(size_t) << 3); ++i) {
bool bit = core_ & 1u;
core_ = static_cast<CoreType>(core_ >> 1u);
if (bit) {
core_ ^= generator;
ret |= flag;
}
flag = static_cast<CoreType>(flag << 1u);
}
return ret;
}
private:
CoreType core_;
};
} // namespace internal
// User-facing implementation of LFSRs of various sizes with pre-selected
// maximum-cycle generators.
template <typename T, typename Enable = void>
class Lfsr;
// MAKE_LFSR
//
// Temporary macro which deals with the boilerplate declaration of an LFSR of a
// particular core size with a particular generator, exposing the constructor in
// the process.
#define MAKE_LFSR(_bits, _gen) \
template <typename T> \
class Lfsr<T, std::enable_if_t<std::is_unsigned_v<T> && ((sizeof(T) << 3) == _bits)>> \
: public internal::Lfsr<uint##_bits##_t, _gen> { \
public: \
using CoreType = uint##_bits##_t; \
\
template <typename U> \
constexpr explicit Lfsr(U initial_core) \
: internal::Lfsr<CoreType, _gen>(static_cast<CoreType>(initial_core)) { \
static_assert(std::is_unsigned_v<U>, "LFSR initializer type must be an unsigned integer!"); \
} \
\
constexpr Lfsr() : internal::Lfsr<CoreType, _gen>(1u) {} \
}
MAKE_LFSR(8, 0xB8);
MAKE_LFSR(16, 0xB400);
MAKE_LFSR(32, 0xA3000000);
MAKE_LFSR(64, 0xD800000000000000);
#undef MAKE_LFSR
} // namespace tests
} // namespace fbl