Skip to content

Commit

Permalink
[Ref] mpt/base/saturate_round.hpp: Rename floating point variants of …
Browse files Browse the repository at this point in the history
…saturate_cast to saturate_trunc in order to make mpt::saturate_cast as broken as C++26 std::saturate_cast.

[Ref] mpt/base/saturate_cast.hpp: Use C++26 saturate_cast if available.


git-svn-id: https://source.openmpt.org/svn/openmpt/trunk/OpenMPT@22561 56274372-70c3-4bfc-bfc3-4c3a0b034d27
  • Loading branch information
manxorist committed Dec 17, 2024
1 parent 031f157 commit e1750e2
Show file tree
Hide file tree
Showing 15 changed files with 83 additions and 48 deletions.
2 changes: 1 addition & 1 deletion misc/mptColor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ namespace mpt::Color

uint8 GetLuma(uint8 r, uint8 g, uint8 b) noexcept
{
return mpt::saturate_cast<uint8>(r * 0.299f + g * 0.587f + b * 0.114f);
return mpt::saturate_trunc<uint8>(r * 0.299f + g * 0.587f + b * 0.114f);
}


Expand Down
6 changes: 3 additions & 3 deletions mptrack/CImageListEx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ bool CImageListEx::Create(UINT resourceID, int cx, int cy, int nInitial, int nGr
auto hsv = mpt::Color::RGB{pixel->r / 255.0f, pixel->g / 255.0f, pixel->b / 255.0f}.ToHSV();
hsv.v = (1.0f - hsv.v) * (1.0f - hsv.s) + (hsv.v) * hsv.s;
const auto rgb = hsv.ToRGB();
pixel->r = mpt::saturate_cast<uint8>(rgb.r * 255.0f);
pixel->g = mpt::saturate_cast<uint8>(rgb.g * 255.0f);
pixel->b = mpt::saturate_cast<uint8>(rgb.b * 255.0f);
pixel->r = mpt::saturate_trunc<uint8>(rgb.r * 255.0f);
pixel->g = mpt::saturate_trunc<uint8>(rgb.g * 255.0f);
pixel->b = mpt::saturate_trunc<uint8>(rgb.b * 255.0f);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion mptrack/Mainfrm.h
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ class CMainFrame
void UpdateTree(CModDoc *pModDoc, UpdateHint hint, CObject *pHint = nullptr);
void RefreshDlsBanks();
static CInputHandler *GetInputHandler();
void SetElapsedTime(double t) { m_dwTimeSec = mpt::saturate_cast<samplecount_t>(t * 10.0); }
void SetElapsedTime(double t) { m_dwTimeSec = mpt::saturate_trunc<samplecount_t>(t * 10.0); }

#if defined(MPT_ENABLE_UPDATE)
bool ShowUpdateIndicator(const UpdateCheckResult &result, const CString &releaseVersion, const CString &infoURL, bool showHighlight);
Expand Down
8 changes: 4 additions & 4 deletions mptrack/ResizableDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,15 +119,15 @@ CRect ResizableDialog::AdjustItemRect(const DynamicItem &item, const CSize windo

CPoint move;
if(item.moveSettings.IsHorizontal())
move.x = mpt::saturate_cast<int>(ratioX * item.moveSettings.m_nXRatio);
move.x = mpt::saturate_trunc<int>(ratioX * item.moveSettings.m_nXRatio);
if(item.moveSettings.IsVertical())
move.y = mpt::saturate_cast<int>(ratioY * item.moveSettings.m_nYRatio);
move.y = mpt::saturate_trunc<int>(ratioY * item.moveSettings.m_nYRatio);

CSize size;
if(item.sizeSettings.IsHorizontal())
size.cx = mpt::saturate_cast<int>(ratioX * item.sizeSettings.m_nXRatio);
size.cx = mpt::saturate_trunc<int>(ratioX * item.sizeSettings.m_nXRatio);
if(item.sizeSettings.IsVertical())
size.cy = mpt::saturate_cast<int>(ratioY * item.sizeSettings.m_nYRatio);
size.cy = mpt::saturate_trunc<int>(ratioY * item.sizeSettings.m_nYRatio);

auto itemPoint = item.initialPoint + move;
auto itemSize = item.initialSize + size;
Expand Down
2 changes: 1 addition & 1 deletion mptrack/View_smp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ void CViewSample::UpdateScrollSize(int newZoom, bool forceRefresh, SmpLength cen
m_timelineUnit = mpt::saturate_round<int>(std::log(static_cast<double>(timelineInterval)) / std::log(power));
if(m_timelineUnit < 1)
m_timelineUnit = 0;
m_timelineUnit = mpt::saturate_cast<int>(std::pow(power, m_timelineUnit));
m_timelineUnit = mpt::saturate_trunc<int>(std::pow(power, m_timelineUnit));
timelineInterval = std::max(1.0, std::round(timelineInterval / m_timelineUnit)) * m_timelineUnit;
if(format == TimelineFormat::Seconds)
timelineInterval *= sampleRate / 1000.0;
Expand Down
4 changes: 2 additions & 2 deletions mptrack/plugins/MidiInOut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ void MidiInOut::Process(float *, float *, uint32 numFrames)
if(m_sendTimingInfo && !m_positionChanged && m_SndFile.m_PlayState.m_ppqPosFract == 0.0)
{
// Send Song Position on every pattern change or start of new measure
uint16 ppq = mpt::saturate_cast<uint16>((m_SndFile.m_PlayState.m_ppqPosBeat + m_SndFile.m_PlayState.m_ppqPosFract) * 4.0);
uint16 ppq = mpt::saturate_trunc<uint16>((m_SndFile.m_PlayState.m_ppqPosBeat + m_SndFile.m_PlayState.m_ppqPosFract) * 4.0);
if(ppq < 16384)
{
uint32 midiCode = MIDIEvents::SongPosition(ppq);
Expand Down Expand Up @@ -574,7 +574,7 @@ void MidiInOut::PositionChanged()
if(m_sendTimingInfo && !m_SndFile.IsPaused())
{
MidiSend(0xFC); // Stop
uint16 ppq = mpt::saturate_cast<uint16>((m_SndFile.m_PlayState.m_ppqPosBeat + m_SndFile.m_PlayState.m_ppqPosFract) * 4.0);
uint16 ppq = mpt::saturate_trunc<uint16>((m_SndFile.m_PlayState.m_ppqPosBeat + m_SndFile.m_PlayState.m_ppqPosFract) * 4.0);
if(ppq < 16384)
MidiSend(MIDIEvents::SongPosition(ppq));
MidiSend(0xFA); // Start
Expand Down
8 changes: 4 additions & 4 deletions soundlib/Load_symmod.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,8 +282,8 @@ struct SymTranswaveInst
std::pair<SmpLength, SmpLength> ConvertLoop(const ModSample &mptSmp) const
{
const double loopScale = static_cast<double>(mptSmp.nLength) / (100 << 16);
const SmpLength start = mpt::saturate_cast<SmpLength>(loopScale * std::min(uint32(100 << 16), loopStart.get()));
const SmpLength length = mpt::saturate_cast<SmpLength>(loopScale * std::min(uint32(100 << 16), loopLen.get()));
const SmpLength start = mpt::saturate_trunc<SmpLength>(loopScale * std::min(uint32(100 << 16), loopStart.get()));
const SmpLength length = mpt::saturate_trunc<SmpLength>(loopScale * std::min(uint32(100 << 16), loopLen.get()));
return {start, std::min(mptSmp.nLength - start, length)};
}
};
Expand Down Expand Up @@ -670,8 +670,8 @@ struct SymInstrument
loopLen = (loopLen << 16) + loopLenFine;

const double loopScale = static_cast<double>(mptSmp.nLength) / (100 << 16);
loopStart = std::min(mptSmp.nLength, mpt::saturate_cast<SmpLength>(loopStart * loopScale));
loopLen = std::min(mptSmp.nLength - loopStart, mpt::saturate_cast<SmpLength>(loopLen * loopScale));
loopStart = std::min(mptSmp.nLength, mpt::saturate_trunc<SmpLength>(loopStart * loopScale));
loopLen = std::min(mptSmp.nLength - loopStart, mpt::saturate_trunc<SmpLength>(loopLen * loopScale));
} else if(mptSmp.HasSampleData())
{
// The order of operations here may seem weird as it reduces precision, but it's taken directly from the original assembly source (UpdateRecalcLoop)
Expand Down
2 changes: 1 addition & 1 deletion soundlib/SampleFormatSFZ.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -901,7 +901,7 @@ bool CSoundFile::ReadSFZInstrument(INSTRUMENTINDEX nInstr, FileReader &file)
if(region.ampEnv.release > 0)
{
const double tickDuration = m_PlayState.m_nSamplesPerTick / static_cast<double>(GetSampleRate());
pIns->nFadeOut = std::min(mpt::saturate_cast<uint32>(32768.0 * tickDuration / region.ampEnv.release), uint32(32767));
pIns->nFadeOut = std::min(mpt::saturate_trunc<uint32>(32768.0 * tickDuration / region.ampEnv.release), uint32(32767));
if(GetType() == MOD_TYPE_IT)
pIns->nFadeOut = std::min((pIns->nFadeOut + 16u) & ~31u, uint32(8192));
}
Expand Down
32 changes: 11 additions & 21 deletions src/mpt/base/saturate_cast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,27 @@



#include "mpt/base/detect.hpp"
#include "mpt/base/namespace.hpp"

#include <algorithm>
#include <limits>
#if MPT_CXX_AT_LEAST(26)
#include <numeric>
#endif



namespace mpt {
inline namespace MPT_INLINE_NS {


#if MPT_CXX_AT_LEAST(26)

using std::saturate_cast;

#else

// Saturate the value of src to the domain of Tdst
template <typename Tdst, typename Tsrc>
constexpr Tdst saturate_cast(Tsrc src) noexcept {
Expand Down Expand Up @@ -51,27 +61,7 @@ constexpr Tdst saturate_cast(Tsrc src) noexcept {
}
}

template <typename Tdst>
constexpr Tdst saturate_cast(double src) {
if (src >= static_cast<double>(std::numeric_limits<Tdst>::max())) {
return std::numeric_limits<Tdst>::max();
}
if (src <= static_cast<double>(std::numeric_limits<Tdst>::min())) {
return std::numeric_limits<Tdst>::min();
}
return static_cast<Tdst>(src);
}

template <typename Tdst>
constexpr Tdst saturate_cast(float src) {
if (src >= static_cast<float>(std::numeric_limits<Tdst>::max())) {
return std::numeric_limits<Tdst>::max();
}
if (src <= static_cast<float>(std::numeric_limits<Tdst>::min())) {
return std::numeric_limits<Tdst>::min();
}
return static_cast<Tdst>(src);
}
#endif


} // namespace MPT_INLINE_NS
Expand Down
31 changes: 27 additions & 4 deletions src/mpt/base/saturate_round.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#include "mpt/base/namespace.hpp"

#include "mpt/base/math.hpp"
#include "mpt/base/saturate_cast.hpp"

#include <limits>

Expand All @@ -18,25 +17,49 @@ namespace mpt {
inline namespace MPT_INLINE_NS {



template <typename Tdst>
constexpr Tdst saturate_trunc(double src) {
if (src >= static_cast<double>(std::numeric_limits<Tdst>::max())) {
return std::numeric_limits<Tdst>::max();
}
if (src <= static_cast<double>(std::numeric_limits<Tdst>::min())) {
return std::numeric_limits<Tdst>::min();
}
return static_cast<Tdst>(src);
}

template <typename Tdst>
constexpr Tdst saturate_trunc(float src) {
if (src >= static_cast<float>(std::numeric_limits<Tdst>::max())) {
return std::numeric_limits<Tdst>::max();
}
if (src <= static_cast<float>(std::numeric_limits<Tdst>::min())) {
return std::numeric_limits<Tdst>::min();
}
return static_cast<Tdst>(src);
}


// Rounds given double value to nearest integer value of type T.
// Out-of-range values are saturated to the specified integer type's limits.

template <typename T>
inline T saturate_round(float val) {
static_assert(std::numeric_limits<T>::is_integer);
return mpt::saturate_cast<T>(mpt::round(val));
return mpt::saturate_trunc<T>(mpt::round(val));
}

template <typename T>
inline T saturate_round(double val) {
static_assert(std::numeric_limits<T>::is_integer);
return mpt::saturate_cast<T>(mpt::round(val));
return mpt::saturate_trunc<T>(mpt::round(val));
}

template <typename T>
inline T saturate_round(long double val) {
static_assert(std::numeric_limits<T>::is_integer);
return mpt::saturate_cast<T>(mpt::round(val));
return mpt::saturate_trunc<T>(mpt::round(val));
}


Expand Down
1 change: 0 additions & 1 deletion src/mpt/base/tests/tests_base_saturate_cast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ MPT_TEST_GROUP_INLINE("mpt/base/saturate_cast")

MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast<int32>(std::numeric_limits<uint64>::max() - 1), std::numeric_limits<int32>::max());

MPT_TEST_EXPECT_EQUAL(mpt::saturate_cast<uint32>(static_cast<double>(std::numeric_limits<int64>::max())), std::numeric_limits<uint32>::max());
}

} // namespace saturate_cast
Expand Down
2 changes: 2 additions & 0 deletions src/mpt/base/tests/tests_base_saturate_round.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ MPT_TEST_GROUP_INLINE("mpt/base/saturate_round")
#pragma clang diagnostic pop
#endif
{
MPT_TEST_EXPECT_EQUAL(mpt::saturate_trunc<uint32>(static_cast<double>(std::numeric_limits<int64>::max())), std::numeric_limits<uint32>::max());

MPT_TEST_EXPECT_EQUAL(mpt::saturate_round<int32>(std::numeric_limits<int32>::max() + 0.1), std::numeric_limits<int32>::max());
MPT_TEST_EXPECT_EQUAL(mpt::saturate_round<int32>(std::numeric_limits<int32>::max() - 0.4), std::numeric_limits<int32>::max());
MPT_TEST_EXPECT_EQUAL(mpt::saturate_round<int32>(std::numeric_limits<int32>::min() + 0.1), std::numeric_limits<int32>::min());
Expand Down
22 changes: 21 additions & 1 deletion src/mpt/base/utility.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#if MPT_CXX_BEFORE(20)
#include "mpt/base/saturate_cast.hpp"
#include "mpt/base/saturate_round.hpp"
#endif

#if MPT_CXX_BEFORE(23) && !MPT_COMPILER_MSVC && !MPT_COMPILER_GCC && !MPT_COMPILER_CLANG
Expand Down Expand Up @@ -42,11 +43,30 @@ using std::in_range;

#else

namespace detail {

template <typename Tdst, typename Tsrc>
constexpr Tdst saturate_cast(Tsrc src) noexcept {
return mpt::saturate_cast<Tdst>(src);
}

template <typename Tdst>
constexpr Tdst saturate_cast(double src) {
return mpt::saturate_trunc<Tdst>(src);
}

template <typename Tdst>
constexpr Tdst saturate_cast(float src) {
return mpt::saturate_trunc<Tdst>(src);
}

}

// Returns true iff Tdst can represent the value val.
// Use as if(mpt::in_range<uint8>(-1)).
template <typename Tdst, typename Tsrc>
constexpr bool in_range(Tsrc val) {
return (static_cast<Tsrc>(mpt::saturate_cast<Tdst>(val)) == val);
return (static_cast<Tsrc>(mpt::detail::saturate_cast<Tdst>(val)) == val);
}

#endif
Expand Down
5 changes: 3 additions & 2 deletions src/openmpt/soundbase/SampleConvert.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "mpt/base/macros.hpp"
#include "mpt/base/math.hpp"
#include "mpt/base/saturate_cast.hpp"
#include "mpt/base/saturate_round.hpp"
#include "openmpt/base/Int24.hpp"
#include "openmpt/base/Types.hpp"
#include "openmpt/soundbase/SampleConvert.hpp"
Expand Down Expand Up @@ -566,7 +567,7 @@ struct Convert<int64, somefloat32>
{
val = mpt::safe_clamp(val, -1.0f, 1.0f);
val *= static_cast<float>(uint64(1) << 63);
return mpt::saturate_cast<int64>(SC::fastround(val));
return mpt::saturate_trunc<int64>(SC::fastround(val));
}
};

Expand All @@ -579,7 +580,7 @@ struct Convert<int64, double>
{
val = std::clamp(val, -1.0, 1.0);
val *= static_cast<double>(uint64(1) << 63);
return mpt::saturate_cast<int64>(SC::fastround(val));
return mpt::saturate_trunc<int64>(SC::fastround(val));
}
};

Expand Down
4 changes: 2 additions & 2 deletions src/openmpt/soundbase/SampleConvertFixedPoint.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ struct ConvertToFixedPoint<int32, somefloat32, fractionalBits>
{
static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(input_t) * 8 - 1);
val = mpt::sanitize_nan(val);
return mpt::saturate_cast<output_t>(SC::fastround(val * factor));
return mpt::saturate_trunc<output_t>(SC::fastround(val * factor));
}
};

Expand All @@ -251,7 +251,7 @@ struct ConvertToFixedPoint<int32, somefloat64, fractionalBits>
{
static_assert(fractionalBits >= 0 && fractionalBits <= sizeof(input_t) * 8 - 1);
val = mpt::sanitize_nan(val);
return mpt::saturate_cast<output_t>(SC::fastround(val * factor));
return mpt::saturate_trunc<output_t>(SC::fastround(val * factor));
}
};

Expand Down

0 comments on commit e1750e2

Please sign in to comment.