Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
MODMED
modmedLog
Commits
bc4cdfc3
Commit
bc4cdfc3
authored
Jul 11, 2019
by
EXT Arnaud Clère
Browse files
Added rough QSettings support
parent
b5a80eb4
Changes
7
Expand all
Hide whitespace changes
Inline
Side-by-side
tests/QBind/QBind.pro
View file @
bc4cdfc3
...
...
@@ -52,6 +52,7 @@ HEADERS += \
QBind_impl
.
h
\
QCbor_impl
.
h
\
QJson_impl
.
h
\
QSettings_impl
.
h
\
QVariant_impl
.
h
\
QModel_impl
.
h
\
QData_impl
.
h
\
...
...
@@ -62,4 +63,5 @@ DISTFILES += \
README
.
md
\
design
.
md
\
persons
.
proto
\
sample
.
ini
\
samples
.
txt
tests/QBind/QSettings_impl.h
0 → 100644
View file @
bc4cdfc3
/****************************************************************************
* **
* ** Copyright (C) 2017 MinMaxMedical.
* ** All rights reserved.
* ** Contact: MinMaxMedical <InCAS@MinMaxMedical.com>
* **
* ** This file is part of the modmedLog module.
* **
* ** $QT_BEGIN_LICENSE:BSD$
* ** You may use this file under the terms of the BSD license as follows:
* **
* ** "Redistribution and use in source and binary forms, with or without
* ** modification, are permitted provided that the following conditions are
* ** met:
* ** * Redistributions of source code must retain the above copyright
* ** notice, this list of conditions and the following disclaimer.
* ** * Redistributions in binary form must reproduce the above copyright
* ** notice, this list of conditions and the following disclaimer in
* ** the documentation and/or other materials provided with the
* ** distribution.
* ** * Neither the name of MinMaxMedical S.A.S. and its Subsidiary(-ies) nor
* ** the names of its contributors may be used to endorse or promote
* ** products derived from this software without specific prior written
* ** permission.
* **
* ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
* ** $QT_END_LICENSE$
* **
* ****************************************************************************/
#pragma once
#include <QtCore/qsettings.h>
#include <QtCore/qvariant.h>
#include <QtCore/qstack.h>
#include "QBind_impl.h"
// //////////////////////////////////////////////////////////////////////////
// QBind<T,QVariant*> support for the fixed set of QSettingsWriter's BindNative types
class
QSettingsWriter
:
public
IWriter
{
Q_DISABLE_COPY
(
QSettingsWriter
)
public:
QSettingsWriter
(
QSettings
*
s
)
:
settings
(
s
)
{
Q_ASSERT
(
s
);
levels
.
push
(
Level
(
""
));
}
// Shortcuts
/**/
Val
<
Cursor
>
value
(
)
{
return
Cursor
(
this
).
value
();
}
/**/
Seq
<
Cursor
>
sequence
(
quint32
*
s
=
nullptr
)
{
return
Cursor
(
this
).
value
().
sequence
(
s
);
}
template
<
typename
T
>
Cursor
bind
(
T
&&
t
)
{
return
Cursor
(
this
).
value
().
bind
(
std
::
forward
<
T
>
(
t
));
}
protected:
template
<
typename
T
>
bool
_bind
(
T
&&
t
)
{
settings
->
setValue
(
key
(),
QVariant
::
fromValue
(
t
)
);
return
true
;
}
bool
_bind
(
quint8
&&
t
)
{
settings
->
setValue
(
key
(),
QVariant
(
int
(
t
)));
return
true
;
}
bool
_bind
(
quint16
&&
t
)
{
settings
->
setValue
(
key
(),
QVariant
(
int
(
t
)));
return
true
;
}
bool
_bind
(
quint32
&&
t
)
{
settings
->
setValue
(
key
(),
QVariant
(
int
(
t
)));
return
true
;
}
bool
_bind
(
const
char
*
u
)
{
settings
->
setValue
(
key
(),
QVariant
(
u
)
);
return
true
;
}
bool
_null
(
)
{
settings
->
setValue
(
key
(),
QVariant
(
)
);
return
true
;
}
bool
_sequence
(
quint32
*
=
nullptr
)
{
settings
->
beginGroup
(
key
());
levels
.
push
(
Level
(
));
return
true
;
}
bool
_record
(
quint32
*
=
nullptr
)
{
settings
->
beginGroup
(
key
());
levels
.
push
(
Level
(
""
));
return
true
;
}
bool
_item
(
QName
n
)
{
levels
.
last
().
key
=
n
;
return
true
;
}
bool
_item
(
)
{
levels
.
last
().
idx
++
;
return
true
;
}
bool
_out
(
)
{
levels
.
pop
();
settings
->
endGroup
();
return
true
;
}
private:
QString
key
()
{
Q_ASSERT
(
!
levels
.
isEmpty
());
return
levels
.
last
().
key
!=
nullptr
?
QString
(
levels
.
last
().
key
)
:
QString
::
number
(
levels
.
last
().
idx
);
}
QSettings
*
settings
;
struct
Level
{
QName
key
;
quint32
idx
=
0
;
Level
(
QName
k
=
nullptr
)
:
key
(
k
)
{}
};
QStack
<
Level
>
levels
=
QStack
<
Level
>
();
//!< minimal dynamic context to implement out() and ensure actual building in case QSettingsWriter is abandoned
};
// --------------------------------------------------------------------------
class
QSettingsReader
:
public
IReader
{
Q_DISABLE_COPY
(
QSettingsReader
)
public:
Q_ENABLE_MOVE
(
QSettingsReader
,
std
::
swap
(
isChoice
,
o
.
isChoice
);
)
QSettingsReader
(
QSettings
*
s
)
:
settings
(
s
)
{
Q_ASSERT
(
s
);
levels
.
push
(
Level
(
""
));
}
struct
Error
{
const
char
*
error
;
QUtf8String
path
;
template
<
class
T
>
T
bind
(
Val
<
T
>&&
value
)
{
return
value
.
bind
(
QUtf8String
(
error
)
+
' '
+
path
);
}
};
QVector
<
Error
>
errors
;
QUtf8String
currentPath
()
{
QUtf8String
path
;
Q_FOREACH
(
Level
l
,
levels
)
{
if
(
l
.
key
)
{
path
.
append
(
'/'
).
append
(
l
.
key
);
}
else
{
path
.
append
(
'/'
).
append
(
QUtf8String
::
number
(
l
.
idx
));
}
}
return
path
;
}
// Shortcuts
template
<
typename
T
>
Cursor
bind
(
T
&&
t
)
{
return
Cursor
(
this
).
value
().
bind
(
std
::
forward
<
T
>
(
t
));
}
protected:
template
<
typename
T
>
bool
_bind
(
T
&
t
)
{
return
set
(
t
,
"Expected declared metatype T"
);
}
bool
_bind
(
QUtf8String
&
t
)
{
return
set
(
t
,
qBindExpectedText
);
}
bool
_bind
(
QString
&
t
)
{
return
set
(
t
,
qBindExpectedText
);
}
bool
_bind
(
bool
&
t
)
{
return
set
(
t
,
qBindExpectedBoolean
);
}
bool
_bind
(
QByteArray
&
t
)
{
return
set
(
t
,
qBindExpectedBytes
);
}
// Convert numerical types to strictly larger ones // TODO convert all compatible values
bool
_bind
(
qint8
&
t
)
{
return
set
(
t
,
qBindExpectedInteger
);
}
bool
_bind
(
qint16
&
t
)
{
return
set
(
t
,
qBindExpectedInteger
);
}
bool
_bind
(
qint32
&
t
)
{
return
set
(
t
,
qBindExpectedInteger
);
}
bool
_bind
(
qint64
&
t
)
{
return
set
(
t
,
qBindExpectedInteger
);
}
bool
_bind
(
quint8
&
t
)
{
return
set
(
t
,
qBindExpectedPositiveNumber
);
}
bool
_bind
(
quint16
&
t
)
{
return
set
(
t
,
qBindExpectedPositiveNumber
);
}
bool
_bind
(
quint32
&
t
)
{
return
set
(
t
,
qBindExpectedPositiveNumber
);
}
bool
_bind
(
quint64
&
t
)
{
return
set
(
t
,
qBindExpectedPositiveNumber
);
}
bool
_bind
(
float
&
t
)
{
return
set
(
t
,
qBindExpectedDecimal
);
}
bool
_bind
(
double
&
t
)
{
return
set
(
t
,
qBindExpectedDecimal
);
}
bool
_sequence
(
quint32
*
=
nullptr
)
{
if
(
levels
.
last
().
isGroup
)
{
levels
.
push
(
Level
(
));
return
true
;
}
_reportError
(
qBindExpectedSequence
);
return
false
;
}
bool
_record
(
quint32
*
=
nullptr
)
{
if
(
levels
.
last
().
isGroup
)
{
levels
.
push
(
Level
(
""
));
return
true
;
}
_reportError
(
qBindExpectedRecord
);
return
false
;
}
bool
_null
(
)
{
if
(
settings
->
value
(
key
()).
isNull
())
{
return
true
;
}
_reportError
(
qBindExpectedNull
);
return
false
;
}
bool
_item
(
QUtf8String
&
k
)
{
levels
.
last
().
key
=
k
;
return
true
;
}
bool
_item
(
)
{
levels
.
last
().
idx
++
;
return
true
;
}
bool
_out
(
)
{
levels
.
pop
();
settings
->
endGroup
();
return
true
;
}
bool
_isOk
()
{
return
settings
;
}
void
_setChoice
(
bool
v
)
{
isChoice
=
v
;
}
void
_reportError
(
const
char
*
error
)
{
if
(
!
isChoice
)
errors
.
append
(
Error
{
error
,
currentPath
()
});
}
private:
template
<
typename
T
>
bool
set
(
T
&
t
,
const
char
*
error
)
{
QVariant
v
=
settings
->
value
(
key
());
if
(
v
.
convert
(
qMetaTypeId
<
T
>
()))
{
t
=
v
.
value
<
T
>
();
return
true
;
}
_reportError
(
error
);
return
false
;
}
QString
key
()
{
Q_ASSERT
(
!
levels
.
isEmpty
());
return
levels
.
last
().
key
!=
nullptr
?
QString
(
levels
.
last
().
key
)
:
QString
::
number
(
levels
.
last
().
idx
);
}
QSettings
*
settings
;
struct
Level
{
QName
key
;
int
idx
=-
1
;
bool
isGroup
=
true
;
Level
(
QName
n
=
nullptr
,
bool
isGroup
=
true
)
:
key
(
n
),
isGroup
(
isGroup
)
{}
};
QStack
<
Level
>
levels
;
bool
isChoice
=
false
;
};
tests/QBind/README.md
View file @
bc4cdfc3
...
...
@@ -3,7 +3,7 @@
QBind was developed to demonstrate the feasibility and advantages of a novel (de)serialization mechanism on top of
existing
[
Qt
](
http://qt.io
)
data formats (Settings, QDataStream, Json, Cbor, Xml) and generic data types (containers, QVariant, QMetaObject, etc.).
> **DISLAIMER** It is not currently unit-tested but
only
provided with a [sample and benchmark](main.cpp). Also, the
> **DISLAIMER** It is not currently unit-tested but provided with a [sample and benchmark](main.cpp). Also, the
> implementation is written in a concise style that supported the multiple refactorings but does not help explaining it.
> The README and [design](design.md) documentation should be read before trying to understand the implementation.
...
...
@@ -45,7 +45,7 @@ See below:
*
**W4. Format can be changed at runtime**
(a compiled tracepoint in a library must be able to generate Json or Cbor as desired by library user)
*
**W5. Good support of Qt data**
:
1.
almost all features of simple data (QJson..., QDataStream,
*
QSettings
(TBD)*
)
1.
almost all features of simple data (QJson..., QDataStream, QSettings)
2.
most features of complex data (QCbor..., QXml..., QMetaObject, QModel...)
*
**W6. No restriction on output data size**
(some restrictions may apply with specific implementations that may, e.g. store context for each data structure levels)
...
...
@@ -75,7 +75,7 @@ for data formats supporting it like [CBOR value sharing tags](http://cbor.schmor
## The key idea
QBind is more general than (de)serialization and should be understood as a generic way to traverse[^1] a C++ dataset a
long with
QBind is more general than (de)serialization and should be understood as a generic way to traverse[^1] a C++ dataset a
nd
another generic dataset, binding the related parts together. In effect:
*
the traversal may be partial, leaving out unrelated dataset parts (satisfying R2)
*
the same traversal may be used to:
...
...
tests/QBind/main.cpp
View file @
bc4cdfc3
...
...
@@ -52,6 +52,7 @@
#include "QVariant_impl.h" // QVariantBuilder, QVariantVisitor and QBind<QVariant,_> support
#include "QModel_impl.h" // Q*ModelWriter support
#include "QXml_impl.h" // QXmlWriter support
#include "QSettings_impl.h" // QSettings* support
#ifdef PROTOBUF
#include "persons.pb.h"
...
...
@@ -944,6 +945,31 @@ int main(int argc, char *argv[])
STOP
(
"Cbor>Json"
,
QString
(
b
.
buffer
()
+
" | "
+
Text
(
readerErrors
)))
}
GROUP_STOP
GROUP
(
"Person<>Settings"
)
//====================================================
{
QFileInfo
iniFile
(
QDir
::
currentPath
()
+
"/../QBind"
);
QSettings
::
setPath
(
QSettings
::
IniFormat
,
QSettings
::
UserScope
,
iniFile
.
path
());
QSettings
ini
(
QSettings
::
IniFormat
,
QSettings
::
UserScope
,
"QBind"
,
"sample"
);
QSettings
nat
(
QSettings
::
UserScope
,
"QBind"
,
"sample"
);
QVector
<
QSettingsReader
::
Error
>
errors
;
//---------------------------------------------------------------------
START
{
QSettingsWriter
(
&
nat
).
bind
(
person
);
}
STOP
(
"P>Settings"
,
QString
(
Text
(
person
)))
START
{
QSettingsReader
r
(
&
nat
);
r
.
bind
(
person
);
errors
=
r
.
errors
;
}
STOP
(
"Settings>P"
,
QString
(
Text
(
person
)
+
" | "
+
Text
(
errors
)))
START
{
QSettingsWriter
(
&
ini
).
bind
(
person
);
}
STOP
(
"P>Settings"
,
iniFile
.
fileName
())
//---------------------------------------------------------------------
}
GROUP_STOP
if
(
argc
<=
1
||
strcmp
(
argv
[
1
],
"gui"
)
==
0
)
{
doGuiExample
();
...
...
tests/QBind/results-build-QBind-Desktop_Qt_5_12_3_MSVC2017_64bit-Release.csv
View file @
bc4cdfc3
This diff is collapsed.
Click to expand it.
tests/QBind/sample.ini
0 → 100644
View file @
bc4cdfc3
[names]
1
=
John
2
=
Doe
[General]
height
=
1.75
age
=
18
comments
=
unicode is likely U+01
\x
1 + U+1F
\x
1f + U+A4
\x
a4 U+B0
\x
b0 U+D8
\x
d8 U+FF
\x
ff
tests/QBind/samples.txt
View file @
bc4cdfc3
...
...
@@ -73,3 +73,7 @@ CborValue>P |(Person)[ names:[ John Doe] height:1.75 age:-1 phones:[] comments
Cbor>CborValue|{"names": ["John", "Doe"], "height": 1.75, "age": -1, "phones": [], "comments": "", "children": []} | []
CborValue>Cbor|a6656e616d657382644a6f686e63446f6566686569676874fb3ffc00000000000063616765206670686f6e65738068636f6d6d656e747360686368696c6472656e80
Cbor>Json |{"names":["John","Doe"],"height":1.75,"age":} | []
Person<>Settings |================================================================================
P>Settings |(Person)[ names:[ John Doe] height:1.75 age:18 phones:[] comments:unicode is likely U+01 + U+1F + U+A4 ¤ U+B0 ° U+D8 Ø U+FF ÿ children:[]]
Settings>P |(Person)[ names:[ John Doe] height:1.75 age:18 phones:[] comments:unicode is likely U+01 + U+1F + U+A4 ¤ U+B0 ° U+D8 Ø U+FF ÿ children:[]] | []
P>Settings |QBind
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment