Skip to content

Commit 2154a81

Browse files
committedAug 11, 2011
Simplified three-value logic code
1 parent 1f98ec5 commit 2154a81

File tree

2 files changed

+42
-85
lines changed

2 files changed

+42
-85
lines changed
 

‎src/core/qgsexpression.cpp

Lines changed: 41 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -30,78 +30,60 @@ extern QgsExpression::Node* parseExpression( const QString& str, QString& parser
3030
///////////////////////////////////////////////
3131
// three-value logic
3232

33-
class TVL
33+
enum TVL
3434
{
35-
public:
36-
enum Value
37-
{
38-
False,
39-
True,
40-
Unknown
41-
};
42-
43-
static TVL::Value AND[3][3];
44-
static TVL::Value OR[3][3];
45-
static TVL::Value NOT[3];
46-
47-
TVL() : val( Unknown ) {}
48-
TVL( bool v ) : val( v ? True : False ) {}
49-
TVL( Value v ) : val( v ) {}
50-
51-
TVL operator!() { return NOT[val]; }
52-
TVL operator&( const TVL& other ) { return AND[val][other.val]; }
53-
TVL operator|( const TVL& other ) { return OR[val][other.val]; }
54-
55-
// conversion for result
56-
QVariant toVariant()
57-
{
58-
if ( val == Unknown )
59-
return QVariant();
60-
else
61-
return ( val == True ? 1 : 0 );
62-
}
63-
64-
Value val;
35+
False,
36+
True,
37+
Unknown
6538
};
6639

67-
// false true unknown
68-
TVL::Value TVL::AND[3][3] = { { TVL::False, TVL::False, TVL::False }, // false
69-
{ TVL::False, TVL::True, TVL::Unknown }, // true
70-
{ TVL::False, TVL::Unknown, TVL::Unknown }
71-
};// unknown
40+
static TVL AND[3][3] = {
41+
// false true unknown
42+
{ False, False, False }, // false
43+
{ False, True, Unknown }, // true
44+
{ False, Unknown, Unknown } // unknown
45+
};
7246

73-
TVL::Value TVL::OR[3][3] = { { TVL::False, TVL::True, TVL::Unknown }, // false
74-
{ TVL::True, TVL::True, TVL::True }, // true
75-
{ TVL::Unknown, TVL::True, TVL::Unknown }
76-
};// unknown
47+
static TVL OR[3][3] = {
48+
{ False, True, Unknown }, // false
49+
{ True, True, True }, // true
50+
{ Unknown, True, Unknown } // unknown
51+
};
7752

78-
TVL::Value TVL::NOT[3] = { TVL::True, TVL::False, TVL::Unknown };
53+
static TVL NOT[3] = { True, False, Unknown };
7954

80-
Q_DECLARE_METATYPE( TVL )
55+
QVariant tvl2variant( TVL v )
56+
{
57+
switch ( v )
58+
{
59+
case False: return 0;
60+
case True: return 1;
61+
case Unknown: return QVariant();
62+
}
63+
}
8164

82-
#define TVL_True QVariant::fromValue(TVL(true))
83-
#define TVL_False QVariant::fromValue(TVL(false))
84-
#define TVL_Unknown QVariant::fromValue(TVL())
65+
#define TVL_True QVariant(1)
66+
#define TVL_False QVariant(0)
67+
#define TVL_Unknown QVariant()
8568

8669
///////////////////////////////////////////////
8770
// QVariant checks and conversions
8871

8972
inline bool isIntSafe( const QVariant& v )
9073
{
91-
if ( v.type() == QVariant::Int || v.canConvert<TVL>() ) return true;
74+
if ( v.type() == QVariant::Int ) return true;
9275
if ( v.type() == QVariant::Double ) return false;
9376
if ( v.type() == QVariant::String ) { bool ok; v.toString().toInt( &ok ); return ok; }
9477
return false;
9578
}
9679
inline bool isDoubleSafe( const QVariant& v )
9780
{
98-
if ( v.type() == QVariant::Double || v.type() == QVariant::Int || v.canConvert<TVL>() ) return true;
81+
if ( v.type() == QVariant::Double || v.type() == QVariant::Int ) return true;
9982
if ( v.type() == QVariant::String ) { bool ok; v.toString().toDouble( &ok ); return ok; }
10083
return false;
10184
}
10285

103-
inline bool isNull( const QVariant& v ) { return v.type() == QVariant::Invalid || ( v.canConvert<TVL>() && v.value<TVL>().val == TVL::Unknown ); }
104-
inline bool isTVL( const QVariant & v ) { return v.canConvert<TVL>(); }
86+
inline bool isNull( const QVariant& v ) { return v.type() == QVariant::Invalid; }
10587

10688
///////////////////////////////////////////////
10789
// evaluation error macros
@@ -131,24 +113,11 @@ const char* QgsExpression::UnaryOperatorText[] =
131113
// implicit conversion to string
132114
static QString getStringValue( const QVariant& value, QgsExpression* )
133115
{
134-
if ( value.canConvert<TVL>() )
135-
{
136-
TVL::Value tvl = value.value<TVL>().val;
137-
Q_ASSERT( tvl != TVL::Unknown ); // null should be handled before calling this function
138-
return ( tvl == TVL::True ? "1" : "0" );
139-
}
140116
return value.toString();
141117
}
142118

143119
static double getDoubleValue( const QVariant& value, QgsExpression* parent )
144120
{
145-
if ( value.canConvert<TVL>() )
146-
{
147-
TVL::Value tvl = value.value<TVL>().val;
148-
Q_ASSERT( tvl != TVL::Unknown ); // null should be handled before calling this function
149-
return ( tvl == TVL::True ? 1 : 0 );
150-
}
151-
152121
bool ok;
153122
double x = value.toDouble( &ok );
154123
if ( !ok )
@@ -161,13 +130,6 @@ static double getDoubleValue( const QVariant& value, QgsExpression* parent )
161130

162131
static int getIntValue( const QVariant& value, QgsExpression* parent )
163132
{
164-
if ( value.canConvert<TVL>() )
165-
{
166-
TVL::Value tvl = value.value<TVL>().val;
167-
Q_ASSERT( tvl != TVL::Unknown ); // null should be handled before calling this function
168-
return ( tvl == TVL::True ? 1 : 0 );
169-
}
170-
171133
bool ok;
172134
int x = value.toInt( &ok );
173135
if ( !ok )
@@ -182,21 +144,21 @@ static int getIntValue( const QVariant& value, QgsExpression* parent )
182144
// this handles also NULL values
183145
static TVL getTVLValue( const QVariant& value, QgsExpression* parent )
184146
{
185-
if ( isTVL( value ) )
186-
return value.value<TVL>();
187-
188147
// we need to convert to TVL
189148
if ( value.type() == QVariant::Invalid )
190-
return TVL();
149+
return Unknown;
150+
151+
if ( value.type() == QVariant::Int )
152+
return value.toInt() != 0 ? True : False;
191153

192154
bool ok;
193155
double x = value.toDouble( &ok );
194156
if ( !ok )
195157
{
196158
parent->setEvalErrorString( QString( "Cannot convert '%1' to boolean" ).arg( value.toString() ) );
197-
return TVL();
159+
return Unknown;
198160
}
199-
return x != 0 ? TVL( true ) : TVL( false );
161+
return x != 0 ? True : False;
200162
}
201163

202164
//////
@@ -509,13 +471,7 @@ QVariant QgsExpression::evaluate( QgsFeature* f )
509471
return QVariant();
510472
}
511473

512-
QVariant res = mRootNode->eval( this, f );
513-
if ( res.canConvert<TVL>() )
514-
{
515-
// convert 3-value logic to int (0/1) or null
516-
return res.value<TVL>().toVariant();
517-
}
518-
return res;
474+
return mRootNode->eval( this, f );
519475
}
520476

521477
QVariant QgsExpression::evaluate( QgsFeature* f, const QgsFieldMap& fields )
@@ -564,7 +520,7 @@ QVariant QgsExpression::NodeUnaryOperator::eval( QgsExpression* parent, QgsFeatu
564520
{
565521
TVL tvl = getTVLValue( val, parent );
566522
ENSURE_NO_EVAL_ERROR;
567-
return QVariant::fromValue( ! tvl );
523+
return tvl2variant( NOT[tvl] );
568524
}
569525

570526
case uoMinus:
@@ -641,14 +597,14 @@ QVariant QgsExpression::NodeBinaryOperator::eval( QgsExpression* parent, QgsFeat
641597
{
642598
TVL tvlL = getTVLValue( vL, parent ), tvlR = getTVLValue( vR, parent );
643599
ENSURE_NO_EVAL_ERROR;
644-
return QVariant::fromValue( tvlL & tvlR );
600+
return tvl2variant( AND[tvlL][tvlR] );
645601
}
646602

647603
case boOr:
648604
{
649605
TVL tvlL = getTVLValue( vL, parent ), tvlR = getTVLValue( vR, parent );
650606
ENSURE_NO_EVAL_ERROR;
651-
return QVariant::fromValue( tvlL | tvlR );
607+
return tvl2variant( OR[tvlL][tvlR] );
652608
}
653609

654610
case boEQ:

‎tests/src/core/testqgsexpression.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ class TestQgsExpression: public QObject
148148
QTest::newRow( "T and T" ) << "1=1 and 2=2" << false << QVariant( 1 );
149149
QTest::newRow( "not T" ) << "not 1=1" << false << QVariant( 0 );
150150
QTest::newRow( "not F" ) << "not 2=3" << false << QVariant( 1 );
151+
QTest::newRow( "null" ) << "null=1" << false << QVariant();
151152
QTest::newRow( "U or F" ) << "null=1 or 2=3" << false << QVariant();
152153
QTest::newRow( "U and F" ) << "null=1 and 2=3" << false << QVariant( 0 );
153154
QTest::newRow( "invalid and" ) << "'foo' and 2=3" << true << QVariant();

0 commit comments

Comments
 (0)
Please sign in to comment.