Orrery
A GPU-accelerated N-body gravitational simulator
Loading...
Searching...
No Matches
binary_stream.hpp File Reference

Fixed-width little-endian reading and writing, which is what makes the two binary formats in this layer specifications rather than memory dumps. More...

#include <array>
#include <bit>
#include <cstddef>
#include <cstdint>
#include <istream>
#include <limits>
#include <ostream>
#include <span>
#include <string>
#include <string_view>
#include <type_traits>
#include "orrery/core/types.hpp"

Go to the source code of this file.

Classes

class  orrery::sim::BinaryWriter
 Writes the scalar types the formats in this layer are built from. More...
class  orrery::sim::BinaryReader
 Reads what BinaryWriter writes. More...

Typedefs

using orrery::sim::RealBits = std::conditional_t<core::kSinglePrecision, std::uint32_t, std::uint64_t>
 An unsigned integer the same width as Real, which is what a bit pattern is carried in between this file and the stream.

Functions

constexpr std::uint64_t orrery::sim::checksum_byte (std::uint64_t checksum, std::byte value) noexcept
 Fold one byte into a running FNV-1a checksum.

Variables

constexpr std::size_t orrery::sim::kRealBytes = sizeof(core::Real)
 How many bytes a Real occupies in both formats.
constexpr std::uint64_t orrery::sim::kChecksumBasis = 0xcbf29ce484222325ULL
 The offset basis and prime of 64-bit FNV-1a.
constexpr std::uint64_t orrery::sim::kChecksumPrime = 0x00000100000001b3ULL

Detailed Description

Fixed-width little-endian reading and writing, which is what makes the two binary formats in this layer specifications rather than memory dumps.

A file format written by pointing ostream::write at a struct is not a format. It records the compiler's padding, the platform's endianness and the width of whatever unsigned long happened to be, none of which appear in any document, and it is read back correctly only by the binary that wrote it. The checkpoint format exists so that a run interrupted on this machine can be resumed, and the trajectory format so that something else can read the positions later, so both have to say exactly which bytes go where.

So every scalar goes through this file. Integers are assembled byte by byte with shifts rather than copied, which means the result does not depend on the endianness of the machine doing the assembling and no #ifdef is needed to say so. Floating-point values are converted to an unsigned integer of the same width and written the same way, which preserves every bit including the sign of a zero and the payload of a NaN. That last property is the one the bitwise-resume requirement in Phase 11 rests on: a checkpoint that wrote 1.0000000000000002 as text and read back 1.0 would resume a different simulation, and the difference would take a few thousand steps to become visible.

The checksum

Both writers finish with a checksum of everything they wrote and both readers verify it. It is FNV-1a over the bytes, which is not a cryptographic hash and is not trying to be: the failure it exists to catch is a checkpoint written by a run that was killed halfway through writing it, which is the ordinary way a long simulation ends and would otherwise be detected as a physically absurd result several hours later. A truncated file also fails the length check, but a file truncated to exactly the right length by a full disc does not, and neither does one that lost a block in the middle.

Typedef Documentation

◆ RealBits

using orrery::sim::RealBits = std::conditional_t<core::kSinglePrecision, std::uint32_t, std::uint64_t>

An unsigned integer the same width as Real, which is what a bit pattern is carried in between this file and the stream.

An alias rather than a branch inside the reading and writing functions. if constexpr discards nothing in a function that is not a template, so a double-precision build would still have to compile a bit_cast between a double and a std::uint32_t and would fail to.

Variable Documentation

◆ kChecksumBasis

std::uint64_t orrery::sim::kChecksumBasis = 0xcbf29ce484222325ULL
inlineconstexpr

The offset basis and prime of 64-bit FNV-1a.

Named rather than written in place because the reader and the writer both need them and a hash that disagreed with itself would reject every file.