Skip to content

Commit

Permalink
Merge pull request #448 from ckormanyos/time_point_rnd_seed
Browse files Browse the repository at this point in the history
Rework snippet 16_08-001 with time-point seed
  • Loading branch information
ckormanyos authored Oct 29, 2023
2 parents 39131e4 + 30f7963 commit 3ea4fd7
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 58 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/real-time-cpp-sonar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
name: sonar-gcc-native
runs-on: ubuntu-latest
env:
SONAR_SCANNER_VERSION: 4.8.0.2856
SONAR_SCANNER_VERSION: 5.0.1.3006
SONAR_SERVER_URL: "https://sonarcloud.io"
BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed
steps:
Expand Down
6 changes: 0 additions & 6 deletions code_snippets/chapter16/chapter16.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,10 @@ rm -f ./bin/*.*

echo build snippets with GCC=$GCC STD=$STD

if [[ "$GCC" == "g++" ]]; then
$GCC -std=$STD -Wall -Wextra -Wpedantic -Werror -Wconversion -Wsign-conversion -O3 -m64 -fsanitize=address -fsanitize=shift -fsanitize=shift-exponent -fsanitize=shift-base -fsanitize=integer-divide-by-zero -fsanitize=null -fsanitize=signed-integer-overflow -fsanitize=bounds -fsanitize=alignment -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fsanitize=enum ./chapter16_08-001_random_engine.cpp -o ./bin/chapter16_08-001_random_engine.exe
fi

if [[ "$GCC" == "g++" ]]; then
ls -la \
./bin/chapter16_08-001_random_engine.exe
else
ls -la
fi

result_ls=$?

Expand Down
159 changes: 112 additions & 47 deletions code_snippets/chapter16/chapter16_08-001_random_engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,26 @@

// chapter16_08-001_random_engine.cpp

// See also https://godbolt.org/z/8c1v1rboh
// See also https://godbolt.org/z/7fW8jYKKx

#include <algorithm>
#include <array>
#include <chrono>
#include <cstddef>
#include <cstdint>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <limits>
#include <random>
#include <sstream>
#include <string>

namespace mcal { namespace random {

class random_engine
{
public:
using result_type = std::uint32_t;
using result_type = std::uint64_t;

random_engine() = default;

Expand All @@ -36,80 +40,141 @@ class random_engine

auto entropy() const noexcept -> std::uint_fast8_t
{
return 4U;
return 1U;
}

result_type operator()()
{
const auto time_stamp = static_cast<result_type>(std::chrono::high_resolution_clock::now().time_since_epoch().count());
const result_type basis_for_seed = seed_value<result_type>();

const result_type basis_for_seed = static_cast<result_type>(time_stamp);

return static_cast<result_type>(crc32_mpeg2(basis_for_seed));
return basis_for_seed;
}

private:
template<typename IntegralType>
auto crc32_mpeg2(const IntegralType v) -> std::uint32_t
static auto seed_value() -> IntegralType
{
// Calculate a bitwise CRC32/MPEG-2 over the
// individual bytes of the input parameter v.
using strftime_uint8_array_type = std::array<std::uint8_t, static_cast<std::size_t>(UINT8_C(64))>;

strftime_uint8_array_type buf_u8 { }; buf_u8.fill(static_cast<std::uint8_t>(UINT8_C(0)));

// Extract the bytes of v into an array.
std::array<std::uint8_t,
std::numeric_limits<IntegralType>::digits / 8U> data;
std::size_t str_tm_len { };

for(auto i = static_cast<std::uint_fast8_t>(UINT8_C(0)); i < static_cast<std::uint_fast8_t>(data.size()); ++ i)
{
data[i] = std::uint8_t(v >> (i * 8U));
// Get the time.
const std::time_t now = std::time(nullptr);

using strftime_char_array_type = std::array<char, std::tuple_size<strftime_uint8_array_type>::value>;

strftime_char_array_type buf { };

#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable : 4996)
#endif
// Format the time in a calendar-style.
strftime(buf.data(), buf.size(), "%c", std::localtime(&now)); // NOLINT(concurrency-mt-unsafe)
#if defined(_MSC_VER)
#pragma warning( pop )
#endif

std::stringstream strm;

// Append the clock()-time in arbitrary units.
strm << buf.data();
strm << '+' << std::setfill('0') << std::setw(static_cast<std::streamsize>(INT8_C(9))) << std::clock();

const auto str_tm = strm.str();

str_tm_len = str_tm.length();

std::copy(str_tm.cbegin(), str_tm.cend(), buf_u8.begin());
}

auto crc = static_cast<std::uint32_t>(UINT32_C(0xFFFFFFFF));
using local_integral_type = IntegralType;

return static_cast<local_integral_type>(crc_crc64(buf_u8.data(), str_tm_len));
}

static constexpr auto test() noexcept -> bool;

// Perform modulo-2 division, one byte at a time.
for(auto byte = static_cast<std::size_t>(UINT8_C(0)); byte < data.size(); ++byte)
template<const std::size_t NumberOfBits,
typename UnsignedIntegralType>
static constexpr auto crc_bitwise_template(const std::uint8_t* message,
const std::size_t count,
const UnsignedIntegralType polynomial, // NOLINT(bugprone-easily-swappable-parameters)
const UnsignedIntegralType initial_value,
const UnsignedIntegralType final_xor_value) -> UnsignedIntegralType
{
using value_type = UnsignedIntegralType;

// The data_type is fixed to exactly 8-bits in width at the moment.
using data_type = std::uint8_t;

value_type crc = initial_value;

// Perform the polynomial division, one element at a time.
for(auto data_index = static_cast<std::size_t>(UINT8_C(0)); data_index < count; ++data_index)
{
// Obtain the next data element (and reflect it if necessary).
const data_type next_data_element = message[data_index]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)

{
constexpr auto left_shift_amount =
static_cast<unsigned>
static_cast<std::size_t>
(
std::numeric_limits<std::uint32_t>::digits - static_cast<int>(INT8_C(8))
std::numeric_limits<value_type>::digits - std::numeric_limits<data_type >::digits
);

// Bring the next byte into the result.
crc ^= static_cast<std::uint32_t>(static_cast<std::uint32_t>(data[byte]) << left_shift_amount);
crc ^= static_cast<value_type>(static_cast<value_type>(next_data_element) << left_shift_amount);
}

// Perform a modulo-2 division, one bit at a time.
for(auto bit = static_cast<std::int_fast8_t>(INT8_C(8)); bit > static_cast<std::int_fast8_t>(INT8_C(0)); --bit)
// Process the next data byte, one bit at a time.
for(std::uint_fast8_t index = 0U;
index < static_cast<std::uint_fast8_t>(std::numeric_limits<data_type>::digits);
++index)
{
const auto left_shift_amount =
static_cast<unsigned>
const auto high_bit_value =
static_cast<value_type>
(
std::numeric_limits<std::uint32_t>::digits - static_cast<int>(INT8_C(1))
crc
& static_cast<value_type>
(
static_cast<std::uintmax_t>(UINT8_C(1)) << static_cast<unsigned>(std::numeric_limits<value_type>::digits - 1)
)
);

constexpr auto mask =
static_cast<std::uint32_t>(static_cast<std::uintmax_t>(UINT8_C(1)) << left_shift_amount);
const bool high_bit_of_crc_is_set = (high_bit_value != static_cast<value_type>(UINT8_C(0)));

// Divide the current data bit.
if(static_cast<std::uint32_t>(crc & mask) != static_cast<std::uint32_t>(UINT8_C(0)))
{
crc =
static_cast<std::uint32_t>
(
static_cast<std::uint32_t>(crc << static_cast<unsigned>(UINT8_C(1)))
^ static_cast<std::uint32_t>(UINT32_C(0x04C11DB7))
);
}
else
crc = crc << static_cast<unsigned>(UINT8_C(1));

if(high_bit_of_crc_is_set)
{
crc <<= static_cast<unsigned>(UINT8_C(1));
// Shift through the polynomial. Also left-justify the
// polynomial within the width of value_type, if necessary.

crc ^= static_cast<value_type>(polynomial);
}
}
}

return static_cast<std::uint32_t>(crc);
// Perform the final XOR on the result.
crc ^= final_xor_value;

return crc;
}

static constexpr auto crc_crc64(const std::uint8_t* message, const std::size_t count) -> std::uint64_t
{
// check: 0x6C40DF5F0B497347
return crc_bitwise_template<static_cast<std::size_t>(UINT8_C(64)), std::uint64_t>
(
message,
count,
static_cast<std::uint64_t>(UINT64_C(0x42F0E1EBA9EA3693)),
static_cast<std::uint64_t>(UINT64_C(0x0000000000000000)),
static_cast<std::uint64_t>(UINT64_C(0x0000000000000000))
);
}
};

Expand All @@ -121,7 +186,7 @@ auto do_something() -> void
{
mcal::random::random_engine rng;
const typename mcal::random::random_engine::result_type seed(rng());
std::mt19937 generator(seed);
std::mt19937_64 generator(seed);

std::uniform_int_distribution<unsigned>
distribution
Expand All @@ -135,14 +200,14 @@ auto do_something() -> void
// Print the seed.
std::cout << "Seed is: 0x"
<< std::hex
<< std::setw(static_cast<std::streamsize>(INT8_C(8)))
<< std::setw(static_cast<std::streamsize>(INT8_C(16)))
<< std::setfill('0')
<< std::uppercase
<< seed
<< ". ";

// Generate 3 pseudo-random numbers in [1, 1023].
const unsigned random_numbers[3U] =
// Generate 9 pseudo-random numbers in [1, 1023].
const std::array<unsigned, static_cast<std::size_t>(UINT8_C(3))> random_numbers =
{
distribution(generator),
distribution(generator),
Expand Down
10 changes: 8 additions & 2 deletions code_snippets/chapter16/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,16 @@ This folder contains the code snippets for Chapter 16.
## Try it at _godbolt_

<p align="center">
<a href="https://godbolt.org/z/8c1v1rboh" alt="godbolt">
<a href="https://godbolt.org/z/7fW8jYKKx" alt="godbolt">
<img src="https://img.shields.io/badge/try%20it%20on-godbolt-green" /></a>
</p>

Try the [`chapter16_08-001_random_engine.cpp`](./chapter16_08-001_random_engine.cpp)
program at this
[short link](https://godbolt.org/z/8c1v1rboh) to [godbolt](https://godbolt.org/).
[short link](https://godbolt.org/z/7fW8jYKKx) to [godbolt](https://godbolt.org/).

This program creates a mock-up of a non-cryptographic, _toy_ random engine.
It uses a combination of both the time-and-date functions of C/C++ as well as
a 64-bit standard CRC to create a pseudo-random seed for
a self-written random engine. This engine is subsequently used to seed
a standard generator that makes sequences of random numbers.
6 changes: 4 additions & 2 deletions ref_app/src/util/STL/charconv
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright Christopher Kormanyos 2021 - 2022.
// Copyright Christopher Kormanyos 2021 - 2023.
// Distributed under the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
Expand All @@ -8,7 +8,9 @@
#ifndef CHARCONV_2021_04_12_
#define CHARCONV_2021_04_12_

// Implement std::time_t of <charconv> for compilers that do not yet support it.
// Implement some of <charconv> for compilers that do not yet support it.
// At the moment, this contains nothing more than the implementation
// of the struct std::to_chars_result.

#include <errno.h>

Expand Down

0 comments on commit 3ea4fd7

Please sign in to comment.