Merge pull request #832 from jpcima/opcode-spec-values

Ability for OpcodeSpec to process number values
This commit is contained in:
JP Cimalando 2021-04-15 16:05:11 +02:00 committed by GitHub
commit 343350ad96
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 59 additions and 27 deletions

View file

@ -33,6 +33,7 @@
#include "SfzHelpers.h"
#include "LFOCommon.h"
#include "MathHelpers.h"
#include "utility/Macros.h"
namespace sfz
@ -68,6 +69,9 @@ struct OpcodeSpec
Range<T> bounds;
int flags;
using Intermediate = typename std::conditional<
std::is_integral<T>::value, int64_t, T>::type;
template <class U>
using IsNormalizable = std::integral_constant<
bool, std::is_arithmetic<U>::value && !std::is_same<U, bool>::value>;

View file

@ -143,10 +143,31 @@ OpcodeCategory Opcode::identifyCategory(absl::string_view name)
}
template <typename T>
absl::optional<T> readInt_(OpcodeSpec<T> spec, absl::string_view v)
absl::optional<T> transformInt_(OpcodeSpec<T> spec, int64_t v)
{
using Limits = std::numeric_limits<T>;
if (v > static_cast<int64_t>(spec.bounds.getEnd())) {
if (spec.flags & kEnforceUpperBound)
return spec.bounds.getEnd();
else if (!(spec.flags & kPermissiveUpperBound))
return absl::nullopt;
} else if (v < static_cast<int64_t>(spec.bounds.getStart())) {
if (spec.flags & kEnforceLowerBound)
return spec.bounds.getStart();
else if (!(spec.flags & kPermissiveLowerBound))
return absl::nullopt;
}
v = std::max<int64_t>(v, Limits::min());
v = std::min<int64_t>(v, Limits::max());
return static_cast<T>(v);
}
template <typename T>
absl::optional<T> readInt_(OpcodeSpec<T> spec, absl::string_view v)
{
int64_t returnedValue;
bool readValueSuccess = false;
@ -163,22 +184,7 @@ absl::optional<T> readInt_(OpcodeSpec<T> spec, absl::string_view v)
if (!readValueSuccess)
return absl::nullopt;
if (returnedValue > static_cast<int64_t>(spec.bounds.getEnd())) {
if (spec.flags & kEnforceUpperBound)
return spec.bounds.getEnd();
else if (!(spec.flags & kPermissiveUpperBound))
return absl::nullopt;
} else if (returnedValue < static_cast<int64_t>(spec.bounds.getStart())) {
if (spec.flags & kEnforceLowerBound)
return spec.bounds.getStart();
else if (!(spec.flags & kPermissiveLowerBound))
return absl::nullopt;
}
returnedValue = std::max<int64_t>(returnedValue, Limits::min());
returnedValue = std::min<int64_t>(returnedValue, Limits::max());
return static_cast<T>(returnedValue);
return transformInt_(spec, returnedValue);
}
#define INSTANTIATE_FOR_INTEGRAL(T) \
@ -186,6 +192,11 @@ absl::optional<T> readInt_(OpcodeSpec<T> spec, absl::string_view v)
absl::optional<T> Opcode::readOptional(OpcodeSpec<T> spec) const \
{ \
return readInt_<T>(spec, value); \
} \
template <> \
absl::optional<T> Opcode::transformOptional(OpcodeSpec<T> spec, int64_t value) const \
{ \
return transformInt_<T>(spec, value); \
}
INSTANTIATE_FOR_INTEGRAL(uint8_t)
@ -198,30 +209,34 @@ INSTANTIATE_FOR_INTEGRAL(int64_t)
template <typename T>
absl::optional<T> readFloat_(OpcodeSpec<T> spec, absl::string_view v)
absl::optional<T> transformFloat_(OpcodeSpec<T> spec, T v)
{
T returnedValue;
if (!readLeadingFloat(v, &returnedValue))
return absl::nullopt;
if (spec.flags & kWrapPhase)
returnedValue = wrapPhase(returnedValue);
v = wrapPhase(v);
if (returnedValue > spec.bounds.getEnd()) {
if (v > spec.bounds.getEnd()) {
if (spec.flags & kEnforceUpperBound)
return spec.bounds.getEnd();
else if (!(spec.flags & kPermissiveUpperBound))
return absl::nullopt;
} else if (returnedValue < spec.bounds.getStart()) {
} else if (v < spec.bounds.getStart()) {
if (spec.flags & kEnforceLowerBound)
return spec.bounds.getStart();
else if (!(spec.flags & kPermissiveLowerBound))
return absl::nullopt;
}
returnedValue = spec.normalizeInput(returnedValue);
return spec.normalizeInput(v);
}
return returnedValue;
template <typename T>
absl::optional<T> readFloat_(OpcodeSpec<T> spec, absl::string_view v)
{
T returnedValue;
if (!readLeadingFloat(v, &returnedValue))
return absl::nullopt;
return transformFloat_(spec, returnedValue);
}
#define INSTANTIATE_FOR_FLOATING_POINT(T) \
@ -229,6 +244,11 @@ absl::optional<T> readFloat_(OpcodeSpec<T> spec, absl::string_view v)
absl::optional<T> Opcode::readOptional(OpcodeSpec<T> spec) const \
{ \
return readFloat_<T>(spec, value); \
} \
template <> \
absl::optional<T> Opcode::transformOptional(OpcodeSpec<T> spec, T value) const \
{ \
return transformFloat_<T>(spec, value); \
}
INSTANTIATE_FOR_FLOATING_POINT(float)

View file

@ -113,6 +113,14 @@ struct Opcode {
template <class T>
T read(OpcodeSpec<T> spec) const { return readOptional(spec).value_or(spec); }
template <class T> using Intermediate = typename OpcodeSpec<T>::Intermediate;
template <class T>
absl::optional<T> transformOptional(OpcodeSpec<T> spec, Intermediate<T> value) const;
template <class T>
T transform(OpcodeSpec<T> spec, Intermediate<T> value) const { return transformOptional(spec, value).value_or(spec); }
private:
static OpcodeCategory identifyCategory(absl::string_view name);
LEAK_DETECTOR(Opcode);