Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[sipify] implement template inheritance
  • Loading branch information
3nids committed May 19, 2017
1 parent bbcc872 commit fb8edea
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 123 deletions.
1 change: 1 addition & 0 deletions python/core/core.sip
Expand Up @@ -113,6 +113,7 @@
%Include qgsobjectcustomproperties.sip
%Include qgsofflineediting.sip
%Include qgsogcutils.sip
%Include qgsoptional.sip
%Include qgsoptionalexpression.sip
%Include qgsowsconnection.sip
%Include qgspaintenginehack.sip
Expand Down
90 changes: 90 additions & 0 deletions python/core/qgsoptional.sip
@@ -0,0 +1,90 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgsoptional.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/



template<T>
class QgsOptional
{
%Docstring

QgsOptional is a container for other classes and adds an additional enabled/disabled flag.

Often it is used for configuration options which can be enabled or disabled but also have
more internal configuration information that should not be lost when disabling and re-enabling.

.. versionadded:: 3.0
%End

%TypeHeaderCode
#include "qgsoptional.h"
%End
public:

QgsOptional();
%Docstring
A QgsOptional is disabled by default if default constructed.
%End

QgsOptional( const T &data );
%Docstring
A QgsOptional is enabled by default if constructed with payload.
%End

QgsOptional( const T &data, bool enabled );
%Docstring
A QgsOptional constructed with enabled status and data
%End

bool operator== ( const QgsOptional<T> &other ) const;

operator bool() const;
%Docstring
Boolean operator. Will return true if this optional is enabled.
%End

bool enabled() const;
%Docstring
Check if this optional is enabled

.. versionadded:: 3.0
:rtype: bool
%End

void setEnabled( bool enabled );
%Docstring
Set if this optional is enabled

.. versionadded:: 3.0
%End


T data() const;
%Docstring
Access the payload data

.. versionadded:: 3.0
:rtype: T
%End

void setData( const T &data );
%Docstring
Set the payload data

.. versionadded:: 3.0
%End

};

/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgsoptional.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
55 changes: 9 additions & 46 deletions python/core/qgsoptionalexpression.sip
Expand Up @@ -9,7 +9,13 @@



class QgsOptionalExpression




typedef QgsOptional<QgsExpression> QgsOptionalQgsExpressionBase;

class QgsOptionalExpression : QgsOptionalQgsExpressionBase
{
%Docstring

Expand All @@ -24,6 +30,8 @@ class QgsOptionalExpression

%TypeHeaderCode
#include "qgsoptionalexpression.h"
#include "qgsoptional.h"
typedef QgsOptional<QgsExpression> QgsOptionalQgsExpressionBase;
%End
public:

Expand All @@ -45,51 +53,6 @@ class QgsOptionalExpression
%End



int operator== ( const QgsOptionalExpression &other ) const;
%MethodCode
sipRes = *sipCpp == *a0;
%End


int __bool__() const;
%Docstring
:rtype: int
%End
%MethodCode
sipRes = sipCpp->enabled();
%End

bool enabled() const;
%Docstring
Check if this optional is enabled

.. versionadded:: 3.0
:rtype: bool
%End

void setEnabled( bool enabled );
%Docstring
Set if this optional is enabled

.. versionadded:: 3.0
%End

QgsExpression data() const;
%Docstring
Access the payload data

.. versionadded:: 3.0
:rtype: QgsExpression
%End

void setData( const QgsExpression &data );
%Docstring
Set the payload data

.. versionadded:: 3.0
%End

void writeXml( QDomElement &element );
%Docstring
Save the optional expression to the provided QDomElement.
Expand Down
47 changes: 30 additions & 17 deletions scripts/sipify.pl
Expand Up @@ -95,21 +95,21 @@ sub dbg_info
}
}

