mirror of
https://github.com/pocoproject/poco.git
synced 2025-10-23 00:07:59 +02:00
4368 oracle odbc tests (#4410)
* feat(format): Add string_view format type spec #4409 * chore(Types): add demangle * fix(Data): Oracle failing ODBC tests #4368 * fix some CQL and fuzz warnings; add Var::typeName() * fix(build): -std=c++17 and c11 * fix windows build * fix(Foundation): test apps vs projects c++17 * chore(build): remove uneeded compiler flag * fix(VarHolder): number of digits range check for int->float conversion (reported by CIFuzz) * fix(test): CIFuzz * fix(CIFuzz): another attempt * fix(progen): add LanguageStandard (stdcpp17, stdc11); regenerate vs170 projects * fix(CiFuzz): add int->float precision loss barrier; fix erroneous number of digits logic * enh(Var): silent loss of precision on int->float conversion #4423 * enh(Var): silent loss of precision on int->float conversion #4423 * chore(build): remove old build files * chore: fix missing parens warning * enh(Thread_POSIX): prevent double-joining; add error description to exceptions * fix(Data): unresolved Column<long> linkage in test * fix(demangle): determine type name from template parameter; add eror diagnostic for demangling failures * chore(buildwin): remove old vs versions from build and progen scripts; update documentation * chore(buildwin): remove leftover closing curly
This commit is contained in:

committed by
GitHub

parent
bf2f96847a
commit
c7d16b2a7e
@@ -475,6 +475,11 @@ public:
|
||||
const std::type_info& type() const;
|
||||
/// Returns the type information of the stored content.
|
||||
|
||||
std::string typeName(bool demangle = true) const;
|
||||
/// Returns the type name of the stored content.
|
||||
/// If demangling is available and emangle is true,
|
||||
/// the returnsed string will be demangled.
|
||||
|
||||
//@ deprecated
|
||||
void empty();
|
||||
/// Empties Var.
|
||||
@@ -521,23 +526,8 @@ public:
|
||||
/// This function returns 0 when Var is empty, 1 for POD or the size (i.e. length)
|
||||
/// for held container.
|
||||
|
||||
std::string toString() const
|
||||
std::string toString() const;
|
||||
/// Returns the stored value as string.
|
||||
{
|
||||
VarHolder* pHolder = content();
|
||||
|
||||
if (!pHolder)
|
||||
throw InvalidAccessException("Can not convert empty value.");
|
||||
|
||||
if (typeid(std::string) == pHolder->type())
|
||||
return extract<std::string>();
|
||||
else
|
||||
{
|
||||
std::string result;
|
||||
pHolder->convert(result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
static Var parse(const std::string& val);
|
||||
/// Parses the string which must be in JSON format
|
||||
@@ -617,17 +607,8 @@ private:
|
||||
_placeholder.assign<VarHolderImpl<ValueType>, ValueType>(value);
|
||||
}
|
||||
|
||||
void construct(const char* value)
|
||||
{
|
||||
std::string val(value);
|
||||
_placeholder.assign<VarHolderImpl<std::string>, std::string>(val);
|
||||
}
|
||||
|
||||
void construct(const Var& other)
|
||||
{
|
||||
if (!other.isEmpty())
|
||||
other.content()->clone(&_placeholder);
|
||||
}
|
||||
void construct(const char* value);
|
||||
void construct(const Var& other);
|
||||
|
||||
Placeholder<VarHolder> _placeholder;
|
||||
};
|
||||
@@ -642,6 +623,20 @@ private:
|
||||
/// Var members
|
||||
///
|
||||
|
||||
inline void Var::construct(const char* value)
|
||||
{
|
||||
std::string val(value);
|
||||
_placeholder.assign<VarHolderImpl<std::string>, std::string>(val);
|
||||
}
|
||||
|
||||
|
||||
inline void Var::construct(const Var& other)
|
||||
{
|
||||
if (!other.isEmpty())
|
||||
other.content()->clone(&_placeholder);
|
||||
}
|
||||
|
||||
|
||||
inline void Var::swap(Var& other)
|
||||
{
|
||||
if (this == &other) return;
|
||||
@@ -674,6 +669,13 @@ inline const std::type_info& Var::type() const
|
||||
}
|
||||
|
||||
|
||||
inline std::string Var::typeName(bool demangle) const
|
||||
{
|
||||
VarHolder* pHolder = content();
|
||||
return pHolder ? demangle ? Poco::demangle(pHolder->type().name()) : pHolder->type().name() : std::string();
|
||||
}
|
||||
|
||||
|
||||
inline Var::ConstIterator Var::begin() const
|
||||
{
|
||||
if (size() == 0) return ConstIterator(const_cast<Var*>(this), true);
|
||||
|
@@ -33,17 +33,27 @@
|
||||
#include "Poco/UTF8String.h"
|
||||
#include "Poco/UUID.h"
|
||||
#include "Poco/Any.h"
|
||||
#include "Poco/Format.h"
|
||||
#include "Poco/Debugger.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <deque>
|
||||
#include <typeinfo>
|
||||
#include <type_traits>
|
||||
#include <string_view>
|
||||
#undef min
|
||||
#undef max
|
||||
#include <limits>
|
||||
|
||||
|
||||
#define POCO_VAR_RANGE_EXCEPTION(str, from) \
|
||||
throw RangeException(Poco::format("%v ((%s/%d) %s > (%s/%d) %s) @ %s.", \
|
||||
std::string_view(#str), Poco::demangle<F>(), numValDigits(from), std::to_string(from), \
|
||||
Poco::demangle<T>(), numTypeDigits<T>(), std::to_string(static_cast<T>(from)), \
|
||||
poco_src_loc))
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Dynamic {
|
||||
|
||||
@@ -312,140 +322,186 @@ protected:
|
||||
return pVarHolder->assign<VarHolderImpl<T>, T>(val);
|
||||
}
|
||||
|
||||
template <typename F, typename T>
|
||||
void convertToSmaller(const F& from, T& to) const
|
||||
/// This function is meant to convert signed numeric values from
|
||||
template <typename F, typename T,
|
||||
typename std::enable_if<(std::is_integral<F>::value && std::is_signed<F>::value) ||
|
||||
std::is_floating_point<F>::value, F>::type* = nullptr,
|
||||
typename std::enable_if<(std::is_integral<T>::value && std::is_signed<T>::value) ||
|
||||
std::is_floating_point<F>::value, T>::type* = nullptr>
|
||||
static void convertToSmaller(const F& from, T& to)
|
||||
/// Converts signed integral, as well as floating-point, values from
|
||||
/// larger to smaller type. It checks the upper and lower bound and
|
||||
/// if from value is within limits of type T (i.e. check calls do not throw),
|
||||
/// it is converted.
|
||||
{
|
||||
poco_static_assert (std::numeric_limits<F>::is_specialized);
|
||||
poco_static_assert (std::numeric_limits<T>::is_specialized);
|
||||
poco_static_assert (std::numeric_limits<F>::is_signed);
|
||||
poco_static_assert (std::numeric_limits<T>::is_signed);
|
||||
|
||||
if constexpr((std::is_integral<F>::value) && (std::is_floating_point<T>::value))
|
||||
{
|
||||
if (isPrecisionLost<F, T>(from))
|
||||
POCO_VAR_RANGE_EXCEPTION ("Lost precision", from);
|
||||
}
|
||||
checkUpperLimit<F,T>(from);
|
||||
checkLowerLimit<F,T>(from);
|
||||
|
||||
to = static_cast<T>(from);
|
||||
}
|
||||
|
||||
template <typename F, typename T>
|
||||
void convertToSmallerUnsigned(const F& from, T& to) const
|
||||
/// This function is meant for converting unsigned integral data types,
|
||||
/// from larger to smaller type. Since lower limit is always 0 for unsigned types,
|
||||
/// only the upper limit is checked, thus saving some cycles compared to the signed
|
||||
/// version of the function. If the value to be converted is smaller than
|
||||
/// the maximum value for the target type, the conversion is performed.
|
||||
template <typename F, typename T,
|
||||
typename std::enable_if<std::is_integral<F>::value && std::is_signed<T>::value, F>::type* = nullptr,
|
||||
typename std::enable_if<std::is_floating_point<T>::value, T>::type* = nullptr>
|
||||
static void convertToSmaller(const F& from, T& to)
|
||||
/// Converts signed integral values from integral to floating-point type. Checks for
|
||||
/// the loss of precision and if from value is within limits of type T (i.e. check calls do not throw),
|
||||
/// it is converted.
|
||||
{
|
||||
poco_static_assert (std::numeric_limits<F>::is_specialized);
|
||||
poco_static_assert (std::numeric_limits<T>::is_specialized);
|
||||
poco_static_assert (!std::numeric_limits<F>::is_signed);
|
||||
poco_static_assert (!std::numeric_limits<T>::is_signed);
|
||||
if (isPrecisionLost<F, T>(from))
|
||||
POCO_VAR_RANGE_EXCEPTION ("Lost precision", from);
|
||||
to = static_cast<T>(from);
|
||||
}
|
||||
|
||||
template <typename F, typename T,
|
||||
typename std::enable_if<std::is_same<F, bool>::value>::type* = nullptr,
|
||||
typename std::enable_if<std::is_floating_point<T>::value, T>::type* = nullptr>
|
||||
static void convertToSmaller(const F& from, T& to)
|
||||
/// Converts boolean values to floating-point type.
|
||||
{
|
||||
to = static_cast<T>(from);
|
||||
}
|
||||
|
||||
template <typename F, typename T,
|
||||
typename std::enable_if<std::is_integral<F>::value && !std::is_signed<F>::value, F>::type* = nullptr,
|
||||
typename std::enable_if<(std::is_integral<T>::value && !std::is_signed<T>::value) || std::is_floating_point<T>::value, T>::type* = nullptr>
|
||||
static void convertToSmallerUnsigned(const F& from, T& to)
|
||||
/// Converts unsigned integral data types from larger to smaller, as well as to floating-point, types.
|
||||
/// Since lower limit is always 0 for unsigned types, only the upper limit is checked, thus
|
||||
/// saving some cycles compared to the signed version of the function. If the
|
||||
/// value to be converted is smaller than the maximum value for the target type,
|
||||
/// the conversion is performed.
|
||||
{
|
||||
checkUpperLimit<F,T>(from);
|
||||
to = static_cast<T>(from);
|
||||
}
|
||||
|
||||
template <typename F, typename T>
|
||||
void convertSignedToUnsigned(const F& from, T& to) const
|
||||
/// This function is meant for converting signed integral data types to
|
||||
/// unsigned data types. Negative values can not be converted and if one
|
||||
/// is encountered, RangeException is thrown.
|
||||
template <typename F, typename T,
|
||||
typename std::enable_if<std::is_integral<F>::value && std::is_signed<F>::value, F>::type* = nullptr,
|
||||
typename std::enable_if<std::is_integral<T>::value && !std::is_signed<T>::value, T>::type* = nullptr>
|
||||
static void convertSignedToUnsigned(const F& from, T& to)
|
||||
/// Converts signed integral data types to unsigned data types.
|
||||
/// Negative values can not be converted and if one is encountered, RangeException is thrown.
|
||||
/// If upper limit is within the target data type limits, the conversion is performed.
|
||||
{
|
||||
poco_static_assert (std::numeric_limits<F>::is_specialized);
|
||||
poco_static_assert (std::numeric_limits<T>::is_specialized);
|
||||
poco_static_assert (std::numeric_limits<F>::is_signed);
|
||||
poco_static_assert (!std::numeric_limits<T>::is_signed);
|
||||
|
||||
if (from < 0)
|
||||
throw RangeException("Value too small.");
|
||||
POCO_VAR_RANGE_EXCEPTION ("Value too small", from);
|
||||
checkUpperLimit<std::make_unsigned_t<F>,T>(from);
|
||||
to = static_cast<T>(from);
|
||||
}
|
||||
|
||||
template <typename F, typename T, std::enable_if_t<std::is_floating_point<F>::value, bool> = true>
|
||||
void convertSignedFloatToUnsigned(const F& from, T& to) const
|
||||
/// This function is meant for converting floating point data types to
|
||||
/// unsigned integral data types. Negative values can not be converted and if one
|
||||
/// is encountered, RangeException is thrown.
|
||||
template <typename F, typename T, std::enable_if_t<std::is_floating_point<F>::value, bool> = true,
|
||||
typename std::enable_if<std::is_integral<T>::value && !std::is_signed<T>::value, T>::type* = nullptr>
|
||||
static void convertSignedFloatToUnsigned(const F& from, T& to)
|
||||
/// Converts floating point data types to unsigned integral data types. Negative values
|
||||
/// can not be converted and if one is encountered, RangeException is thrown.
|
||||
/// If upper limit is within the target data type limits, the conversion is performed.
|
||||
{
|
||||
poco_static_assert (std::numeric_limits<F>::is_specialized);
|
||||
poco_static_assert (std::numeric_limits<T>::is_specialized);
|
||||
poco_static_assert (!std::numeric_limits<F>::is_integer);
|
||||
poco_static_assert (std::numeric_limits<T>::is_integer);
|
||||
poco_static_assert (!std::numeric_limits<T>::is_signed);
|
||||
|
||||
if (from < 0)
|
||||
throw RangeException("Value too small.");
|
||||
POCO_VAR_RANGE_EXCEPTION ("Value too small", from);
|
||||
checkUpperLimit<F,T>(from);
|
||||
to = static_cast<T>(from);
|
||||
}
|
||||
|
||||
template <typename F, typename T>
|
||||
void convertUnsignedToSigned(const F& from, T& to) const
|
||||
/// This function is meant for converting unsigned integral data types to
|
||||
/// signed integral data types. Negative values can not be converted and if one
|
||||
/// is encountered, RangeException is thrown.
|
||||
template <typename F, typename T,
|
||||
typename std::enable_if<std::is_integral<F>::value && !std::is_signed<F>::value, F>::type* = nullptr,
|
||||
typename std::enable_if<std::is_integral<T>::value && std::is_signed<T>::value, T>::type* = nullptr>
|
||||
static void convertUnsignedToSigned(const F& from, T& to)
|
||||
/// Converts unsigned integral data types to signed integral data types.
|
||||
/// If upper limit is within the target data type limits, the conversion is performed.
|
||||
{
|
||||
poco_static_assert (std::numeric_limits<F>::is_specialized);
|
||||
poco_static_assert (std::numeric_limits<T>::is_specialized);
|
||||
poco_static_assert (!std::numeric_limits<F>::is_signed);
|
||||
poco_static_assert (std::numeric_limits<T>::is_signed);
|
||||
|
||||
checkUpperLimit<F,T>(from);
|
||||
to = static_cast<T>(from);
|
||||
}
|
||||
|
||||
template <typename F, typename T,
|
||||
std::enable_if_t<std::is_integral<F>::value, bool> = true,
|
||||
std::enable_if_t<std::is_floating_point<T>::value, bool> = true>
|
||||
static void convertToFP(F& from, T& to)
|
||||
/// Converts unsigned integral data types to floating-point data types.
|
||||
/// If the number of significant digits used for the integer vaue exceeds the number
|
||||
/// of available digits in the floatinng-point destination (ie. if precision would be lost
|
||||
/// by casting the value), RangeException is thrown.
|
||||
{
|
||||
if (isPrecisionLost<F, T>(from))
|
||||
POCO_VAR_RANGE_EXCEPTION ("Lost precision", from);
|
||||
to = static_cast<T>(from);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template <typename F, typename T, std::enable_if_t<std::is_integral<F>::value, bool> = true>
|
||||
void checkUpperLimit(const F& from) const
|
||||
template <typename T, std::enable_if_t<std::is_integral<T>::value, bool> = true>
|
||||
static constexpr int numValDigits(const T& value)
|
||||
{
|
||||
if (from > std::numeric_limits<T>::max())
|
||||
throw RangeException("Value too large.");
|
||||
using U = std::make_unsigned_t<T>;
|
||||
if (value == 0) return 0;
|
||||
int digitCount = 0;
|
||||
U locVal = value; // to prevent sign preservation
|
||||
while (locVal >>= 1) ++digitCount;
|
||||
return digitCount;
|
||||
}
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_floating_point<T>::value, bool> = true>
|
||||
static constexpr int numValDigits(T value)
|
||||
{
|
||||
return numValDigits<int64_t>(static_cast<int64_t>(value));
|
||||
}
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_floating_point<T>::value, bool> = true>
|
||||
static constexpr int numTypeDigits()
|
||||
{
|
||||
return std::numeric_limits<T>::digits;
|
||||
}
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_integral<T>::value, bool> = true>
|
||||
static constexpr int numTypeDigits()
|
||||
{
|
||||
return numValDigits(std::numeric_limits<T>::max());
|
||||
}
|
||||
|
||||
template <typename F, typename T,
|
||||
std::enable_if_t<std::is_integral<F>::value, bool> = true,
|
||||
std::enable_if_t<std::is_floating_point<T>::value, bool> = true>
|
||||
static bool isPrecisionLost(const F& from)
|
||||
// Checks for loss of precision in integral -> floating point conversion.
|
||||
{
|
||||
return numValDigits(from) > numTypeDigits<T>();
|
||||
}
|
||||
|
||||
template <typename F, typename T, std::enable_if_t<std::is_integral<F>::value, bool> = true>
|
||||
void checkLowerLimit(const F& from) const
|
||||
static void checkUpperLimit(const F& from)
|
||||
{
|
||||
if (from < std::numeric_limits<T>::min())
|
||||
throw RangeException("Value too small.");
|
||||
if (from > static_cast<F>(std::numeric_limits<T>::max()))
|
||||
POCO_VAR_RANGE_EXCEPTION ("Value too big", from);
|
||||
}
|
||||
|
||||
template <typename F, typename T, std::enable_if_t<std::is_integral<F>::value, bool> = true>
|
||||
static void checkLowerLimit(const F& from)
|
||||
{
|
||||
if (from < static_cast<F>(std::numeric_limits<T>::min()))
|
||||
POCO_VAR_RANGE_EXCEPTION ("Value too small", from);
|
||||
}
|
||||
|
||||
template <typename F, typename T, std::enable_if_t<std::is_floating_point<F>::value, bool> = true>
|
||||
void checkUpperLimit(const F& from) const
|
||||
static void checkUpperLimit(const F& from)
|
||||
{
|
||||
if (std::is_floating_point<T>::value)
|
||||
{
|
||||
if (from > std::numeric_limits<T>::max())
|
||||
throw RangeException("Value too large.");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Avoid clang -Wimplicit-int-float-conversion warning with an explicit cast.
|
||||
if (from > static_cast<F>(std::numeric_limits<T>::max()))
|
||||
throw RangeException("Value too large.");
|
||||
}
|
||||
if ((from > static_cast<F>(std::numeric_limits<T>::max())))
|
||||
POCO_VAR_RANGE_EXCEPTION ("Value too big", from);
|
||||
}
|
||||
|
||||
template <typename F, typename T, std::enable_if_t<std::is_floating_point<F>::value, bool> = true>
|
||||
void checkLowerLimit(const F& from) const
|
||||
static void checkLowerLimit(const F& from)
|
||||
{
|
||||
if (std::is_floating_point<T>::value)
|
||||
if constexpr(std::is_floating_point<T>::value)
|
||||
{
|
||||
if (from < -std::numeric_limits<T>::max())
|
||||
throw RangeException("Value too small.");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Avoid clang -Wimplicit-int-float-conversion warning with an explicit cast.
|
||||
if (from < static_cast<F>(std::numeric_limits<T>::min()))
|
||||
throw RangeException("Value too small.");
|
||||
if (static_cast<F>(-std::numeric_limits<T>::max()) > from)
|
||||
POCO_VAR_RANGE_EXCEPTION ("Value too small", from);
|
||||
}
|
||||
else if (from < static_cast<F>(std::numeric_limits<T>::min()))
|
||||
POCO_VAR_RANGE_EXCEPTION ("Value too small", from);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -828,12 +884,12 @@ public:
|
||||
|
||||
void convert(float& val) const
|
||||
{
|
||||
val = static_cast<float>(_val);
|
||||
convertToFP(_val, val);
|
||||
}
|
||||
|
||||
void convert(double& val) const
|
||||
{
|
||||
val = static_cast<double>(_val);
|
||||
convertToFP(_val, val);
|
||||
}
|
||||
|
||||
void convert(char& val) const
|
||||
@@ -984,12 +1040,12 @@ public:
|
||||
|
||||
void convert(float& val) const
|
||||
{
|
||||
val = static_cast<float>(_val);
|
||||
convertToFP(_val, val);
|
||||
}
|
||||
|
||||
void convert(double& val) const
|
||||
{
|
||||
val = static_cast<double>(_val);
|
||||
convertToFP(_val, val);
|
||||
}
|
||||
|
||||
void convert(char& val) const
|
||||
@@ -1137,12 +1193,12 @@ public:
|
||||
|
||||
void convert(float& val) const
|
||||
{
|
||||
val = static_cast<float>(_val);
|
||||
convertToFP(_val, val);
|
||||
}
|
||||
|
||||
void convert(double& val) const
|
||||
{
|
||||
val = static_cast<double>(_val);
|
||||
convertToFP(_val, val);
|
||||
}
|
||||
|
||||
void convert(char& val) const
|
||||
@@ -1289,12 +1345,12 @@ public:
|
||||
|
||||
void convert(float& val) const
|
||||
{
|
||||
val = static_cast<float>(_val);
|
||||
convertToFP(_val, val);
|
||||
}
|
||||
|
||||
void convert(double& val) const
|
||||
{
|
||||
val = static_cast<double>(_val);
|
||||
convertToFP(_val, val);
|
||||
}
|
||||
|
||||
void convert(char& val) const
|
||||
@@ -1456,12 +1512,12 @@ public:
|
||||
|
||||
void convert(float& val) const
|
||||
{
|
||||
val = static_cast<float>(_val);
|
||||
convertToFP(_val, val);
|
||||
}
|
||||
|
||||
void convert(double& val) const
|
||||
{
|
||||
val = static_cast<double>(_val);
|
||||
convertToFP(_val, val);
|
||||
}
|
||||
|
||||
void convert(char& val) const
|
||||
@@ -1608,12 +1664,12 @@ public:
|
||||
|
||||
void convert(float& val) const
|
||||
{
|
||||
val = static_cast<float>(_val);
|
||||
convertToFP(_val, val);
|
||||
}
|
||||
|
||||
void convert(double& val) const
|
||||
{
|
||||
val = static_cast<double>(_val);
|
||||
convertToFP(_val, val);
|
||||
}
|
||||
|
||||
void convert(char& val) const
|
||||
@@ -1760,12 +1816,12 @@ public:
|
||||
|
||||
void convert(float& val) const
|
||||
{
|
||||
val = static_cast<float>(_val);
|
||||
convertToFP(_val, val);
|
||||
}
|
||||
|
||||
void convert(double& val) const
|
||||
{
|
||||
val = static_cast<double>(_val);
|
||||
convertToFP(_val, val);
|
||||
}
|
||||
|
||||
void convert(char& val) const
|
||||
@@ -1912,12 +1968,12 @@ public:
|
||||
|
||||
void convert(float& val) const
|
||||
{
|
||||
val = static_cast<float>(_val);
|
||||
convertToFP(_val, val);
|
||||
}
|
||||
|
||||
void convert(double& val) const
|
||||
{
|
||||
val = static_cast<double>(_val);
|
||||
convertToFP(_val, val);
|
||||
}
|
||||
|
||||
void convert(char& val) const
|
||||
|
Reference in New Issue
Block a user