blob: 81cbbe2569cffa1c40b22dad4502ec913aa70e78 [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