sub detect_following_body_or_list {
sub detect_and_remove_following_body_or_initializerlist {
# https://regex101.com/r/ZaP3tC/6
do {no warnings 'uninitialized';
if ( $line =~ m/^(\s*)?((?:(?:explicit|static|const|unsigned|virtual)\s+)*)(([\w:]+(<.*?>)?\s+[*&]?)?(~?\w+|(\w+::)?operator.{1,2})\(([\w=()\/ ,&*<>."-]|::)*\)( (?:const|SIP_[A-Z_]*?))*)\s*((\s*[:,]\s+\w+\(.*\))*\s*\{.*\};?|(?!;))(\s*\/\/.*)?$/
if ( $line =~ m/^(\s*)?((?:(?:explicit|static|const|unsigned|virtual)\s+)*)(([\w:]+(<.*?>)?\s+[*&]?)?(~?\w+|(\w+::)?operator.{1,2})\s*\(([\w=()\/ ,&*<>."-]|::)*\)( (?:const|SIP_[A-Z_]*?))*)\s*((\s*[:,]\s+\w+\(.*\))*\s*\{.*\};?|(?!;))(\s*\/\/.*)?$/
|| $line =~ m/SIP_SKIP\s*(?!;)\s*(\/\/.*)?$/
|| $line =~ m/^\s*class.*SIP_SKIP/ ){
dbg_info("remove constructor definition, function bodies, member initializing list");
my $newline = "$1$2$3;";
remove_initializerlist_or_body() unless $line =~ m/{.*}(\s*SIP_\w+)*\s*(\/\/.*)?$/;
remove_following_body_or_initializerlist() unless $line =~ m/{.*}(\s*SIP_\w+)*\s*(\/\/.*)?$/;
$line = $newline;
}
};
}

sub remove_initializerlist_or_body {
sub remove_following_body_or_initializerlist {
do {no warnings 'uninitialized';
dbg_info("remove constructor definition, function bodies, member initializing list");
$line = $lines[$line_idx];
Expand Down Expand Up @@ -368,7 +368,7 @@ sub detect_comment_block{
$MULTILINE_DEFINITION = 0;
}
# also skip method body if there is one
detect_following_body_or_list();
detect_and_remove_following_body_or_initializerlist();
# line skipped, go to next iteration
next;
}
Expand Down Expand Up @@ -432,8 +432,9 @@ sub detect_comment_block{
next;
}
# Skip operators
if ( $line =~ m/operator(=|<<|>>)\s*\(/ ){
if ( $line =~ m/operator(=|<<|>>|->)\s*\(/ ){
dbg_info("skip operator");
detect_and_remove_following_body_or_initializerlist();
next;
}

Expand Down Expand Up @@ -475,12 +476,14 @@ sub detect_comment_block{
my $m = $4;
$m =~ s/public //g;
$m =~ s/[,:]?\s*private \w+(::\w+)?//g;
while ($m =~ /[,:]\s+(\w+)<((\w|::)+)>/g){
# detect template based inheritance
while ($m =~ /[,:]\s+((?!QList)\w+)<((\w|::)+)>/g){
dbg_info("template class");
push @template_inheritance_template, $1;
push @template_inheritance_class, $2;
}
$m =~ s/\w+<(\w|::)+>//g; # remove template Inheritance, not handled at the moment (see commented lines below)
$m =~ s/(\b(?!QList)\w+)<((?:\w|::)+)>/$1${2}Base/g; # use the typeded as template inheritance
$m =~ s/(\w+)<((?:\w|::)+)>//g; # remove remaining templates
$m =~ s/([:,])\s*,/$1/g;
$m =~ s/(\s*[:,])?\s*$//;
$line .= $m;
Expand All @@ -496,14 +499,17 @@ sub detect_comment_block{
$line .= "%Docstring\n$comment\n%End\n";
}
$line .= "\n%TypeHeaderCode\n#include \"" . basename($headerfile) . "\"";
# for template based inheritance, add a typedef to define the base type
# add it to the class and to the TypeHeaderCode
# also include the template header
# see https://www.riverbankcomputing.com/pipermail/pyqt/2015-May/035893.html
# this doesn't work as expected since it leads to double definitions (typedef vs class)
# while (@template_inheritance_template) {
# my $tpl = pop @template_inheritance_template;
# my $cls = pop @template_inheritance_class;
# $line .= "\n#include \"" . lc $tpl . ".h\"";
# $line .= "\ntypedef $tpl<$cls> $classname;";
# }
while (@template_inheritance_template) {
my $tpl = pop @template_inheritance_template;
my $cls = pop @template_inheritance_class;
$line = "\ntypedef $tpl<$cls> ${tpl}${cls}Base;\n\n$line";
$line .= "\n#include \"" . lc $tpl . ".h\"";
$line .= "\ntypedef $tpl<$cls> ${tpl}${cls}Base;";
}
push @output, dbg("CLS")."$line\n";

# Skip opening curly bracket, we already added that above
Expand Down Expand Up @@ -612,13 +618,16 @@ sub detect_comment_block{
$line =~ s/^(\s*?)\b(.*)$/$1virtual $2\n/;
}
}

# keyword fixes
$line =~ s/^(\s*template<)(?:class|typename) (\w+>)(.*)$/$1$2$3/;
$line =~ s/\s*\boverride\b//;
$line =~ s/^(\s*)?(const )?(virtual |static )?inline /$1$2$3/;
$line =~ s/\bnullptr\b/0/g;
$line =~ s/\s*=\s*default\b//g;

# remove constructor definition, function bodies, member initializing list
$SIP_RUN == 1 or detect_following_body_or_list();
$SIP_RUN == 1 or detect_and_remove_following_body_or_initializerlist();

# remove inline declarations
if ( $line =~ m/^(\s*)?(static |const )*(([\w:]+(<.*?>)?\s+(\*|&)?)?(\w+)( (?:const*?))*)\s*(\{.*\});(\s*\/\/.*)?$/ ){
Expand Down Expand Up @@ -674,7 +683,7 @@ sub detect_comment_block{
if ( $SIP_RUN == 0 && $line !~ m/(\{.*\}|;)\s*(\/\/.*)?$/ ){
dbg_info("remove following body of multiline def");
my $last_line = $line;
remove_initializerlist_or_body();
remove_following_body_or_initializerlist();
# add missing semi column
my $dummy = pop(@output);
push @output, dbg("MLT")."$last_line;\n";
Expand All @@ -697,6 +706,10 @@ sub detect_comment_block{
$is_override = 0;
next;
}
if ( $line =~ m/^\s*template<.*>/ ){
# do not comment now for templates, wait for class definition
next;
}
elsif ( $line =~ m/\/\// ||
$line =~ m/\s*typedef / ||
$line =~ m/\s*struct / ||
Expand Down
3 changes: 1 addition & 2 deletions src/core/qgsoptional.h
Expand Up @@ -28,9 +28,8 @@
* more internal configuration information that should not be lost when disabling and re-enabling.
*
* \since QGIS 3.0
* \note For Python you need to use implementations for specific template classes
*/
template<class T>
template<typename T>
class CORE_EXPORT QgsOptional
{
public:
Expand Down
55 changes: 3 additions & 52 deletions src/core/qgsoptionalexpression.h
Expand Up @@ -21,6 +21,7 @@

#include "qgis_core.h"


/**
* \ingroup core
*
Expand All @@ -33,6 +34,8 @@
* \since QGIS 2.18
*/



class CORE_EXPORT QgsOptionalExpression : public QgsOptional<QgsExpression>
{
public:
Expand All @@ -55,58 +58,6 @@ class CORE_EXPORT QgsOptionalExpression : public QgsOptional<QgsExpression>
QgsOptionalExpression( const QgsExpression &expression, bool enabled );


// SIP does not handle properly template class Inheritance at the moment
// following is copied from QgsOptional header
#ifdef SIP_RUN

/**
* Compare this QgsOptionalExpression to another one.
*
* This will compare the enabled flag and call the == operator
* of the contained class.
*
* @note Added in QGIS 3.0
*/
int operator== ( const QgsOptionalExpression &other ) const;
% MethodCode
sipRes = *sipCpp == *a0;
% End


int __bool__() const;
% MethodCode
sipRes = sipCpp->enabled();
% End

/**
* Check if this optional is enabled
*
* \since QGIS 3.0
*/
bool enabled() const;

/**
* Set if this optional is enabled
*
* \since QGIS 3.0
*/
void setEnabled( bool enabled );

/**
* Access the payload data
*
* \since QGIS 3.0
*/
QgsExpression data() const;

/**
* Set the payload data
*
* \since QGIS 3.0
*/
void setData( const QgsExpression &data );
#endif

/**
* Save the optional expression to the provided QDomElement.
*
Expand Down

0 comments on commit fb8edea

Please sign in to comment.