openMSX
EmuDuration.hh
Go to the documentation of this file.
1#ifndef EMUDURATION_HH
2#define EMUDURATION_HH
3
4#include "narrow.hh"
5#include "serialize.hh"
6#include <cassert>
7#include <concepts>
8#include <cstdint>
9#include <limits>
10#include <type_traits>
11
12namespace openmsx {
13
14// constants
15inline constexpr uint64_t MAIN_FREQ = 3579545ULL * 960;
16inline constexpr unsigned MAIN_FREQ32 = MAIN_FREQ;
17static_assert(MAIN_FREQ < (1ULL << 32), "must fit in 32 bit");
18inline constexpr double RECIP_MAIN_FREQ = 1.0 / MAIN_FREQ;
19
20
22{
23public:
24 // This is only a very small class (one 64-bit member). On 64-bit CPUs
25 // it's cheaper to pass this by value. On 32-bit CPUs pass-by-reference
26 // is cheaper.
27#ifdef __x86_64
28 using param = EmuDuration;
29#else
30 using param = const EmuDuration&;
31#endif
32
33 // friends
34 friend class EmuTime;
35
36 // constructors
37 constexpr EmuDuration() = default;
38 constexpr explicit EmuDuration(uint64_t n) : time(n) {}
39 constexpr explicit EmuDuration(double duration)
40 : time(uint64_t(duration * MAIN_FREQ + 0.5)) {}
41
42 static constexpr EmuDuration sec(unsigned x)
43 { return EmuDuration(x * MAIN_FREQ); }
44 static constexpr EmuDuration msec(unsigned x)
45 { return EmuDuration(x * MAIN_FREQ / 1000); }
46 static constexpr EmuDuration usec(unsigned x)
47 { return EmuDuration(x * MAIN_FREQ / 1000000); }
48 static constexpr EmuDuration hz(unsigned x)
49 { return EmuDuration(MAIN_FREQ / x); }
50
51 // conversions
52 [[nodiscard]] constexpr double toDouble() const { return double(time) * RECIP_MAIN_FREQ; }
53 [[nodiscard]] constexpr uint64_t length() const { return time; }
54
55 // comparison operators
56 [[nodiscard]] constexpr auto operator<=>(const EmuDuration&) const = default;
57
58 // arithmetic operators
59 [[nodiscard]] constexpr friend EmuDuration operator%(const EmuDuration& l, const EmuDuration& r)
60 { return EmuDuration(l.time % r.time); }
61 [[nodiscard]] constexpr friend EmuDuration operator+(const EmuDuration& l, const EmuDuration& r)
62 { return EmuDuration(l.time + r.time); }
63 [[nodiscard]] constexpr friend EmuDuration operator*(const EmuDuration& l, uint64_t fact)
64 { return EmuDuration(l.time * fact); }
65 [[nodiscard]] constexpr friend EmuDuration operator/(const EmuDuration& l, unsigned fact)
66 { return EmuDuration(l.time / fact); }
67 [[nodiscard]] constexpr EmuDuration divRoundUp(unsigned fact) const
68 { return EmuDuration((time + fact - 1) / fact); }
69 [[nodiscard]] constexpr friend unsigned operator/(const EmuDuration& l, const EmuDuration& r)
70 {
71 uint64_t result = l.time / r.time;
72#ifdef DEBUG
73 // we don't even want this overhead in devel builds
74 assert(result == unsigned(result));
75#endif
76 return unsigned(result);
77 }
78 [[nodiscard]] constexpr unsigned divUp(EmuDuration::param d) const {
79 uint64_t result = (time + d.time - 1) / d.time;
80#ifdef DEBUG
81 assert(result == unsigned(result));
82#endif
83 return unsigned(result);
84 }
85 [[nodiscard]] constexpr double div(EmuDuration::param d) const
86 { return narrow_cast<double>(time) / narrow_cast<double>(d.time); }
87
88 constexpr EmuDuration& operator*=(unsigned fact)
89 { time *= fact; return *this; }
90 constexpr EmuDuration& operator*=(double fact)
91 { time = narrow_cast<uint64_t>(narrow_cast<double>(time) * fact); return *this; }
92 constexpr EmuDuration& operator/=(double fact)
93 { time = narrow_cast<uint64_t>(narrow_cast<double>(time) / fact); return *this; }
94
95 // The smallest duration larger than zero
96 [[nodiscard]] static constexpr EmuDuration epsilon() {
97 return EmuDuration(uint64_t(1));
98 }
99
100 // ticks
101 // TODO: Used in WavAudioInput. Keep or use DynamicClock instead?
102 [[nodiscard]] constexpr unsigned getTicksAt(unsigned freq) const
103 {
104 uint64_t result = time / (MAIN_FREQ32 / freq);
105#ifdef DEBUG
106 // we don't even want this overhead in devel builds
107 assert(result == unsigned(result));
108#endif
109 return unsigned(result);
110 }
111
112 [[nodiscard]] static constexpr EmuDuration zero()
113 {
114 return EmuDuration(uint64_t(0));
115 }
116
117 [[nodiscard]] static constexpr EmuDuration infinity()
118 {
119 return EmuDuration(std::numeric_limits<uint64_t>::max());
120 }
121
122 template<typename Archive>
123 void serialize(Archive& ar, unsigned /*version*/)
124 {
125 ar.serialize("time", time);
126 }
127
128private:
129 uint64_t time = 0;
130};
131
132template<> struct SerializeAsMemcpy<EmuDuration> : std::true_type {};
133
134
135template<std::unsigned_integral T> class EmuDurationCompactStorage
136{
137public:
139 : time(T(e.length()))
140 {
141 assert(e.length() <= std::numeric_limits<T>::max());
142 }
143
144 [[nodiscard]] explicit constexpr operator EmuDuration() const
145 {
146 return EmuDuration(uint64_t(time));
147 }
148private:
149 T time;
150};
151
155
156namespace detail {
157 // via intermediate variable to work around gcc-10 warning
158 inline constexpr uint64_t max32 = std::numeric_limits<uint32_t>::max();
159 inline constexpr uint64_t max16 = std::numeric_limits<uint16_t>::max();
160 inline constexpr uint64_t max8 = std::numeric_limits<uint8_t >::max();
161}
162template<uint64_t MAX>
163using EmuDurationStorageFor = std::conditional_t<(MAX > detail::max32), EmuDuration,
164 std::conditional_t<(MAX > detail::max16), EmuDuration32,
165 std::conditional_t<(MAX > detail::max8 ), EmuDuration16,
166 EmuDuration8>>>;
167} // namespace openmsx
168
169#endif
constexpr EmuDurationCompactStorage(EmuDuration e)
void serialize(Archive &ar, unsigned)
static constexpr EmuDuration sec(unsigned x)
constexpr unsigned divUp(EmuDuration::param d) const
constexpr EmuDuration(double duration)
constexpr uint64_t length() const
constexpr EmuDuration(uint64_t n)
constexpr friend unsigned operator/(const EmuDuration &l, const EmuDuration &r)
constexpr EmuDuration()=default
constexpr EmuDuration & operator/=(double fact)
static constexpr EmuDuration infinity()
constexpr friend EmuDuration operator/(const EmuDuration &l, unsigned fact)
constexpr friend EmuDuration operator%(const EmuDuration &l, const EmuDuration &r)
static constexpr EmuDuration epsilon()
friend class EmuTime
static constexpr EmuDuration hz(unsigned x)
constexpr EmuDuration & operator*=(double fact)
constexpr EmuDuration divRoundUp(unsigned fact) const
static constexpr EmuDuration msec(unsigned x)
constexpr friend EmuDuration operator+(const EmuDuration &l, const EmuDuration &r)
constexpr double toDouble() const
constexpr EmuDuration & operator*=(unsigned fact)
constexpr unsigned getTicksAt(unsigned freq) const
constexpr auto operator<=>(const EmuDuration &) const =default
static constexpr EmuDuration zero()
static constexpr EmuDuration usec(unsigned x)
constexpr double div(EmuDuration::param d) const
constexpr friend EmuDuration operator*(const EmuDuration &l, uint64_t fact)
Definition join.hh:10
This file implemented 3 utility functions:
Definition Autofire.cc:11
EmuDurationCompactStorage< uint32_t > EmuDuration32
constexpr double RECIP_MAIN_FREQ
std::conditional_t<(MAX > detail::max32), EmuDuration, std::conditional_t<(MAX > detail::max16), EmuDuration32, std::conditional_t<(MAX > detail::max8), EmuDuration16, EmuDuration8 > > > EmuDurationStorageFor
constexpr unsigned MAIN_FREQ32
constexpr uint64_t MAIN_FREQ