Merge pull request #361 from jpcima/opcodes-light

Move template functions of Opcode.h to implementation side
This commit is contained in:
JP Cimalando 2020-08-18 00:45:07 +02:00 committed by GitHub
commit 02e4f0e468
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 151 additions and 101 deletions

View file

@ -13,7 +13,9 @@
#include <cctype>
#include <cassert>
sfz::Opcode::Opcode(absl::string_view inputOpcode, absl::string_view inputValue)
namespace sfz {
Opcode::Opcode(absl::string_view inputOpcode, absl::string_view inputValue)
: opcode(trim(inputOpcode))
, value(trim(inputValue))
, category(identifyCategory(inputOpcode))
@ -49,7 +51,7 @@ static absl::string_view extractBackInteger(absl::string_view opcodeName)
return opcodeName.substr(i);
}
std::string sfz::Opcode::getDerivedName(sfz::OpcodeCategory newCategory, unsigned number) const
std::string Opcode::getDerivedName(OpcodeCategory newCategory, unsigned number) const
{
std::string derivedName(opcode);
@ -95,9 +97,9 @@ std::string sfz::Opcode::getDerivedName(sfz::OpcodeCategory newCategory, unsigne
return derivedName;
}
sfz::OpcodeCategory sfz::Opcode::identifyCategory(absl::string_view name)
OpcodeCategory Opcode::identifyCategory(absl::string_view name)
{
sfz::OpcodeCategory category = kOpcodeNormal;
OpcodeCategory category = kOpcodeNormal;
if (!name.empty() && absl::ascii_isdigit(name.back())) {
absl::string_view part = name;
@ -115,7 +117,7 @@ sfz::OpcodeCategory sfz::Opcode::identifyCategory(absl::string_view name)
return category;
}
absl::optional<uint8_t> sfz::readNoteValue(absl::string_view value)
absl::optional<uint8_t> readNoteValue(absl::string_view value)
{
char noteLetter = absl::ascii_tolower(value.empty() ? '\0' : value.front());
value.remove_prefix(1);
@ -156,6 +158,142 @@ absl::optional<uint8_t> sfz::readNoteValue(absl::string_view value)
return static_cast<uint8_t>(noteNumber);
}
///
template <typename ValueType, absl::enable_if_t<std::is_integral<ValueType>::value, int>>
absl::optional<ValueType> readOpcode(absl::string_view value, const Range<ValueType>& validRange)
{
size_t numberEnd = 0;
if (numberEnd < value.size() && (value[numberEnd] == '+' || value[numberEnd] == '-'))
++numberEnd;
while (numberEnd < value.size() && absl::ascii_isdigit(value[numberEnd]))
++numberEnd;
value = value.substr(0, numberEnd);
int64_t returnedValue;
if (!absl::SimpleAtoi(value, &returnedValue))
return absl::nullopt;
if (returnedValue > std::numeric_limits<ValueType>::max())
returnedValue = std::numeric_limits<ValueType>::max();
if (returnedValue < std::numeric_limits<ValueType>::min())
returnedValue = std::numeric_limits<ValueType>::min();
return validRange.clamp(static_cast<ValueType>(returnedValue));
}
template <typename ValueType, absl::enable_if_t<std::is_floating_point<ValueType>::value, int>>
absl::optional<ValueType> readOpcode(absl::string_view value, const Range<ValueType>& validRange)
{
size_t numberEnd = 0;
if (numberEnd < value.size() && (value[numberEnd] == '+' || value[numberEnd] == '-'))
++numberEnd;
while (numberEnd < value.size() && absl::ascii_isdigit(value[numberEnd]))
++numberEnd;
if (numberEnd < value.size() && value[numberEnd] == '.') {
++numberEnd;
while (numberEnd < value.size() && absl::ascii_isdigit(value[numberEnd]))
++numberEnd;
}
value = value.substr(0, numberEnd);
float returnedValue;
if (!absl::SimpleAtof(value, &returnedValue))
return absl::nullopt;
return validRange.clamp(returnedValue);
}
absl::optional<bool> readBooleanFromOpcode(const Opcode& opcode)
{
switch (hash(opcode.value)) {
case hash("off"):
return false;
case hash("on"):
return true;
default:
return {};
}
}
template <class ValueType>
void setValueFromOpcode(const Opcode& opcode, ValueType& target, const Range<ValueType>& validRange)
{
auto value = readOpcode(opcode.value, validRange);
if (!value) // Try and read a note rather than a number
value = readNoteValue(opcode.value);
if (value)
target = *value;
}
template <class ValueType>
inline void setValueFromOpcode(const Opcode& opcode, absl::optional<ValueType>& target, const Range<ValueType>& validRange)
{
auto value = readOpcode(opcode.value, validRange);
if (!value) // Try and read a note rather than a number
value = readNoteValue(opcode.value);
if (value)
target = *value;
}
template <class ValueType>
void setRangeEndFromOpcode(const Opcode& opcode, Range<ValueType>& target, const Range<ValueType>& validRange)
{
auto value = readOpcode(opcode.value, validRange);
if (!value) // Try and read a note rather than a number
value = readNoteValue(opcode.value);
if (value)
target.setEnd(*value);
}
template <class ValueType>
void setRangeStartFromOpcode(const Opcode& opcode, Range<ValueType>& target, const Range<ValueType>& validRange)
{
auto value = readOpcode(opcode.value, validRange);
if (!value) // Try and read a note rather than a number
value = readNoteValue(opcode.value);
if (value)
target.setStart(*value);
}
template <class ValueType>
void setCCPairFromOpcode(const Opcode& opcode, absl::optional<CCData<ValueType>>& target, const Range<ValueType>& validRange)
{
auto value = readOpcode(opcode.value, validRange);
if (value && Default::ccNumberRange.containsWithEnd(opcode.parameters.back()))
target = { opcode.parameters.back(), *value };
else
target = {};
}
///
#define INSTANCIATE_FOR(T) \
template absl::optional<T> readOpcode<T>(absl::string_view value, const Range<T>& validRange); /*NOLINT(bugprone-macro-parentheses)*/ \
template void setValueFromOpcode<T>(const Opcode& opcode, T& target, const Range<T>& validRange); /*NOLINT(bugprone-macro-parentheses)*/ \
template void setValueFromOpcode<T>(const Opcode& opcode, absl::optional<T>& target, const Range<T>& validRange); /*NOLINT(bugprone-macro-parentheses)*/ \
template void setRangeEndFromOpcode(const Opcode& opcode, Range<T>& target, const Range<T>& validRange); /*NOLINT(bugprone-macro-parentheses)*/ \
template void setRangeStartFromOpcode(const Opcode& opcode, Range<T>& target, const Range<T>& validRange); /*NOLINT(bugprone-macro-parentheses)*/ \
template void setCCPairFromOpcode(const Opcode& opcode, absl::optional<CCData<T>>& target, const Range<T>& validRange); /*NOLINT(bugprone-macro-parentheses)*/
INSTANCIATE_FOR(float)
INSTANCIATE_FOR(double)
INSTANCIATE_FOR(int8_t)
INSTANCIATE_FOR(int16_t)
INSTANCIATE_FOR(int32_t)
INSTANCIATE_FOR(int64_t)
INSTANCIATE_FOR(uint8_t)
INSTANCIATE_FOR(uint16_t)
INSTANCIATE_FOR(uint32_t)
//INSTANCIATE_FOR(uint64_t)
#undef INSTANCIATE_FOR
} // namespace sfz
std::ostream &operator<<(std::ostream &os, const sfz::Opcode &opcode)
{
return os << opcode.opcode << '=' << '"' << opcode.value << '"';

View file

@ -125,28 +125,7 @@ absl::optional<uint8_t> readNoteValue(absl::string_view value);
* @return absl::optional<ValueType> the cast value, or null
*/
template <typename ValueType, absl::enable_if_t<std::is_integral<ValueType>::value, int> = 0>
inline absl::optional<ValueType> readOpcode(absl::string_view value, const Range<ValueType>& validRange)
{
size_t numberEnd = 0;
if (numberEnd < value.size() && (value[numberEnd] == '+' || value[numberEnd] == '-'))
++numberEnd;
while (numberEnd < value.size() && absl::ascii_isdigit(value[numberEnd]))
++numberEnd;
value = value.substr(0, numberEnd);
int64_t returnedValue;
if (!absl::SimpleAtoi(value, &returnedValue))
return absl::nullopt;
if (returnedValue > std::numeric_limits<ValueType>::max())
returnedValue = std::numeric_limits<ValueType>::max();
if (returnedValue < std::numeric_limits<ValueType>::min())
returnedValue = std::numeric_limits<ValueType>::min();
return validRange.clamp(static_cast<ValueType>(returnedValue));
}
absl::optional<ValueType> readOpcode(absl::string_view value, const Range<ValueType>& validRange);
/**
* @brief Read a value from the sfz file and cast it to the destination parameter along
@ -159,44 +138,12 @@ inline absl::optional<ValueType> readOpcode(absl::string_view value, const Range
* @return absl::optional<ValueType> the cast value, or null
*/
template <typename ValueType, absl::enable_if_t<std::is_floating_point<ValueType>::value, int> = 0>
inline absl::optional<ValueType> readOpcode(absl::string_view value, const Range<ValueType>& validRange)
{
size_t numberEnd = 0;
if (numberEnd < value.size() && (value[numberEnd] == '+' || value[numberEnd] == '-'))
++numberEnd;
while (numberEnd < value.size() && absl::ascii_isdigit(value[numberEnd]))
++numberEnd;
if (numberEnd < value.size() && value[numberEnd] == '.') {
++numberEnd;
while (numberEnd < value.size() && absl::ascii_isdigit(value[numberEnd]))
++numberEnd;
}
value = value.substr(0, numberEnd);
float returnedValue;
if (!absl::SimpleAtof(value, &returnedValue))
return absl::nullopt;
return validRange.clamp(returnedValue);
}
absl::optional<ValueType> readOpcode(absl::string_view value, const Range<ValueType>& validRange);
/**
* @brief Read a boolean value from the sfz file and cast it to the destination parameter.
*/
inline absl::optional<bool> readBooleanFromOpcode(const Opcode& opcode)
{
switch (hash(opcode.value)) {
case hash("off"):
return false;
case hash("on"):
return true;
default:
return {};
}
}
absl::optional<bool> readBooleanFromOpcode(const Opcode& opcode);
/**
* @brief Set a target parameter from an opcode value, with possibly a textual note rather
@ -208,14 +155,7 @@ inline absl::optional<bool> readBooleanFromOpcode(const Opcode& opcode)
* @param validRange the range of admitted values used to clamp the opcode
*/
template <class ValueType>
inline void setValueFromOpcode(const Opcode& opcode, ValueType& target, const Range<ValueType>& validRange)
{
auto value = readOpcode(opcode.value, validRange);
if (!value) // Try and read a note rather than a number
value = readNoteValue(opcode.value);
if (value)
target = *value;
}
void setValueFromOpcode(const Opcode& opcode, ValueType& target, const Range<ValueType>& validRange);
/**
* @brief Set a target parameter from an opcode value, with possibly a textual note rather
@ -227,14 +167,7 @@ inline void setValueFromOpcode(const Opcode& opcode, ValueType& target, const Ra
* @param validRange the range of admitted values used to clamp the opcode
*/
template <class ValueType>
inline void setValueFromOpcode(const Opcode& opcode, absl::optional<ValueType>& target, const Range<ValueType>& validRange)
{
auto value = readOpcode(opcode.value, validRange);
if (!value) // Try and read a note rather than a number
value = readNoteValue(opcode.value);
if (value)
target = *value;
}
void setValueFromOpcode(const Opcode& opcode, absl::optional<ValueType>& target, const Range<ValueType>& validRange);
/**
* @brief Set a target end of a range from an opcode value, with possibly a textual note rather
@ -246,14 +179,7 @@ inline void setValueFromOpcode(const Opcode& opcode, absl::optional<ValueType>&
* @param validRange the range of admitted values used to clamp the opcode
*/
template <class ValueType>
inline void setRangeEndFromOpcode(const Opcode& opcode, Range<ValueType>& target, const Range<ValueType>& validRange)
{
auto value = readOpcode(opcode.value, validRange);
if (!value) // Try and read a note rather than a number
value = readNoteValue(opcode.value);
if (value)
target.setEnd(*value);
}
void setRangeEndFromOpcode(const Opcode& opcode, Range<ValueType>& target, const Range<ValueType>& validRange);
/**
* @brief Set a target beginning of a range from an opcode value, with possibly a textual note rather
@ -265,14 +191,7 @@ inline void setRangeEndFromOpcode(const Opcode& opcode, Range<ValueType>& target
* @param validRange the range of admitted values used to clamp the opcode
*/
template <class ValueType>
inline void setRangeStartFromOpcode(const Opcode& opcode, Range<ValueType>& target, const Range<ValueType>& validRange)
{
auto value = readOpcode(opcode.value, validRange);
if (!value) // Try and read a note rather than a number
value = readNoteValue(opcode.value);
if (value)
target.setStart(*value);
}
void setRangeStartFromOpcode(const Opcode& opcode, Range<ValueType>& target, const Range<ValueType>& validRange);
/**
* @brief Set a CC modulation parameter from an opcode value.
@ -283,14 +202,7 @@ inline void setRangeStartFromOpcode(const Opcode& opcode, Range<ValueType>& targ
* @param validRange the range of admitted values used to clamp the opcode
*/
template <class ValueType>
inline void setCCPairFromOpcode(const Opcode& opcode, absl::optional<CCData<ValueType>>& target, const Range<ValueType>& validRange)
{
auto value = readOpcode(opcode.value, validRange);
if (value && Default::ccNumberRange.containsWithEnd(opcode.parameters.back()))
target = { opcode.parameters.back(), *value };
else
target = {};
}
void setCCPairFromOpcode(const Opcode& opcode, absl::optional<CCData<ValueType>>& target, const Range<ValueType>& validRange);
}