* Move the ToIntegral function from NCSF specifically to the framework in general, so it can be used in the base framework's code too.
* Use type traits a bit more.
* Move convertTo into the ConvertFuncs class.
| ... | ... |
@@ -23,6 +23,7 @@ |
| 23 | 23 |
#include "XSFCommon.h" |
| 24 | 24 |
#include "common.h" |
| 25 | 25 |
#include "consts.h" |
| 26 |
+#include "convert.h" |
|
| 26 | 27 |
|
| 27 | 28 |
NDSSoundRegister::NDSSoundRegister() : volumeMul(0), volumeDiv(0), panning(0), waveDuty(0), repeatMode(0), format(0), enable(false), |
| 28 | 29 |
source(nullptr), timer(0), psgX(0), psgLast(0), psgLastCount(0), samplePosition(0), sampleIncrease(0), loopStart(0), length(0), totalLength(0) |
| ... | ... |
@@ -123,7 +124,7 @@ void Channel::UpdatePorta(const Track &trk) |
| 123 | 124 |
this->manualSweep = false; |
| 124 | 125 |
this->sweepPitch = trk.sweepPitch; |
| 125 | 126 |
this->sweepCnt = 0; |
| 126 |
- if (!trk.state[ToIntegral(TrackState::PortamentoBit)]) |
|
| 127 |
+ if (!trk.state[ConvertFuncs::ToIntegral(TrackState::PortamentoBit)]) |
|
| 127 | 128 |
{
|
| 128 | 129 |
this->sweepLen = 0; |
| 129 | 130 |
return; |
| ... | ... |
@@ -192,7 +193,7 @@ void Channel::UpdateTrack() |
| 192 | 193 |
if (trackFlags.none()) |
| 193 | 194 |
return; |
| 194 | 195 |
|
| 195 |
- if (trackFlags[ToIntegral(TrackUpdateFlag::Length)]) |
|
| 196 |
+ if (trackFlags[ConvertFuncs::ToIntegral(TrackUpdateFlag::Length)]) |
|
| 196 | 197 |
{
|
| 197 | 198 |
ChannelState st = this->state; |
| 198 | 199 |
if (st > ChannelState::Start) |
| ... | ... |
@@ -203,30 +204,30 @@ void Channel::UpdateTrack() |
| 203 | 204 |
++this->sweepCnt; |
| 204 | 205 |
} |
| 205 | 206 |
} |
| 206 |
- if (trackFlags[ToIntegral(TrackUpdateFlag::Volume)]) |
|
| 207 |
+ if (trackFlags[ConvertFuncs::ToIntegral(TrackUpdateFlag::Volume)]) |
|
| 207 | 208 |
{
|
| 208 | 209 |
this->UpdateVol(trk); |
| 209 |
- this->flags.set(ToIntegral(ChannelFlag::UpdateVolume)); |
|
| 210 |
+ this->flags.set(ConvertFuncs::ToIntegral(ChannelFlag::UpdateVolume)); |
|
| 210 | 211 |
} |
| 211 |
- if (trackFlags[ToIntegral(TrackUpdateFlag::Pan)]) |
|
| 212 |
+ if (trackFlags[ConvertFuncs::ToIntegral(TrackUpdateFlag::Pan)]) |
|
| 212 | 213 |
{
|
| 213 | 214 |
this->UpdatePan(trk); |
| 214 |
- this->flags.set(ToIntegral(ChannelFlag::UpdatePan)); |
|
| 215 |
+ this->flags.set(ConvertFuncs::ToIntegral(ChannelFlag::UpdatePan)); |
|
| 215 | 216 |
} |
| 216 |
- if (trackFlags[ToIntegral(TrackUpdateFlag::Timer)]) |
|
| 217 |
+ if (trackFlags[ConvertFuncs::ToIntegral(TrackUpdateFlag::Timer)]) |
|
| 217 | 218 |
{
|
| 218 | 219 |
this->UpdateTune(trk); |
| 219 |
- this->flags.set(ToIntegral(ChannelFlag::UpdateTimer)); |
|
| 220 |
+ this->flags.set(ConvertFuncs::ToIntegral(ChannelFlag::UpdateTimer)); |
|
| 220 | 221 |
} |
| 221 |
- if (trackFlags[ToIntegral(TrackUpdateFlag::Modulation)]) |
|
| 222 |
+ if (trackFlags[ConvertFuncs::ToIntegral(TrackUpdateFlag::Modulation)]) |
|
| 222 | 223 |
{
|
| 223 | 224 |
int oldType = this->modType; |
| 224 | 225 |
int newType = trk.modType; |
| 225 | 226 |
this->UpdateMod(trk); |
| 226 | 227 |
if (oldType != newType) |
| 227 | 228 |
{
|
| 228 |
- this->flags.set(ToIntegral(getModFlag(oldType))); |
|
| 229 |
- this->flags.set(ToIntegral(getModFlag(newType))); |
|
| 229 |
+ this->flags.set(ConvertFuncs::ToIntegral(getModFlag(oldType))); |
|
| 230 |
+ this->flags.set(ConvertFuncs::ToIntegral(getModFlag(newType))); |
|
| 230 | 231 |
} |
| 231 | 232 |
} |
| 232 | 233 |
} |
| ... | ... |
@@ -444,9 +445,9 @@ void Channel::Update() |
| 444 | 445 |
bool bInStart = this->state == ChannelState::Start; |
| 445 | 446 |
bool bPitchSweep = this->sweepPitch && this->sweepLen && this->sweepCnt <= this->sweepLen; |
| 446 | 447 |
bool bModulation = !!this->modDepth; |
| 447 |
- bool bVolNeedUpdate = this->flags[ToIntegral(ChannelFlag::UpdateVolume)] || bNotInSustain; |
|
| 448 |
- bool bPanNeedUpdate = this->flags[ToIntegral(ChannelFlag::UpdatePan)] || bInStart; |
|
| 449 |
- bool bTmrNeedUpdate = this->flags[ToIntegral(ChannelFlag::UpdateTimer)] || bInStart || bPitchSweep; |
|
| 448 |
+ bool bVolNeedUpdate = this->flags[ConvertFuncs::ToIntegral(ChannelFlag::UpdateVolume)] || bNotInSustain; |
|
| 449 |
+ bool bPanNeedUpdate = this->flags[ConvertFuncs::ToIntegral(ChannelFlag::UpdatePan)] || bInStart; |
|
| 450 |
+ bool bTmrNeedUpdate = this->flags[ConvertFuncs::ToIntegral(ChannelFlag::UpdateTimer)] || bInStart || bPitchSweep; |
|
| 450 | 451 |
int modParam = 0; |
| 451 | 452 |
|
| 452 | 453 |
switch (this->state) |
| ... | ... |
@@ -548,7 +549,7 @@ void Channel::Update() |
| 548 | 549 |
tmr = Timer_Adjust(tmr, totalAdj); |
| 549 | 550 |
this->reg.timer = -tmr; |
| 550 | 551 |
this->reg.sampleIncrease = (ARM7_CLOCK / static_cast<double>(this->ply->sampleRate * 2)) / (0x10000 - this->reg.timer); |
| 551 |
- this->flags.reset(ToIntegral(ChannelFlag::UpdateTimer)); |
|
| 552 |
+ this->flags.reset(ConvertFuncs::ToIntegral(ChannelFlag::UpdateTimer)); |
|
| 552 | 553 |
} |
| 553 | 554 |
|
| 554 | 555 |
if (bVolNeedUpdate || bPanNeedUpdate) |
| ... | ... |
@@ -576,7 +577,7 @@ void Channel::Update() |
| 576 | 577 |
|
| 577 | 578 |
this->vol = static_cast<std::uint16_t>(((cr & SOUND_VOL(0x7F)) << 4) >> calcVolDivShift((cr & SOUND_VOLDIV(3)) >> 8)); |
| 578 | 579 |
|
| 579 |
- this->flags.reset(ToIntegral(ChannelFlag::UpdateVolume)); |
|
| 580 |
+ this->flags.reset(ConvertFuncs::ToIntegral(ChannelFlag::UpdateVolume)); |
|
| 580 | 581 |
} |
| 581 | 582 |
|
| 582 | 583 |
if (bPanNeedUpdate) |
| ... | ... |
@@ -590,7 +591,7 @@ void Channel::Update() |
| 590 | 591 |
|
| 591 | 592 |
cr &= ~SOUND_PAN(0x7F); |
| 592 | 593 |
cr |= SOUND_PAN(realPan); |
| 593 |
- this->flags.reset(ToIntegral(ChannelFlag::UpdatePan)); |
|
| 594 |
+ this->flags.reset(ConvertFuncs::ToIntegral(ChannelFlag::UpdatePan)); |
|
| 594 | 595 |
} |
| 595 | 596 |
|
| 596 | 597 |
this->tempReg.CR = cr; |
| ... | ... |
@@ -18,6 +18,7 @@ |
| 18 | 18 |
#include <cstdint> |
| 19 | 19 |
#include "common.h" |
| 20 | 20 |
#include "consts.h" |
| 21 |
+#include "convert.h" |
|
| 21 | 22 |
|
| 22 | 23 |
struct SWAV; |
| 23 | 24 |
struct Track; |
| ... | ... |
@@ -179,7 +180,7 @@ struct Channel |
| 179 | 180 |
std::uint8_t prio; |
| 180 | 181 |
bool manualSweep; |
| 181 | 182 |
|
| 182 |
- std::bitset<ToIntegral(ChannelFlag::Bits)> flags; |
|
| 183 |
+ std::bitset<ConvertFuncs::ToIntegral(ChannelFlag::Bits)> flags; |
|
| 183 | 184 |
std::int8_t pan; // -64 .. 63 |
| 184 | 185 |
std::int16_t extAmpl; |
| 185 | 186 |
|
| ... | ... |
@@ -9,6 +9,7 @@ |
| 9 | 9 |
#pragma once |
| 10 | 10 |
|
| 11 | 11 |
#include <map> |
| 12 |
+#include <type_traits> |
|
| 12 | 13 |
#include <cstdint> |
| 13 | 14 |
#include "INFOEntry.h" |
| 14 | 15 |
|
| ... | ... |
@@ -16,7 +17,7 @@ struct PseudoFile; |
| 16 | 17 |
|
| 17 | 18 |
template<typename T> struct INFORecord |
| 18 | 19 |
{
|
| 19 |
- std::map<std::uint32_t, T> entries; |
|
| 20 |
+ std::enable_if_t<std::is_base_of_v<INFOEntry, T>, std::map<std::uint32_t, T>> entries; |
|
| 20 | 21 |
|
| 21 | 22 |
INFORecord(); |
| 22 | 23 |
|
| ... | ... |
@@ -13,6 +13,7 @@ |
| 13 | 13 |
#include "SSEQ.h" |
| 14 | 14 |
#include "common.h" |
| 15 | 15 |
#include "consts.h" |
| 16 |
+#include "convert.h" |
|
| 16 | 17 |
|
| 17 | 18 |
Player::Player() : prio(0), nTracks(0), tempo(0), tempoCount(0), tempoRate(0), masterVol(0), sseqVol(0), sseq(nullptr), allowedChannels(0), sampleRate(0), |
| 18 | 19 |
interpolation(Interpolation::None) |
| ... | ... |
@@ -96,8 +97,8 @@ int Player::ChannelAlloc(ChannelAllocateType type, int priority) |
| 96 | 97 |
static const std::uint8_t arraySizes[] = { sizeof(pcmChnArray), sizeof(psgChnArray), sizeof(noiseChnArray) };
|
| 97 | 98 |
static const std::uint8_t *const arrayArray[] = { pcmChnArray, psgChnArray, noiseChnArray };
|
| 98 | 99 |
|
| 99 |
- auto chnArray = arrayArray[ToIntegral(type)]; |
|
| 100 |
- int arraySize = arraySizes[ToIntegral(type)]; |
|
| 100 |
+ auto chnArray = arrayArray[ConvertFuncs::ToIntegral(type)]; |
|
| 101 |
+ int arraySize = arraySizes[ConvertFuncs::ToIntegral(type)]; |
|
| 101 | 102 |
|
| 102 | 103 |
int curChnNo = -1; |
| 103 | 104 |
for (int i = 0; i < arraySize; ++i) |
| ... | ... |
@@ -133,10 +134,10 @@ int Player::TrackAlloc() |
| 133 | 134 |
for (int i = 0; i < FSS_MAXTRACKS; ++i) |
| 134 | 135 |
{
|
| 135 | 136 |
Track &thisTrk = this->tracks[i]; |
| 136 |
- if (!thisTrk.state[ToIntegral(TrackState::AllocateBit)]) |
|
| 137 |
+ if (!thisTrk.state[ConvertFuncs::ToIntegral(TrackState::AllocateBit)]) |
|
| 137 | 138 |
{
|
| 138 | 139 |
thisTrk.Zero(); |
| 139 |
- thisTrk.state.set(ToIntegral(TrackState::AllocateBit)); |
|
| 140 |
+ thisTrk.state.set(ConvertFuncs::ToIntegral(TrackState::AllocateBit)); |
|
| 140 | 141 |
thisTrk.updateFlags.reset(); |
| 141 | 142 |
return i; |
| 142 | 143 |
} |
| ... | ... |
@@ -19,6 +19,7 @@ |
| 19 | 19 |
#include "Track.h" |
| 20 | 20 |
#include "common.h" |
| 21 | 21 |
#include "consts.h" |
| 22 |
+#include "convert.h" |
|
| 22 | 23 |
|
| 23 | 24 |
Track::Track() |
| 24 | 25 |
{
|
| ... | ... |
@@ -71,8 +72,8 @@ void Track::Zero() |
| 71 | 72 |
void Track::ClearState() |
| 72 | 73 |
{
|
| 73 | 74 |
this->state.reset(); |
| 74 |
- this->state.set(ToIntegral(TrackState::AllocateBit)); |
|
| 75 |
- this->state.set(ToIntegral(TrackState::NoteWait)); |
|
| 75 |
+ this->state.set(ConvertFuncs::ToIntegral(TrackState::AllocateBit)); |
|
| 76 |
+ this->state.set(ConvertFuncs::ToIntegral(TrackState::NoteWait)); |
|
| 76 | 77 |
this->prio = this->ply->prio + 64; |
| 77 | 78 |
|
| 78 | 79 |
this->pos = this->startPos; |
| ... | ... |
@@ -253,7 +254,7 @@ int Track::NoteOnTie(std::uint8_t key, int vel) |
| 253 | 254 |
chn->UpdatePorta(*this); |
| 254 | 255 |
|
| 255 | 256 |
this->portaKey = key; |
| 256 |
- chn->flags.set(ToIntegral(ChannelFlag::UpdateTimer)); |
|
| 257 |
+ chn->flags.set(ConvertFuncs::ToIntegral(ChannelFlag::UpdateTimer)); |
|
| 257 | 258 |
|
| 258 | 259 |
return i; |
| 259 | 260 |
} |
| ... | ... |
@@ -493,10 +494,10 @@ static inline std::function<bool (std::int16_t, std::int16_t)> CompareFunc(int c |
| 493 | 494 |
void Track::Run() |
| 494 | 495 |
{
|
| 495 | 496 |
// Indicate "heartbeat" for this track |
| 496 |
- this->updateFlags.set(ToIntegral(TrackUpdateFlag::Length)); |
|
| 497 |
+ this->updateFlags.set(ConvertFuncs::ToIntegral(TrackUpdateFlag::Length)); |
|
| 497 | 498 |
|
| 498 | 499 |
// Exit if the track has already ended |
| 499 |
- if (this->state[ToIntegral(TrackState::End)]) |
|
| 500 |
+ if (this->state[ConvertFuncs::ToIntegral(TrackState::End)]) |
|
| 500 | 501 |
return; |
| 501 | 502 |
|
| 502 | 503 |
if (this->wait) |
| ... | ... |
@@ -521,9 +522,9 @@ void Track::Run() |
| 521 | 522 |
std::uint8_t key = static_cast<std::uint8_t>(cmd + this->transpose); |
| 522 | 523 |
int vel = this->overriding.val<std::uint8_t>(pData, read8, true); |
| 523 | 524 |
int len = this->overriding.val<int>(pData, readvl); |
| 524 |
- if (this->state[ToIntegral(TrackState::NoteWait)]) |
|
| 525 |
+ if (this->state[ConvertFuncs::ToIntegral(TrackState::NoteWait)]) |
|
| 525 | 526 |
this->wait = len; |
| 526 |
- if (this->state[ToIntegral(TrackState::TieBit)]) |
|
| 527 |
+ if (this->state[ConvertFuncs::ToIntegral(TrackState::TieBit)]) |
|
| 527 | 528 |
this->NoteOnTie(key, vel); |
| 528 | 529 |
else |
| 529 | 530 |
this->NoteOn(key, vel, len); |
| ... | ... |
@@ -579,18 +580,18 @@ void Track::Run() |
| 579 | 580 |
|
| 580 | 581 |
case SSEQCommand::Pan: |
| 581 | 582 |
this->pan = this->overriding.val<std::uint8_t>(pData, read8) - 64; |
| 582 |
- this->updateFlags.set(ToIntegral(TrackUpdateFlag::Pan)); |
|
| 583 |
+ this->updateFlags.set(ConvertFuncs::ToIntegral(TrackUpdateFlag::Pan)); |
|
| 583 | 584 |
break; |
| 584 | 585 |
|
| 585 | 586 |
case SSEQCommand::Volume: |
| 586 | 587 |
this->vol = this->overriding.val<std::uint8_t>(pData, read8); |
| 587 |
- this->updateFlags.set(ToIntegral(TrackUpdateFlag::Volume)); |
|
| 588 |
+ this->updateFlags.set(ConvertFuncs::ToIntegral(TrackUpdateFlag::Volume)); |
|
| 588 | 589 |
break; |
| 589 | 590 |
|
| 590 | 591 |
case SSEQCommand::MasterVolume: |
| 591 | 592 |
this->ply->masterVol = Cnv_Sust(this->overriding.val<std::uint8_t>(pData, read8)); |
| 592 | 593 |
for (std::uint8_t i = 0; i < this->ply->nTracks; ++i) |
| 593 |
- this->ply->tracks[this->ply->trackIds[i]].updateFlags.set(ToIntegral(TrackUpdateFlag::Volume)); |
|
| 594 |
+ this->ply->tracks[this->ply->trackIds[i]].updateFlags.set(ConvertFuncs::ToIntegral(TrackUpdateFlag::Volume)); |
|
| 594 | 595 |
break; |
| 595 | 596 |
|
| 596 | 597 |
case SSEQCommand::Priority: |
| ... | ... |
@@ -599,17 +600,17 @@ void Track::Run() |
| 599 | 600 |
break; |
| 600 | 601 |
|
| 601 | 602 |
case SSEQCommand::NoteWait: |
| 602 |
- this->state.set(ToIntegral(TrackState::NoteWait), !!read8(pData)); |
|
| 603 |
+ this->state.set(ConvertFuncs::ToIntegral(TrackState::NoteWait), !!read8(pData)); |
|
| 603 | 604 |
break; |
| 604 | 605 |
|
| 605 | 606 |
case SSEQCommand::Tie: |
| 606 |
- this->state.set(ToIntegral(TrackState::TieBit), !!read8(pData)); |
|
| 607 |
+ this->state.set(ConvertFuncs::ToIntegral(TrackState::TieBit), !!read8(pData)); |
|
| 607 | 608 |
this->ReleaseAllNotes(); |
| 608 | 609 |
break; |
| 609 | 610 |
|
| 610 | 611 |
case SSEQCommand::Expression: |
| 611 | 612 |
this->expr = this->overriding.val<std::uint8_t>(pData, read8); |
| 612 |
- this->updateFlags.set(ToIntegral(TrackUpdateFlag::Volume)); |
|
| 613 |
+ this->updateFlags.set(ConvertFuncs::ToIntegral(TrackUpdateFlag::Volume)); |
|
| 613 | 614 |
break; |
| 614 | 615 |
|
| 615 | 616 |
case SSEQCommand::Tempo: |
| ... | ... |
@@ -617,7 +618,7 @@ void Track::Run() |
| 617 | 618 |
break; |
| 618 | 619 |
|
| 619 | 620 |
case SSEQCommand::End: |
| 620 |
- this->state.set(ToIntegral(TrackState::End)); |
|
| 621 |
+ this->state.set(ConvertFuncs::ToIntegral(TrackState::End)); |
|
| 621 | 622 |
return; |
| 622 | 623 |
|
| 623 | 624 |
case SSEQCommand::LoopStart: |
| ... | ... |
@@ -652,12 +653,12 @@ void Track::Run() |
| 652 | 653 |
|
| 653 | 654 |
case SSEQCommand::PitchBend: |
| 654 | 655 |
this->pitchBend = this->overriding.val<std::int8_t>(pData, read8); |
| 655 |
- this->updateFlags.set(ToIntegral(TrackUpdateFlag::Timer)); |
|
| 656 |
+ this->updateFlags.set(ConvertFuncs::ToIntegral(TrackUpdateFlag::Timer)); |
|
| 656 | 657 |
break; |
| 657 | 658 |
|
| 658 | 659 |
case SSEQCommand::PitchBendRange: |
| 659 | 660 |
this->pitchBendRange = read8(pData); |
| 660 |
- this->updateFlags.set(ToIntegral(TrackUpdateFlag::Timer)); |
|
| 661 |
+ this->updateFlags.set(ConvertFuncs::ToIntegral(TrackUpdateFlag::Timer)); |
|
| 661 | 662 |
break; |
| 662 | 663 |
|
| 663 | 664 |
//----------------------------------------------------------------- |
| ... | ... |
@@ -686,24 +687,24 @@ void Track::Run() |
| 686 | 687 |
|
| 687 | 688 |
case SSEQCommand::PortamentoKey: |
| 688 | 689 |
this->portaKey = static_cast<std::uint8_t>(read8(pData) + this->transpose); |
| 689 |
- this->state.set(ToIntegral(TrackState::PortamentoBit)); |
|
| 690 |
+ this->state.set(ConvertFuncs::ToIntegral(TrackState::PortamentoBit)); |
|
| 690 | 691 |
// Update here? |
| 691 | 692 |
break; |
| 692 | 693 |
|
| 693 | 694 |
case SSEQCommand::PortamentoFlag: |
| 694 |
- this->state.set(ToIntegral(TrackState::PortamentoBit), !!read8(pData)); |
|
| 695 |
+ this->state.set(ConvertFuncs::ToIntegral(TrackState::PortamentoBit), !!read8(pData)); |
|
| 695 | 696 |
// Update here? |
| 696 | 697 |
break; |
| 697 | 698 |
|
| 698 | 699 |
case SSEQCommand::PortamentoTime: |
| 699 | 700 |
this->portaTime = this->overriding.val<std::uint8_t>(pData, read8); |
| 700 |
- this->state.set(ToIntegral(TrackState::PortamentoBit)); |
|
| 701 |
+ this->state.set(ConvertFuncs::ToIntegral(TrackState::PortamentoBit)); |
|
| 701 | 702 |
// Update here? |
| 702 | 703 |
break; |
| 703 | 704 |
|
| 704 | 705 |
case SSEQCommand::SweepPitch: |
| 705 | 706 |
this->sweepPitch = this->overriding.val<std::int16_t>(pData, read16); |
| 706 |
- this->state.set(ToIntegral(TrackState::PortamentoBit)); |
|
| 707 |
+ this->state.set(ConvertFuncs::ToIntegral(TrackState::PortamentoBit)); |
|
| 707 | 708 |
// Update here? |
| 708 | 709 |
break; |
| 709 | 710 |
|
| ... | ... |
@@ -713,27 +714,27 @@ void Track::Run() |
| 713 | 714 |
|
| 714 | 715 |
case SSEQCommand::ModulationDepth: |
| 715 | 716 |
this->modDepth = this->overriding.val<std::uint8_t>(pData, read8); |
| 716 |
- this->updateFlags.set(ToIntegral(TrackUpdateFlag::Modulation)); |
|
| 717 |
+ this->updateFlags.set(ConvertFuncs::ToIntegral(TrackUpdateFlag::Modulation)); |
|
| 717 | 718 |
break; |
| 718 | 719 |
|
| 719 | 720 |
case SSEQCommand::ModulationSpeed: |
| 720 | 721 |
this->modSpeed = this->overriding.val<std::uint8_t>(pData, read8); |
| 721 |
- this->updateFlags.set(ToIntegral(TrackUpdateFlag::Modulation)); |
|
| 722 |
+ this->updateFlags.set(ConvertFuncs::ToIntegral(TrackUpdateFlag::Modulation)); |
|
| 722 | 723 |
break; |
| 723 | 724 |
|
| 724 | 725 |
case SSEQCommand::ModulationType: |
| 725 | 726 |
this->modType = read8(pData); |
| 726 |
- this->updateFlags.set(ToIntegral(TrackUpdateFlag::Modulation)); |
|
| 727 |
+ this->updateFlags.set(ConvertFuncs::ToIntegral(TrackUpdateFlag::Modulation)); |
|
| 727 | 728 |
break; |
| 728 | 729 |
|
| 729 | 730 |
case SSEQCommand::ModulationRange: |
| 730 | 731 |
this->modRange = read8(pData); |
| 731 |
- this->updateFlags.set(ToIntegral(TrackUpdateFlag::Modulation)); |
|
| 732 |
+ this->updateFlags.set(ConvertFuncs::ToIntegral(TrackUpdateFlag::Modulation)); |
|
| 732 | 733 |
break; |
| 733 | 734 |
|
| 734 | 735 |
case SSEQCommand::ModulationDelay: |
| 735 | 736 |
this->modDelay = this->overriding.val<std::uint16_t>(pData, read16); |
| 736 |
- this->updateFlags.set(ToIntegral(TrackUpdateFlag::Modulation)); |
|
| 737 |
+ this->updateFlags.set(ConvertFuncs::ToIntegral(TrackUpdateFlag::Modulation)); |
|
| 737 | 738 |
break; |
| 738 | 739 |
|
| 739 | 740 |
//----------------------------------------------------------------- |
| ... | ... |
@@ -744,7 +745,7 @@ void Track::Run() |
| 744 | 745 |
{
|
| 745 | 746 |
this->overriding() = true; |
| 746 | 747 |
this->overriding.cmd = read8(pData); |
| 747 |
- if ((this->overriding.cmd >= ToIntegral(SSEQCommand::SetVariable) && this->overriding.cmd <= ToIntegral(SSEQCommand::CompareNotEqualTo)) || this->overriding.cmd < 0x80) |
|
| 748 |
+ if ((this->overriding.cmd >= ConvertFuncs::ToIntegral(SSEQCommand::SetVariable) && this->overriding.cmd <= ConvertFuncs::ToIntegral(SSEQCommand::CompareNotEqualTo)) || this->overriding.cmd < 0x80) |
|
| 748 | 749 |
this->overriding.extraValue = read8(pData); |
| 749 | 750 |
std::int16_t minVal = static_cast<std::int16_t>(read16(pData)); |
| 750 | 751 |
std::int16_t maxVal = static_cast<std::int16_t>(read16(pData)); |
| ... | ... |
@@ -759,7 +760,7 @@ void Track::Run() |
| 759 | 760 |
case SSEQCommand::FromVariable: |
| 760 | 761 |
this->overriding() = true; |
| 761 | 762 |
this->overriding.cmd = read8(pData); |
| 762 |
- if ((this->overriding.cmd >= ToIntegral(SSEQCommand::SetVariable) && this->overriding.cmd <= ToIntegral(SSEQCommand::CompareNotEqualTo)) || this->overriding.cmd < 0x80) |
|
| 763 |
+ if ((this->overriding.cmd >= ConvertFuncs::ToIntegral(SSEQCommand::SetVariable) && this->overriding.cmd <= ConvertFuncs::ToIntegral(SSEQCommand::CompareNotEqualTo)) || this->overriding.cmd < 0x80) |
|
| 763 | 764 |
this->overriding.extraValue = read8(pData); |
| 764 | 765 |
this->overriding.value = this->ply->variables[read8(pData)]; |
| 765 | 766 |
break; |
| ... | ... |
@@ -774,7 +775,7 @@ void Track::Run() |
| 774 | 775 |
{
|
| 775 | 776 |
std::int8_t varNo = this->overriding.val<std::int8_t>(pData, read8, true); |
| 776 | 777 |
value = this->overriding.val<std::int16_t>(pData, read16); |
| 777 |
- if (cmd == ToIntegral(SSEQCommand::DivideVariable) && !value) // Division by 0, skip it to prevent crashing |
|
| 778 |
+ if (cmd == ConvertFuncs::ToIntegral(SSEQCommand::DivideVariable) && !value) // Division by 0, skip it to prevent crashing |
|
| 778 | 779 |
break; |
| 779 | 780 |
this->ply->variables[varNo] = VarFunc(cmd)(this->ply->variables[varNo], static_cast<std::int16_t>(value)); |
| 780 | 781 |
break; |
| ... | ... |
@@ -808,7 +809,7 @@ void Track::Run() |
| 808 | 809 |
if (extraByte) |
| 809 | 810 |
{
|
| 810 | 811 |
int extraCmd = read8(pData); |
| 811 |
- if ((extraCmd >= ToIntegral(SSEQCommand::SetVariable) && extraCmd <= ToIntegral(SSEQCommand::CompareNotEqualTo)) || extraCmd < 0x80) |
|
| 812 |
+ if ((extraCmd >= ConvertFuncs::ToIntegral(SSEQCommand::SetVariable) && extraCmd <= ConvertFuncs::ToIntegral(SSEQCommand::CompareNotEqualTo)) || extraCmd < 0x80) |
|
| 812 | 813 |
++cmdBytes; |
| 813 | 814 |
} |
| 814 | 815 |
*pData += cmdBytes; |
| ... | ... |
@@ -822,7 +823,7 @@ void Track::Run() |
| 822 | 823 |
} |
| 823 | 824 |
} |
| 824 | 825 |
|
| 825 |
- if (cmd != ToIntegral(SSEQCommand::Random) && cmd != ToIntegral(SSEQCommand::FromVariable)) |
|
| 826 |
+ if (cmd != ConvertFuncs::ToIntegral(SSEQCommand::Random) && cmd != ConvertFuncs::ToIntegral(SSEQCommand::FromVariable)) |
|
| 826 | 827 |
this->overriding() = false; |
| 827 | 828 |
} |
| 828 | 829 |
} |
| ... | ... |
@@ -14,6 +14,7 @@ |
| 14 | 14 |
#include <cstdint> |
| 15 | 15 |
#include "common.h" |
| 16 | 16 |
#include "consts.h" |
| 17 |
+#include "convert.h" |
|
| 17 | 18 |
|
| 18 | 19 |
struct Player; |
| 19 | 20 |
|
| ... | ... |
@@ -55,7 +56,7 @@ struct Track |
| 55 | 56 |
{
|
| 56 | 57 |
std::int8_t trackId; |
| 57 | 58 |
|
| 58 |
- std::bitset<ToIntegral(TrackState::Bits)> state; |
|
| 59 |
+ std::bitset<ConvertFuncs::ToIntegral(TrackState::Bits)> state; |
|
| 59 | 60 |
std::uint8_t num, prio; |
| 60 | 61 |
Player *ply; |
| 61 | 62 |
|
| ... | ... |
@@ -82,7 +83,7 @@ struct Track |
| 82 | 83 |
std::uint8_t modType, modSpeed, modDepth, modRange; |
| 83 | 84 |
std::uint16_t modDelay; |
| 84 | 85 |
|
| 85 |
- std::bitset<ToIntegral(TrackUpdateFlag::Bits)> updateFlags; |
|
| 86 |
+ std::bitset<ConvertFuncs::ToIntegral(TrackUpdateFlag::Bits)> updateFlags; |
|
| 86 | 87 |
|
| 87 | 88 |
Track(); |
| 88 | 89 |
|
| ... | ... |
@@ -29,7 +29,7 @@ struct PseudoFile |
| 29 | 29 |
{
|
| 30 | 30 |
} |
| 31 | 31 |
|
| 32 |
- template<typename T> T ReadLE() |
|
| 32 |
+ template<typename T> typename std::enable_if_t<std::is_integral_v<T>, T> ReadLE() |
|
| 33 | 33 |
{
|
| 34 | 34 |
T finalVal = 0; |
| 35 | 35 |
for (std::size_t i = 0; i < sizeof(T); ++i) |
| ... | ... |
@@ -37,7 +37,7 @@ struct PseudoFile |
| 37 | 37 |
return finalVal; |
| 38 | 38 |
} |
| 39 | 39 |
|
| 40 |
- template<typename T, std::size_t N> void ReadLE(T (&arr)[N]) |
|
| 40 |
+ template<typename T, std::size_t N> typename std::enable_if_t<std::is_integral_v<T>> ReadLE(T (&arr)[N]) |
|
| 41 | 41 |
{
|
| 42 | 42 |
for (std::size_t i = 0; i < N; ++i) |
| 43 | 43 |
arr[i] = this->ReadLE<T>(); |
| ... | ... |
@@ -49,7 +49,7 @@ struct PseudoFile |
| 49 | 49 |
this->pos += N; |
| 50 | 50 |
} |
| 51 | 51 |
|
| 52 |
- template<typename T> void ReadLE(std::vector<T> &arr) |
|
| 52 |
+ template<typename T> typename std::enable_if_t<std::is_integral_v<T>> ReadLE(std::vector<T> &arr) |
|
| 53 | 53 |
{
|
| 54 | 54 |
for (std::size_t i = 0, len = arr.size(); i < len; ++i) |
| 55 | 55 |
arr[i] = this->ReadLE<T>(); |
| ... | ... |
@@ -83,7 +83,7 @@ struct PseudoFile |
| 83 | 83 |
* as little-endian formating. |
| 84 | 84 |
*/ |
| 85 | 85 |
|
| 86 |
-template<typename T> inline T ReadLE(const std::uint8_t *arr) |
|
| 86 |
+template<typename T> inline typename std::enable_if_t<std::is_integral_v<T>, T> ReadLE(const std::uint8_t *arr) |
|
| 87 | 87 |
{
|
| 88 | 88 |
T finalVal = 0; |
| 89 | 89 |
for (std::size_t i = 0; i < sizeof(T); ++i) |
| ... | ... |
@@ -97,7 +97,7 @@ template<typename T> inline T ReadLE(const std::uint8_t *arr) |
| 97 | 97 |
* integers are in the format of 0x00, 16-bit integers are in the format of |
| 98 | 98 |
* 0x0000, and so on. |
| 99 | 99 |
*/ |
| 100 |
-template<typename T> inline std::string NumToHexString(const T &num) |
|
| 100 |
+template<typename T> inline typename std::enable_if_t<std::is_integral_v<T>, std::string> NumToHexString(const T &num) |
|
| 101 | 101 |
{
|
| 102 | 102 |
std::string hex; |
| 103 | 103 |
std::uint8_t len = sizeof(T) * 2; |
| ... | ... |
@@ -123,12 +123,6 @@ inline constexpr int REC_GROUP = 5; |
| 123 | 123 |
inline constexpr int REC_PLAYER2 = 6; |
| 124 | 124 |
inline constexpr int REC_STRM = 7; |
| 125 | 125 |
|
| 126 |
-// Comes from https://stackoverflow.com/a/14589519 |
|
| 127 |
-template<typename T> inline constexpr auto ToIntegral(const T &e) |
|
| 128 |
-{
|
|
| 129 |
- return static_cast<std::underlying_type_t<T>>(e); |
|
| 130 |
-} |
|
| 131 |
- |
|
| 132 | 126 |
template<std::size_t N> inline bool VerifyHeader(std::int8_t (&arr)[N], const std::string &header) |
| 133 | 127 |
{
|
| 134 | 128 |
std::string arrHeader = std::string(&arr[0], &arr[N]); |
| ... | ... |
@@ -312,7 +312,7 @@ void XSFConfig_NCSF::RefreshSoundView() |
| 312 | 312 |
} |
| 313 | 313 |
|
| 314 | 314 |
static const std::wstring states[] = { L"NONE", L"START", L"ATTACK", L"DECAY", L"SUSTAIN", L"RELEASE" };
|
| 315 |
- SetDlgItemTextW(hDlg, IDC_SOUND0STATE + chanId, states[ToIntegral(chn.state)].c_str()); |
|
| 315 |
+ SetDlgItemTextW(hDlg, IDC_SOUND0STATE + chanId, states[ConvertFuncs::ToIntegral(chn.state)].c_str()); |
|
| 316 | 316 |
|
| 317 | 317 |
SetDlgItemTextW(hDlg, IDC_SOUND0PNT + chanId, (L"samp #" + std::to_wstring(chn.reg.loopStart)).c_str()); |
| 318 | 318 |
|
| ... | ... |
@@ -7,9 +7,10 @@ |
| 7 | 7 |
|
| 8 | 8 |
#pragma once |
| 9 | 9 |
|
| 10 |
-#include <limits> |
|
| 11 | 10 |
#include <fstream> |
| 11 |
+#include <limits> |
|
| 12 | 12 |
#include <string> |
| 13 |
+#include <type_traits> |
|
| 13 | 14 |
#define _USE_MATH_DEFINES |
| 14 | 15 |
#include <cmath> |
| 15 | 16 |
#include <cstddef> |
| ... | ... |
@@ -19,7 +20,7 @@ |
| 19 | 20 |
#include "convert.h" |
| 20 | 21 |
|
| 21 | 22 |
// Code from http://learningcppisfun.blogspot.com/2010/04/comparing-floating-point-numbers.html |
| 22 |
-template<typename T> inline bool fEqual(T x, T y, int N = 1) |
|
| 23 |
+template<typename T> inline typename std::enable_if_t<std::is_floating_point_v<T>, bool> fEqual(T x, T y, int N = 1) |
|
| 23 | 24 |
{
|
| 24 | 25 |
T diff = std::abs(x - y); |
| 25 | 26 |
T tolerance = N * std::numeric_limits<T>::epsilon(); |
| ... | ... |
@@ -40,7 +41,7 @@ inline std::uint32_t Get32BitsLE(std::ifstream &input) |
| 40 | 41 |
|
| 41 | 42 |
// Code from the following answer on Stack Overflow: |
| 42 | 43 |
// http://stackoverflow.com/a/15479212 |
| 43 |
-template<typename T> inline T NextHighestPowerOf2(T value) |
|
| 44 |
+template<typename T> inline typename std::enable_if_t<std::is_integral_v<T>, T> NextHighestPowerOf2(T value) |
|
| 44 | 45 |
{
|
| 45 | 46 |
if (value < 1) |
| 46 | 47 |
return 1; |
| ... | ... |
@@ -270,8 +270,8 @@ void XSFConfig::InitializeConfigDialog(XSFConfigDialog *dialog) |
| 270 | 270 |
dialog->skipSilenceOnStart = ConvertFuncs::MSToString(this->skipSilenceOnStartSec); |
| 271 | 271 |
dialog->detectSilence = ConvertFuncs::MSToString(this->detectSilenceSec); |
| 272 | 272 |
dialog->volume = this->volume; |
| 273 |
- dialog->replayGain = static_cast<std::underlying_type_t<VolumeType>>(this->volumeType); |
|
| 274 |
- dialog->clipProtect = static_cast<std::underlying_type_t<PeakType>>(this->peakType); |
|
| 273 |
+ dialog->replayGain = ConvertFuncs::ToIntegral(this->volumeType); |
|
| 274 |
+ dialog->clipProtect = ConvertFuncs::ToIntegral(this->peakType); |
|
| 275 | 275 |
auto found = std::find(this->supportedSampleRates.begin(), this->supportedSampleRates.end(), this->sampleRate); |
| 276 | 276 |
dialog->sampleRate = found == this->supportedSampleRates.end() ? 0 : found - this->supportedSampleRates.begin(); |
| 277 | 277 |
dialog->titleFormat = this->titleFormat; |
| ... | ... |
@@ -287,8 +287,8 @@ void XSFConfig::ResetConfigDefaults(XSFConfigDialog *dialog) |
| 287 | 287 |
dialog->skipSilenceOnStart = XSFConfig::initSkipSilenceOnStartSec; |
| 288 | 288 |
dialog->detectSilence = XSFConfig::initDetectSilenceSec; |
| 289 | 289 |
dialog->volume = XSFConfig::initVolume; |
| 290 |
- dialog->replayGain = static_cast<std::underlying_type_t<VolumeType>>(XSFConfig::initVolumeType); |
|
| 291 |
- dialog->clipProtect = static_cast<std::underlying_type_t<PeakType>>(XSFConfig::initPeakType); |
|
| 290 |
+ dialog->replayGain = ConvertFuncs::ToIntegral(XSFConfig::initVolumeType); |
|
| 291 |
+ dialog->clipProtect = ConvertFuncs::ToIntegral(XSFConfig::initPeakType); |
|
| 292 | 292 |
auto found = std::find(this->supportedSampleRates.begin(), this->supportedSampleRates.end(), XSFConfig::initSampleRate); |
| 293 | 293 |
dialog->sampleRate = found == this->supportedSampleRates.end() ? 0 : found - this->supportedSampleRates.begin(); |
| 294 | 294 |
dialog->titleFormat = XSFConfig::initTitleFormat; |
| ... | ... |
@@ -26,17 +26,17 @@ private: |
| 26 | 26 |
// enum versions |
| 27 | 27 |
template<typename T> typename std::enable_if_t<std::is_enum_v<T>, T> GetValueInternal(const std::string &name, const T &defaultValue) const |
| 28 | 28 |
{
|
| 29 |
- return convertTo<T>(this->GetValueString(name, std::to_string(static_cast<std::underlying_type_t<T>>(defaultValue)))); |
|
| 29 |
+ return ConvertFuncs::To<T>(this->GetValueString(name, std::to_string(ConvertFuncs::ToIntegral(defaultValue)))); |
|
| 30 | 30 |
} |
| 31 | 31 |
template<typename T> typename std::enable_if_t<std::is_enum_v<T>> SetValueInternal(const std::string &name, const T &value) |
| 32 | 32 |
{
|
| 33 |
- this->SetValueString(name, std::to_string(static_cast<std::underlying_type_t<T>>(value))); |
|
| 33 |
+ this->SetValueString(name, std::to_string(ConvertFuncs::ToIntegral(value))); |
|
| 34 | 34 |
} |
| 35 | 35 |
|
| 36 | 36 |
// non-enum versions |
| 37 | 37 |
template<typename T> typename std::enable_if_t<!std::is_enum_v<T> && std::is_arithmetic_v<T>, T> GetValueInternal(const std::string &name, const T &defaultValue) const |
| 38 | 38 |
{
|
| 39 |
- return convertTo<T>(this->GetValueString(name, std::to_string(defaultValue))); |
|
| 39 |
+ return ConvertFuncs::To<T>(this->GetValueString(name, std::to_string(defaultValue))); |
|
| 40 | 40 |
} |
| 41 | 41 |
template<typename T> typename std::enable_if_t<!std::is_enum_v<T> && std::is_arithmetic_v<T>> SetValueInternal(const std::string &name, const T &value) |
| 42 | 42 |
{
|
| ... | ... |
@@ -301,24 +301,24 @@ double XSFFile::GetVolume(VolumeType preferredVolumeType, PeakType preferredPeak |
| 301 | 301 |
bool hadReplayGain = false; |
| 302 | 302 |
if (preferredVolumeType == VolumeType::ReplayGainAlbum && !replaygain_album_gain.empty()) |
| 303 | 303 |
{
|
| 304 |
- gain = convertTo<double>(replaygain_album_gain); |
|
| 304 |
+ gain = ConvertFuncs::To<double>(replaygain_album_gain); |
|
| 305 | 305 |
hadReplayGain = true; |
| 306 | 306 |
} |
| 307 | 307 |
if (!hadReplayGain && preferredVolumeType != VolumeType::Volume && !replaygain_track_gain.empty()) |
| 308 | 308 |
{
|
| 309 |
- gain = convertTo<double>(replaygain_track_gain); |
|
| 309 |
+ gain = ConvertFuncs::To<double>(replaygain_track_gain); |
|
| 310 | 310 |
hadReplayGain = true; |
| 311 | 311 |
} |
| 312 | 312 |
if (hadReplayGain) |
| 313 | 313 |
{
|
| 314 | 314 |
double vol = std::pow(10.0, gain / 20.0), peak = 1.0; |
| 315 | 315 |
if (preferredPeakType == PeakType::ReplayGainAlbum && !replaygain_album_peak.empty()) |
| 316 |
- peak = convertTo<double>(replaygain_album_peak); |
|
| 316 |
+ peak = ConvertFuncs::To<double>(replaygain_album_peak); |
|
| 317 | 317 |
else if (preferredPeakType != PeakType::None && !replaygain_track_peak.empty()) |
| 318 |
- peak = convertTo<double>(replaygain_track_peak); |
|
| 318 |
+ peak = ConvertFuncs::To<double>(replaygain_track_peak); |
|
| 319 | 319 |
return !fEqual(peak, 1.0) ? std::min(vol, 1.0 / peak) : vol; |
| 320 | 320 |
} |
| 321 |
- return volume.empty() ? 1.0 : convertTo<double>(volume); |
|
| 321 |
+ return volume.empty() ? 1.0 : ConvertFuncs::To<double>(volume); |
|
| 322 | 322 |
} |
| 323 | 323 |
|
| 324 | 324 |
std::string XSFFile::FormattedTitleOptionalBlock(const std::string &block, bool &hadReplacement, unsigned level) const |
| ... | ... |
@@ -61,7 +61,7 @@ public: |
| 61 | 61 |
std::string GetTagValue(const std::string &name) const; |
| 62 | 62 |
template<typename T> T GetTagValue(const std::string &name, const T &defaultValue) const |
| 63 | 63 |
{
|
| 64 |
- return this->GetTagExists(name) ? convertTo<T>(this->GetTagValue(name)) : defaultValue; |
|
| 64 |
+ return this->GetTagExists(name) ? ConvertFuncs::To<T>(this->GetTagValue(name)) : defaultValue; |
|
| 65 | 65 |
} |
| 66 | 66 |
unsigned long GetLengthMS(unsigned long defaultLength) const; |
| 67 | 67 |
unsigned long GetFadeMS(unsigned long defaultFade) const; |
| ... | ... |
@@ -13,47 +13,6 @@ |
| 13 | 13 |
#include <cstddef> |
| 14 | 14 |
#include "windowsh_wrapper.h" |
| 15 | 15 |
|
| 16 |
-/* |
|
| 17 |
- * Originally the convert* functions came from the C++ FAQ, Miscellaneous Technical Issues: |
|
| 18 |
- * https://isocpp.org/wiki/faq/misc-technical-issues#convert-string-to-any |
|
| 19 |
- * |
|
| 20 |
- * They have been replaced with a couple functions that use the C++11 std::enable_if |
|
| 21 |
- * construct along with various other type traits constructs to use the proper |
|
| 22 |
- * string conversions. |
|
| 23 |
- */ |
|
| 24 |
-template<typename T, typename S> inline typename std::enable_if_t<!std::is_enum_v<T> &&std::is_arithmetic_v<T>, T> convertTo(const std::basic_string<S> &s) |
|
| 25 |
-{
|
|
| 26 |
- if (std::is_integral_v<T>) |
|
| 27 |
- {
|
|
| 28 |
- if (std::is_unsigned_v<T>) |
|
| 29 |
- {
|
|
| 30 |
- if (std::is_same_v<unsigned long long, std::remove_cv_t<T>>) |
|
| 31 |
- return static_cast<T>(std::stoull(s)); |
|
| 32 |
- else |
|
| 33 |
- return static_cast<T>(std::stoul(s)); |
|
| 34 |
- } |
|
| 35 |
- else if (std::is_same_v<long long, std::remove_cv_t<T>>) |
|
| 36 |
- return static_cast<T>(std::stoll(s)); |
|
| 37 |
- else if (std::is_same_v<long, std::remove_cv_t<T>>) |
|
| 38 |
- return static_cast<T>(std::stol(s)); |
|
| 39 |
- else |
|
| 40 |
- return static_cast<T>(std::stoi(s)); |
|
| 41 |
- } |
|
| 42 |
- else if (std::is_floating_point_v<T>) |
|
| 43 |
- {
|
|
| 44 |
- if (std::is_same_v<long double, std::remove_cv_t<T>>) |
|
| 45 |
- return static_cast<T>(std::stold(s)); |
|
| 46 |
- else if (std::is_same_v<double, std::remove_cv_t<T>>) |
|
| 47 |
- return static_cast<T>(std::stod(s)); |
|
| 48 |
- else |
|
| 49 |
- return static_cast<T>(std::stof(s)); |
|
| 50 |
- } |
|
| 51 |
-} |
|
| 52 |
-template<typename T, typename S> inline typename std::enable_if_t<std::is_enum_v<T>, T> convertTo(const std::basic_string<S> &s) |
|
| 53 |
-{
|
|
| 54 |
- return static_cast<T>(convertTo<std::underlying_type_t<T>>(s)); |
|
| 55 |
-} |
|
| 56 |
- |
|
| 57 | 16 |
// Miscellaneous conversion functions |
| 58 | 17 |
class ConvertFuncs |
| 59 | 18 |
{
|
| ... | ... |
@@ -69,8 +28,55 @@ private: |
| 69 | 28 |
return false; |
| 70 | 29 |
return true; |
| 71 | 30 |
} |
| 72 |
- |
|
| 73 | 31 |
public: |
| 32 |
+ /* |
|
| 33 |
+ * Originally the convert* functions came from the C++ FAQ, Miscellaneous Technical Issues: |
|
| 34 |
+ * https://isocpp.org/wiki/faq/misc-technical-issues#convert-string-to-any |
|
| 35 |
+ * |
|
| 36 |
+ * They have been replaced with a couple functions that use the C++11 std::enable_if |
|
| 37 |
+ * construct along with various other type traits constructs to use the proper |
|
| 38 |
+ * string conversions. |
|
| 39 |
+ */ |
|
| 40 |
+ template<typename T, typename S> static typename std::enable_if_t<!std::is_enum_v<T> && std::is_arithmetic_v<T>, T> To(const std::basic_string<S> &s) |
|
| 41 |
+ {
|
|
| 42 |
+ if (std::is_integral_v<T>) |
|
| 43 |
+ {
|
|
| 44 |
+ if (std::is_unsigned_v<T>) |
|
| 45 |
+ {
|
|
| 46 |
+ if (std::is_same_v<unsigned long long, std::remove_cv_t<T>>) |
|
| 47 |
+ return static_cast<T>(std::stoull(s)); |
|
| 48 |
+ else |
|
| 49 |
+ return static_cast<T>(std::stoul(s)); |
|
| 50 |
+ } |
|
| 51 |
+ else if (std::is_same_v<long long, std::remove_cv_t<T>>) |
|
| 52 |
+ return static_cast<T>(std::stoll(s)); |
|
| 53 |
+ else if (std::is_same_v<long, std::remove_cv_t<T>>) |
|
| 54 |
+ return static_cast<T>(std::stol(s)); |
|
| 55 |
+ else |
|
| 56 |
+ return static_cast<T>(std::stoi(s)); |
|
| 57 |
+ } |
|
| 58 |
+ else if (std::is_floating_point_v<T>) |
|
| 59 |
+ {
|
|
| 60 |
+ if (std::is_same_v<long double, std::remove_cv_t<T>>) |
|
| 61 |
+ return static_cast<T>(std::stold(s)); |
|
| 62 |
+ else if (std::is_same_v<double, std::remove_cv_t<T>>) |
|
| 63 |
+ return static_cast<T>(std::stod(s)); |
|
| 64 |
+ else |
|
| 65 |
+ return static_cast<T>(std::stof(s)); |
|
| 66 |
+ } |
|
| 67 |
+ } |
|
| 68 |
+ |
|
| 69 |
+ template<typename T, typename S> static typename std::enable_if_t<std::is_enum_v<T>, T> To(const std::basic_string<S> &s) |
|
| 70 |
+ {
|
|
| 71 |
+ return static_cast<T>(ConvertFuncs::To<std::underlying_type_t<T>>(s)); |
|
| 72 |
+ } |
|
| 73 |
+ |
|
| 74 |
+ // Comes from https://stackoverflow.com/a/14589519 |
|
| 75 |
+ template<typename T> static constexpr typename std::enable_if_t<std::is_enum_v<T>, std::underlying_type_t<T>> ToIntegral(const T &e) |
|
| 76 |
+ {
|
|
| 77 |
+ return static_cast<std::underlying_type_t<T>>(e); |
|
| 78 |
+ } |
|
| 79 |
+ |
|
| 74 | 80 |
static unsigned long StringToMS(const std::string &time) |
| 75 | 81 |
{
|
| 76 | 82 |
unsigned long hours = 0, minutes = 0; |
| ... | ... |
@@ -99,13 +105,13 @@ public: |
| 99 | 105 |
{
|
| 100 | 106 |
if (!ConvertFuncs::IsDigitsOnly(hoursStr)) |
| 101 | 107 |
return 0; |
| 102 |
- hours = convertTo<unsigned long>(hoursStr); |
|
| 108 |
+ hours = ConvertFuncs::To<unsigned long>(hoursStr); |
|
| 103 | 109 |
} |
| 104 | 110 |
if (!minutesStr.empty()) |
| 105 | 111 |
{
|
| 106 | 112 |
if (!ConvertFuncs::IsDigitsOnly(minutesStr)) |
| 107 | 113 |
return 0; |
| 108 |
- minutes = convertTo<unsigned long>(minutesStr); |
|
| 114 |
+ minutes = ConvertFuncs::To<unsigned long>(minutesStr); |
|
| 109 | 115 |
} |
| 110 | 116 |
if (!secondsStr.empty()) |
| 111 | 117 |
{
|
| ... | ... |
@@ -114,7 +120,7 @@ public: |
| 114 | 120 |
std::size_t comma = secondsStr.find(',');
|
| 115 | 121 |
if (comma != std::string::npos) |
| 116 | 122 |
secondsStr[comma] = '.'; |
| 117 |
- seconds = convertTo<double>(secondsStr); |
|
| 123 |
+ seconds = ConvertFuncs::To<double>(secondsStr); |
|
| 118 | 124 |
} |
| 119 | 125 |
seconds += minutes * 60 + hours * 1440; |
| 120 | 126 |
return static_cast<unsigned long>(std::floor(seconds * 1000 + 0.5)); |