Commit 4c4b40e9 authored by EXT Arnaud Clère's avatar EXT Arnaud Clère
Browse files

Added partial support for integral types (only int works for now)

parent 875cd548
......@@ -51,6 +51,8 @@ namespace cbor {
//! Encoded in the high 3 bits of the descriptor byte
//! \see http://tools.ietf.org/html/rfc7049#section-2.1
enum MajorTypes {
UnsignedIntegerType = 0,
NegativeIntegerType = 1,
TextStringType = 3,
ArrayType = 4,
SimpleTypesType = 7
......@@ -121,10 +123,19 @@ protected:
bool _bind( bool& b) { return io->putChar(b ? cbor::TrueByte : cbor::FalseByte); }
bool _bind( float& n) { union { float value; quint32 bits; } number = { n };
char bytes[sizeof(number.bits)]; qToBigEndian(number.bits, bytes);
return (io->putChar((cbor::SimpleTypesType << cbor::MajorTypeShift) | cbor::SinglePrecisionFloat) && io->write(bytes, sizeof(bytes))); }
return (io->putChar((cbor::SimpleTypesType << cbor::MajorTypeShift) | cbor::SinglePrecisionFloat)
&& io->write(bytes, sizeof(bytes))); }
bool _bind( double& n) { union { double value; quint64 bits; } number = { n };
char bytes[sizeof(number.bits)]; qToBigEndian(number.bits, bytes);
return (io->putChar((cbor::SimpleTypesType << cbor::MajorTypeShift) | cbor::DoublePrecisionFloat) && io->write(bytes, sizeof(bytes))); }
return (io->putChar((cbor::SimpleTypesType << cbor::MajorTypeShift) | cbor::DoublePrecisionFloat)
&& io->write(bytes, sizeof(bytes))); }
// This dispatch would be more simple with C++17 constexpr if
template<typename T> bool _bind(T t, typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value>::type* =nullptr) {
return putInteger(cbor::UnsignedIntegerType, quint64(t)); }
template<typename T> bool _bind(T t, typename std::enable_if<std::is_integral<T>::value && std:: is_signed<T>::value>::type* =nullptr) {
return t<0 ? putInteger(cbor::NegativeIntegerType, quint64(-1-t)) // see https://tools.ietf.org/html/rfc7049#section-2.1
: putInteger(cbor::UnsignedIntegerType, quint64( t)); }
template<class T_> friend class Seq; // calls methods below
......@@ -151,3 +162,5 @@ template<> struct BindSupport<CborWriter,const char*> : BindNative {};
template<> struct BindSupport<CborWriter, bool&> : BindNative {};
template<> struct BindSupport<CborWriter, float&> : BindNative {};
template<> struct BindSupport<CborWriter, double&> : BindNative {};
template<> struct BindSupport<CborWriter, int&> : BindNative {}; // TODO remove
template<typename T> struct BindSupport<CborWriter,T&,typename std::enable_if<std::is_integral<T>::value,T&>::type> : BindNative {};
......@@ -87,7 +87,7 @@ protected:
bool _bind( bool& b) { set(QJsonValue(b)); return true; }
bool _bind( double& d) { set(QJsonValue(d)); return true; }
template<typename T> bool _bind(T t, typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr) { return _bind(double(t)); }
template<typename T> bool _bind(T& t, typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr) { double d(t); return _bind(d); }
template<class T_> friend class Seq; // calls methods below
......@@ -115,7 +115,8 @@ QJsonBuilder::QJsonBuilder(QJsonValue* v) : QScopedResult(new QJsonBuilderImpl(v
template<> struct BindSupport<QJsonBuilderImpl,const char*> : BindNative {};
template<> struct BindSupport<QJsonBuilderImpl, bool&> : BindNative {};
template<> struct BindSupport<QJsonBuilderImpl, double&> : BindNative {};
//template<typename T> struct BindSupport<QJsonBuilderImpl,std::enable_if_t<std::is_arithmetic<T>::value,T>> : BindNative {};
template<> struct BindSupport<QJsonBuilderImpl, int&> : BindNative {}; // TODO remove
template<typename T> struct BindSupport<QJsonBuilderImpl,T&,typename std::enable_if<std::is_arithmetic<T>::value,T&>::type> : BindNative {};
// --------------------------------------------------------------------------
......@@ -169,7 +170,7 @@ protected:
bool _bind(QString& v) { if (current()->isString()) { v = current()->toString(); return true; } reportError(qBindExpectedText ); return false; }
bool _bind( bool& v) { if (current()->isBool ()) { v = current()->toBool (); return true; } reportError(qBindExpectedBoolean ); return false; }
bool _bind( double& v) { if (current()->isDouble()) { v = current()->toDouble(); return true; } reportError(qBindExpectedDecimal ); return false; }
//template<typename T> bool _bind(T& t, std::enable_if_t<std::is_arithmetic<T>::value>* = nullptr) { double d; if (_bind(d)) { t = d; return true; } return false; }
template<typename T> bool _bind(T& t, typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr) { double d; if (_bind(d)) { t = d; return true; } return false; }
template<class T_> friend class Seq; // calls methods below
......@@ -189,7 +190,8 @@ template<> struct BindSupport<JsonVisitorImpl,const char*> : BindNative {};
template<> struct BindSupport<JsonVisitorImpl, QString&> : BindNative {};
template<> struct BindSupport<JsonVisitorImpl, bool&> : BindNative {};
template<> struct BindSupport<JsonVisitorImpl, double&> : BindNative {};
// TODO template<> struct BindSupport<JsonVisitorImpl,std::enable_if_t<std::is_arithmetic<T>::value,T&> : BindNative {};
template<> struct BindSupport<JsonVisitorImpl, int&> : BindNative {}; // TODO remove
template<typename T> struct BindSupport<JsonVisitorImpl,T&,typename std::enable_if<std::is_arithmetic<T>::value,T&>::type> : BindNative {};
// --------------------------------------------------------------------------
......@@ -231,12 +233,12 @@ protected:
bool _bind( bool& n) { return io->write( n? "true" : "false" ); }
bool _bind( float& n) { return io->write(QByteArray::number(n, 'g', std::numeric_limits< float>::max_digits10)); }
bool _bind( double& n) { return io->write(QByteArray::number(n, 'g', std::numeric_limits<double>::max_digits10)); }
bool _bind(qulonglong& n) { return io->write(QByteArray::number(n )); }
bool _bind( qlonglong& n) { return io->write(QByteArray::number(n )); }
// This dispatch would be more simple with C++17 constexpr if
template<typename T> bool _bind(T t, typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value>::type* =nullptr) { return _bind(qulonglong(t)); }
template<typename T> bool _bind(T t, typename std::enable_if<std::is_integral<T>::value && std:: is_signed<T>::value>::type* =nullptr) { return _bind( qlonglong(t)); }
template<typename T> bool _bind(T t, typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value>::type* =nullptr) {
return io->write(QByteArray::number(qulonglong(t))); }
template<typename T> bool _bind(T t, typename std::enable_if<std::is_integral<T>::value && std:: is_signed<T>::value>::type* =nullptr) {
return io->write(QByteArray::number( qlonglong(t))); }
template<class T_> friend class Seq; // calls methods below
......@@ -253,8 +255,8 @@ template<> struct BindSupport<QJsonWriterImpl,const char*> : BindNative {};
template<> struct BindSupport<QJsonWriterImpl, bool&> : BindNative {};
template<> struct BindSupport<QJsonWriterImpl, float&> : BindNative {};
template<> struct BindSupport<QJsonWriterImpl, double&> : BindNative {};
template<> struct BindSupport<QJsonWriterImpl,qulonglong&> : BindNative {};
template<> struct BindSupport<QJsonWriterImpl, qlonglong&> : BindNative {};
template<> struct BindSupport<QJsonWriterImpl, int&> : BindNative {}; // TODO remove
template<typename T> struct BindSupport<QJsonWriterImpl,T&,typename std::enable_if<std::is_integral<T>::value,T&>::type> : BindNative {};
// --------------------------------------------------------------------------
......@@ -337,42 +339,19 @@ protected:
}
reportError(qBindExpectedBoolean);
return false; }
bool _bind( double& n) { qlonglong ll=0; double d=0; int digit;
bool isNegative = get('-', "[{\"0123456789.");
if ((digit = getDigit()) < 0) {
reportError(qBindExpectedDecimal);
return false; // do not accept no digit otherwise we may accept an empty mantissa or string!
}
do { // TODO detect overflow
ll=ll*10+digit; d=d*10+digit;
}
while (0 <= (digit = getDigit())); // accept many leading '0' which is more permissive than JSON
if ( get('.')) {
// roughly
// d = ll;
// m_stream >> decimal // except it would eat exponent
// d += decimal
double decimal=.1;
while (0 <= (digit = getDigit())) {
d+=decimal*digit; decimal/=10;
}
}
bool _bind( float& n) { double d; qlonglong i; bool b;
auto r=getNumber(d, i, b); if (r) n = d; return r; }
bool _bind( double& n) { double d; qlonglong i; bool b;
auto r=getNumber(d, i, b); if (r) n = d; return r; }
if ( get('e') || get('E')) {
qlonglong exponent = 0;
bool isNegativeExponent = get('-');
get('+');
while (0 <= (digit = getDigit())) {
exponent=exponent*10+digit; // TODO detect overflow
}
// TODO detect overflow
d *=10^(isNegativeExponent ? -exponent : exponent);
}
// TODO if (!next(",]}") {}
// This dispatch would be more simple with C++17 constexpr if
template<typename T> bool _bind(T& t, typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value>::type* =nullptr) {
double d; qlonglong i; bool isNegative;
auto r=getNumber(d, i, isNegative); if (r && !isNegative) t=i; return r; }
template<typename T> bool _bind(T& t, typename std::enable_if<std::is_integral<T>::value && std:: is_signed<T>::value>::type* =nullptr) {
double d; qlonglong i; bool isNegative;
auto r=getNumber(d, i, isNegative); if (r) t=(isNegative?-i:i); return r; }
n = isNegative ? -d : d;
return true; }
bool _any() { QByteArray t; double d; bool b;
return (_sequence() && _out())
|| _bind(t)
......@@ -397,6 +376,48 @@ protected:
return get(*level.end, "}"); }
private:
bool getNumber(double& d, qlonglong&i, bool& isNegative) {
isNegative = get('-', "[{\"0123456789.");
int digit;
if ((digit = getDigit()) < 0) {
reportError(qBindExpectedDecimal);
return false; // do not accept no digit otherwise we may accept an empty mantissa or string!
}
i=0; d=0;
do { // TODO detect overflow
i=i*10+digit; d=d*10+digit;
}
while (0 <= (digit = getDigit())); // accept many leading '0' which is more permissive than JSON
if ( get('.')) {
// roughly
// d = i;
// m_stream >> decimal // except it would eat exponent
// d += decimal
double decimal=.1;
while (0 <= (digit = getDigit())) {
d+=decimal*digit; decimal/=10;
}
}
if ( get('e') || get('E')) {
qlonglong exponent = 0;
bool isNegativeExponent = get('-');
get('+');
while (0 <= (digit = getDigit())) {
exponent=exponent*10+digit; // TODO detect overflow
}
// TODO detect overflow
d *=10^(isNegativeExponent ? -exponent : exponent);
}
// TODO if (!next(",]}") {}
if (isNegative)
d=-d;
return true;
}
int getDigit(int base = 10) { Q_ASSERT(0<base);
int digit;
if ( 0 <= (digit=nextChar()-'0' ) && digit < base && base <= 10) { getChar(); return digit; }
......@@ -461,7 +482,10 @@ private:
QJsonReader::QJsonReader(QIODevice* io) : QScopedResult(new QJsonReaderImpl(io), true) {}
template<> struct BindSupport<QJsonReaderImpl,QByteArray&> : BindNative {};
template<> struct BindSupport<QJsonReaderImpl, bool&> : BindNative {};
template<> struct BindSupport<QJsonReaderImpl, float&> : BindNative {};
template<> struct BindSupport<QJsonReaderImpl, double&> : BindNative {};
template<> struct BindSupport<QJsonReaderImpl, int&> : BindNative {}; // TODO remove
template<typename T> struct BindSupport<QJsonReaderImpl,T&,typename std::enable_if<std::is_integral<T>::value,T&>::type> : BindNative {};
// //////////////////////////////////////////////////////////////////////////
// QBind<TResult,QJson*> support
......
......@@ -54,7 +54,7 @@
struct Person
{
QString firstName, lastName; double height; QVector<QString> phones;
QString firstName, lastName; double height; int age; QVector<QString> phones;
template<class TResult>
TResult bind(Val<TResult> value) { // since we only bind T& (no const T&), it works with TResult::Mode==Read as well as Write
......@@ -63,7 +63,7 @@ struct Person
.bind(firstName)
.bind(lastName)
.bind(height)
// TODO .any() // ignored weight
.bind(age) // TODO .any() // ignored
.bind(phones) // recursive calls to QBind will take care of that part
; // automagically closes all opened structures
}
......@@ -147,7 +147,7 @@ int main()
2./3, 1./3, 2./3, 1.,
1./3, 2./3, 1./3, 1.,
0. , 0. , 0. , 1.});
Person person{"John","Doe",1.75,{"+44 1234567","+44 2345678"}};
Person person{"John","Doe",1.75,-1,{"+44 1234567","+44 2345678"}};
const double PI=3.141592653589793;
// Temporary buffers
......@@ -299,7 +299,7 @@ int main()
{
QBuffer json;
json.open(QIODevice::ReadOnly);
json.buffer() = "_[ _\"John\" _, \"Doe\" , _1.75 , " /*69.,*/ " [ \"+44 1234567\" , \"+44 2345678\" ], \"superfluous item\" _] ";
json.buffer() = "_[ _\"John\" _, \"Doe\" , _1.75 , 18, [ \"+44 1234567\" , \"+44 2345678\" ], \"superfluous item\" _] ";
QJsonValue v;
Person p;
QVector<QJsonReaderImpl::Error> jsonReaderErrors ;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment