<commit_before>#include "Test.h"

TEST_CASE("Named sequences") {
    auto tree = SyntaxTree::fromText(R"(
module m;
    sequence seq(x, y, min, max, delay1);
        x ##delay1 y[*min:max];
    endsequence
endmodule
)");

    Compilation compilation;
    compilation.addSyntaxTree(tree);
    NO_COMPILATION_ERRORS;
}

TEST_CASE("Named properties") {
    auto tree = SyntaxTree::fromText(R"(
module m;
    property p1(x,y);
        ##1 x |-> y;
    endproperty

    property p2;
        @(posedge clk)
        a ##1 (b || c)[->1] |->
            if (b)
                p1(d,e)
            else
                f;
    endproperty
endmodule
)");

    Compilation compilation;
    compilation.addSyntaxTree(tree);
    NO_COMPILATION_ERRORS;
}

TEST_CASE("Concurrent assertion expressions") {
    auto tree = SyntaxTree::fromText(R"(
module m;
    string a;
    int b,c,d,e;

    foo: assert property (a);
    assert property (a ##1 b ##[+] c ##[*] d ##[1:5] e);
    assert property (##0 a[*0:4] ##0 b[=4] ##0 c[->1:2] ##0 c[*] ##1 d[+]);
    assert property (##[0:$] a[*0:$]);
    assert property ((a ##0 b) and (c or d));
    assert property ((a ##0 b) and (c or d));
    assert property (a intersect b and d throughout e within c);
    assert property (a iff b until d s_until e until_with c s_until_with d);
    assert property (((a)) |-> b |=> (d implies (e #-# (d #=# a))));
    assert property ((a within b) within (((c))[*3]));
    assert property (((a)) throughout c);
    assert property ((@(posedge b) a and b) intersect c);
    assert property ((@(posedge b) a iff b) implies c);
    assert property (first_match(a and b));
    assert property (always b and c);
    assert property ((s_always [3:4] b and c) and (s_eventually [1:$] b) and (eventually [1:2] c));
    assert property ((nexttime [3] b) and (s_nexttime b));
    assert property (strong(a ##1 b) and weak(a intersect b));
    assert property (not a ##1 b);
    assert property (accept_on(b) sync_reject_on(c) sync_accept_on(d) reject_on(e) b ##1 c);
    assert property (if (b) a ##1 c else d ##1 e);
    assert property (case (b) 1, 2, 3: 1 ##1 b; 4: a and b; default: 1 |-> b; endcase);
    assert property (@(posedge b) ((b) and b) ##0 b);
endmodule
)");

    Compilation compilation;
    compilation.addSyntaxTree(tree);
    NO_COMPILATION_ERRORS;
}

TEST_CASE("Concurrent assertion expression errors") {
    auto tree = SyntaxTree::fromText(R"(
class C;
    int bar;
endclass

function int func(output o);
endfunction

module m;
    int a[];
    int b;
    chandle c;
    C d = new;
    logic o;
    localparam real p = 3.14;

    assert property (a ##1 b++);
    assert property (c == null);
    assert property (d.bar);
    assert property (func(o));
    assert property (b[* -1:4]);
    assert property (b ##[4:1] b);
    assert property (b ##p b);
    assert property (##0 b[*3-:4] ##0 b[=]);
    assert property (##[] b ##[1+:5] b);
    assert property ((b iff b) |-> b);
    assert property ((b and b)[*3] throughout b);
    assert property (b[*3] throughout b);
    assert property (always [] b);
    assert property (always [4] b);
    assert property (s_always b);
    assert property (nexttime [1:2] b);
    assert property (eventually [1:$] b);
    assert property (b or @o);
endmodule
)");

    Compilation compilation;
    compilation.addSyntaxTree(tree);

    auto& diags = compilation.getAllDiagnostics();
    REQUIRE(diags.size() == 21);
    CHECK(diags[0].code == diag::AssertionExprType);
    CHECK(diags[1].code == diag::IncDecNotAllowed);
    CHECK(diags[2].code == diag::CHandleInAssertion);
    CHECK(diags[3].code == diag::ClassMemberInAssertion);
    CHECK(diags[4].code == diag::AssertionFuncArg);
    CHECK(diags[5].code == diag::ValueMustBePositive);
    CHECK(diags[6].code == diag::SeqRangeMinMax);
    CHECK(diags[7].code == diag::ExprMustBeIntegral);
    CHECK(diags[8].code == diag::InvalidSequenceRange);
    CHECK(diags[9].code == diag::ExpectedExpression);
    CHECK(diags[10].code == diag::ExpectedExpression);
    CHECK(diags[11].code == diag::InvalidSequenceRange);
    CHECK(diags[12].code == diag::PropertyLhsInvalid);
    CHECK(diags[13].code == diag::ThroughoutLhsInvalid);
    CHECK(diags[14].code == diag::ThroughoutLhsInvalid);
    CHECK(diags[15].code == diag::ExpectedExpression);
    CHECK(diags[16].code == diag::InvalidPropertyRange);
    CHECK(diags[17].code == diag::InvalidPropertyRange);
    CHECK(diags[18].code == diag::InvalidPropertyIndex);
    CHECK(diags[19].code == diag::UnboundedNotAllowed);
    CHECK(diags[20].code == diag::ExpectedExpression);
}

TEST_CASE("Sequence & property instances") {
    auto tree = SyntaxTree::fromText(R"(
module m;
    assert property (n.a(3));
    assert property (b);

    int c, d;
    sequence b;
        ##1 c ##1 d;
    endsequence
endmodule

module n;
    int c, d;
    property a(int i, foo = 1);
        ##1 c ##1 d ##1 i;
    endproperty
endmodule
)");

    Compilation compilation;
    compilation.addSyntaxTree(tree);
    NO_COMPILATION_ERRORS;
}

TEST_CASE("Assertion instance arg errors") {
    auto tree = SyntaxTree::fromText(R"(
module m;
    assert property (a(, .a(1), .b(), .d(1)));
    assert property (a(1, 2));
    assert property (a(1, 2, 3, 4));

    sequence a(a, b, c);
        1;
    endsequence
endmodule
)");

    Compilation compilation;
    compilation.addSyntaxTree(tree);

    auto& diags = compilation.getAllDiagnostics();
    REQUIRE(diags.size() == 7);
    CHECK(diags[0].code == diag::UnconnectedArg);
    CHECK(diags[1].code == diag::ArgCannotBeEmpty);
    CHECK(diags[2].code == diag::DuplicateArgAssignment);
    CHECK(diags[3].code == diag::ArgCannotBeEmpty);
    CHECK(diags[4].code == diag::ArgDoesNotExist);
    CHECK(diags[5].code == diag::TooFewArguments);
    CHECK(diags[6].code == diag::TooManyArguments);
}

TEST_CASE("Assertion instance arg type checking") {
    auto tree = SyntaxTree::fromText(R"(
module m;
    int foo[];
    assert property (a(1, 1 iff 2, foo, 1 and 2));
    assert property (a(1 iff 2, 1, 1));
    assert property (a(1, 1, foo[*]));

    int e;
    sequence a(sequence a, property b, int c[], untyped d = e);
        1;
    endsequence
endmodule
)");

    Compilation compilation;
    compilation.addSyntaxTree(tree);

    auto& diags = compilation.getAllDiagnostics();
    REQUIRE(diags.size() == 3);
    CHECK(diags[0].code == diag::AssertionArgTypeSequence);
    CHECK(diags[1].code == diag::AssertionArgTypeMismatch);
    CHECK(diags[2].code == diag::AssertionArgNeedsRegExpr);
}

TEST_CASE("Assertion instance arg expansion") {
    auto tree = SyntaxTree::fromText(R"(
module m;
    logic [7:0] bar;

    assert property (s1($, 5));
    assert property (s1(bar, 9.2));
    assert property (s3(9));
    assert property (s4(1 and 2));

    sequence s1(a, int b);
        s2(a) ##1 bar[b:0];
    endsequence

    sequence s2(foo);
        1 ##[0:foo] 2 ##1 foo;
    endsequence

    sequence s3(sequence a);
        1 ##[0:a] 2;
    endsequence

    sequence s4(foo);
        foo ##1 1 + foo;
    endsequence
endmodule
)");

    Compilation compilation;
    compilation.addSyntaxTree(tree);

    auto& diags = compilation.getAllDiagnostics();
    REQUIRE(diags.size() == 5);
    CHECK(diags[0].code == diag::UnboundedNotAllowed);
    CHECK(diags[1].code == diag::BadRangeExpression);
    CHECK(diags[2].code == diag::ConstEvalNonConstVariable);
    CHECK(diags[3].code == diag::ExprMustBeIntegral);
    CHECK(diags[4].code == diag::BadBinaryExpression);
}

TEST_CASE("More complex sequence arg expansion") {
    auto tree = SyntaxTree::fromText(R"(
module m;
    sequence s1;
        int foo;
        s2(s2(foo));
    endsequence

    sequence s2(a);
        a;
    endsequence

    assert property (s1);
endmodule
)");

    Compilation compilation;
    compilation.addSyntaxTree(tree);
    NO_COMPILATION_ERRORS;
}

TEST_CASE("Default disable declarations") {
    auto tree = SyntaxTree::fromText(R"(
module m;
    int i;
    default disable iff i > 1;
endmodule

module n;
    int a, b;
    default disable iff a;
    default disable iff b;
endmodule
)");

    Compilation compilation;
    compilation.addSyntaxTree(tree);

    auto& diags = compilation.getAllDiagnostics();
    REQUIRE(diags.size() == 1);
    CHECK(diags[0].code == diag::MultipleDefaultDisable);
}

TEST_CASE("Hierarchical access to assertion ports") {
    auto tree = SyntaxTree::fromText(R"(
module m;
    sequence s(int i);
        i;
    endsequence

    int i = s.i;
endmodule
)");

    Compilation compilation;
    compilation.addSyntaxTree(tree);

    auto& diags = compilation.getAllDiagnostics();
    REQUIRE(diags.size() == 1);
    CHECK(diags[0].code == diag::TooFewArguments);
}

TEST_CASE("Local vars in assertions") {
    auto tree = SyntaxTree::fromText(R"(
module m;
    sequence s(int i);
        int j, k = j;
        (i && j, j = 1, j++)[*0:1];
    endsequence

    int baz;
    sequence s2;
        int j, k = j;
        first_match(j, !j, j + k, baz = 1, baz++);
    endsequence

    typedef int Foo;
    property p;
        Foo u, v;
        s(u) and v and s2;
    endproperty

    assert property (p);
endmodule
)");

    Compilation compilation;
    compilation.addSyntaxTree(tree);

    auto& diags = compilation.getAllDiagnostics();
    REQUIRE(diags.size() == 4);
    CHECK(diags[0].code == diag::InvalidMatchItem);
    CHECK(diags[1].code == diag::InvalidMatchItem);
    CHECK(diags[2].code == diag::LocalVarMatchItem);
    CHECK(diags[3].code == diag::LocalVarMatchItem);
}

TEST_CASE("Sequence triggered method") {
    auto tree = SyntaxTree::fromText(R"(
module m;
    wire clk, ready;
    sequence e1;
        @(posedge clk) $rose(ready) ##1 1 ##1 2;
    endsequence

    sequence rule;
        @(posedge clk) e1.triggered ##1 1;
    endsequence

    sequence e2(a,b,c);
        @(posedge clk) $rose(a) ##1 b ##1 c;
    endsequence

    wire proc1, proc2;
    sequence rule2;
        @(posedge clk) e2(ready,proc1,proc2).triggered ##1 1;
    endsequence

    sequence e3(sequence a, untyped b);
        @(posedge clk) a.triggered ##1 b;
    endsequence

    sequence rule3;
        @(posedge clk) e3(ready ##1 proc1, proc2) ##1 1;
    endsequence

    assert property (rule);
    assert property (rule2);
    assert property (rule3);
endmodule
)");

    Compilation compilation;
    compilation.addSyntaxTree(tree);
    NO_COMPILATION_ERRORS;
}
<commit_msg>Add tests for sequence event controls<commit_after>#include "Test.h"

TEST_CASE("Named sequences") {
    auto tree = SyntaxTree::fromText(R"(
module m;
    sequence seq(x, y, min, max, delay1);
        x ##delay1 y[*min:max];
    endsequence
endmodule
)");

    Compilation compilation;
    compilation.addSyntaxTree(tree);
    NO_COMPILATION_ERRORS;
}

TEST_CASE("Named properties") {
    auto tree = SyntaxTree::fromText(R"(
module m;
    property p1(x,y);
        ##1 x |-> y;
    endproperty

    property p2;
        @(posedge clk)
        a ##1 (b || c)[->1] |->
            if (b)
                p1(d,e)
            else
                f;
    endproperty
endmodule
)");

    Compilation compilation;
    compilation.addSyntaxTree(tree);
    NO_COMPILATION_ERRORS;
}

TEST_CASE("Concurrent assertion expressions") {
    auto tree = SyntaxTree::fromText(R"(
module m;
    string a;
    int b,c,d,e;

    foo: assert property (a);
    assert property (a ##1 b ##[+] c ##[*] d ##[1:5] e);
    assert property (##0 a[*0:4] ##0 b[=4] ##0 c[->1:2] ##0 c[*] ##1 d[+]);
    assert property (##[0:$] a[*0:$]);
    assert property ((a ##0 b) and (c or d));
    assert property ((a ##0 b) and (c or d));
    assert property (a intersect b and d throughout e within c);
    assert property (a iff b until d s_until e until_with c s_until_with d);
    assert property (((a)) |-> b |=> (d implies (e #-# (d #=# a))));
    assert property ((a within b) within (((c))[*3]));
    assert property (((a)) throughout c);
    assert property ((@(posedge b) a and b) intersect c);
    assert property ((@(posedge b) a iff b) implies c);
    assert property (first_match(a and b));
    assert property (always b and c);
    assert property ((s_always [3:4] b and c) and (s_eventually [1:$] b) and (eventually [1:2] c));
    assert property ((nexttime [3] b) and (s_nexttime b));
    assert property (strong(a ##1 b) and weak(a intersect b));
    assert property (not a ##1 b);
    assert property (accept_on(b) sync_reject_on(c) sync_accept_on(d) reject_on(e) b ##1 c);
    assert property (if (b) a ##1 c else d ##1 e);
    assert property (case (b) 1, 2, 3: 1 ##1 b; 4: a and b; default: 1 |-> b; endcase);
    assert property (@(posedge b) ((b) and b) ##0 b);
endmodule
)");

    Compilation compilation;
    compilation.addSyntaxTree(tree);
    NO_COMPILATION_ERRORS;
}

TEST_CASE("Concurrent assertion expression errors") {
    auto tree = SyntaxTree::fromText(R"(
class C;
    int bar;
endclass

function int func(output o);
endfunction

module m;
    int a[];
    int b;
    chandle c;
    C d = new;
    logic o;
    localparam real p = 3.14;

    assert property (a ##1 b++);
    assert property (c == null);
    assert property (d.bar);
    assert property (func(o));
    assert property (b[* -1:4]);
    assert property (b ##[4:1] b);
    assert property (b ##p b);
    assert property (##0 b[*3-:4] ##0 b[=]);
    assert property (##[] b ##[1+:5] b);
    assert property ((b iff b) |-> b);
    assert property ((b and b)[*3] throughout b);
    assert property (b[*3] throughout b);
    assert property (always [] b);
    assert property (always [4] b);
    assert property (s_always b);
    assert property (nexttime [1:2] b);
    assert property (eventually [1:$] b);
    assert property (b or @o);
endmodule
)");

    Compilation compilation;
    compilation.addSyntaxTree(tree);

    auto& diags = compilation.getAllDiagnostics();
    REQUIRE(diags.size() == 21);
    CHECK(diags[0].code == diag::AssertionExprType);
    CHECK(diags[1].code == diag::IncDecNotAllowed);
    CHECK(diags[2].code == diag::CHandleInAssertion);
    CHECK(diags[3].code == diag::ClassMemberInAssertion);
    CHECK(diags[4].code == diag::AssertionFuncArg);
    CHECK(diags[5].code == diag::ValueMustBePositive);
    CHECK(diags[6].code == diag::SeqRangeMinMax);
    CHECK(diags[7].code == diag::ExprMustBeIntegral);
    CHECK(diags[8].code == diag::InvalidSequenceRange);
    CHECK(diags[9].code == diag::ExpectedExpression);
    CHECK(diags[10].code == diag::ExpectedExpression);
    CHECK(diags[11].code == diag::InvalidSequenceRange);
    CHECK(diags[12].code == diag::PropertyLhsInvalid);
    CHECK(diags[13].code == diag::ThroughoutLhsInvalid);
    CHECK(diags[14].code == diag::ThroughoutLhsInvalid);
    CHECK(diags[15].code == diag::ExpectedExpression);
    CHECK(diags[16].code == diag::InvalidPropertyRange);
    CHECK(diags[17].code == diag::InvalidPropertyRange);
    CHECK(diags[18].code == diag::InvalidPropertyIndex);
    CHECK(diags[19].code == diag::UnboundedNotAllowed);
    CHECK(diags[20].code == diag::ExpectedExpression);
}

TEST_CASE("Sequence & property instances") {
    auto tree = SyntaxTree::fromText(R"(
module m;
    assert property (n.a(3));
    assert property (b);

    int c, d;
    sequence b;
        ##1 c ##1 d;
    endsequence
endmodule

module n;
    int c, d;
    property a(int i, foo = 1);
        ##1 c ##1 d ##1 i;
    endproperty
endmodule
)");

    Compilation compilation;
    compilation.addSyntaxTree(tree);
    NO_COMPILATION_ERRORS;
}

TEST_CASE("Assertion instance arg errors") {
    auto tree = SyntaxTree::fromText(R"(
module m;
    assert property (a(, .a(1), .b(), .d(1)));
    assert property (a(1, 2));
    assert property (a(1, 2, 3, 4));

    sequence a(a, b, c);
        1;
    endsequence
endmodule
)");

    Compilation compilation;
    compilation.addSyntaxTree(tree);

    auto& diags = compilation.getAllDiagnostics();
    REQUIRE(diags.size() == 7);
    CHECK(diags[0].code == diag::UnconnectedArg);
    CHECK(diags[1].code == diag::ArgCannotBeEmpty);
    CHECK(diags[2].code == diag::DuplicateArgAssignment);
    CHECK(diags[3].code == diag::ArgCannotBeEmpty);
    CHECK(diags[4].code == diag::ArgDoesNotExist);
    CHECK(diags[5].code == diag::TooFewArguments);
    CHECK(diags[6].code == diag::TooManyArguments);
}

TEST_CASE("Assertion instance arg type checking") {
    auto tree = SyntaxTree::fromText(R"(
module m;
    int foo[];
    assert property (a(1, 1 iff 2, foo, 1 and 2));
    assert property (a(1 iff 2, 1, 1));
    assert property (a(1, 1, foo[*]));

    int e;
    sequence a(sequence a, property b, int c[], untyped d = e);
        1;
    endsequence
endmodule
)");

    Compilation compilation;
    compilation.addSyntaxTree(tree);

    auto& diags = compilation.getAllDiagnostics();
    REQUIRE(diags.size() == 3);
    CHECK(diags[0].code == diag::AssertionArgTypeSequence);
    CHECK(diags[1].code == diag::AssertionArgTypeMismatch);
    CHECK(diags[2].code == diag::AssertionArgNeedsRegExpr);
}

TEST_CASE("Assertion instance arg expansion") {
    auto tree = SyntaxTree::fromText(R"(
module m;
    logic [7:0] bar;

    assert property (s1($, 5));
    assert property (s1(bar, 9.2));
    assert property (s3(9));
    assert property (s4(1 and 2));

    sequence s1(a, int b);
        s2(a) ##1 bar[b:0];
    endsequence

    sequence s2(foo);
        1 ##[0:foo] 2 ##1 foo;
    endsequence

    sequence s3(sequence a);
        1 ##[0:a] 2;
    endsequence

    sequence s4(foo);
        foo ##1 1 + foo;
    endsequence
endmodule
)");

    Compilation compilation;
    compilation.addSyntaxTree(tree);

    auto& diags = compilation.getAllDiagnostics();
    REQUIRE(diags.size() == 5);
    CHECK(diags[0].code == diag::UnboundedNotAllowed);
    CHECK(diags[1].code == diag::BadRangeExpression);
    CHECK(diags[2].code == diag::ConstEvalNonConstVariable);
    CHECK(diags[3].code == diag::ExprMustBeIntegral);
    CHECK(diags[4].code == diag::BadBinaryExpression);
}

TEST_CASE("More complex sequence arg expansion") {
    auto tree = SyntaxTree::fromText(R"(
module m;
    sequence s1;
        int foo;
        s2(s2(foo));
    endsequence

    sequence s2(a);
        a;
    endsequence

    assert property (s1);
endmodule
)");

    Compilation compilation;
    compilation.addSyntaxTree(tree);
    NO_COMPILATION_ERRORS;
}

TEST_CASE("Default disable declarations") {
    auto tree = SyntaxTree::fromText(R"(
module m;
    int i;
    default disable iff i > 1;
endmodule

module n;
    int a, b;
    default disable iff a;
    default disable iff b;
endmodule
)");

    Compilation compilation;
    compilation.addSyntaxTree(tree);

    auto& diags = compilation.getAllDiagnostics();
    REQUIRE(diags.size() == 1);
    CHECK(diags[0].code == diag::MultipleDefaultDisable);
}

TEST_CASE("Hierarchical access to assertion ports") {
    auto tree = SyntaxTree::fromText(R"(
module m;
    sequence s(int i);
        i;
    endsequence

    int i = s.i;
endmodule
)");

    Compilation compilation;
    compilation.addSyntaxTree(tree);

    auto& diags = compilation.getAllDiagnostics();
    REQUIRE(diags.size() == 1);
    CHECK(diags[0].code == diag::TooFewArguments);
}

TEST_CASE("Local vars in assertions") {
    auto tree = SyntaxTree::fromText(R"(
module m;
    sequence s(int i);
        int j, k = j;
        (i && j, j = 1, j++)[*0:1];
    endsequence

    int baz;
    sequence s2;
        int j, k = j;
        first_match(j, !j, j + k, baz = 1, baz++);
    endsequence

    typedef int Foo;
    property p;
        Foo u, v;
        s(u) and v and s2;
    endproperty

    assert property (p);
endmodule
)");

    Compilation compilation;
    compilation.addSyntaxTree(tree);

    auto& diags = compilation.getAllDiagnostics();
    REQUIRE(diags.size() == 4);
    CHECK(diags[0].code == diag::InvalidMatchItem);
    CHECK(diags[1].code == diag::InvalidMatchItem);
    CHECK(diags[2].code == diag::LocalVarMatchItem);
    CHECK(diags[3].code == diag::LocalVarMatchItem);
}

TEST_CASE("Sequence triggered method") {
    auto tree = SyntaxTree::fromText(R"(
module m;
    wire clk, ready;
    sequence e1;
        @(posedge clk) $rose(ready) ##1 1 ##1 2;
    endsequence

    sequence rule;
        @(posedge clk) e1.triggered ##1 1;
    endsequence

    sequence e2(a,b,c);
        @(posedge clk) $rose(a) ##1 b ##1 c;
    endsequence

    wire proc1, proc2;
    sequence rule2;
        @(posedge clk) e2(ready,proc1,proc2).triggered ##1 1;
    endsequence

    sequence e3(sequence a, untyped b);
        @(posedge clk) a.triggered ##1 b;
    endsequence

    sequence rule3;
        @(posedge clk) e3(ready ##1 proc1, proc2) ##1 1;
    endsequence

    assert property (rule);
    assert property (rule2);
    assert property (rule3);
endmodule
)");

    Compilation compilation;
    compilation.addSyntaxTree(tree);
    NO_COMPILATION_ERRORS;
}

TEST_CASE("Sequence event control") {
    auto tree = SyntaxTree::fromText(R"(
wire a, b, c, clk;
sequence abc;
    @(posedge clk) a ##1 b ##1 c;
endsequence

module m;
    initial begin
        @ abc $display("Saw a-b-c");
    end
endmodule
)");

    Compilation compilation;
    compilation.addSyntaxTree(tree);
    NO_COMPILATION_ERRORS;
}

TEST_CASE("Level-sensitive sequence control") {
    auto tree = SyntaxTree::fromText(R"(
wire a, b, c, clk;
sequence abc;
    @(posedge clk) a ##1 b ##1 c;
endsequence

wire d, e;
sequence de;
    @(negedge clk) d ##[2:5] e;
endsequence

program check;
    initial begin
        wait (abc.triggered || de.triggered);
        if (abc.triggered)
            $display("abc succeeded");
        if (de.triggered)
            $display("de succeeded");
    end
endprogram
)");

    Compilation compilation;
    compilation.addSyntaxTree(tree);
    NO_COMPILATION_ERRORS;
}
<|endoftext|>


<commit_before>#include "MovieSprite.h"

#include "core/oxygine.h"
#include "core/Mutex.h"
#include "core/ImageDataOperations.h"
#include "core/UberShaderProgram.h"
#include "RenderState.h"
#include "STDRenderer.h"
#include "Stage.h"
#include "core/ThreadMessages.h"

namespace oxygine
{
    UberShaderProgram* MovieSprite::_shader = 0;

    MovieSprite::MovieSprite() : _dirty(false),
        _completeDispatched(false),
        _bufferSize(0, 0),
        _movieRect(0, 0, 0, 0),
        _initialized(false), _volume(100), _paused(false), _playing(false),
        _looped(false),
        _skipFrames(true),
        _ready(false),
        _hasAlphaChannel(false),
        _detachWhenDone(false)
    {
    }

    MovieSprite::~MovieSprite()
    {
        if (_textureUV)
            _textureUV->release();
        if (_textureYA)
            _textureYA->release();
        //clear();
    }

    void MovieSprite::convert()
    {
        if (_dirty && _textureUV)
        {
            MutexAutoLock l(_mutex);
            _textureUV->updateRegion(0, 0, _mtUV.lock());
            _textureYA->updateRegion(0, 0, _mtYA.lock());
            _dirty = false;
            _ready = true;
        }
    }

    void MovieSprite::setUniforms(IVideoDriver* driver, ShaderProgram* prog)
    {
        driver->setUniform("yaScale", &_yaScale, 1);
    }

    void MovieSprite::doRender(const RenderState& rs)
    {
        convert();

        if (!_ready)
            return;

        _shader->setShaderUniformsCallback(CLOSURE(this, &MovieSprite::setUniforms));

#if OXYGINE_RENDERER > 2
        STDRenderer* renderer = STDRenderer::instance;
        renderer->setUberShaderProgram(_shader);
        Sprite::doRender(rs);
        renderer->setUberShaderProgram(&STDRenderer::uberShader);
#else
        STDRenderer* renderer = safeCast<STDRenderer*>(rs.renderer);
        renderer->setUberShaderProgram(_shader);
        Sprite::doRender(rs);
        renderer->setUberShaderProgram(&Renderer::uberShader);
#endif

        _shader->setShaderUniformsCallback(UberShaderProgram::ShaderUniformsCallback());

        //Sprite::doRender(rs);
    }

    /*
    void MovieSprite::setBufferSize(const Point& size)
    {
        _bufferSize = size;
    }
    */

    void MovieSprite::initPlayer()
    {
        if (_initialized)
            return;

        _initialized = true;

        _initPlayer();

        Point sz = _bufferSize;
        sz = Point(nextPOT(sz.x), nextPOT(sz.y));

        Point uvSize = _bufferSize / 2;
        uvSize = Point(nextPOT(uvSize.x), nextPOT(uvSize.y));
        //uvSize = sz;
        _mtUV.init(uvSize.x, uvSize.y, TF_A8L8);
        _mtUV.fill_zero();
        _textureUV = IVideoDriver::instance->createTexture();
        _textureUV->init(uvSize.x, uvSize.y, _mtUV.getFormat(), false);

        _mtYA.init(sz.x, sz.y, _hasAlphaChannel ? TF_A8L8 : TF_L8);
        _mtYA.fill_zero();
        _textureYA = IVideoDriver::instance->createTexture();
        _textureYA->init(sz.x, sz.y, _mtYA.getFormat(), false);

        if (_hasAlphaChannel)
            setBlendMode(blend_premultiplied_alpha);
        else
            setBlendMode(blend_disabled);

        Diffuse d;
        d.base = _textureYA;
        d.alpha = _textureUV;
        d.premultiplied = true;

        AnimationFrame frame;
        RectF mr = _movieRect.cast<RectF>();

        Vector2 szf = sz.cast<Vector2>();
        RectF tcYA = RectF(mr.pos.div(szf), mr.size.div(szf));
        frame.init(0, d, tcYA, mr, mr.size);

        _yaScale = Vector2(uvSize.x / szf.x, uvSize.y / szf.y);
        _yaScale = Vector2(0.5f, 0.5f);
        _yaScale = Vector2(1, 1);
        Vector2 s = getSize();
        setAnimFrame(frame);
        setSize(s);
    }

    void MovieSprite::doUpdate(const UpdateState& us)
    {
        _update(us);
    }

    void MovieSprite::setVolume(int v)
    {
        _volume = v;
        _setVolume(v);
    }

    void MovieSprite::setLooped(bool l)
    {
        _looped = l;
    }

    void MovieSprite::setSkipFrames(bool skip)
    {
        _skipFrames = skip;
    }

    void MovieSprite::setDetachWhenDone(bool detach)
    {
        _detachWhenDone = detach;
    }

    Point MovieSprite::getMovieSize() const
    {
        return _movieRect.getSize();
    }

    void MovieSprite::clear()
    {
        _clear();

        _dirty = false;
        _playing = false;
        _paused = false;
        _ready = false;

        if (_textureUV)
            _textureUV->release();
        _textureUV = 0;

        if (_textureYA)
            _textureYA->release();
        _textureYA = 0;

        _movieRect = Rect(0, 0, 0, 0);

        setAnimFrame(0);

        _initialized = false;

        {
            MutexAutoLock m(_mutex);

            _mtUV.cleanup();
            _mtYA.cleanup();
        }
    }

    void MovieSprite::setMovie(const std::string& movie, bool hasAlpha)
    {
        clear();
        _hasAlphaChannel = hasAlpha;
        _fname = movie;
        initPlayer();
    }

    void MovieSprite::play()
    {
        if (_playing)
        {
            if (_paused)
            {
                _resume();
                _paused = false;
                return;
            }

            return;
        }

        _playing = true;

        initPlayer();

        _completeDispatched = false;
        _play();
    }

    void MovieSprite::pause()
    {
        if (_paused)
            return;

        _pause();
        _paused = true;
    }

    void MovieSprite::stop()
    {
        clear();
    }

    bool MovieSprite::isPlaying() const
    {
        return _playing && !_paused;
    }

    void MovieSprite::asyncDone()
    {
        addRef();
        core::getMainThreadDispatcher().postCallback([ = ]()
        {
            _playing = false;

            Event ev(MovieSprite::COMPLETE);
            dispatchEvent(&ev);

            if (_detachWhenDone)
                detach();

            releaseRef();
        });
    }
}
<commit_msg>don't use POW2 textures<commit_after>#include "MovieSprite.h"

#include "core/oxygine.h"
#include "core/Mutex.h"
#include "core/ImageDataOperations.h"
#include "core/UberShaderProgram.h"
#include "RenderState.h"
#include "STDRenderer.h"
#include "Stage.h"
#include "core/ThreadMessages.h"

namespace oxygine
{
    UberShaderProgram* MovieSprite::_shader = 0;

    MovieSprite::MovieSprite() : _dirty(false),
        _completeDispatched(false),
        _bufferSize(0, 0),
        _movieRect(0, 0, 0, 0),
        _initialized(false), _volume(100), _paused(false), _playing(false),
        _looped(false),
        _skipFrames(true),
        _ready(false),
        _hasAlphaChannel(false),
        _detachWhenDone(false)
    {
    }

    MovieSprite::~MovieSprite()
    {
        if (_textureUV)
            _textureUV->release();
        if (_textureYA)
            _textureYA->release();
        //clear();
    }

    void MovieSprite::convert()
    {
        if (_dirty && _textureUV)
        {
            MutexAutoLock l(_mutex);
            _textureUV->updateRegion(0, 0, _mtUV.lock());
            _textureYA->updateRegion(0, 0, _mtYA.lock());
            _dirty = false;
            _ready = true;
        }
    }

    void MovieSprite::setUniforms(IVideoDriver* driver, ShaderProgram* prog)
    {
        driver->setUniform("yaScale", &_yaScale, 1);
    }

    void MovieSprite::doRender(const RenderState& rs)
    {
        convert();

        if (!_ready)
            return;

        _shader->setShaderUniformsCallback(CLOSURE(this, &MovieSprite::setUniforms));

#if OXYGINE_RENDERER > 2
        STDRenderer* renderer = STDRenderer::instance;
        renderer->setUberShaderProgram(_shader);
        Sprite::doRender(rs);
        renderer->setUberShaderProgram(&STDRenderer::uberShader);
#else
        STDRenderer* renderer = safeCast<STDRenderer*>(rs.renderer);
        renderer->setUberShaderProgram(_shader);
        Sprite::doRender(rs);
        renderer->setUberShaderProgram(&Renderer::uberShader);
#endif

        _shader->setShaderUniformsCallback(UberShaderProgram::ShaderUniformsCallback());

        //Sprite::doRender(rs);
    }

    /*
    void MovieSprite::setBufferSize(const Point& size)
    {
        _bufferSize = size;
    }
    */

    void MovieSprite::initPlayer()
    {
        if (_initialized)
            return;

        _initialized = true;

        _initPlayer();

        Point sz = _bufferSize;
        //sz = Point(nextPOT(sz.x), nextPOT(sz.y));

        Point uvSize = _bufferSize / 2;
        //uvSize = Point(nextPOT(uvSize.x), nextPOT(uvSize.y));
        //uvSize = sz;
        _mtUV.init(uvSize.x, uvSize.y, TF_A8L8);
        _mtUV.fill_zero();
        _textureUV = IVideoDriver::instance->createTexture();
        _textureUV->init(uvSize.x, uvSize.y, _mtUV.getFormat(), false);

        _mtYA.init(sz.x, sz.y, _hasAlphaChannel ? TF_A8L8 : TF_L8);
        _mtYA.fill_zero();
        _textureYA = IVideoDriver::instance->createTexture();
        _textureYA->init(sz.x, sz.y, _mtYA.getFormat(), false);

        if (_hasAlphaChannel)
            setBlendMode(blend_premultiplied_alpha);
        else
            setBlendMode(blend_disabled);

        Diffuse d;
        d.base = _textureYA;
        d.alpha = _textureUV;
        d.premultiplied = true;

        AnimationFrame frame;
        RectF mr = _movieRect.cast<RectF>();

        Vector2 szf = sz.cast<Vector2>();
        RectF tcYA = RectF(mr.pos.div(szf), mr.size.div(szf));
        frame.init(0, d, tcYA, mr, mr.size);

        _yaScale = Vector2(uvSize.x / szf.x, uvSize.y / szf.y);
        _yaScale = Vector2(0.5f, 0.5f);
        _yaScale = Vector2(1, 1);
        Vector2 s = getSize();
        setAnimFrame(frame);
        setSize(s);
    }

    void MovieSprite::doUpdate(const UpdateState& us)
    {
        _update(us);
    }

    void MovieSprite::setVolume(int v)
    {
        _volume = v;
        _setVolume(v);
    }

    void MovieSprite::setLooped(bool l)
    {
        _looped = l;
    }

    void MovieSprite::setSkipFrames(bool skip)
    {
        _skipFrames = skip;
    }

    void MovieSprite::setDetachWhenDone(bool detach)
    {
        _detachWhenDone = detach;
    }

    Point MovieSprite::getMovieSize() const
    {
        return _movieRect.getSize();
    }

    void MovieSprite::clear()
    {
        _clear();

        _dirty = false;
        _playing = false;
        _paused = false;
        _ready = false;

        if (_textureUV)
            _textureUV->release();
        _textureUV = 0;

        if (_textureYA)
            _textureYA->release();
        _textureYA = 0;

        _movieRect = Rect(0, 0, 0, 0);

        setAnimFrame(0);

        _initialized = false;

        {
            MutexAutoLock m(_mutex);

            _mtUV.cleanup();
            _mtYA.cleanup();
        }
    }

    void MovieSprite::setMovie(const std::string& movie, bool hasAlpha)
    {
        clear();
        _hasAlphaChannel = hasAlpha;
        _fname = movie;
        initPlayer();
    }

    void MovieSprite::play()
    {
        if (_playing)
        {
            if (_paused)
            {
                _resume();
                _paused = false;
                return;
            }

            return;
        }

        _playing = true;

        initPlayer();

        _completeDispatched = false;
        _play();
    }

    void MovieSprite::pause()
    {
        if (_paused)
            return;

        _pause();
        _paused = true;
    }

    void MovieSprite::stop()
    {
        clear();
    }

    bool MovieSprite::isPlaying() const
    {
        return _playing && !_paused;
    }

    void MovieSprite::asyncDone()
    {
        addRef();
        core::getMainThreadDispatcher().postCallback([ = ]()
        {
            _playing = false;

            Event ev(MovieSprite::COMPLETE);
            dispatchEvent(&ev);

            if (_detachWhenDone)
                detach();

            releaseRef();
        });
    }
}
<|endoftext|>


<commit_before>#include "Globals.h"
#include "Application.h"
#include "ModuleScene.h"
#include "ModuleRenderer3D.h"
#include "ModuleWindow.h"
#include "ModuleInput.h"
#include "ModuleGOManager.h"
#include "ModuleCamera3D.h"
#include "GameObject.h"
#include "ComponentMesh.h"
#include "ComponentCamera.h"
#include "ComponentTransformation.h"
#include "ModuleEditor.h"
#include "Mesh.h"
#include "Primitive.h"
#include "DebugPainter.h"
#include "ImGui/imgui.h"

ModuleScene::ModuleScene(Application* app, bool start_enabled) : Module(app, start_enabled)
{
	name.assign("Scene");
}

ModuleScene::~ModuleScene()
{}

// Load assets
bool ModuleScene::Start()
{
	LOG("Loading Intro assets");
	bool ret = true;

	picking = LineSegment(vec::zero, vec::unitX);

	return ret;
}

// Load assets
bool ModuleScene::CleanUp()
{
	LOG("Unloading Intro scene");

	return true;
}

// Update
update_status ModuleScene::Update(float dt)
{
	Plane_P p(0, 1, 0, 0);
	p.axis = true;
	p.Render();

	if (App->input->GetMouseButton(SDL_BUTTON_LEFT) == KEY_DOWN && ImGui::IsMouseHoveringAnyWindow() == false)
	{
		float2 mouse_click(App->input->GetMouseX(), App->input->GetMouseY());

		float mc_normalized_x = -(1.0f - (mouse_click.x * 2.0f) / App->window->GetWindowSize().x);
		float mc_normalized_y = (1.0f - (mouse_click.y * 2.0f) / App->window->GetWindowSize().y);

		picking = App->renderer3D->GetRenderingCamera()->GetFrustum().UnProjectLineSegment(mc_normalized_x, mc_normalized_y);
		//LOG("Segment point A: %.2f point B: %.2f", picking.a, picking.b);

		std::vector<GameObject*> candidates;
		App->go_manager->FindCandidates(picking, candidates);
		LOG("Candidates: %d", candidates.size());

		if (candidates.size() == 0)
		{
			App->editor->SetSelectedGO(nullptr);
		}

		GameObject* picked = nullptr;
		float min_dist = App->camera->GetCamera()->GetFarPlane();

		for (uint i = 0; i < candidates.size(); i++)
		{
			GameObject* go = candidates[i];
			ComponentMesh* mesh = (ComponentMesh*)go->GetComponentByType(Component::Type::Geometry);

			for (uint i = 0; i < mesh->GetMesh()->num_indices; i+=3)
			{
				vec vertex_1 = mesh->GetMesh()->vertices[mesh->GetMesh()->indices[i]];
				vec vertex_2 = mesh->GetMesh()->vertices[mesh->GetMesh()->indices[i + 1]];
				vec vertex_3 = mesh->GetMesh()->vertices[mesh->GetMesh()->indices[i + 2]];

				Triangle to_test(vertex_1, vertex_2, vertex_3);
				to_test.Transform(go->transform->GetGlobalMatrix());
				float hit_distance = 0;
				vec hit_point = vec::zero;

				if (to_test.Intersects(picking, &hit_distance, &hit_point))
				{
					if (hit_distance < min_dist)
					{
						picked = go;
						min_dist = hit_distance;
					}
				}
			}
		}
		App->editor->SetSelectedGO(picked);
	}

	DebugDraw(picking, Red);

	return UPDATE_CONTINUE;
}<commit_msg>Picking now is working moving linesegment and not each triangle.<commit_after>#include "Globals.h"
#include "Application.h"
#include "ModuleScene.h"
#include "ModuleRenderer3D.h"
#include "ModuleWindow.h"
#include "ModuleInput.h"
#include "ModuleGOManager.h"
#include "ModuleCamera3D.h"
#include "GameObject.h"
#include "ComponentMesh.h"
#include "ComponentCamera.h"
#include "ComponentTransformation.h"
#include "ModuleEditor.h"
#include "Mesh.h"
#include "Primitive.h"
#include "DebugPainter.h"
#include "ImGui/imgui.h"

ModuleScene::ModuleScene(Application* app, bool start_enabled) : Module(app, start_enabled)
{
	name.assign("Scene");
}

ModuleScene::~ModuleScene()
{}

// Load assets
bool ModuleScene::Start()
{
	LOG("Loading Intro assets");
	bool ret = true;

	picking = LineSegment(vec::zero, vec::unitX);

	return ret;
}

// Load assets
bool ModuleScene::CleanUp()
{
	LOG("Unloading Intro scene");

	return true;
}

// Update
update_status ModuleScene::Update(float dt)
{
	Plane_P p(0, 1, 0, 0);
	p.axis = true;
	p.Render();

	if (App->input->GetMouseButton(SDL_BUTTON_LEFT) == KEY_DOWN && ImGui::IsMouseHoveringAnyWindow() == false)
	{
		float2 mouse_click(App->input->GetMouseX(), App->input->GetMouseY());

		float mc_normalized_x = -(1.0f - (mouse_click.x * 2.0f) / App->window->GetWindowSize().x);
		float mc_normalized_y = (1.0f - (mouse_click.y * 2.0f) / App->window->GetWindowSize().y);

		picking = App->renderer3D->GetRenderingCamera()->GetFrustum().UnProjectLineSegment(mc_normalized_x, mc_normalized_y);
		//LOG("Segment point A: %.2f point B: %.2f", picking.a, picking.b);

		std::vector<GameObject*> candidates;
		App->go_manager->FindCandidates(picking, candidates);
		//LOG("Candidates: %d", candidates.size());

		if (candidates.size() == 0)
		{
			App->editor->SetSelectedGO(nullptr);
		}

		GameObject* picked = nullptr;
		float min_dist = App->camera->GetCamera()->GetFarPlane();

		for (uint i = 0; i < candidates.size(); i++)
		{
			GameObject* go = candidates[i];
			LineSegment tmp = picking;
			ComponentMesh* mesh = (ComponentMesh*)go->GetComponentByType(Component::Type::Geometry);

			tmp.Transform(go->transform->GetGlobalMatrix().Inverted());

			for (uint i = 0; i < mesh->GetMesh()->num_indices; i+=3)
			{
				vec vertex_1 = mesh->GetMesh()->vertices[mesh->GetMesh()->indices[i]];
				vec vertex_2 = mesh->GetMesh()->vertices[mesh->GetMesh()->indices[i + 1]];
				vec vertex_3 = mesh->GetMesh()->vertices[mesh->GetMesh()->indices[i + 2]];

				Triangle to_test(vertex_1, vertex_2, vertex_3);
				float hit_distance = 0;
				vec hit_point = vec::zero;

				if (to_test.Intersects(tmp, &hit_distance, &hit_point))
				{
					if (hit_distance < min_dist)
					{
						picked = go;
						min_dist = hit_distance;
					}
				}
			}
		}
		App->editor->SetSelectedGO(picked);
	}

	DebugDraw(picking, Red);

	return UPDATE_CONTINUE;
}<|endoftext|>


<commit_before>/*
 *  DBusTL - DBus Template Library
 *
 *  Copyright (C) 2008, 2009  Fabien Chevalier <chefabien@gmail.com>
 *
 *
 *  This file is part of the DBus Template Library.
 *
 *  The DBus Template Library is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 2.1 of the License, or
 *  (at your option) any later version.
 *
 *  DBus Template Library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with DBus Template Library.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <dbus/dbus.h>

#include <dbustl-1/Connection>
#include <dbustl-1/ServerProxy>

#include <sstream>
#include <cassert>

namespace dbustl {

DBusObjectPathVTable ServerProxy::_vtable = {
    NULL,
    &ServerProxy::signalsProcessingMethod,
    0,
    0,
    0,
    0
};

ServerProxy::ServerProxy(Connection* conn, const std::string& path, const std::string& destination) :
  _conn(conn), _path(path), _destination(destination), _timeout(-1)
{
    assert(_conn->isConnected());
    if(!dbus_connection_register_object_path(_conn->dbus(), _path.c_str(), &_vtable, this)) {
        throw_or_set(DBUS_ERROR_NO_MEMORY, "Not enough memory to register object path handler");
    }
}

ServerProxy::~ServerProxy()
{
    dbus_connection_unregister_object_path(_conn->dbus(), _path.c_str());

    std::map<std::string, SignalCallbackWrapperBase* >::iterator it;
    while((it = _signalsHandlers.begin()) != _signalsHandlers.end()) {
        // Beware : due to the fact the method below erases() the map element while we still
        // need some bits of its (i.e. signal name), we have to make a copy
        std::string sigName = it->first;
        //C++ Destructors must not throw, so protect those calls
        try {
            removeSignalHandler(sigName);
        }
        catch(const DBusException&) {
            //Skip exception
        }
    }
}

Message ServerProxy::createMethodCall(const std::string& methodName)
{
    const char *dest = _destination.empty() ? NULL : _destination.c_str();
    const char *intf = _interface.empty() ? NULL : _interface.c_str();

    Message method_call(dbus_message_new_method_call(dest, _path.c_str(),
                    intf, methodName.c_str()));

    if(method_call.dbus()) {
        // Blank out error status
        errorReset();
    }
    else {
        throw_or_set(DBUS_ERROR_NO_MEMORY, "Not enough memory to allocate DBUS message");
    }

    return method_call;
}

Message ServerProxy::call(Message& method_call)
{
    DBusException error;
    DBusMessage *reply;

    reply = dbus_connection_send_with_reply_and_block(_conn->dbus(), method_call.dbus(), _timeout, error.dbus());
    if(!reply) {
        throw_or_set(error);
    }
    return Message(reply);
}

void ServerProxy::processInArgs(Message& msg)
{
    if(!msg.error()) {
        Message reply(call(msg));
        // Overwrite message
        msg = reply;
    }
}

void ServerProxy::processOutArgs(Message& reply)
{
    if(reply.error()) {
        throw_or_set( *(reply.error()) );
    }
}

void ServerProxy::callCompleted(DBusPendingCall *pending, void *user_data)
{
    DBusException e;
    MethodCallbackWrapperBase *callback = static_cast<MethodCallbackWrapperBase*>(user_data);

    Message reply(dbus_pending_call_steal_reply(pending));

    dbus_set_error_from_message(e.dbus(), reply.dbus());

    //call user function
    callback->execute(reply, e);

    dbus_pending_call_unref(pending);
}

void ServerProxy::methodCallbackWrapperDelete(void *object)
{
    MethodCallbackWrapperBase *cb = static_cast<MethodCallbackWrapperBase*>(object);
    delete cb;
}

void ServerProxy::executeAsyncCall(Message& method_call, MethodCallbackWrapperBase *wrapper)
{
    if(!method_call.error()) {
        DBusPendingCall *pending_return;
        if(dbus_connection_send_with_reply(_conn->dbus(), method_call.dbus(), &pending_return, _timeout) == TRUE) {
            if(pending_return) {
                if(dbus_pending_call_set_notify(pending_return, callCompleted,
                      wrapper, methodCallbackWrapperDelete) == FALSE) {
                    delete wrapper;
                    throw_or_set(DBUS_ERROR_NO_MEMORY, "Not enough memory to set callback for D-Bus message");
                }
            }
            else {
                delete wrapper;
                //we borrowed this one from dbus library, to be in sync with what call() would do.
                throw_or_set(DBUS_ERROR_DISCONNECTED, "Connection is closed");
            }
        }
        else {
            delete wrapper;
            throw_or_set(DBUS_ERROR_NO_MEMORY, "Not enough memory to send D-Bus message");
        }
    }
    else {
        delete wrapper;
    }
}

DBusHandlerResult ServerProxy::signalsProcessingMethod(DBusConnection *,
    DBusMessage *dbusMessage, void *user_data)
{
    ServerProxy* proxy = static_cast<ServerProxy *>(user_data);

    /* Basic sanity check : libdbus tries an approximate match on objects
     * paths, but we want a perfect match */

    if(proxy->_path != dbus_message_get_path(dbusMessage)) {
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    }

    Message msg(dbusMessage);

    /* libdbus keeps ownership of the message, but our Message class
     * wants ownership too: as a result both will free the message
     * once it is not used anymore. Ref it one more time as a workaround. */
    dbus_message_ref(msg.dbus());

    if(dbus_message_get_type(msg.dbus()) == DBUS_MESSAGE_TYPE_SIGNAL) {
        std::string sigName = msg.member();
        std::string handlerName;

        //First check if we can have an exact match
        if(proxy->_signalsHandlers.count(sigName)) {
            handlerName = sigName;
        }
        //Second check for a generic handler
        else if(proxy->_signalsHandlers.count("")) {
            handlerName = "";
        }
        else {
            return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
        }

        proxy->_signalsHandlers[handlerName]->execute(msg);

    	return DBUS_HANDLER_RESULT_HANDLED;
    }
    else {
    	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    }
}

void ServerProxy::removeSignalHandler(const std::string& signalName)
{
    if(_signalsHandlers.count(signalName)) {
        SignalCallbackWrapperBase *cb = _signalsHandlers[signalName];
        _signalsHandlers.erase(signalName);
        delete cb;
        //Note: we do free mem ops before to call this as it may throw
        setWatchSignal(signalName, false);
    }
}

void ServerProxy::setWatchSignal(const std::string& signalName, bool enable)
{
    if(!_conn->isPrivate()) {
        std::stringstream match;
        DBusException error;

        //Reset global error status
        errorReset();

        match << "type='signal',path='" << _path << "'";

        if(signalName.size()) {
            match << ",member='" << signalName << "'";
        }

        if(enable) {
            dbus_bus_add_match(_conn->dbus(), match.str().c_str(), error.dbus());
        }
        else {
            dbus_bus_remove_match(_conn->dbus(), match.str().c_str(), error.dbus());
        }

        if(error.isSet()) {
            throw_or_set(error);
        }
    }
}

void ServerProxy::enableSignal(const std::string& signalName, SignalCallbackWrapperBase* signalCb)
{
    if(!_signalsHandlers.count(signalName)) {
#ifndef DBUSTL_NO_EXCEPTIONS
        try {
#endif
            setWatchSignal(signalName, true);

            if(!DBUSTL_HAS_ERROR()) {
                _signalsHandlers[signalName] = signalCb;
            }
            return;
#ifndef DBUSTL_NO_EXCEPTIONS
        }
        catch(...) {
            delete signalCb;
            throw;
        }
#else
        delete signalCb;
#endif
    }
    else {
        //Already there
        SignalCallbackWrapperBase *cb = _signalsHandlers[signalName];
        //Put new callback in place
        _signalsHandlers[signalName] = signalCb;
        //Delete old one;
        delete cb;
    }
}

}
<commit_msg>Removed useless use of stringstreams<commit_after>/*
 *  DBusTL - DBus Template Library
 *
 *  Copyright (C) 2008, 2009  Fabien Chevalier <chefabien@gmail.com>
 *
 *
 *  This file is part of the DBus Template Library.
 *
 *  The DBus Template Library is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 2.1 of the License, or
 *  (at your option) any later version.
 *
 *  DBus Template Library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with DBus Template Library.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <dbus/dbus.h>

#include <dbustl-1/Connection>
#include <dbustl-1/ServerProxy>

#include <cassert>

namespace dbustl {

DBusObjectPathVTable ServerProxy::_vtable = {
    NULL,
    &ServerProxy::signalsProcessingMethod,
    0,
    0,
    0,
    0
};

ServerProxy::ServerProxy(Connection* conn, const std::string& path, const std::string& destination) :
  _conn(conn), _path(path), _destination(destination), _timeout(-1)
{
    assert(_conn->isConnected());
    if(!dbus_connection_register_object_path(_conn->dbus(), _path.c_str(), &_vtable, this)) {
        throw_or_set(DBUS_ERROR_NO_MEMORY, "Not enough memory to register object path handler");
    }
}

ServerProxy::~ServerProxy()
{
    dbus_connection_unregister_object_path(_conn->dbus(), _path.c_str());

    std::map<std::string, SignalCallbackWrapperBase* >::iterator it;
    while((it = _signalsHandlers.begin()) != _signalsHandlers.end()) {
        // Beware : due to the fact the method below erases() the map element while we still
        // need some bits of its (i.e. signal name), we have to make a copy
        std::string sigName = it->first;
        //C++ Destructors must not throw, so protect those calls
        try {
            removeSignalHandler(sigName);
        }
        catch(const DBusException&) {
            //Skip exception
        }
    }
}

Message ServerProxy::createMethodCall(const std::string& methodName)
{
    const char *dest = _destination.empty() ? NULL : _destination.c_str();
    const char *intf = _interface.empty() ? NULL : _interface.c_str();

    Message method_call(dbus_message_new_method_call(dest, _path.c_str(),
                    intf, methodName.c_str()));

    if(method_call.dbus()) {
        // Blank out error status
        errorReset();
    }
    else {
        throw_or_set(DBUS_ERROR_NO_MEMORY, "Not enough memory to allocate DBUS message");
    }

    return method_call;
}

Message ServerProxy::call(Message& method_call)
{
    DBusException error;
    DBusMessage *reply;

    reply = dbus_connection_send_with_reply_and_block(_conn->dbus(), method_call.dbus(), _timeout, error.dbus());
    if(!reply) {
        throw_or_set(error);
    }
    return Message(reply);
}

void ServerProxy::processInArgs(Message& msg)
{
    if(!msg.error()) {
        Message reply(call(msg));
        // Overwrite message
        msg = reply;
    }
}

void ServerProxy::processOutArgs(Message& reply)
{
    if(reply.error()) {
        throw_or_set( *(reply.error()) );
    }
}

void ServerProxy::callCompleted(DBusPendingCall *pending, void *user_data)
{
    DBusException e;
    MethodCallbackWrapperBase *callback = static_cast<MethodCallbackWrapperBase*>(user_data);

    Message reply(dbus_pending_call_steal_reply(pending));

    dbus_set_error_from_message(e.dbus(), reply.dbus());

    //call user function
    callback->execute(reply, e);

    dbus_pending_call_unref(pending);
}

void ServerProxy::methodCallbackWrapperDelete(void *object)
{
    MethodCallbackWrapperBase *cb = static_cast<MethodCallbackWrapperBase*>(object);
    delete cb;
}

void ServerProxy::executeAsyncCall(Message& method_call, MethodCallbackWrapperBase *wrapper)
{
    if(!method_call.error()) {
        DBusPendingCall *pending_return;
        if(dbus_connection_send_with_reply(_conn->dbus(), method_call.dbus(), &pending_return, _timeout) == TRUE) {
            if(pending_return) {
                if(dbus_pending_call_set_notify(pending_return, callCompleted,
                      wrapper, methodCallbackWrapperDelete) == FALSE) {
                    delete wrapper;
                    throw_or_set(DBUS_ERROR_NO_MEMORY, "Not enough memory to set callback for D-Bus message");
                }
            }
            else {
                delete wrapper;
                //we borrowed this one from dbus library, to be in sync with what call() would do.
                throw_or_set(DBUS_ERROR_DISCONNECTED, "Connection is closed");
            }
        }
        else {
            delete wrapper;
            throw_or_set(DBUS_ERROR_NO_MEMORY, "Not enough memory to send D-Bus message");
        }
    }
    else {
        delete wrapper;
    }
}

DBusHandlerResult ServerProxy::signalsProcessingMethod(DBusConnection *,
    DBusMessage *dbusMessage, void *user_data)
{
    ServerProxy* proxy = static_cast<ServerProxy *>(user_data);

    /* Basic sanity check : libdbus tries an approximate match on objects
     * paths, but we want a perfect match */

    if(proxy->_path != dbus_message_get_path(dbusMessage)) {
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    }

    Message msg(dbusMessage);

    /* libdbus keeps ownership of the message, but our Message class
     * wants ownership too: as a result both will free the message
     * once it is not used anymore. Ref it one more time as a workaround. */
    dbus_message_ref(msg.dbus());

    if(dbus_message_get_type(msg.dbus()) == DBUS_MESSAGE_TYPE_SIGNAL) {
        std::string sigName = msg.member();
        std::string handlerName;

        //First check if we can have an exact match
        if(proxy->_signalsHandlers.count(sigName)) {
            handlerName = sigName;
        }
        //Second check for a generic handler
        else if(proxy->_signalsHandlers.count("")) {
            handlerName = "";
        }
        else {
            return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
        }

        proxy->_signalsHandlers[handlerName]->execute(msg);

    	return DBUS_HANDLER_RESULT_HANDLED;
    }
    else {
    	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    }
}

void ServerProxy::removeSignalHandler(const std::string& signalName)
{
    if(_signalsHandlers.count(signalName)) {
        SignalCallbackWrapperBase *cb = _signalsHandlers[signalName];
        _signalsHandlers.erase(signalName);
        delete cb;
        //Note: we do free mem ops before to call this as it may throw
        setWatchSignal(signalName, false);
    }
}

void ServerProxy::setWatchSignal(const std::string& signalName, bool enable)
{
    if(!_conn->isPrivate()) {
        std::string match;
        DBusException error;

        //Reset global error status
        errorReset();

        match = std::string("type='signal',path='") +  _path + "'";

        if(signalName.size()) {
            match = match + ",member='" + signalName + "'";
        }

        if(enable) {
            dbus_bus_add_match(_conn->dbus(), match.c_str(), error.dbus());
        }
        else {
            dbus_bus_remove_match(_conn->dbus(), match.c_str(), error.dbus());
        }

        if(error.isSet()) {
            throw_or_set(error);
        }
    }
}

void ServerProxy::enableSignal(const std::string& signalName, SignalCallbackWrapperBase* signalCb)
{
    if(!_signalsHandlers.count(signalName)) {
#ifndef DBUSTL_NO_EXCEPTIONS
        try {
#endif
            setWatchSignal(signalName, true);

            if(!DBUSTL_HAS_ERROR()) {
                _signalsHandlers[signalName] = signalCb;
            }
            return;
#ifndef DBUSTL_NO_EXCEPTIONS
        }
        catch(...) {
            delete signalCb;
            throw;
        }
#else
        delete signalCb;
#endif
    }
    else {
        //Already there
        SignalCallbackWrapperBase *cb = _signalsHandlers[signalName];
        //Put new callback in place
        _signalsHandlers[signalName] = signalCb;
        //Delete old one;
        delete cb;
    }
}

}
<|endoftext|>


<commit_before>#include <fstream>
#include <unistd.h>

#include <NTL/ZZX.h>
#include <NTL/vector.h>

#include "FHE.h"
#include "timing.h"
#include "EncryptedArray.h"

long compareFiles(string filename1, string filename2){

  ifstream file1(filename1);
  ifstream file2(filename2);

  if(!file1.is_open() && !file2.is_open()){
    cerr << "Could not open one of the following files:" << endl;
    cerr << filename1 << " and/or " << filename2 << endl;
    exit(EXIT_FAILURE);
  }

  fstream::pos_type file1size, file2size;

  file1size = file1.seekg(0, ifstream::end).tellg();
  file1.seekg(0, ifstream::beg);

  file2size = file2.seekg(0, ifstream::end).tellg();
  file2.seekg(0, ifstream::beg);

  // Quick compare sizes.
  if(file1size != file2size){
    file1.close();
    file2.close();
    cerr << "Files "<<filename1<<" and "<<filename2<<" not the same size :("<< endl;
    return -1;
  }

  // Now compare byte blocks at a time.
  const size_t BLOCKSIZE = 4096; // 4 kB

  char buffer1[BLOCKSIZE];
  char buffer2[BLOCKSIZE];
  size_t curBlckSz = 0;

  for(size_t i=file1size, cnt=0; i > 0; i-=curBlckSz, cnt++) {

    curBlckSz = std::min(BLOCKSIZE, i);

    file1.read(buffer1, curBlckSz);
    file2.read(buffer2, curBlckSz);

    if(memcmp(buffer1, buffer2, curBlckSz)){
      cerr << "Block "<<cnt<<" (block size: "<<BLOCKSIZE<<" bytes) "<<cnt<<" does not match :("<<endl;
      return 1;
    }

  }

  return 0; // Files are the same!

}

int main(int argc, char *argv[])
{

  cout << "\n*** TEST BINARY IO " << endl << endl;

  ArgMapping amap;

  long m=7;
  long r=1;
  long p=2;
  long c=2;
  long w=64;
  long L=5;
  long cleanup=1;

  amap.arg("m", m, "order of cyclotomic polynomial");
  amap.arg("p", p, "plaintext base");
  amap.arg("r", r, "lifting");
  amap.arg("c", c, "number of columns in the key-switching matrices");
  amap.arg("L", L, "number of levels wanted");
  amap.arg("cleanup", cleanup, "cleanup files created");
  amap.parse(argc, argv);

  const char* asciiFile1 = "iotest_ascii1.txt";
  const char* asciiFile2 = "iotest_ascii2.txt";
  const char* binFile1 = "iotest_bin.bin";

// Write ASCII and bin files.
{

  cout << "Test to write out ASCII and Binary Files.\n";

  ofstream asciiFile(asciiFile1);
  ofstream binFile(binFile1, ios::binary);
  assert(asciiFile.is_open());

  FHEcontext* context = new FHEcontext(m, p, r);
  buildModChain(*context, L, c);  // Set the modulus chain

  context->zMStar.printout(); // Printout context params
  cout << "\tSecurity Level: " << context->securityLevel() << endl;

  FHESecKey* secKey = new FHESecKey(*context);
  FHEPubKey* pubKey = secKey;
  secKey->GenSecKey(w);
  addSome1DMatrices(*secKey);
  addFrbMatrices(*secKey);

  // ASCII
  cout << "\tWriting ASCII1 file " << asciiFile1 << endl;
  writeContextBase(asciiFile, *context);
  asciiFile << *context << endl << endl;
  asciiFile << *pubKey << endl << endl;
  asciiFile << *secKey << endl << endl;

  // Bin
  cout << "\tWriting Binary file " << binFile1<< endl;
  writeContextBaseBinary(binFile, *context);
  writeContextBinary(binFile, *context);
  writePubKeyBinary(binFile, *pubKey);
  writeSecKeyBinary(binFile, *secKey);

  asciiFile.close();
  binFile.close();

  cout << "Test successful.\n\n";

}

// Read in bin files and write out ASCII.
{
  cout << "Test to read binary file and write it out as ASCII" << endl;

  ifstream inFile(binFile1, ios::binary);
  ofstream outFile(asciiFile2);

  // Read in context,
  FHEcontext* context;

//  cout << "\tReading Binary Base." << endl;
  readContextBaseBinary(inFile, context);
//  cout << "\tReading Binary Context." << endl;
  readContextBinary(inFile, *context);

  // Read in SecKey and PubKey.
  // Got to insert pubKey into seckey obj first.
  FHESecKey* secKey = new FHESecKey(*context);
  FHEPubKey* pubKey = secKey;

  readPubKeyBinary(inFile, *pubKey);
  readSecKeyBinary(inFile, *secKey);

  // ASCII
  cout << "\tWriting ASCII2 file." << endl;
  writeContextBase(outFile, *context);
  outFile << *context << endl << endl;
  outFile << *pubKey << endl << endl;
  outFile << *secKey << endl << endl;

  inFile.close();
  outFile.close();

  cout << "Test successful.\n\n";

}

// Compare byte-wise the two ASCII files
{
  cout << "Comparing the two ASCII files\n";

  long differ = compareFiles(asciiFile1, asciiFile2);

  if(differ != 0){
    cout << "\tFAIL - Files differ. Return Code: " << differ << endl;
    cout << "Test failed.\n";
    exit(EXIT_FAILURE);
  } else {
    cout << "\tSUCCESS - Files are identical.\n";
  }

  cout << "Test successful.\n\n";
}

// Read in binary and perform operation.
{

  cout << "Test reading in Binary files and performing an operation between two ctxts\n";

  ifstream inFile(binFile1, ios::binary);

  // Read in context,
  FHEcontext* context;

//  cout << "Reading Binary Base." << endl;
  readContextBaseBinary(inFile, context);
//  cout << "Reading Binary Context." << endl;
  readContextBinary(inFile, *context);

  // Read in PubKey.
  FHESecKey* secKey = new FHESecKey(*context);
  FHEPubKey* pubKey = secKey;
  readPubKeyBinary(inFile, *pubKey);
  readSecKeyBinary(inFile, *secKey);

  // Get the ea
  const EncryptedArray& ea = *context->ea;

  // Setup some ptxts and ctxts.
  Ctxt c1(*pubKey), c2(*pubKey);
  NewPlaintextArray p1(ea),  p2(ea);

  random(ea, p1);
  random(ea, p2);

  ea.encrypt(c1, *pubKey, p1);
  ea.encrypt(c2, *pubKey, p2);

  // Operation multiply and add.
  mul(ea, p1, p2);
//  random(ea, p1);
  c1 *= c2;

  // Decrypt and Compare.
  NewPlaintextArray pp1(ea);
  ea.decrypt(c1, *secKey, pp1);

  if(!equals(ea, p1, pp1)){
    cout << "\tFAIL - polynomials are not equal\n";
    cout << "Test failed.\n";
    exit(EXIT_FAILURE);
  }

  cout << "\tGOOD - polynomials are equal\n";

  inFile.close();

  if(cleanup){
    cout << "Clean up. Deleting created files." << endl;
    if(unlink(asciiFile1)) cerr << "Delete of "<<asciiFile1<<" failed."<<endl;
    if(unlink(asciiFile2)) cerr << "Delete of "<<asciiFile2<<" failed."<<endl;
    if(unlink(binFile1)) cerr << "Delete of "<<binFile1<<" failed."<<endl;
  }

  cout << "Test successful.\n\n";

}

  return 0;
}

<commit_msg>added licence spiel to Test_Bin_IO.cpp<commit_after>/* Copyright (C) 2012-2017 IBM Corp.
 * This program is Licensed under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *   http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. See accompanying LICENSE file.
 */

#include <fstream>
#include <unistd.h>

#include <NTL/ZZX.h>
#include <NTL/vector.h>

#include "FHE.h"
#include "timing.h"
#include "EncryptedArray.h"

long compareFiles(string filename1, string filename2){

  ifstream file1(filename1);
  ifstream file2(filename2);

  if(!file1.is_open() && !file2.is_open()){
    cerr << "Could not open one of the following files:" << endl;
    cerr << filename1 << " and/or " << filename2 << endl;
    exit(EXIT_FAILURE);
  }

  fstream::pos_type file1size, file2size;

  file1size = file1.seekg(0, ifstream::end).tellg();
  file1.seekg(0, ifstream::beg);

  file2size = file2.seekg(0, ifstream::end).tellg();
  file2.seekg(0, ifstream::beg);

  // Quick compare sizes.
  if(file1size != file2size){
    file1.close();
    file2.close();
    cerr << "Files "<<filename1<<" and "<<filename2<<" not the same size :("<< endl;
    return -1;
  }

  // Now compare byte blocks at a time.
  const size_t BLOCKSIZE = 4096; // 4 kB

  char buffer1[BLOCKSIZE];
  char buffer2[BLOCKSIZE];
  size_t curBlckSz = 0;

  for(size_t i=file1size, cnt=0; i > 0; i-=curBlckSz, cnt++) {

    curBlckSz = std::min(BLOCKSIZE, i);

    file1.read(buffer1, curBlckSz);
    file2.read(buffer2, curBlckSz);

    if(memcmp(buffer1, buffer2, curBlckSz)){
      cerr << "Block "<<cnt<<" (block size: "<<BLOCKSIZE<<" bytes) "<<cnt<<" does not match :("<<endl;
      return 1;
    }

  }

  return 0; // Files are the same!

}

int main(int argc, char *argv[])
{

  cout << "\n*** TEST BINARY IO " << endl << endl;

  ArgMapping amap;

  long m=7;
  long r=1;
  long p=2;
  long c=2;
  long w=64;
  long L=5;
  long cleanup=1;

  amap.arg("m", m, "order of cyclotomic polynomial");
  amap.arg("p", p, "plaintext base");
  amap.arg("r", r, "lifting");
  amap.arg("c", c, "number of columns in the key-switching matrices");
  amap.arg("L", L, "number of levels wanted");
  amap.arg("cleanup", cleanup, "cleanup files created");
  amap.parse(argc, argv);

  const char* asciiFile1 = "iotest_ascii1.txt";
  const char* asciiFile2 = "iotest_ascii2.txt";
  const char* binFile1 = "iotest_bin.bin";

// Write ASCII and bin files.
{

  cout << "Test to write out ASCII and Binary Files.\n";

  ofstream asciiFile(asciiFile1);
  ofstream binFile(binFile1, ios::binary);
  assert(asciiFile.is_open());

  FHEcontext* context = new FHEcontext(m, p, r);
  buildModChain(*context, L, c);  // Set the modulus chain

  context->zMStar.printout(); // Printout context params
  cout << "\tSecurity Level: " << context->securityLevel() << endl;

  FHESecKey* secKey = new FHESecKey(*context);
  FHEPubKey* pubKey = secKey;
  secKey->GenSecKey(w);
  addSome1DMatrices(*secKey);
  addFrbMatrices(*secKey);

  // ASCII
  cout << "\tWriting ASCII1 file " << asciiFile1 << endl;
  writeContextBase(asciiFile, *context);
  asciiFile << *context << endl << endl;
  asciiFile << *pubKey << endl << endl;
  asciiFile << *secKey << endl << endl;

  // Bin
  cout << "\tWriting Binary file " << binFile1<< endl;
  writeContextBaseBinary(binFile, *context);
  writeContextBinary(binFile, *context);
  writePubKeyBinary(binFile, *pubKey);
  writeSecKeyBinary(binFile, *secKey);

  asciiFile.close();
  binFile.close();

  cout << "Test successful.\n\n";

}

// Read in bin files and write out ASCII.
{
  cout << "Test to read binary file and write it out as ASCII" << endl;

  ifstream inFile(binFile1, ios::binary);
  ofstream outFile(asciiFile2);

  // Read in context,
  FHEcontext* context;

//  cout << "\tReading Binary Base." << endl;
  readContextBaseBinary(inFile, context);
//  cout << "\tReading Binary Context." << endl;
  readContextBinary(inFile, *context);

  // Read in SecKey and PubKey.
  // Got to insert pubKey into seckey obj first.
  FHESecKey* secKey = new FHESecKey(*context);
  FHEPubKey* pubKey = secKey;

  readPubKeyBinary(inFile, *pubKey);
  readSecKeyBinary(inFile, *secKey);

  // ASCII
  cout << "\tWriting ASCII2 file." << endl;
  writeContextBase(outFile, *context);
  outFile << *context << endl << endl;
  outFile << *pubKey << endl << endl;
  outFile << *secKey << endl << endl;

  inFile.close();
  outFile.close();

  cout << "Test successful.\n\n";

}

// Compare byte-wise the two ASCII files
{
  cout << "Comparing the two ASCII files\n";

  long differ = compareFiles(asciiFile1, asciiFile2);

  if(differ != 0){
    cout << "\tFAIL - Files differ. Return Code: " << differ << endl;
    cout << "Test failed.\n";
    exit(EXIT_FAILURE);
  } else {
    cout << "\tSUCCESS - Files are identical.\n";
  }

  cout << "Test successful.\n\n";
}

// Read in binary and perform operation.
{

  cout << "Test reading in Binary files and performing an operation between two ctxts\n";

  ifstream inFile(binFile1, ios::binary);

  // Read in context,
  FHEcontext* context;

//  cout << "Reading Binary Base." << endl;
  readContextBaseBinary(inFile, context);
//  cout << "Reading Binary Context." << endl;
  readContextBinary(inFile, *context);

  // Read in PubKey.
  FHESecKey* secKey = new FHESecKey(*context);
  FHEPubKey* pubKey = secKey;
  readPubKeyBinary(inFile, *pubKey);
  readSecKeyBinary(inFile, *secKey);

  // Get the ea
  const EncryptedArray& ea = *context->ea;

  // Setup some ptxts and ctxts.
  Ctxt c1(*pubKey), c2(*pubKey);
  NewPlaintextArray p1(ea),  p2(ea);

  random(ea, p1);
  random(ea, p2);

  ea.encrypt(c1, *pubKey, p1);
  ea.encrypt(c2, *pubKey, p2);

  // Operation multiply and add.
  mul(ea, p1, p2);
//  random(ea, p1);
  c1 *= c2;

  // Decrypt and Compare.
  NewPlaintextArray pp1(ea);
  ea.decrypt(c1, *secKey, pp1);

  if(!equals(ea, p1, pp1)){
    cout << "\tFAIL - polynomials are not equal\n";
    cout << "Test failed.\n";
    exit(EXIT_FAILURE);
  }

  cout << "\tGOOD - polynomials are equal\n";

  inFile.close();

  if(cleanup){
    cout << "Clean up. Deleting created files." << endl;
    if(unlink(asciiFile1)) cerr << "Delete of "<<asciiFile1<<" failed."<<endl;
    if(unlink(asciiFile2)) cerr << "Delete of "<<asciiFile2<<" failed."<<endl;
    if(unlink(binFile1)) cerr << "Delete of "<<binFile1<<" failed."<<endl;
  }

  cout << "Test successful.\n\n";

}

  return 0;
}

<|endoftext|>


<commit_before>/**************************************************************************

 The MIT License (MIT)

 Copyright (c) 2015 Dmitry Sovetov

 https://github.com/dmsovetov

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:
 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.

 **************************************************************************/

#include "DebugSpriteTransformRenderer.h"

DC_BEGIN_DREEMCHEST

namespace scene {

// ** DebugSpriteTransformRenderPass::DebugSpriteTransformRenderPass
DebugSpriteTransformRenderPass::DebugSpriteTransformRenderPass( Ecs::Entities& entities, const Renderer& renderer ) : RenderPass( entities, "DebugSpriteTransformRenderPass", renderer )
{
}

// ** DebugSpriteTransformRenderPass::process
void DebugSpriteTransformRenderPass::process( u32 currentTime, f32 dt, SceneObject& sceneObject, Sprite& sprite, Transform& transform )
{
	m_renderer.m_renderer2d->point( transform.x(), transform.y(), Rgba( 0.0f, 1.0f, 0.0f, 1.0f ) );
}

// ** DebugSpriteTransformRenderPass::begin
bool DebugSpriteTransformRenderPass::begin( u32 currentTime )
{
	m_renderer.m_renderer2d->begin( m_viewProj );
	return true;
}

// ** DebugSpriteTransformRenderPass::end
void DebugSpriteTransformRenderPass::end( void )
{
	m_renderer.m_renderer2d->end();
}

} // namespace scene

DC_END_DREEMCHEST<commit_msg>Debug sprite transform renderer now outputs transform bases<commit_after>/**************************************************************************

 The MIT License (MIT)

 Copyright (c) 2015 Dmitry Sovetov

 https://github.com/dmsovetov

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:
 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.

 **************************************************************************/

#include "DebugSpriteTransformRenderer.h"

DC_BEGIN_DREEMCHEST

namespace scene {

// ** DebugSpriteTransformRenderPass::DebugSpriteTransformRenderPass
DebugSpriteTransformRenderPass::DebugSpriteTransformRenderPass( Ecs::Entities& entities, const Renderer& renderer ) : RenderPass( entities, "DebugSpriteTransformRenderPass", renderer )
{
}

// ** DebugSpriteTransformRenderPass::process
void DebugSpriteTransformRenderPass::process( u32 currentTime, f32 dt, SceneObject& sceneObject, Sprite& sprite, Transform& transform )
{
	const Quat& rotation = transform.rotation();

	f32  x	  = transform.x();
	f32  y	  = transform.y();
	Vec3 left = rotation.rotate( Vec3( 10, 0, 0 ) );
	Vec3 up   = rotation.rotate( Vec3( 0, 10, 0 ) );

	m_renderer.m_renderer2d->line( x, y, x + left.x, y + left.y, Rgba( 1.0f, 0.0f, 0.0f ) );
	m_renderer.m_renderer2d->line( x, y, x + up.x,   y + up.y,   Rgba( 0.0f, 1.0f, 0.0f ) );
}

// ** DebugSpriteTransformRenderPass::begin
bool DebugSpriteTransformRenderPass::begin( u32 currentTime )
{
	m_renderer.m_renderer2d->begin( m_viewProj );
	return true;
}

// ** DebugSpriteTransformRenderPass::end
void DebugSpriteTransformRenderPass::end( void )
{
	m_renderer.m_renderer2d->end();
}

} // namespace scene

DC_END_DREEMCHEST<|endoftext|>


<commit_before>//Copyright (c) 2017 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "utils/intpoint.h" //To normalize vectors.
#include "utils/math.h" //For round_up_divide.
#include "utils/MinimumSpanningTree.h" //For the
#include "utils/polygonUtils.h" //For moveInside.

#include "TreeSupport.h"

#define SQRT_2 1.4142135623730950488 //Square root of 2.

namespace cura
{

TreeSupport::TreeSupport()
{
}

void TreeSupport::generateSupportAreas(SliceDataStorage& storage)
{
    std::vector<std::unordered_set<Point>> contact_points;
    contact_points.reserve(storage.support.supportLayers.size());
    for (size_t layer_nr = 0; layer_nr < storage.support.supportLayers.size(); layer_nr++) //Generate empty layers to store the points in.
    {
        contact_points.emplace_back();
    }
    for (SliceMeshStorage& mesh : storage.meshes)
    {
        if (!mesh.getSettingBoolean("support_tree_enable"))
        {
            return;
        }
        generateContactPoints(mesh, contact_points);
    }

    //Generate areas that have to be avoided.
    const coord_t layer_height = storage.getSettingInMicrons("layer_height");
    const double angle = storage.getSettingInAngleRadians("support_tree_angle");
    const coord_t maximum_move_distance = tan(angle) * layer_height;
    std::vector<Polygons> model_collision;
    const coord_t xy_distance = storage.getSettingInMicrons("support_xy_distance") + (storage.getSettingInMicrons("support_tree_branch_diameter") >> 1);
    constexpr bool include_helper_parts = false;
    model_collision.push_back(storage.getLayerOutlines(0, include_helper_parts).offset(xy_distance));
    //TODO: If allowing support to rest on model, these need to be just the model outlines.
    for (size_t layer_nr = 1; layer_nr < storage.print_layer_count; layer_nr ++)
    {
        //Generate an area above the current layer where you'd still collide with the current layer if you were to move with at most maximum_move_distance.
        model_collision.push_back(model_collision[layer_nr - 1].offset(-maximum_move_distance)); //Inset previous layer with maximum_move_distance to allow some movement.
        model_collision[layer_nr] = model_collision[layer_nr].unionPolygons(storage.getLayerOutlines(layer_nr, include_helper_parts).offset(xy_distance)); //Add current layer's collision to that.
    }

    //Use Minimum Spanning Tree to connect the points on each layer and move them while dropping them down.
    for (size_t layer_nr = contact_points.size() - 1; layer_nr > 0; layer_nr--) //Skip layer 0, since we can't drop down the vertices there.
    {
        MinimumSpanningTree mst(contact_points[layer_nr]);
        for (Point vertex : contact_points[layer_nr])
        {
            std::vector<Point> neighbours = mst.adjacentNodes(vertex);
            if (neighbours.size() == 1) //This is a leaf.
            {
                Point direction = neighbours[0] - vertex;
                if (vSize2(direction) < maximum_move_distance * maximum_move_distance) //Smaller than one step. Leave this one out.
                {
                    continue;
                }
                Point motion = normal(direction, maximum_move_distance);
                Point next_layer_vertex = vertex + motion;
                PolygonUtils::moveOutside(model_collision[layer_nr], next_layer_vertex, maximum_move_distance); //Avoid collision.
                contact_points[layer_nr - 1].insert(next_layer_vertex);
            }
            else //Not a leaf or just a single vertex.
            {
                PolygonUtils::moveOutside(model_collision[layer_nr], vertex, maximum_move_distance); //Avoid collision.
                contact_points[layer_nr - 1].insert(vertex); //Just drop the leaves directly down.
                //TODO: Avoid collisions.
            }
        }
    }

    //TODO: When reaching the bottom, cut away all edges of the MST that are still not contracted.
    //TODO: Do a second pass of dropping down but with leftover edges removed.

    //Placeholder to test with that generates a simple diamond at each contact point (without generating any trees yet).
    for (size_t layer_nr = 0; layer_nr < contact_points.size(); layer_nr++)
    {
        for (Point point : contact_points[layer_nr])
        {
            PolygonsPart outline;
            Polygon diamond;
            diamond.add(point + Point(0, 1000));
            diamond.add(point + Point(-1000, 0));
            diamond.add(point + Point(0, -1000));
            diamond.add(point + Point(1000, 0));
            outline.add(diamond);
            storage.support.supportLayers[layer_nr].support_infill_parts.emplace_back(outline, 350);
        }
        if (!contact_points[layer_nr].empty())
        {
            storage.support.layer_nr_max_filled_layer = layer_nr;
        }
    }

    //TODO: Apply some diameter to the tree branches.

    storage.support.generated = true;
}

void TreeSupport::generateContactPoints(const SliceMeshStorage& mesh, std::vector<std::unordered_set<Point>>& contact_points)
{
    const coord_t layer_height = mesh.getSettingInMicrons("layer_height");
    const coord_t z_distance_top = mesh.getSettingInMicrons("support_top_distance");
    const size_t z_distance_top_layers = std::max(0U, round_up_divide(z_distance_top, layer_height)) + 1; //Support must always be 1 layer below overhang.
    for (size_t layer_nr = 0; layer_nr < mesh.overhang_areas.size() - z_distance_top_layers; layer_nr++)
    {
        const Polygons& overhang = mesh.overhang_areas[layer_nr + z_distance_top_layers];
        if (overhang.empty())
        {
            continue;
        }

        //First generate a lot of points in a grid pattern.
        Polygons outside_polygons = overhang.getOutsidePolygons();
        AABB bounding_box(outside_polygons); //To know how far we should generate points.
        coord_t point_spread = mesh.getSettingInMicrons("support_tree_branch_distance");
        point_spread *= SQRT_2; //We'll rotate these points 45 degrees, so this is the point distance when axis-aligned.
        bounding_box.round(point_spread);
        for (PolygonRef overhang_part : outside_polygons)
        {
            AABB bounding_box(outside_polygons);
            bounding_box.round(point_spread);
            bool added = false; //Did we add a point this way?
            for (coord_t x = bounding_box.min.X; x <= bounding_box.max.X; x += point_spread >> 1)
            {
                for (coord_t y = bounding_box.min.Y + (point_spread << 1) * (x % 2); y <= bounding_box.max.Y; y += point_spread) //This produces points in a 45-degree rotated grid.
                {
                    Point candidate(x, y);
                    constexpr bool border_is_inside = true;
                    if (overhang_part.inside(candidate, border_is_inside))
                    {
                        contact_points[layer_nr].insert(candidate);
                        added = true;
                    }
                }
            }
            if (!added) //If we didn't add any points due to bad luck, we want to add one anyway such that loose parts are also supported.
            {
                Point candidate = bounding_box.getMiddle();
                PolygonUtils::moveInside(overhang_part, candidate);
                contact_points[layer_nr].insert(candidate);
            }
        }
    }
}

}<commit_msg>Move inner points towards centre of all neighbours too<commit_after>//Copyright (c) 2017 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "utils/intpoint.h" //To normalize vectors.
#include "utils/math.h" //For round_up_divide.
#include "utils/MinimumSpanningTree.h" //For the
#include "utils/polygonUtils.h" //For moveInside.

#include "TreeSupport.h"

#define SQRT_2 1.4142135623730950488 //Square root of 2.

namespace cura
{

TreeSupport::TreeSupport()
{
}

void TreeSupport::generateSupportAreas(SliceDataStorage& storage)
{
    std::vector<std::unordered_set<Point>> contact_points;
    contact_points.reserve(storage.support.supportLayers.size());
    for (size_t layer_nr = 0; layer_nr < storage.support.supportLayers.size(); layer_nr++) //Generate empty layers to store the points in.
    {
        contact_points.emplace_back();
    }
    for (SliceMeshStorage& mesh : storage.meshes)
    {
        if (!mesh.getSettingBoolean("support_tree_enable"))
        {
            return;
        }
        generateContactPoints(mesh, contact_points);
    }

    //Generate areas that have to be avoided.
    const coord_t layer_height = storage.getSettingInMicrons("layer_height");
    const double angle = storage.getSettingInAngleRadians("support_tree_angle");
    const coord_t maximum_move_distance = tan(angle) * layer_height;
    std::vector<Polygons> model_collision;
    const coord_t xy_distance = storage.getSettingInMicrons("support_xy_distance") + (storage.getSettingInMicrons("support_tree_branch_diameter") >> 1);
    constexpr bool include_helper_parts = false;
    model_collision.push_back(storage.getLayerOutlines(0, include_helper_parts).offset(xy_distance));
    //TODO: If allowing support to rest on model, these need to be just the model outlines.
    for (size_t layer_nr = 1; layer_nr < storage.print_layer_count; layer_nr ++)
    {
        //Generate an area above the current layer where you'd still collide with the current layer if you were to move with at most maximum_move_distance.
        model_collision.push_back(model_collision[layer_nr - 1].offset(-maximum_move_distance)); //Inset previous layer with maximum_move_distance to allow some movement.
        model_collision[layer_nr] = model_collision[layer_nr].unionPolygons(storage.getLayerOutlines(layer_nr, include_helper_parts).offset(xy_distance)); //Add current layer's collision to that.
    }

    //Use Minimum Spanning Tree to connect the points on each layer and move them while dropping them down.
    for (size_t layer_nr = contact_points.size() - 1; layer_nr > 0; layer_nr--) //Skip layer 0, since we can't drop down the vertices there.
    {
        MinimumSpanningTree mst(contact_points[layer_nr]);
        for (Point vertex : contact_points[layer_nr])
        {
            std::vector<Point> neighbours = mst.adjacentNodes(vertex);
            if (neighbours.empty()) //Just a single vertex.
            {
                PolygonUtils::moveOutside(model_collision[layer_nr], vertex, maximum_move_distance); //Avoid collision.
                contact_points[layer_nr - 1].insert(vertex);
            }
            Point sum_direction(0, 0);
            for (Point neighbour : neighbours)
            {
                sum_direction += neighbour - vertex;
            }
            if (neighbours.size() == 1 && vSize2(sum_direction) < maximum_move_distance * maximum_move_distance) //Smaller than one step. Leave this one out.
            {
                continue;
            }
            Point motion = normal(sum_direction, maximum_move_distance);
            Point next_layer_vertex = vertex + motion;
            PolygonUtils::moveOutside(model_collision[layer_nr], next_layer_vertex, maximum_move_distance); //Avoid collision.
            contact_points[layer_nr - 1].insert(next_layer_vertex);
        }
    }

    //TODO: When reaching the bottom, cut away all edges of the MST that are still not contracted.
    //TODO: Do a second pass of dropping down but with leftover edges removed.

    //Placeholder to test with that generates a simple diamond at each contact point (without generating any trees yet).
    for (size_t layer_nr = 0; layer_nr < contact_points.size(); layer_nr++)
    {
        for (Point point : contact_points[layer_nr])
        {
            PolygonsPart outline;
            Polygon diamond;
            diamond.add(point + Point(0, 1000));
            diamond.add(point + Point(-1000, 0));
            diamond.add(point + Point(0, -1000));
            diamond.add(point + Point(1000, 0));
            outline.add(diamond);
            storage.support.supportLayers[layer_nr].support_infill_parts.emplace_back(outline, 350);
        }
        if (!contact_points[layer_nr].empty())
        {
            storage.support.layer_nr_max_filled_layer = layer_nr;
        }
    }

    //TODO: Apply some diameter to the tree branches.

    storage.support.generated = true;
}

void TreeSupport::generateContactPoints(const SliceMeshStorage& mesh, std::vector<std::unordered_set<Point>>& contact_points)
{
    const coord_t layer_height = mesh.getSettingInMicrons("layer_height");
    const coord_t z_distance_top = mesh.getSettingInMicrons("support_top_distance");
    const size_t z_distance_top_layers = std::max(0U, round_up_divide(z_distance_top, layer_height)) + 1; //Support must always be 1 layer below overhang.
    for (size_t layer_nr = 0; layer_nr < mesh.overhang_areas.size() - z_distance_top_layers; layer_nr++)
    {
        const Polygons& overhang = mesh.overhang_areas[layer_nr + z_distance_top_layers];
        if (overhang.empty())
        {
            continue;
        }

        //First generate a lot of points in a grid pattern.
        Polygons outside_polygons = overhang.getOutsidePolygons();
        AABB bounding_box(outside_polygons); //To know how far we should generate points.
        coord_t point_spread = mesh.getSettingInMicrons("support_tree_branch_distance");
        point_spread *= SQRT_2; //We'll rotate these points 45 degrees, so this is the point distance when axis-aligned.
        bounding_box.round(point_spread);
        for (PolygonRef overhang_part : outside_polygons)
        {
            AABB bounding_box(outside_polygons);
            bounding_box.round(point_spread);
            bool added = false; //Did we add a point this way?
            for (coord_t x = bounding_box.min.X; x <= bounding_box.max.X; x += point_spread >> 1)
            {
                for (coord_t y = bounding_box.min.Y + (point_spread << 1) * (x % 2); y <= bounding_box.max.Y; y += point_spread) //This produces points in a 45-degree rotated grid.
                {
                    Point candidate(x, y);
                    constexpr bool border_is_inside = true;
                    if (overhang_part.inside(candidate, border_is_inside))
                    {
                        contact_points[layer_nr].insert(candidate);
                        added = true;
                    }
                }
            }
            if (!added) //If we didn't add any points due to bad luck, we want to add one anyway such that loose parts are also supported.
            {
                Point candidate = bounding_box.getMiddle();
                PolygonUtils::moveInside(overhang_part, candidate);
                contact_points[layer_nr].insert(candidate);
            }
        }
    }
}

}<|endoftext|>


<commit_before>/*****************************************************************************
 * PokerTH - The open source texas holdem engine                             *
 * Copyright (C) 2006-2011 Felix Hammer, Florian Thauer, Lothar May          *
 *                                                                           *
 * This program is free software: you can redistribute it and/or modify      *
 * it under the terms of the GNU Affero General Public License as            *
 * published by the Free Software Foundation, either version 3 of the        *
 * License, or (at your option) any later version.                           *
 *                                                                           *
 * This program is distributed in the hope that it will be useful,           *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 * GNU Affero General Public License for more details.                       *
 *                                                                           *
 * You should have received a copy of the GNU Affero General Public License  *
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.     *
 *****************************************************************************/
#include "mynicklistsortfilterproxymodel.h"
#include <QtGui>
#include <QtCore>

MyNickListSortFilterProxyModel::MyNickListSortFilterProxyModel(QObject *parent)
: QSortFilterProxyModel(parent), filterState(0), lastFilterStateAlpha(true), lastFilterStateCountry(false)
{
}

bool MyNickListSortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{

	switch(filterState) {

	case 0: {
		return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
	}
	break;
	case 1: {
		return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
	}
	break;
	case 2: {
		QModelIndex index0 = sourceModel()->index(sourceRow, 0, sourceParent);
		return sourceModel()->data(index0, 34).toString().contains("idle") && QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
	}
	break;

	}

	return false;
}

bool MyNickListSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
	switch(filterState) {

	case 0: {
		return QSortFilterProxyModel::lessThan(left, right);
	}
	break;
	case 1: {
		QString leftCountryAndName(sourceModel()->data(left, 33).toString().toUpper()+sourceModel()->data(left, Qt::DisplayRole).toString().toLower());
		QString rightCountryAndName(sourceModel()->data(right, 33).toString().toUpper()+sourceModel()->data(right, Qt::DisplayRole).toString().toLower());
		return leftCountryAndName < rightCountryAndName;
	}
	break;
	case 2: {
		if(lastFilterStateCountry) {
			QString leftCountryAndName(sourceModel()->data(left, 33).toString().toUpper()+sourceModel()->data(left, Qt::DisplayRole).toString().toLower());
			QString rightCountryAndName(sourceModel()->data(right, 33).toString().toUpper()+sourceModel()->data(right, Qt::DisplayRole).toString().toLower());
			return leftCountryAndName < rightCountryAndName;
		}
		else if(lastFilterStateAlpha) {
			return QSortFilterProxyModel::lessThan(left, right);
		}
	}
	break;
	}

	return false;
}

void MyNickListSortFilterProxyModel::setFilterState(int state)
{
	filterState = state;
}

<commit_msg>make cppcheck noch happier<commit_after>/*****************************************************************************
 * PokerTH - The open source texas holdem engine                             *
 * Copyright (C) 2006-2011 Felix Hammer, Florian Thauer, Lothar May          *
 *                                                                           *
 * This program is free software: you can redistribute it and/or modify      *
 * it under the terms of the GNU Affero General Public License as            *
 * published by the Free Software Foundation, either version 3 of the        *
 * License, or (at your option) any later version.                           *
 *                                                                           *
 * This program is distributed in the hope that it will be useful,           *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 * GNU Affero General Public License for more details.                       *
 *                                                                           *
 * You should have received a copy of the GNU Affero General Public License  *
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.     *
 *****************************************************************************/
#include "mynicklistsortfilterproxymodel.h"
#include <QtGui>
#include <QtCore>

MyNickListSortFilterProxyModel::MyNickListSortFilterProxyModel(QObject *parent)
: QSortFilterProxyModel(parent), filterState(0), lastFilterStateCountry(false), lastFilterStateAlpha(true)
{
}

bool MyNickListSortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{

	switch(filterState) {

	case 0: {
		return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
	}
	break;
	case 1: {
		return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
	}
	break;
	case 2: {
		QModelIndex index0 = sourceModel()->index(sourceRow, 0, sourceParent);
		return sourceModel()->data(index0, 34).toString().contains("idle") && QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
	}
	break;

	}

	return false;
}

bool MyNickListSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
	switch(filterState) {

	case 0: {
		return QSortFilterProxyModel::lessThan(left, right);
	}
	break;
	case 1: {
		QString leftCountryAndName(sourceModel()->data(left, 33).toString().toUpper()+sourceModel()->data(left, Qt::DisplayRole).toString().toLower());
		QString rightCountryAndName(sourceModel()->data(right, 33).toString().toUpper()+sourceModel()->data(right, Qt::DisplayRole).toString().toLower());
		return leftCountryAndName < rightCountryAndName;
	}
	break;
	case 2: {
		if(lastFilterStateCountry) {
			QString leftCountryAndName(sourceModel()->data(left, 33).toString().toUpper()+sourceModel()->data(left, Qt::DisplayRole).toString().toLower());
			QString rightCountryAndName(sourceModel()->data(right, 33).toString().toUpper()+sourceModel()->data(right, Qt::DisplayRole).toString().toLower());
			return leftCountryAndName < rightCountryAndName;
		}
		else if(lastFilterStateAlpha) {
			return QSortFilterProxyModel::lessThan(left, right);
		}
	}
	break;
	}

	return false;
}

void MyNickListSortFilterProxyModel::setFilterState(int state)
{
	filterState = state;
}

<|endoftext|>