<commit_before>/*
 *  Project:    moba-ambilight
 *
 *  Version:    1.0.0
 *
 *  Copyright (C) 2016 Stefan Paproth <pappi-@gmx.de>
 *
 *  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/agpl.txt>.
 *
 */

#include "handler.h"

#include "processdata.h"
#include "processdatahold.h"
#include "processdataplain.h"
#include "processdatawobble.h"

#include <moba/log.h>
#include <moba/ringbuffer.h>

#include <wiringPi.h>
#include <string.h>
#include <sys/time.h>

Handler::Handler(
    boost::shared_ptr<Bridge> bridge,
    boost::shared_ptr<moba::IPC> ipc,
    boost::shared_ptr<moba::SignalHandler> sigTerm
) : ipc(ipc), bridge(bridge), sigTerm(sigTerm), emergency(false), interuptMode(false) {
    duration = DEFAULT_DURATION;
}

void Handler::run() {
    do {
        fetchNextMsg();

        if(!regularBuffer.hasItems()) {
            usleep(50000);
            continue;
        }

        boost::shared_ptr<ProcessData> next = regularBuffer.pop();
        int interruption = next->getInterruptionTime();
        int i = 0;
        do {
            if(++i % 1000) {
                fetchNextMsg();
            }
            delayMicroseconds(interruption);
            if(emergency) {
                continue;
            }

            if(!next->hasNext(!interuptMode)) {
                break;
            }
        } while(true);
    } while(true);
}

void Handler::fetchNextMsg() {
    moba::IPC::Message msg;

    while(true) {
        if(sigTerm->hasAnySignalTriggered()) {
            throw HandlerException("sig-term caught");
        }

        if(!ipc->receive(msg)) {
            if(!emergency) {
                return;
            }
            usleep(50000);
            continue;
        }

        switch(msg.mtype) {
            case moba::IPC::CMD_EMERGENCY_STOP: {
                LOG(moba::DEBUG) << "CMD_EMERGENCY_STOP..." << std::endl;
                if(emergency) {
                    LOG(moba::WARNING) << "emergency already set!" << std::endl;
                    break;
                }
                runEmergencyMode(msg.mtext);
                emergency = true;
                break;
            }

            case moba::IPC::CMD_EMERGENCY_RELEASE: {
                LOG(moba::DEBUG) << "CMD_EMERGENCY_RELEASE..." << std::endl;
                if(!emergency) {
                    LOG(moba::WARNING) << "emergency not set!" << std::endl;
                    break;
                }
                releaseEmergencyStop();
                emergency = false;
                break;
            }

            case moba::IPC::CMD_TEST: {
                LOG(moba::DEBUG) << "CMD_TEST..." << std::endl;
                runTestMode();
                LOG(moba::DEBUG) << "testing finished!" << std::endl;
                return;
            }

            case moba::IPC::CMD_RUN: {
                LOG(moba::DEBUG) << "CMD_RUN..." << std::endl;
                insertNext(msg.mtext);
                break;
            }

            case moba::IPC::CMD_RESET: {
                LOG(moba::DEBUG) << "CMD_RESET..." << std::endl;
                reset(msg.mtext);
                break;
            }

            case moba::IPC::CMD_TERMINATE: {
                LOG(moba::DEBUG) << "CMD_TERMINATE..." << std::endl;
                throw HandlerException("terminate received");
            }

            case moba::IPC::CMD_INTERRUPT: {
                LOG(moba::DEBUG) << "CMD_INTERRUPT..." << std::endl;
               // controller->setNewTarget(parseMessageData(msg.mtext), true);
                break;
            }

            case moba::IPC::CMD_RESUME: {
                LOG(moba::DEBUG) << "CMD_RESUME..." << std::endl;
                //controller->resume();
                break;
            }

            case moba::IPC::CMD_SET_DURATION: {
                LOG(moba::DEBUG) << "CMD_SET_DURATION... " << std::endl;
                duration = atoi(msg.mtext);
                LOG(moba::DEBUG) <<
                    "duration total: ~" << duration <<
                    " sec. (~" << (int)(duration / 60) << " min.)" << std::endl;
                break;
            }

            default:
                LOG(moba::WARNING) << "ignoring unknown message-type <" << msg.mtype << ">" << std::endl;
                break;
        }
        if(emergency) {
            return;
        }
    }
}

void Handler::runTestMode() {
    const BankColorValues::BankColor bcolor[] = {
        BankColorValues::BLUE,
        BankColorValues::GREEN,
        BankColorValues::RED,
        BankColorValues::WHITE
    };

    bridge->setPWMlg(BankColorValues::BLUE, 0);
    bridge->setPWMlg(BankColorValues::GREEN, 0);
    bridge->setPWMlg(BankColorValues::WHITE, 0);
    bridge->setPWMlg(BankColorValues::RED, 211);
    sleep(1);
    bridge->setPWMlg(BankColorValues::RED, 0);
    for(int b = 0; b < 4; ++b) {
        LOG(moba::DEBUG) << "testing bank <" << b << ">" << std::endl;
        for(int j = 0; j < 4; ++j) {
            for(int k = 0; k < 2; ++k) {
                bridge->setData(bcolor[j], b, 0, 150);
                delay(500);
                bridge->setData(bcolor[j], b, 0, 600);
                delay(500);
            }
            bridge->setData(bcolor[j], b, 0, 0);
        }
    }
    bridge->setPWMlg(BankColorValues::GREEN, 211);
    sleep(1);
    bridge->setAllOff();
    sleep(1);
}

void Handler::reset(const std::string &data) {
    BankColorValues values;
    if(data != "") {
        std::string::size_type pos = 0;
        std::string::size_type found = 0;

        int val;

        for(int i = 0; i < BankColorValues::COLOR_COUNT ; ++i) {
            found = data.find(';', pos);
            val = atoi(data.substr(pos, found - pos).c_str());
            values.setValue(i, val);
            pos = found + 1;
        }
    }
    currentValues.setAll(values);
    bridge->setPWMlg(values);
    regularBuffer.reset();
    emergency = false;
}

void Handler::insertNext(const std::string &data) {
    LOG(moba::DEBUG) << "data: <" << data << ">" << std::endl;
    if(data == "") {
        LOG(moba::WARNING) << "no values given!" << std::endl;
        return;
    }

    BankColorValues values;

    std::string::size_type pos = 0;
    std::string::size_type found = 0;

    int durationOverride = duration;
    int val;

    for(int i = 0; i < 5; ++i) {
        found = data.find(';', pos);
        switch(i) {
            case BankColorValues::WHITE:
            case BankColorValues::GREEN:
            case BankColorValues::RED:
            case BankColorValues::BLUE:
                val = atoi(data.substr(pos, found - pos).c_str());
                for(int b = 0; b < Bridge::BANK_COUNT; ++b) {
                    values.setValue(b, i, val);
                }
                break;

            case 4:
                if(found != std::string::npos) { // FIXME:
                    durationOverride = atoi(data.substr(pos, found - pos).c_str());
                }
                break;
        }
        pos = found + 1;
    }
    boost::shared_ptr<ProcessData> item(new ProcessDataPlain(bridge, currentValues, values, durationOverride));

    currentValues.setAll(values);
    regularBuffer.push(item);
}

void Handler::runEmergencyMode(const std::string &data) {
    int duration = EMERGENCY_DURATION;
    int brightness = EMERGENCY_BRIGHTNESS;

    if(data != "") {
        std::string::size_type pos = 0;
        std::string::size_type found = data.find(';', pos);
        int val = atoi(data.substr(pos, found - pos).c_str());
        if(val < Bridge::MIN_VALUE) {
            val = Bridge::MIN_VALUE;
        }
        if(val > Bridge::MAX_VALUE) {
            val = Bridge::MAX_VALUE;
        }
        brightness = val;
        if(found != std::string::npos) {
            duration = atoi(data.substr(found + 1).c_str());
        }
    }
    //controller->emergencyStop(brightness, duration);
}

void Handler::releaseEmergencyStop() {

}
<commit_msg>bugfix...<commit_after>/*
 *  Project:    moba-ambilight
 *
 *  Version:    1.0.0
 *
 *  Copyright (C) 2016 Stefan Paproth <pappi-@gmx.de>
 *
 *  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/agpl.txt>.
 *
 */

#include "handler.h"

#include "processdata.h"
#include "processdatahold.h"
#include "processdataplain.h"
#include "processdatawobble.h"

#include <moba/log.h>
#include <moba/ringbuffer.h>

#include <wiringPi.h>
#include <string.h>
#include <sys/time.h>

Handler::Handler(
    boost::shared_ptr<Bridge> bridge,
    boost::shared_ptr<moba::IPC> ipc,
    boost::shared_ptr<moba::SignalHandler> sigTerm
) : ipc(ipc), bridge(bridge), sigTerm(sigTerm), emergency(false), interuptMode(false) {
    duration = DEFAULT_DURATION;
}

void Handler::run() {
    do {
        fetchNextMsg();

        if(!regularBuffer.hasItems()) {
            usleep(50000);
            continue;
        }

        boost::shared_ptr<ProcessData> next = regularBuffer.pop();
        int interruption = next->getInterruptionTime();
        int i = 0;
        do {
            if(!(++i % 1000)) {
                fetchNextMsg();
            }
            delayMicroseconds(interruption);
            if(emergency) {
                continue;
            }

            if(!next->hasNext(!interuptMode)) {
                break;
            }
        } while(true);
    } while(true);
}

void Handler::fetchNextMsg() {
    moba::IPC::Message msg;

    while(true) {
        if(sigTerm->hasAnySignalTriggered()) {
            throw HandlerException("sig-term caught");
        }

        if(!ipc->receive(msg)) {
            if(!emergency) {
                return;
            }
            usleep(50000);
            continue;
        }

        switch(msg.mtype) {
            case moba::IPC::CMD_EMERGENCY_STOP: {
                LOG(moba::DEBUG) << "CMD_EMERGENCY_STOP..." << std::endl;
                if(emergency) {
                    LOG(moba::WARNING) << "emergency already set!" << std::endl;
                    break;
                }
                runEmergencyMode(msg.mtext);
                emergency = true;
                break;
            }

            case moba::IPC::CMD_EMERGENCY_RELEASE: {
                LOG(moba::DEBUG) << "CMD_EMERGENCY_RELEASE..." << std::endl;
                if(!emergency) {
                    LOG(moba::WARNING) << "emergency not set!" << std::endl;
                    break;
                }
                releaseEmergencyStop();
                emergency = false;
                break;
            }

            case moba::IPC::CMD_TEST: {
                LOG(moba::DEBUG) << "CMD_TEST..." << std::endl;
                runTestMode();
                LOG(moba::DEBUG) << "testing finished!" << std::endl;
                return;
            }

            case moba::IPC::CMD_RUN: {
                LOG(moba::DEBUG) << "CMD_RUN..." << std::endl;
                insertNext(msg.mtext);
                break;
            }

            case moba::IPC::CMD_RESET: {
                LOG(moba::DEBUG) << "CMD_RESET..." << std::endl;
                reset(msg.mtext);
                break;
            }

            case moba::IPC::CMD_TERMINATE: {
                LOG(moba::DEBUG) << "CMD_TERMINATE..." << std::endl;
                throw HandlerException("terminate received");
            }

            case moba::IPC::CMD_INTERRUPT: {
                LOG(moba::DEBUG) << "CMD_INTERRUPT..." << std::endl;
               // controller->setNewTarget(parseMessageData(msg.mtext), true);
                break;
            }

            case moba::IPC::CMD_RESUME: {
                LOG(moba::DEBUG) << "CMD_RESUME..." << std::endl;
                //controller->resume();
                break;
            }

            case moba::IPC::CMD_SET_DURATION: {
                LOG(moba::DEBUG) << "CMD_SET_DURATION... " << std::endl;
                duration = atoi(msg.mtext);
                LOG(moba::DEBUG) <<
                    "duration total: ~" << duration <<
                    " sec. (~" << (int)(duration / 60) << " min.)" << std::endl;
                break;
            }

            default:
                LOG(moba::WARNING) << "ignoring unknown message-type <" << msg.mtype << ">" << std::endl;
                break;
        }
        if(emergency) {
            return;
        }
    }
}

void Handler::runTestMode() {
    const BankColorValues::BankColor bcolor[] = {
        BankColorValues::BLUE,
        BankColorValues::GREEN,
        BankColorValues::RED,
        BankColorValues::WHITE
    };

    bridge->setPWMlg(BankColorValues::BLUE, 0);
    bridge->setPWMlg(BankColorValues::GREEN, 0);
    bridge->setPWMlg(BankColorValues::WHITE, 0);
    bridge->setPWMlg(BankColorValues::RED, 211);
    sleep(1);
    bridge->setPWMlg(BankColorValues::RED, 0);
    for(int b = 0; b < 4; ++b) {
        LOG(moba::DEBUG) << "testing bank <" << b << ">" << std::endl;
        for(int j = 0; j < 4; ++j) {
            for(int k = 0; k < 2; ++k) {
                bridge->setData(bcolor[j], b, 0, 150);
                delay(500);
                bridge->setData(bcolor[j], b, 0, 600);
                delay(500);
            }
            bridge->setData(bcolor[j], b, 0, 0);
        }
    }
    bridge->setPWMlg(BankColorValues::GREEN, 211);
    sleep(1);
    bridge->setAllOff();
    sleep(1);
}

void Handler::reset(const std::string &data) {
    BankColorValues values;
    if(data != "") {
        std::string::size_type pos = 0;
        std::string::size_type found = 0;

        int val;

        for(int i = 0; i < BankColorValues::COLOR_COUNT ; ++i) {
            found = data.find(';', pos);
            val = atoi(data.substr(pos, found - pos).c_str());
            values.setValue(i, val);
            pos = found + 1;
        }
    }
    currentValues.setAll(values);
    bridge->setPWMlg(values);
    regularBuffer.reset();
    emergency = false;
}

void Handler::insertNext(const std::string &data) {
    LOG(moba::DEBUG) << "data: <" << data << ">" << std::endl;
    if(data == "") {
        LOG(moba::WARNING) << "no values given!" << std::endl;
        return;
    }

    BankColorValues values;

    std::string::size_type pos = 0;
    std::string::size_type found = 0;

    int durationOverride = duration;
    int val;

    for(int i = 0; i < 5; ++i) {
        found = data.find(';', pos);
        switch(i) {
            case BankColorValues::WHITE:
            case BankColorValues::GREEN:
            case BankColorValues::RED:
            case BankColorValues::BLUE:
                val = atoi(data.substr(pos, found - pos).c_str());
                for(int b = 0; b < Bridge::BANK_COUNT; ++b) {
                    values.setValue(b, i, val);
                }
                break;

            case 4:
                if(found != std::string::npos) { // FIXME:
                    durationOverride = atoi(data.substr(pos, found - pos).c_str());
                }
                break;
        }
        pos = found + 1;
    }
    boost::shared_ptr<ProcessData> item(new ProcessDataPlain(bridge, currentValues, values, durationOverride));

    currentValues.setAll(values);
    regularBuffer.push(item);
}

void Handler::runEmergencyMode(const std::string &data) {
    int duration = EMERGENCY_DURATION;
    int brightness = EMERGENCY_BRIGHTNESS;

    if(data != "") {
        std::string::size_type pos = 0;
        std::string::size_type found = data.find(';', pos);
        int val = atoi(data.substr(pos, found - pos).c_str());
        if(val < Bridge::MIN_VALUE) {
            val = Bridge::MIN_VALUE;
        }
        if(val > Bridge::MAX_VALUE) {
            val = Bridge::MAX_VALUE;
        }
        brightness = val;
        if(found != std::string::npos) {
            duration = atoi(data.substr(found + 1).c_str());
        }
    }
    //controller->emergencyStop(brightness, duration);
}

void Handler::releaseEmergencyStop() {

}
<|endoftext|>


<commit_before><commit_msg>Removed extraneous call to the now depreacted WebCore::parseURL().<commit_after><|endoftext|>


<commit_before>// Title       : Implementation of Coroutine in Cpp
// Author      : hanzh.xu@gmail.com
// Date        : 11-22-2020
// License     : MIT License

#include <cstdlib>
#include <ctime>
#include <iostream>
#include <functional>
#include <memory>
#include <string>
#include <tuple>
#include <typeinfo>
#include <utility>
#include <vector>

using namespace std;

template<typename T>
class Gen : public std::enable_shared_from_this<Gen<T>> {
public:
    int state;
    Gen() : state(0) {}
    virtual bool next(T& output) = 0;
    bool operator()(T& output) {
        return next(output);
    }
};

template<typename S, typename T>
class Coroutine : public std::enable_shared_from_this<Coroutine<S,T>> {
public:
    int state;
    Coroutine() : state(0) {}
    virtual ~Coroutine() {}
    virtual bool next(S& input, T &output) = 0;
    bool operator()(S& input, T &output) {
        return next(input, output);
    }
    shared_ptr<Coroutine<S,T>> getPtr() { return this->shared_from_this(); }
};

#define PRG_BEG \
switch(state) { \
case 0:;

#define PRG_END \
case -1:; \
default: { return false; } }

#define YIELD() \
do { state=__LINE__; return true; case __LINE__:; } while (0)

#define RETURN() { state = -1; return false; }

/* Examples */

/*
L: def prod_iter(s):
0:   if len(s) == 0:
1:     yield []
2:   else:
3:     x = 0
4:     while true:
5:       xs = []
6:       iter = generator.create(prod_iter(s[1:]))
7:       while true:
8:         xs, isAlive = iter.resume()
9:         if !isAlive:
10           break
11         yield [x] + xs
12       x += 1
13       if x >= s[0]:
14         break
-1   return
*/
class BetterProdGen : public Gen<vector<int>> {
public:
    vector<unsigned int> s;
    int x;
    shared_ptr<BetterProdGen> iter;
    vector<int> xs;
    BetterProdGen(const vector<unsigned int>& _s) : s(_s) {}
    bool next(vector<int>& output) {
        PRG_BEG
        if(s.size()==0) {
            output.clear();
            YIELD();
            RETURN();
        }
        for(x = 0; x < s[0]; ++x) {
            iter = make_shared<BetterProdGen>(
            vector<unsigned int>(s.begin() + 1, s.end()));
            while(iter->next(xs)) {
                output.clear();
                output.push_back(x);
                output.insert(output.end(), xs.begin(), xs.end());
                YIELD();
            }
        }
        PRG_END
    }
};

/*
def hanoi(n, a, b, c):
    if n == 1:
        s = str(a) +  ' --> ' + str(c)
        yield s
    else:
        for s in hanoi(n - 1, a, c, b):
            yield s
        for s in hanoi(1    , a, b, c):
            yield s
        for s in hanoi(n - 1, b, a, c):
            yield s
*/
class BetterHanoiGen : public Gen<string> {
public:
    int n;
    string a, b, c;
    shared_ptr<Gen<string> > iter;
    BetterHanoiGen(int _n, string _a, string _b, string _c):
        n(_n), a(_a), b(_b), c(_c) {}
    bool next(string& output) {
        PRG_BEG
        if(n == 1) {
            output = a + " --> " + c;
            YIELD();
            RETURN();
        }
        iter = make_shared<BetterHanoiGen>(n - 1, a, c, b);
        while(iter->next(output)) YIELD();
        iter = make_shared<BetterHanoiGen>(1, a, b, c);
        while(iter->next(output)) YIELD();
        iter = make_shared<BetterHanoiGen>(n - 1, b, a, c);
        while(iter->next(output)) YIELD();
        PRG_END
    }
};

class PrimeGen : public Gen<int> {
public:
    vector<int> primes;
    int i, j;
    PrimeGen() {}
    bool next(int& output) {
        PRG_BEG
        for(i = 2; true; ++i) {
            j = 0;
            for(j = 0; j < primes.size(); ++j) {
                if(i % primes[j] == 0) {
                    goto loop1_end;
                }
            }
            primes.push_back(i);
            output = i;
            YIELD();
            loop1_end:;
        }
        PRG_END
    }
};

class SubsetGen: public Gen<vector<int> > {
public:
    int n, i, j;
    SubsetGen(int _n) : n(_n) {}
    bool next(vector<int>& output) {
        PRG_BEG
        for(i = 0; i < (1 << n); ++i) {
            output.clear();
            for(int j = 0; j < n; ++j) {
                if((i >> j) & 1) {
                    output.push_back(j);
                }
            }
            YIELD();
        }
        PRG_END
    }
};

class PermutationGen: public Gen<vector<int> > {
public:
    int beg, n, i;
    vector<int>& arr;
    shared_ptr<PermutationGen> iter;
    PermutationGen(int _beg, vector<int>& _arr) : beg(_beg), n(_arr.size()), arr(_arr) {}
    bool next(vector<int>& output) {
        PRG_BEG
        if(beg >= n - 1) {
            for(i = 0; i < n; ++i) {
                output[i] = arr[i];
            }
            YIELD();
            RETURN();
        }
        for(i = beg; i < n; ++i) {
            swap(arr[beg], arr[i]);
            iter = make_shared<PermutationGen>(beg + 1, arr);
            while((*iter)(output)) YIELD();
            swap(arr[beg], arr[i]);
        }
        PRG_END
    }
    void swap(int& a, int &b) {
        int c = a;
        a = b;
        b = c;
    }
};

class GuessNumber : public Coroutine<int, int> {
public:
    int t, num;
    GuessNumber() {}
    bool next(int& input, int& output) {
        PRG_BEG
        t = 0;
        srand(time(0));
        cout << "Guess a number between 0 and 100!" << endl;
        while(true) {
            cout << "Match " << t << endl;
            num = rand() % 100;
            cout << "input a number:";
            YIELD();
            while(input != num) {
                if(input == -1) RETURN();
                if(input < num) {
                    cout << "Too low!" << endl;
                    output = -1;
                } else {
                    cout << "Too high!" << endl;
                    output = 1;
                }
                cout << "input a number agian:";
                YIELD();
            }
            cout << "Bingo! It's " << num << "!" << endl;
            cout << "Let's play it again!" << endl;
            t++;
            output = 0;
        }
        cout << "ByeBye!" << endl;
        PRG_END
    }
};

class GuessYourNumber : public Coroutine<string, int> {
public:
    int beg, end, mid;
    GuessYourNumber() {}
    bool next(string& input, int& output) {
        PRG_BEG
        cout << "Keep a number between 0 and 100 in your mind!" << endl;
        cout << "Are you ready?(y/n)" << endl;
        YIELD();
        if(input[0] != 'y') {
            goto bye;
        }
        beg = 0, end = 101;
        while(beg < end) {
            mid = (beg + end) / 2;
            cout << "Is it " << mid << "?" << endl;
            cout << "Input 's' if it is smaller than your number." << endl;
            cout << "Input 'b' if it is bigger than your number." << endl;
            cout << "Input 'y' if it is your number!" << endl;
            YIELD();
            if(input[0] == 's') {
                beg = mid+1;
            } else if(input[0] == 'b') {
                end = mid;
            } else {
                cout << "YES! It's " << mid << "!" << endl;
                RETURN();
            }
        }
        cout << "No possible! The number must be " << mid << "!" << endl;
        bye:;
        cout << "ByeBye!" << endl;
        PRG_END
    }
};

template<typename T>
void print(vector<T>& vec) {
    cout << "{ ";
    for(int i = 0; i < vec.size(); ++i) {
        cout << vec[i] << ", ";
    }
    cout << "}" << endl;
}

void testBetterHanoiGen() {
    cout << "testBetterHanoiGen" << endl;
    string s;
    BetterHanoiGen gen(3, "A", "B", "C");
    int k = 0;
    while(gen(s)) {
        cout << s << endl;
        k++;
    }
    cout << "HanoiGen is solved in " << k << " steps." << endl;
}

void testPrimeGen() {
    cout << "Prime numbers" << endl;
    PrimeGen primeGen;
    int p;
    for(int i = 0; i < 30; ++i) {
        primeGen(p);
        cout << p << " ";
    }
    cout << endl;
}

void testSubsetGen() {
    cout << "testSubsetGen" << endl;
    int n = 5;
    vector<int> output(n);
    SubsetGen gen(n);
    int k = 0;
    while(gen(output)) {
        print(output);
        k++;
    }
    cout << "Generated " << k << " Subsets." << endl;
}

void testPermutationGen() {
    cout << "testPermutationGen" << endl;
    vector<int> arr({1,2,3,4});
    PermutationGen gen(0, arr);
    vector<int> output(arr.size());
    int k = 0;
    while(gen(output)) {
        print(output);
        k++;
    }
    cout << "Generated " << k << " Permutations." << endl;
}

void testBetterProdGen() {
    cout << "testBetterProdGen" << endl;
    vector<unsigned int> dimSize({3,2,4});
    vector<int> output(dimSize.size());
    BetterProdGen gen(dimSize);
    int k = 0;
    while(gen(output)) {
        print(output);
        k++;
    }
    cout << "Generated " << k << " rows." << endl;
}

void testGuessNumber() {
    GuessNumber guess;
    int num, output;
    guess(num, output);
    do {
        cin >> num;
    } while(guess(num, output));
}

void testGuessYourNumber() {
    cout << "testGuessYourNumber" << endl;
    GuessYourNumber guess;
    string input;
    int output;
    guess(input, output);
    do {
        cin >> input;
    } while(guess(input, output));
}

int main() {

    testBetterHanoiGen();

    testPrimeGen();

    testSubsetGen();

    testPermutationGen();

    testBetterProdGen();

    // testGuessNumber();

    // testGuessYourNumber();

    return 0;
}
<commit_msg>Update macro_v2.cpp<commit_after>// Title       : Implementation of Coroutine in Cpp
// Author      : hanzh.xu@gmail.com
// Date        : 11-22-2020
// License     : MIT License

#include <cstdlib>
#include <ctime>
#include <iostream>
#include <functional>
#include <memory>
#include <string>
#include <tuple>
#include <typeinfo>
#include <utility>
#include <vector>

using namespace std;

template<typename T>
class Gen : public std::enable_shared_from_this<Gen<T>> {
public:
    int state;
    Gen() : state(0) {}
    virtual bool next(T& output) = 0;
    bool operator()(T& output) {
        return next(output);
    }
};

template<typename S, typename T>
class Coroutine : public std::enable_shared_from_this<Coroutine<S,T>> {
public:
    int state;
    Coroutine() : state(0) {}
    virtual ~Coroutine() {}
    virtual bool next(S& input, T &output) = 0;
    bool operator()(S& input, T &output) {
        return next(input, output);
    }
    shared_ptr<Coroutine<S,T>> getPtr() { return this->shared_from_this(); }
};

#define PRG_BEG \
switch(state) { \
case 0:;

#define PRG_END \
case -1:; \
default: { return false; } }

#define YIELD() \
do { state=__LINE__; return true; case __LINE__:; } while (0)

#define RETURN() { state = -1; return false; }

/* Examples */

/*
L: def prod_iter(s):
0:   if len(s) == 0:
1:     yield []
2:   else:
3:     x = 0
4:     while true:
5:       xs = []
6:       iter = generator.create(prod_iter(s[1:]))
7:       while true:
8:         xs, isAlive = iter.resume()
9:         if !isAlive:
10           break
11         yield [x] + xs
12       x += 1
13       if x >= s[0]:
14         break
-1   return
*/
class BetterProdGen : public Gen<vector<int>> {
public:
    vector<unsigned int> s;
    int x;
    shared_ptr<BetterProdGen> iter;
    vector<int> xs;
    BetterProdGen(const vector<unsigned int>& _s) : s(_s) {}
    bool next(vector<int>& output) {
        PRG_BEG
        if(s.size()==0) {
            output.clear();
            YIELD();
            RETURN();
        }
        for(x = 0; x < s[0]; ++x) {
            iter = make_shared<BetterProdGen>(
                vector<unsigned int>(s.begin() + 1, s.end()));
            while(iter->next(xs)) {
                output.clear();
                output.push_back(x);
                output.insert(output.end(), xs.begin(), xs.end());
                YIELD();
            }
        }
        PRG_END
    }
};

/*
def hanoi(n, a, b, c):
    if n == 1:
        s = str(a) +  ' --> ' + str(c)
        yield s
    else:
        for s in hanoi(n - 1, a, c, b):
            yield s
        for s in hanoi(1    , a, b, c):
            yield s
        for s in hanoi(n - 1, b, a, c):
            yield s
*/
class BetterHanoiGen : public Gen<string> {
public:
    int n;
    string a, b, c;
    shared_ptr<Gen<string> > iter;
    BetterHanoiGen(int _n, string _a, string _b, string _c):
        n(_n), a(_a), b(_b), c(_c) {}
    bool next(string& output) {
        PRG_BEG
        if(n == 1) {
            output = a + " --> " + c;
            YIELD();
            RETURN();
        }
        iter = make_shared<BetterHanoiGen>(n - 1, a, c, b);
        while(iter->next(output)) YIELD();
        iter = make_shared<BetterHanoiGen>(1, a, b, c);
        while(iter->next(output)) YIELD();
        iter = make_shared<BetterHanoiGen>(n - 1, b, a, c);
        while(iter->next(output)) YIELD();
        PRG_END
    }
};

class PrimeGen : public Gen<int> {
public:
    vector<int> primes;
    int i, j;
    PrimeGen() {}
    bool next(int& output) {
        PRG_BEG
        for(i = 2; true; ++i) {
            j = 0;
            for(j = 0; j < primes.size(); ++j) {
                if(i % primes[j] == 0) {
                    goto loop1_end;
                }
            }
            primes.push_back(i);
            output = i;
            YIELD();
            loop1_end:;
        }
        PRG_END
    }
};

class SubsetGen: public Gen<vector<int> > {
public:
    int n, i, j;
    SubsetGen(int _n) : n(_n) {}
    bool next(vector<int>& output) {
        PRG_BEG
        for(i = 0; i < (1 << n); ++i) {
            output.clear();
            for(int j = 0; j < n; ++j) {
                if((i >> j) & 1) {
                    output.push_back(j);
                }
            }
            YIELD();
        }
        PRG_END
    }
};

class PermutationGen: public Gen<vector<int> > {
public:
    int beg, n, i;
    vector<int>& arr;
    shared_ptr<PermutationGen> iter;
    PermutationGen(int _beg, vector<int>& _arr) : beg(_beg), n(_arr.size()), arr(_arr) {}
    bool next(vector<int>& output) {
        PRG_BEG
        if(beg >= n - 1) {
            for(i = 0; i < n; ++i) {
                output[i] = arr[i];
            }
            YIELD();
            RETURN();
        }
        for(i = beg; i < n; ++i) {
            swap(arr[beg], arr[i]);
            iter = make_shared<PermutationGen>(beg + 1, arr);
            while((*iter)(output)) YIELD();
            swap(arr[beg], arr[i]);
        }
        PRG_END
    }
    void swap(int& a, int &b) {
        int c = a;
        a = b;
        b = c;
    }
};

class GuessNumber : public Coroutine<int, int> {
public:
    int t, num;
    GuessNumber() {}
    bool next(int& input, int& output) {
        PRG_BEG
        t = 0;
        srand(time(0));
        cout << "Guess a number between 0 and 100!" << endl;
        while(true) {
            cout << "Match " << t << endl;
            num = rand() % 100;
            cout << "input a number:";
            YIELD();
            while(input != num) {
                if(input == -1) RETURN();
                if(input < num) {
                    cout << "Too low!" << endl;
                    output = -1;
                } else {
                    cout << "Too high!" << endl;
                    output = 1;
                }
                cout << "input a number agian:";
                YIELD();
            }
            cout << "Bingo! It's " << num << "!" << endl;
            cout << "Let's play it again!" << endl;
            t++;
            output = 0;
        }
        cout << "ByeBye!" << endl;
        PRG_END
    }
};

class GuessYourNumber : public Coroutine<string, int> {
public:
    int beg, end, mid;
    GuessYourNumber() {}
    bool next(string& input, int& output) {
        PRG_BEG
        cout << "Keep a number between 0 and 100 in your mind!" << endl;
        cout << "Are you ready?(y/n)" << endl;
        YIELD();
        if(input[0] != 'y') {
            goto bye;
        }
        beg = 0, end = 101;
        while(beg < end) {
            mid = (beg + end) / 2;
            cout << "Is it " << mid << "?" << endl;
            cout << "Input 's' if it is smaller than your number." << endl;
            cout << "Input 'b' if it is bigger than your number." << endl;
            cout << "Input 'y' if it is your number!" << endl;
            YIELD();
            if(input[0] == 's') {
                beg = mid+1;
            } else if(input[0] == 'b') {
                end = mid;
            } else {
                cout << "YES! It's " << mid << "!" << endl;
                RETURN();
            }
        }
        cout << "No possible! The number must be " << mid << "!" << endl;
        bye:;
        cout << "ByeBye!" << endl;
        PRG_END
    }
};

template<typename T>
void print(vector<T>& vec) {
    cout << "{ ";
    for(int i = 0; i < vec.size(); ++i) {
        cout << vec[i] << ", ";
    }
    cout << "}" << endl;
}

void testBetterHanoiGen() {
    cout << "testBetterHanoiGen" << endl;
    string s;
    BetterHanoiGen gen(3, "A", "B", "C");
    int k = 0;
    while(gen(s)) {
        cout << s << endl;
        k++;
    }
    cout << "HanoiGen is solved in " << k << " steps." << endl;
}

void testPrimeGen() {
    cout << "Prime numbers" << endl;
    PrimeGen primeGen;
    int p;
    for(int i = 0; i < 30; ++i) {
        primeGen(p);
        cout << p << " ";
    }
    cout << endl;
}

void testSubsetGen() {
    cout << "testSubsetGen" << endl;
    int n = 5;
    vector<int> output(n);
    SubsetGen gen(n);
    int k = 0;
    while(gen(output)) {
        print(output);
        k++;
    }
    cout << "Generated " << k << " Subsets." << endl;
}

void testPermutationGen() {
    cout << "testPermutationGen" << endl;
    vector<int> arr({1,2,3,4});
    PermutationGen gen(0, arr);
    vector<int> output(arr.size());
    int k = 0;
    while(gen(output)) {
        print(output);
        k++;
    }
    cout << "Generated " << k << " Permutations." << endl;
}

void testBetterProdGen() {
    cout << "testBetterProdGen" << endl;
    vector<unsigned int> dimSize({3,2,4});
    vector<int> output(dimSize.size());
    BetterProdGen gen(dimSize);
    int k = 0;
    while(gen(output)) {
        print(output);
        k++;
    }
    cout << "Generated " << k << " rows." << endl;
}

void testGuessNumber() {
    GuessNumber guess;
    int num, output;
    guess(num, output);
    do {
        cin >> num;
    } while(guess(num, output));
}

void testGuessYourNumber() {
    cout << "testGuessYourNumber" << endl;
    GuessYourNumber guess;
    string input;
    int output;
    guess(input, output);
    do {
        cin >> input;
    } while(guess(input, output));
}

int main() {

    testBetterHanoiGen();

    testPrimeGen();

    testSubsetGen();

    testPermutationGen();

    testBetterProdGen();

    // testGuessNumber();

    // testGuessYourNumber();

    return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012-2015 Daniele Bartolini and individual contributors.
 * License: https://github.com/taylor001/crown/blob/master/LICENSE
 */

#include "physics_world.h"
#include "vector3.h"
#include "actor.h"
#include "device.h"
#include "quaternion.h"
#include "scene_graph.h"
#include "controller.h"
#include "joint.h"
#include "physics_callback.h"
#include "proxy_allocator.h"
#include "memory.h"
#include "string_utils.h"
#include "actor.h"
#include "resource_manager.h"
#include "raycast.h"
#include "unit.h"
#include "config.h"
#include "world.h"
#include "debug_line.h"
#include "color4.h"
#include "int_setting.h"
#include "physics.h"
#include "matrix4x4.h"
#include "log.h"
#include "PxPhysicsAPI.h"

using physx::PxSceneDesc;
using physx::PxVec3;
using physx::PxTransform;
using physx::PxQuat;
using physx::PxHalfPi;

using physx::PxPlaneGeometry;
using physx::PxMaterial;
using physx::PxShape;
using physx::PxRigidStatic;
using physx::PxActiveTransform;
using physx::PxU32;
using physx::PxSceneFlag;
using physx::PxFilterFlags;
using physx::PxFilterData;
using physx::PxPairFlags;
using physx::PxFilterObjectAttributes;
using physx::PxFilterObjectIsTrigger;
using physx::PxPairFlag;
using physx::PxFilterFlag;
using physx::PxSceneLimits;
using physx::PxVisualizationParameter;
using physx::PxSphereGeometry;
using physx::PxCapsuleGeometry;
using physx::PxBoxGeometry;
using physx::PxRenderBuffer;
using physx::PxDebugLine;

namespace crown
{

namespace physics_globals
{
	using physx::PxFoundation;
	using physx::PxPhysics;
	using physx::PxCooking;
	using physx::PxCookingParams;
	using physx::PxTolerancesScale;
	using physx::PxAllocatorCallback;
	using physx::PxErrorCallback;
	using physx::PxErrorCode;

	class PhysXAllocator : public PxAllocatorCallback
	{
	public:

		PhysXAllocator()
			: m_backing("physics", default_allocator())
		{
		}

		void* allocate(size_t size, const char*, const char*, int)
		{
			return m_backing.allocate(size, 16);
		}

		void deallocate(void* p)
		{
			m_backing.deallocate(p);
		}

	private:

		ProxyAllocator m_backing;
	};

	class PhysXError : public PxErrorCallback
	{
	public:

		void reportError(PxErrorCode::Enum code, const char* message, const char* /*file*/, int /*line*/)
		{
			switch (code)
			{
				case PxErrorCode::eDEBUG_INFO:
				{
					CE_LOGI("PhysX: %s", message);
					break;
				}
				case PxErrorCode::eDEBUG_WARNING:
				case PxErrorCode::ePERF_WARNING:
				{
					CE_LOGW("PhysX: %s", message);
					break;
				}
				case PxErrorCode::eINVALID_PARAMETER:
				case PxErrorCode::eINVALID_OPERATION:
				case PxErrorCode::eOUT_OF_MEMORY:
				case PxErrorCode::eINTERNAL_ERROR:
				case PxErrorCode::eABORT:
				{
					CE_ASSERT(false, "PhysX: %s", message);
					break;
				}
				default:
				{
					CE_FATAL("Oops, unknown physx error");
					break;
				}
			}
		}
	};

	PxFilterFlags FilterShader(PxFilterObjectAttributes attributes0, PxFilterData filterData0,
									PxFilterObjectAttributes attributes1, PxFilterData filterData1,
									PxPairFlags& pairFlags, const void* constantBlock, PxU32 constantBlockSize)
	{
		// let triggers through
		if(PxFilterObjectIsTrigger(attributes0) || PxFilterObjectIsTrigger(attributes1))
		{
			pairFlags = PxPairFlag::eNOTIFY_TOUCH_FOUND | PxPairFlag::eNOTIFY_TOUCH_LOST;
			return PxFilterFlag::eDEFAULT;
		}

		// trigger the contact callback for pairs (A,B) where
		// the filtermask of A contains the ID of B and vice versa.
		if((filterData0.word0 & filterData1.word1) && (filterData1.word0 & filterData0.word1))
		{
			pairFlags |= PxPairFlag::eCONTACT_DEFAULT
			 		  | PxPairFlag::eNOTIFY_TOUCH_FOUND
					  | PxPairFlag::eNOTIFY_TOUCH_LOST
					  | PxPairFlag::eNOTIFY_CONTACT_POINTS;
			return PxFilterFlag::eDEFAULT;
		}

		return PxFilterFlag::eSUPPRESS;
	}

	// Global PhysX objects
	static PhysXAllocator* s_px_allocator;
	static PhysXError* s_px_error;
	static PxFoundation* s_foundation;
	static PxPhysics* s_physics;
	static PxCooking* s_cooking;

	void init()
	{
		s_px_allocator = CE_NEW(default_allocator(), PhysXAllocator)();
		s_px_error = CE_NEW(default_allocator(), PhysXError)();

		s_foundation = PxCreateFoundation(PX_PHYSICS_VERSION, *s_px_allocator, *s_px_error);
		CE_ASSERT(s_foundation, "Unable to create PhysX Foundation");

		s_physics = PxCreatePhysics(PX_PHYSICS_VERSION, *s_foundation, physx::PxTolerancesScale());
		CE_ASSERT(s_physics, "Unable to create PhysX Physics");

		bool extension = PxInitExtensions(*s_physics);
		CE_ASSERT(extension, "Unable to initialize PhysX Extensions");
		CE_UNUSED(extension);

		s_cooking = PxCreateCooking(PX_PHYSICS_VERSION, *s_foundation, PxCookingParams(PxTolerancesScale()));
		CE_ASSERT(s_cooking, "Unable to create PhysX Cooking");
	}

	void shutdown()
	{
		PxCloseExtensions();
		s_cooking->release();
		s_physics->release();
		s_foundation->release();

		CE_DELETE(default_allocator(), s_px_error);
		CE_DELETE(default_allocator(), s_px_allocator);
	}
} // namespace physics_globals

PhysicsWorld::PhysicsWorld(World& world)
	: m_world(world)
	, m_scene(NULL)
	, m_buffer(m_hits, 64)
	, m_actors_pool(default_allocator(), CE_MAX_ACTORS, sizeof(Actor), CE_ALIGNOF(Actor))
	, m_controllers_pool(default_allocator(), CE_MAX_CONTROLLERS, sizeof(Controller), CE_ALIGNOF(Controller))
	, m_joints_pool(default_allocator(), CE_MAX_JOINTS, sizeof(Joint), CE_ALIGNOF(Joint))
	, m_raycasts_pool(default_allocator(), CE_MAX_RAYCASTS, sizeof(Raycast), CE_ALIGNOF(Raycast))
	, m_events(default_allocator())
	, m_callback(m_events)
{
	// Create the scene
	PxSceneLimits scene_limits;
	scene_limits.maxNbActors = CE_MAX_ACTORS;
	CE_ASSERT(scene_limits.isValid(), "Scene limits is not valid");

	PxSceneDesc scene_desc(physics_globals::s_physics->getTolerancesScale());
	scene_desc.gravity = PxVec3(0.0f, -9.81f, 0.0f);
	scene_desc.limits = scene_limits;
	scene_desc.filterShader = physics_globals::FilterShader;
	scene_desc.simulationEventCallback = &m_callback;
	scene_desc.flags = 	PxSceneFlag::eENABLE_ACTIVETRANSFORMS
					  | PxSceneFlag::eENABLE_KINEMATIC_STATIC_PAIRS
					  | PxSceneFlag::eENABLE_KINEMATIC_PAIRS;

	if(!scene_desc.cpuDispatcher)
	{
		m_cpu_dispatcher = physx::PxDefaultCpuDispatcherCreate(1);
		CE_ASSERT(m_cpu_dispatcher != NULL, "Failed to create PhysX cpu dispatcher");

		scene_desc.cpuDispatcher = m_cpu_dispatcher;
	}

	CE_ASSERT(scene_desc.isValid(), "Scene is not valid");
	m_scene = physics_globals::s_physics->createScene(scene_desc);

	// Create controller manager
	m_controller_manager = PxCreateControllerManager(*m_scene);
	CE_ASSERT(m_controller_manager != NULL, "Failed to create PhysX controller manager");

	m_resource = (PhysicsConfigResource*) device()->resource_manager()->get(PHYSICS_CONFIG_TYPE, StringId64("global"));

#if CROWN_DEBUG
	m_scene->setVisualizationParameter(PxVisualizationParameter::eSCALE, 1);
	m_scene->setVisualizationParameter(PxVisualizationParameter::eACTOR_AXES, 1);
	m_scene->setVisualizationParameter(PxVisualizationParameter::eCOLLISION_SHAPES, 1);
#endif
}

PhysicsWorld::~PhysicsWorld()
{
	m_cpu_dispatcher->release();
	m_controller_manager->release();
	m_scene->release();
}

ActorId	PhysicsWorld::create_actor(const ActorResource* ar, SceneGraph& sg, UnitId unit_id)
{
	Actor* actor = CE_NEW(m_actors_pool, Actor)(*this, ar, sg, unit_id);
	return id_array::create(m_actors, actor);
}

void PhysicsWorld::destroy_actor(ActorId id)
{
	CE_DELETE(m_actors_pool, id_array::get(m_actors, id));
	id_array::destroy(m_actors, id);
}

ControllerId PhysicsWorld::create_controller(const ControllerResource* cr, SceneGraph& sg, UnitId id)
{
	Controller* controller = CE_NEW(m_controllers_pool, Controller)(cr, sg, id, physics_globals::s_physics, m_controller_manager);
	return id_array::create(m_controllers, controller);
}

void PhysicsWorld::destroy_controller(ControllerId id)
{
	CE_DELETE(m_controllers_pool, id_array::get(m_controllers, id));
	id_array::destroy(m_controllers, id);
}

JointId	PhysicsWorld::create_joint(const JointResource* jr, const Actor& actor_0, const Actor& actor_1)
{
	Joint* joint = CE_NEW(m_joints_pool, Joint)(physics_globals::s_physics, jr, actor_0, actor_1);
	return id_array::create(m_joints, joint);
}

void PhysicsWorld::destroy_joint(JointId id)
{
	CE_DELETE(m_joints_pool, id_array::get(m_joints, id));
	id_array::destroy(m_joints, id);
}

RaycastId PhysicsWorld::create_raycast(CollisionMode::Enum mode, CollisionType::Enum filter)
{
	Raycast* raycast = CE_NEW(m_raycasts_pool, Raycast)(m_scene, mode, filter);
	return id_array::create(m_raycasts, raycast);
}

void PhysicsWorld::destroy_raycast(RaycastId id)
{
	CE_DELETE(m_raycasts_pool, id_array::get(m_raycasts, id));
	id_array::destroy(m_raycasts, id);
}

Actor* PhysicsWorld::get_actor(ActorId id)
{
	return id_array::get(m_actors, id);
}

Controller* PhysicsWorld::get_controller(ControllerId id)
{
	return id_array::get(m_controllers, id);
}

Raycast* PhysicsWorld::get_raycast(RaycastId id)
{
	return id_array::get(m_raycasts, id);
}

Vector3 PhysicsWorld::gravity() const
{
	PxVec3 g = m_scene->getGravity();
	return Vector3(g.x, g.y, g.z);
}

void PhysicsWorld::set_gravity(const Vector3& g)
{
	m_scene->setGravity(PxVec3(g.x, g.y, g.z));
}

void PhysicsWorld::overlap_test(CollisionType::Enum filter, ShapeType::Enum type,
								const Vector3& pos, const Quaternion& rot, const Vector3& size, Array<Actor*>& actors)
{
	PxTransform transform(PxVec3(pos.x, pos.y, pos.z), PxQuat(rot.x, rot.y, rot.z, rot.w));

	switch(type)
	{
		case ShapeType::SPHERE:
		{
			PxSphereGeometry geometry(size.x);
			m_scene->overlap(geometry, transform, m_buffer);
			break;
		}
		case ShapeType::CAPSULE:
		{
			PxCapsuleGeometry geometry(size.x, size.y);
			m_scene->overlap(geometry, transform, m_buffer);
			break;
		}
		case ShapeType::BOX:
		{
			PxBoxGeometry geometry(size.x, size.y, size.z);
			m_scene->overlap(geometry, transform, m_buffer);
			break;
		}
		default: CE_FATAL("Only spheres, capsules and boxs are supported in overlap test"); break;
	}

	for (uint32_t i = 0; i < m_buffer.getNbAnyHits(); i++)
	{
		PxOverlapHit oh = m_buffer.getAnyHit(i);

		array::push_back(actors, (Actor*)(oh.actor->userData));
	}
}

void PhysicsWorld::update(float dt)
{
	// Run with fixed timestep
	m_scene->simulate(1.0 / 60.0);

	while (!m_scene->fetchResults());

	// Update transforms
	PxU32 num_active_transforms;
	const PxActiveTransform* active_transforms = m_scene->getActiveTransforms(num_active_transforms);

	// Update each actor with its new transform
	for (PxU32 i = 0; i < num_active_transforms; i++)
	{
		// Actors with userData == NULL are controllers
		if (active_transforms[i].userData == NULL) continue;

		const PxTransform tr = active_transforms[i].actor2World;
		const Vector3 pos(tr.p.x, tr.p.y, tr.p.z);
		const Quaternion rot(tr.q.x, tr.q.y, tr.q.z, tr.q.w);

		static_cast<Actor*>(active_transforms[i].userData)->update(Matrix4x4(rot, pos));
	}

	// Update controllers
	for (uint32_t i = 0; i < id_array::size(m_controllers); i++)
	{
		m_controllers[i]->update();
	}
}

void PhysicsWorld::draw_debug(DebugLine& lines)
{
	CE_UNUSED(lines);
#if CROWN_DEBUG
	const PxRenderBuffer& rb = m_scene->getRenderBuffer();
	for(PxU32 i = 0; i < rb.getNbLines(); i++)
	{
		const PxDebugLine& pxline = rb.getLines()[i];
		lines.add_line(Vector3(pxline.pos0.x, pxline.pos0.y, pxline.pos0.z),
						Vector3(pxline.pos1.x, pxline.pos1.y, pxline.pos1.z),
						Color4(pxline.color0));
	}

	lines.commit();
	lines.clear();
#endif // CROWN_DEBUG
}

PxPhysics* PhysicsWorld::physx_physics() { return physics_globals::s_physics; }
PxCooking* PhysicsWorld::physx_cooking() { return physics_globals::s_cooking; }
PxScene* PhysicsWorld::physx_scene() { return m_scene; }

} // namespace crown
<commit_msg>Delete physics_world.cpp<commit_after><|endoftext|>


<commit_before>
//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2014 Ulrich von Zadow
//
//  This 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 of the License, or (at your option) any later version.
//
//  This 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 this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "SubscriberInfo.h"

#include "../base/Exception.h"
#include "../base/ObjectCounter.h"
#include "../base/ScopeTimer.h"

#include <boost/python/slice.hpp>

using namespace std;

namespace avg {

SubscriberInfo::SubscriberInfo(int id, PyObject* pCallable)
    : m_ID(id),
      m_pWeakSelf(Py_None),
      m_pPyFunction(Py_None),
      m_pWeakClass(Py_None)
{
    ObjectCounter::get()->incRef(&typeid(*this));
    AVG_ASSERT(PyCallable_Check(pCallable));

    if(PyMethod_Check(pCallable)) { //Bound method
        m_pWeakSelf = PyWeakref_NewRef(PyMethod_Self(pCallable), NULL);
        AVG_ASSERT(m_pWeakSelf != Py_None);
        m_pPyFunction = PyWeakref_NewRef(PyMethod_Function(pCallable), NULL);
        AVG_ASSERT(m_pPyFunction != Py_None);
        #if PY_MAJOR_VERSION < 3
            m_pWeakClass = PyWeakref_NewRef(PyMethod_Class(pCallable), NULL);
        #endif

    }else{
        m_pPyFunction = pCallable;
        Py_INCREF(m_pPyFunction); //We need to keep a reference to the unbound function
        AVG_ASSERT(m_pPyFunction != Py_None);
    }
}

SubscriberInfo::~SubscriberInfo()
{
    ObjectCounter::get()->decRef(&typeid(*this));
    if(m_pWeakSelf != Py_None){
        Py_DECREF(m_pWeakSelf);
    }
    Py_DECREF(m_pPyFunction);
}

bool SubscriberInfo::hasExpired() const
{
    bool expired;
    if(m_pWeakSelf == Py_None) { //Unbound function
        return false; //Unbound functions can't really expire
    }else{
        //If self still exists, the function should still be valid or people are messing
        //too deeply with python
        expired = PyWeakref_GetObject(m_pWeakSelf) == Py_None;
    }
    return expired;
}

static ProfilingZoneID InvokeSubscriberProfilingZone("SubscriberInfo: invoke");

void SubscriberInfo::invoke(py::list args) const
{
    ScopeTimer timer(InvokeSubscriberProfilingZone);

    if(m_pWeakSelf != Py_None) { //Bound method case
        PyObject * pFunction = PyWeakref_GetObject(m_pPyFunction);
        AVG_ASSERT(pFunction != Py_None);
        PyObject * pSelf = PyWeakref_GetObject(m_pWeakSelf);
        AVG_ASSERT(pSelf != Py_None);
        #if PY_MAJOR_VERSION < 3
            PyObject * pClass = PyWeakref_GetObject(m_pWeakClass);
            AVG_ASSERT(pClass != Py_None);
            PyObject * pCallable = PyMethod_New(pFunction, pSelf, pClass);  //Bind function to self --> creating a bound method
        #else
            PyObject * pCallable = PyMethod_New(pFunction, pSelf);  //Bind function to self --> creating a bound method
        #endif
        AVG_ASSERT(pCallable != Py_None);
        py::tuple argsTuple(args);
        PyObject* pyResult = PyObject_CallObject(pCallable, argsTuple.ptr());
        if (pyResult == NULL) {
            throw py::error_already_set();
        }
        Py_DECREF(pCallable);
        Py_DECREF(pyResult);
    }else{ //unbound method case
        py::tuple argsTuple(args);
        PyObject* pyResult = PyObject_CallObject(m_pPyFunction, argsTuple.ptr());
        if (pyResult == NULL) {
            throw py::error_already_set();
        }
        Py_XDECREF(pyResult);
    }
}

int SubscriberInfo::getID() const
{
    return m_ID;
}

bool SubscriberInfo::isCallable(const PyObject* pCallable) const
{
    if(m_pWeakSelf != Py_None) {
        PyObject * lhsCallable = PyWeakref_GetObject(m_pPyFunction);
        PyObject * rhsCallable = PyMethod_Function(const_cast<PyObject*>(pCallable));
        return lhsCallable == rhsCallable;
    }else{
        return m_pPyFunction == pCallable;
    }
}

}
<commit_msg>PreProcessor Directive indentation<commit_after>
//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2014 Ulrich von Zadow
//
//  This 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 of the License, or (at your option) any later version.
//
//  This 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 this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "SubscriberInfo.h"

#include "../base/Exception.h"
#include "../base/ObjectCounter.h"
#include "../base/ScopeTimer.h"

#include <boost/python/slice.hpp>

using namespace std;

namespace avg {

SubscriberInfo::SubscriberInfo(int id, PyObject* pCallable)
    : m_ID(id),
      m_pWeakSelf(Py_None),
      m_pPyFunction(Py_None),
      m_pWeakClass(Py_None)
{
    ObjectCounter::get()->incRef(&typeid(*this));
    AVG_ASSERT(PyCallable_Check(pCallable));

    if(PyMethod_Check(pCallable)) { //Bound method
        m_pWeakSelf = PyWeakref_NewRef(PyMethod_Self(pCallable), NULL);
        AVG_ASSERT(m_pWeakSelf != Py_None);
        m_pPyFunction = PyWeakref_NewRef(PyMethod_Function(pCallable), NULL);
        AVG_ASSERT(m_pPyFunction != Py_None);
#if PY_MAJOR_VERSION < 3
        m_pWeakClass = PyWeakref_NewRef(PyMethod_Class(pCallable), NULL);
#endif

    }else{
        m_pPyFunction = pCallable;
        Py_INCREF(m_pPyFunction); //We need to keep a reference to the unbound function
        AVG_ASSERT(m_pPyFunction != Py_None);
    }
}

SubscriberInfo::~SubscriberInfo()
{
    ObjectCounter::get()->decRef(&typeid(*this));
    if(m_pWeakSelf != Py_None){
        Py_DECREF(m_pWeakSelf);
    }
    Py_DECREF(m_pPyFunction);
}

bool SubscriberInfo::hasExpired() const
{
    bool expired;
    if(m_pWeakSelf == Py_None) { //Unbound function
        return false; //Unbound functions can't really expire
    }else{
        //If self still exists, the function should still be valid or people are messing
        //too deeply with python
        expired = PyWeakref_GetObject(m_pWeakSelf) == Py_None;
    }
    return expired;
}

static ProfilingZoneID InvokeSubscriberProfilingZone("SubscriberInfo: invoke");

void SubscriberInfo::invoke(py::list args) const
{
    ScopeTimer timer(InvokeSubscriberProfilingZone);

    if(m_pWeakSelf != Py_None) { //Bound method case
        PyObject * pFunction = PyWeakref_GetObject(m_pPyFunction);
        AVG_ASSERT(pFunction != Py_None);
        PyObject * pSelf = PyWeakref_GetObject(m_pWeakSelf);
        AVG_ASSERT(pSelf != Py_None);
#if PY_MAJOR_VERSION < 3
        PyObject * pClass = PyWeakref_GetObject(m_pWeakClass);
        AVG_ASSERT(pClass != Py_None);
        PyObject * pCallable = PyMethod_New(pFunction, pSelf, pClass);  //Bind function to self --> creating a bound method
#else
        PyObject * pCallable = PyMethod_New(pFunction, pSelf);  //Bind function to self --> creating a bound method
#endif
        AVG_ASSERT(pCallable != Py_None);
        py::tuple argsTuple(args);
        PyObject* pyResult = PyObject_CallObject(pCallable, argsTuple.ptr());
        if (pyResult == NULL) {
            throw py::error_already_set();
        }
        Py_DECREF(pCallable);
        Py_DECREF(pyResult);
    }else{ //unbound method case
        py::tuple argsTuple(args);
        PyObject* pyResult = PyObject_CallObject(m_pPyFunction, argsTuple.ptr());
        if (pyResult == NULL) {
            throw py::error_already_set();
        }
        Py_XDECREF(pyResult);
    }
}

int SubscriberInfo::getID() const
{
    return m_ID;
}

bool SubscriberInfo::isCallable(const PyObject* pCallable) const
{
    if(m_pWeakSelf != Py_None) {
        PyObject * lhsCallable = PyWeakref_GetObject(m_pPyFunction);
        PyObject * rhsCallable = PyMethod_Function(const_cast<PyObject*>(pCallable));
        return lhsCallable == rhsCallable;
    }else{
        return m_pPyFunction == pCallable;
    }
}

}
<|endoftext|>


<commit_before>/**
 * @file
 *
 * @brief Plugin which acts as proxy and calls other plugins written in python
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 *
 */

#ifndef SWIG_TYPE_TABLE
#error Build system error, SWIG_TYPE_TABLE is not defined
#endif

#include <Python.h>

#ifndef HAVE_KDBCONFIG
#include <kdbconfig.h>
#endif
#include <kdbhelper.h>
#include SWIG_RUNTIME
#include "python.hpp"

#include <key.hpp>
#include <keyset.hpp>
#include <libgen.h>
#include <mutex>

using namespace ckdb;
#include <kdberrors.h>

#define PYTHON_PLUGIN_NAME_STR2(x) ELEKTRA_QUOTE (x)
#define PYTHON_PLUGIN_NAME_STR PYTHON_PLUGIN_NAME_STR2 (PYTHON_PLUGIN_NAME)

static PyObject * Python_fromSWIG (ckdb::Key * key)
{
	swig_type_info * ti = SWIG_TypeQuery ("kdb::Key *");
	if (key == nullptr || ti == nullptr) return Py_None;
	return SWIG_NewPointerObj (new kdb::Key (key), ti, 0);
}

static PyObject * Python_fromSWIG (ckdb::KeySet * keyset)
{
	swig_type_info * ti = SWIG_TypeQuery ("kdb::KeySet *");
	if (keyset == nullptr || ti == nullptr) return Py_None;
	return SWIG_NewPointerObj (new kdb::KeySet (keyset), ti, 0);
}

class Python_LockSwap
{
public:
	Python_LockSwap (PyThreadState * newstate)
	{
		gstate = PyGILState_Ensure ();
		tstate = PyThreadState_Swap (newstate);
	}

	~Python_LockSwap ()
	{
		PyThreadState_Swap (tstate);
		PyGILState_Release (gstate);
	}

private:
	PyGILState_STATE gstate;
	PyThreadState * tstate;
};

typedef struct
{
	PyThreadState * tstate;
	PyObject * instance;
	int printError;
	int shutdown;
} moduleData;

static int Python_AppendToSysPath (const char * path)
{
	if (path == nullptr) return 0;

	PyObject * sysPath = PySys_GetObject ((char *) "path");
	PyObject * pyPath = PyUnicode_FromString (path);
	PyList_Append (sysPath, pyPath);
	Py_DECREF (pyPath);
	return 1;
}

static PyObject * Python_CallFunction (PyObject * object, PyObject * args)
{
	if (!PyCallable_Check (object)) return nullptr;

	PyObject * res = PyObject_CallObject (object, args ? args : PyTuple_New (0));
	Py_XINCREF (res);
	return res;
}

static int Python_CallFunction_Int (moduleData * data, PyObject * object, PyObject * args, ckdb::Key * errorKey)
{
	int ret = -1;
	PyObject * res = Python_CallFunction (object, args);
	if (!res)
	{
		ELEKTRA_SET_ERROR (111, errorKey, "Error while calling python function");
		if (data->printError) PyErr_Print ();
	}
	else
	{
#if PY_MAJOR_VERSION >= 3
		if (!PyLong_Check (res))
#else
		if (!PyInt_Check (res))
#endif
			ELEKTRA_SET_ERROR (111, errorKey, "Return value is no integer");
		else
			ret = PyLong_AsLong (res);
	}

	Py_XDECREF (res);
	return ret;
}

static int Python_CallFunction_Helper1 (moduleData * data, const char * funcName, ckdb::Key * errorKey)
{
	int ret = 0;
	Python_LockSwap pylock (data->tstate);
	PyObject * func = PyObject_GetAttrString (data->instance, funcName);
	if (func)
	{
		PyObject * arg0 = Python_fromSWIG (errorKey);
		PyObject * args = Py_BuildValue ("(O)", arg0);
		ret = Python_CallFunction_Int (data, func, args, errorKey);
		Py_DECREF (arg0);
		Py_DECREF (args);
		Py_DECREF (func);
	}
	return ret;
}

static int Python_CallFunction_Helper2 (moduleData * data, const char * funcName, ckdb::KeySet * returned, ckdb::Key * parentKey)
{
	int ret = 0;
	Python_LockSwap pylock (data->tstate);
	PyObject * func = PyObject_GetAttrString (data->instance, funcName);
	if (func)
	{
		PyObject * arg0 = Python_fromSWIG (returned);
		PyObject * arg1 = Python_fromSWIG (parentKey);
		PyObject * args = Py_BuildValue ("(OO)", arg0, arg1);
		ret = Python_CallFunction_Int (data, func, args, parentKey);
		Py_DECREF (arg0);
		Py_DECREF (arg1);
		Py_DECREF (args);
		Py_DECREF (func);
	}
	return ret;
}

static std::mutex mutex;
static unsigned open_cnt = 0;

static void Python_Shutdown (moduleData * data)
{
	if (!data->shutdown) return;

	/* destroy python if plugin isn't used anymore */
	if (Py_IsInitialized ())
	{
		if (data->tstate)
		{
			Python_LockSwap pylock (data->tstate);

			/* clean up references */
			Py_XDECREF (data->instance);
			data->instance = nullptr;

			/* destroy sub interpreter */
			Py_EndInterpreter (data->tstate);
		}
		mutex.lock ();
		if (open_cnt && !--open_cnt && data->shutdown) // order matters!
			Py_Finalize ();
		mutex.unlock ();
	}
}

extern "C" {
int PYTHON_PLUGIN_FUNCTION (Open) (ckdb::Plugin * handle, ckdb::Key * errorKey)
{
	KeySet * config = elektraPluginGetConfig (handle);

	Key * script = ksLookupByName (config, "/script", 0);
	if (script == nullptr || !strlen (keyString (script)))
	{
		if (ksLookupByName (config, "/module", 0) != nullptr)
		{
			return 0; // by convention: success if /module exists
		}
		ELEKTRA_SET_ERROR (111, errorKey, "No python script set");
		return -1;
	}

	/* create module data */
	auto data = new moduleData;
	data->tstate = nullptr;
	data->instance = nullptr;
	data->printError = (ksLookupByName (config, "/print", 0) != nullptr);
	/* shutdown flag is integer by design. This way users can set the
	 * expected behaviour without worring about default values
	 */
	data->shutdown = (ksLookupByName (config, "/shutdown", 0) && !!strcmp (keyString (ksLookupByName (config, "/shutdown", 0)), "0"));

	{
		/* initialize python interpreter if necessary */
		mutex.lock ();
		if (!Py_IsInitialized ())
		{
			Py_Initialize ();
			if (!Py_IsInitialized ())
			{
				mutex.unlock ();
				goto error;
			}
			open_cnt++;
		}
		else if (open_cnt) // we have initialized python before
			open_cnt++;
		mutex.unlock ();

		/* init threads */
		PyEval_InitThreads ();

		/* acquire GIL */
		Python_LockSwap pylock (nullptr);

		/* create a new sub-interpreter */
		data->tstate = Py_NewInterpreter ();
		if (data->tstate == nullptr)
		{
			ELEKTRA_SET_ERROR (111, errorKey, "Unable to create sub interpreter");
			goto error;
		}
		PyThreadState_Swap (data->tstate);

		/* import kdb */
		PyObject * kdbModule = PyImport_ImportModule ("kdb");
		if (kdbModule == nullptr)
		{
			ELEKTRA_SET_ERROR (111, errorKey, "Unable to import kdb module");
			goto error_print;
		}
		Py_XDECREF (kdbModule);

		/* extend sys path */
		char * tmpScript = elektraStrDup (keyString (script));
		const char * dname = dirname (tmpScript);
		if (!Python_AppendToSysPath (dname))
		{
			ELEKTRA_SET_ERROR (111, errorKey, "Unable to extend sys.path");
			elektraFree (tmpScript);
			goto error;
		}
		elektraFree (tmpScript);

		/* import module/script */
		tmpScript = elektraStrDup (keyString (script));
		char * bname = basename (tmpScript);
		size_t bname_len = strlen (bname);
		if (bname_len >= 4 && strcmp (bname + bname_len - 3, ".py") == 0) bname[bname_len - 3] = '\0';

		PyObject * pModule = PyImport_ImportModule (bname);
		if (pModule == nullptr)
		{
			ELEKTRA_SET_ERRORF (111, errorKey, "Unable to import python script %s", keyString (script));
			elektraFree (tmpScript);
			goto error_print;
		}
		elektraFree (tmpScript);

		/* get class */
		PyObject * klass = PyObject_GetAttrString (pModule, "ElektraPlugin");
		Py_DECREF (pModule);
		if (klass == nullptr)
		{
			ELEKTRA_SET_ERROR (111, errorKey, "Module doesn't provide a ElektraPlugin class");
			goto error_print;
		}

		/* create instance of class */
		PyObject * inst_args = Py_BuildValue ("()");
		PyObject * inst = PyEval_CallObject (klass, inst_args);
		Py_DECREF (klass);
		Py_DECREF (inst_args);
		if (inst == nullptr)
		{
			ELEKTRA_SET_ERROR (111, errorKey, "Unable to create instance of ElektraPlugin");
			goto error_print;
		}
		data->instance = inst;
	}

	/* store module data after everything is set up */
	elektraPluginSetData (handle, data);

	/* call python function */
	return Python_CallFunction_Helper2 (data, "open", config, errorKey);

error_print:
	if (data->printError) PyErr_Print ();
error:
	/* destroy python */
	Python_Shutdown (data);
	delete data;
	elektraPluginSetData (handle, nullptr);
	return -1;
}

int PYTHON_PLUGIN_FUNCTION (Close) (ckdb::Plugin * handle, ckdb::Key * errorKey)
{
	moduleData * data = static_cast<moduleData *> (elektraPluginGetData (handle));
	if (data == nullptr) return 0;

	int ret = Python_CallFunction_Helper1 (data, "close", errorKey);

	/* destroy python */
	Python_Shutdown (data);
	delete data;
	elektraPluginSetData (handle, nullptr);
	return ret;
}

int PYTHON_PLUGIN_FUNCTION (Get) (ckdb::Plugin * handle, ckdb::KeySet * returned, ckdb::Key * parentKey)
{
#define _MODULE_CONFIG_PATH "system/elektra/modules/" PYTHON_PLUGIN_NAME_STR
	if (!strcmp (keyName (parentKey), _MODULE_CONFIG_PATH))
	{
		KeySet * n;
		ksAppend (returned,
			  n = ksNew (30, keyNew (_MODULE_CONFIG_PATH, KEY_VALUE, "python interpreter waits for your orders", KEY_END),
				     keyNew (_MODULE_CONFIG_PATH "/exports", KEY_END),
				     keyNew (_MODULE_CONFIG_PATH "/exports/get", KEY_FUNC, PYTHON_PLUGIN_FUNCTION (Get), KEY_END),
				     keyNew (_MODULE_CONFIG_PATH "/exports/set", KEY_FUNC, PYTHON_PLUGIN_FUNCTION (Set), KEY_END),
				     keyNew (_MODULE_CONFIG_PATH "/exports/error", KEY_FUNC, PYTHON_PLUGIN_FUNCTION (Error), KEY_END),
				     keyNew (_MODULE_CONFIG_PATH "/exports/open", KEY_FUNC, PYTHON_PLUGIN_FUNCTION (Open), KEY_END),
				     keyNew (_MODULE_CONFIG_PATH "/exports/close", KEY_FUNC, PYTHON_PLUGIN_FUNCTION (Close), KEY_END),
#include ELEKTRA_README (PYTHON_PLUGIN_NAME)
				     keyNew (_MODULE_CONFIG_PATH "/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END));
		ksDel (n);
	}

	moduleData * data = static_cast<moduleData *> (elektraPluginGetData (handle));
	if (data != nullptr) return Python_CallFunction_Helper2 (data, "get", returned, parentKey);
	return 0;
}

int PYTHON_PLUGIN_FUNCTION (Set) (ckdb::Plugin * handle, ckdb::KeySet * returned, ckdb::Key * parentKey)
{
	moduleData * data = static_cast<moduleData *> (elektraPluginGetData (handle));
	if (data != nullptr) return Python_CallFunction_Helper2 (data, "set", returned, parentKey);
	return 0;
}

int PYTHON_PLUGIN_FUNCTION (Error) (ckdb::Plugin * handle, ckdb::KeySet * returned, ckdb::Key * parentKey)
{
	moduleData * data = static_cast<moduleData *> (elektraPluginGetData (handle));
	if (data != nullptr) return Python_CallFunction_Helper2 (data, "error", returned, parentKey);
	return 0;
}

ckdb::Plugin * PYTHON_PLUGIN_EXPORT (PYTHON_PLUGIN_NAME)
{
	// clang-format off
	return elektraPluginExport(PYTHON_PLUGIN_NAME_STR,
		ELEKTRA_PLUGIN_OPEN,  &PYTHON_PLUGIN_FUNCTION(Open),
		ELEKTRA_PLUGIN_CLOSE, &PYTHON_PLUGIN_FUNCTION(Close),
		ELEKTRA_PLUGIN_GET,   &PYTHON_PLUGIN_FUNCTION(Get),
		ELEKTRA_PLUGIN_SET,   &PYTHON_PLUGIN_FUNCTION(Set),
		ELEKTRA_PLUGIN_ERROR, &PYTHON_PLUGIN_FUNCTION(Error),
		ELEKTRA_PLUGIN_END);
}
}
<commit_msg>python: try to work without sub-interpreters<commit_after>/**
 * @file
 *
 * @brief Plugin which acts as proxy and calls other plugins written in python
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 *
 */

#ifndef SWIG_TYPE_TABLE
#error Build system error, SWIG_TYPE_TABLE is not defined
#endif

#include <Python.h>

#ifndef HAVE_KDBCONFIG
#include <kdbconfig.h>
#endif
#include <kdbhelper.h>
#include SWIG_RUNTIME
#include "python.hpp"

#include <key.hpp>
#include <keyset.hpp>
#include <libgen.h>
#include <mutex>

using namespace ckdb;
#include <kdberrors.h>

#define PYTHON_PLUGIN_NAME_STR2(x) ELEKTRA_QUOTE (x)
#define PYTHON_PLUGIN_NAME_STR PYTHON_PLUGIN_NAME_STR2 (PYTHON_PLUGIN_NAME)

static PyObject * Python_fromSWIG (ckdb::Key * key)
{
	swig_type_info * ti = SWIG_TypeQuery ("kdb::Key *");
	if (key == nullptr || ti == nullptr) return Py_None;
	return SWIG_NewPointerObj (new kdb::Key (key), ti, 0);
}

static PyObject * Python_fromSWIG (ckdb::KeySet * keyset)
{
	swig_type_info * ti = SWIG_TypeQuery ("kdb::KeySet *");
	if (keyset == nullptr || ti == nullptr) return Py_None;
	return SWIG_NewPointerObj (new kdb::KeySet (keyset), ti, 0);
}

class Python_LockSwap
{
public:
	Python_LockSwap (PyThreadState * newstate)
	{
		gstate = PyGILState_Ensure ();
		tstate = PyThreadState_Swap (newstate);
	}

	~Python_LockSwap ()
	{
		PyThreadState_Swap (tstate);
		PyGILState_Release (gstate);
	}

private:
	PyGILState_STATE gstate;
	PyThreadState * tstate;
};

typedef struct
{
	PyThreadState * tstate;
	PyObject * instance;
	int printError;
	int shutdown;
} moduleData;

static int Python_AppendToSysPath (const char * path)
{
	if (path == nullptr) return 0;

	PyObject * sysPath = PySys_GetObject ((char *) "path");
	PyObject * pyPath = PyUnicode_FromString (path);
	PyList_Append (sysPath, pyPath);
	Py_DECREF (pyPath);
	return 1;
}

static PyObject * Python_CallFunction (PyObject * object, PyObject * args)
{
	if (!PyCallable_Check (object)) return nullptr;

	PyObject * res = PyObject_CallObject (object, args ? args : PyTuple_New (0));
	Py_XINCREF (res);
	return res;
}

static int Python_CallFunction_Int (moduleData * data, PyObject * object, PyObject * args, ckdb::Key * errorKey)
{
	int ret = -1;
	PyObject * res = Python_CallFunction (object, args);
	if (!res)
	{
		ELEKTRA_SET_ERROR (111, errorKey, "Error while calling python function");
		if (data->printError) PyErr_Print ();
	}
	else
	{
#if PY_MAJOR_VERSION >= 3
		if (!PyLong_Check (res))
#else
		if (!PyInt_Check (res))
#endif
			ELEKTRA_SET_ERROR (111, errorKey, "Return value is no integer");
		else
			ret = PyLong_AsLong (res);
	}

	Py_XDECREF (res);
	return ret;
}

static int Python_CallFunction_Helper1 (moduleData * data, const char * funcName, ckdb::Key * errorKey)
{
	int ret = 0;
	Python_LockSwap pylock (data->tstate);
	PyObject * func = PyObject_GetAttrString (data->instance, funcName);
	if (func)
	{
		PyObject * arg0 = Python_fromSWIG (errorKey);
		PyObject * args = Py_BuildValue ("(O)", arg0);
		ret = Python_CallFunction_Int (data, func, args, errorKey);
		Py_DECREF (arg0);
		Py_DECREF (args);
		Py_DECREF (func);
	}
	return ret;
}

static int Python_CallFunction_Helper2 (moduleData * data, const char * funcName, ckdb::KeySet * returned, ckdb::Key * parentKey)
{
	int ret = 0;
	Python_LockSwap pylock (data->tstate);
	PyObject * func = PyObject_GetAttrString (data->instance, funcName);
	if (func)
	{
		PyObject * arg0 = Python_fromSWIG (returned);
		PyObject * arg1 = Python_fromSWIG (parentKey);
		PyObject * args = Py_BuildValue ("(OO)", arg0, arg1);
		ret = Python_CallFunction_Int (data, func, args, parentKey);
		Py_DECREF (arg0);
		Py_DECREF (arg1);
		Py_DECREF (args);
		Py_DECREF (func);
	}
	return ret;
}

static std::mutex mutex;
static unsigned open_cnt = 0;

static void Python_Shutdown (moduleData * data)
{
	/* destroy python if plugin isn't used anymore */
	if (Py_IsInitialized ())
	{
		// Do we have a sub-interpreter?
		if (data->tstate)
		{
			Python_LockSwap pylock (data->tstate);

			/* clean up references */
			Py_XDECREF (data->instance);
			data->instance = nullptr;

			/* destroy sub interpreter */
			Py_EndInterpreter (data->tstate);
		}
		mutex.lock ();
		if (open_cnt && !--open_cnt && data->shutdown) // order matters!
			Py_Finalize ();
		mutex.unlock ();
	}
}

extern "C" {
int PYTHON_PLUGIN_FUNCTION (Open) (ckdb::Plugin * handle, ckdb::Key * errorKey)
{
	KeySet * config = elektraPluginGetConfig (handle);

	Key * script = ksLookupByName (config, "/script", 0);
	if (script == nullptr || !strlen (keyString (script)))
	{
		if (ksLookupByName (config, "/module", 0) != nullptr)
		{
			return 0; // by convention: success if /module exists
		}
		ELEKTRA_SET_ERROR (111, errorKey, "No python script set");
		return -1;
	}

	/* create module data */
	auto data = new moduleData;
	data->tstate = nullptr;
	data->instance = nullptr;
	data->printError = (ksLookupByName (config, "/print", 0) != nullptr);
	/* shutdown flag is integer by design. This way users can set the
	 * expected behaviour without worring about default values
	 */
	data->shutdown = (ksLookupByName (config, "/shutdown", 0) && !!strcmp (keyString (ksLookupByName (config, "/shutdown", 0)), "0"));
	data->subinterpreter = (ksLookupByName (config, "/subinterpreter", 0) &&
				!!strcmp (keyString (ksLookupByName (config, "/subinterpreter", 0)), "0"));

	{
		/* initialize python interpreter if necessary */
		mutex.lock ();
		if (!Py_IsInitialized ())
		{
			Py_Initialize ();
			if (!Py_IsInitialized ())
			{
				mutex.unlock ();
				goto error;
			}
			open_cnt++;
		}
		else if (open_cnt) // we have initialized python before
			open_cnt++;
		mutex.unlock ();

		/* init threads */
		PyEval_InitThreads ();

		/* acquire GIL */
		Python_LockSwap pylock (nullptr);

		if (data->subinterpreter)
		{
			/* Create a new sub-interpreter.
			This is incompatible with PyGILState_Ensure, see directly above
			https://docs.python.org/3/c-api/init.html#c.PyGILState_Ensure */
			data->tstate = Py_NewInterpreter ();
			if (data->tstate == nullptr)
			{
				ELEKTRA_SET_ERROR (111, errorKey, "Unable to create sub interpreter");
				goto error;
			}
			PyThreadState_Swap (data->tstate);
		}

		/* import kdb */
		PyObject * kdbModule = PyImport_ImportModule ("kdb");
		if (kdbModule == nullptr)
		{
			ELEKTRA_SET_ERROR (111, errorKey, "Unable to import kdb module");
			goto error_print;
		}
		Py_XDECREF (kdbModule);

		/* extend sys path */
		char * tmpScript = elektraStrDup (keyString (script));
		const char * dname = dirname (tmpScript);
		if (!Python_AppendToSysPath (dname))
		{
			ELEKTRA_SET_ERROR (111, errorKey, "Unable to extend sys.path");
			elektraFree (tmpScript);
			goto error;
		}
		elektraFree (tmpScript);

		/* import module/script */
		tmpScript = elektraStrDup (keyString (script));
		char * bname = basename (tmpScript);
		size_t bname_len = strlen (bname);
		if (bname_len >= 4 && strcmp (bname + bname_len - 3, ".py") == 0) bname[bname_len - 3] = '\0';

		PyObject * pModule = PyImport_ImportModule (bname);
		if (pModule == nullptr)
		{
			ELEKTRA_SET_ERRORF (111, errorKey, "Unable to import python script %s", keyString (script));
			elektraFree (tmpScript);
			goto error_print;
		}
		elektraFree (tmpScript);

		/* get class */
		PyObject * klass = PyObject_GetAttrString (pModule, "ElektraPlugin");
		Py_DECREF (pModule);
		if (klass == nullptr)
		{
			ELEKTRA_SET_ERROR (111, errorKey, "Module doesn't provide a ElektraPlugin class");
			goto error_print;
		}

		/* create instance of class */
		PyObject * inst_args = Py_BuildValue ("()");
		PyObject * inst = PyEval_CallObject (klass, inst_args);
		Py_DECREF (klass);
		Py_DECREF (inst_args);
		if (inst == nullptr)
		{
			ELEKTRA_SET_ERROR (111, errorKey, "Unable to create instance of ElektraPlugin");
			goto error_print;
		}
		data->instance = inst;
	}

	/* store module data after everything is set up */
	elektraPluginSetData (handle, data);

	/* call python function */
	return Python_CallFunction_Helper2 (data, "open", config, errorKey);

error_print:
	if (data->printError) PyErr_Print ();
error:
	/* destroy python */
	Python_Shutdown (data);
	delete data;
	elektraPluginSetData (handle, nullptr);
	return -1;
}

int PYTHON_PLUGIN_FUNCTION (Close) (ckdb::Plugin * handle, ckdb::Key * errorKey)
{
	moduleData * data = static_cast<moduleData *> (elektraPluginGetData (handle));
	if (data == nullptr) return 0;

	int ret = Python_CallFunction_Helper1 (data, "close", errorKey);

	/* destroy python */
	Python_Shutdown (data);
	delete data;
	elektraPluginSetData (handle, nullptr);
	return ret;
}

int PYTHON_PLUGIN_FUNCTION (Get) (ckdb::Plugin * handle, ckdb::KeySet * returned, ckdb::Key * parentKey)
{
#define _MODULE_CONFIG_PATH "system/elektra/modules/" PYTHON_PLUGIN_NAME_STR
	if (!strcmp (keyName (parentKey), _MODULE_CONFIG_PATH))
	{
		KeySet * n;
		ksAppend (returned,
			  n = ksNew (30, keyNew (_MODULE_CONFIG_PATH, KEY_VALUE, "python interpreter waits for your orders", KEY_END),
				     keyNew (_MODULE_CONFIG_PATH "/exports", KEY_END),
				     keyNew (_MODULE_CONFIG_PATH "/exports/get", KEY_FUNC, PYTHON_PLUGIN_FUNCTION (Get), KEY_END),
				     keyNew (_MODULE_CONFIG_PATH "/exports/set", KEY_FUNC, PYTHON_PLUGIN_FUNCTION (Set), KEY_END),
				     keyNew (_MODULE_CONFIG_PATH "/exports/error", KEY_FUNC, PYTHON_PLUGIN_FUNCTION (Error), KEY_END),
				     keyNew (_MODULE_CONFIG_PATH "/exports/open", KEY_FUNC, PYTHON_PLUGIN_FUNCTION (Open), KEY_END),
				     keyNew (_MODULE_CONFIG_PATH "/exports/close", KEY_FUNC, PYTHON_PLUGIN_FUNCTION (Close), KEY_END),
#include ELEKTRA_README (PYTHON_PLUGIN_NAME)
				     keyNew (_MODULE_CONFIG_PATH "/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END));
		ksDel (n);
	}

	moduleData * data = static_cast<moduleData *> (elektraPluginGetData (handle));
	if (data != nullptr) return Python_CallFunction_Helper2 (data, "get", returned, parentKey);
	return 0;
}

int PYTHON_PLUGIN_FUNCTION (Set) (ckdb::Plugin * handle, ckdb::KeySet * returned, ckdb::Key * parentKey)
{
	moduleData * data = static_cast<moduleData *> (elektraPluginGetData (handle));
	if (data != nullptr) return Python_CallFunction_Helper2 (data, "set", returned, parentKey);
	return 0;
}

int PYTHON_PLUGIN_FUNCTION (Error) (ckdb::Plugin * handle, ckdb::KeySet * returned, ckdb::Key * parentKey)
{
	moduleData * data = static_cast<moduleData *> (elektraPluginGetData (handle));
	if (data != nullptr) return Python_CallFunction_Helper2 (data, "error", returned, parentKey);
	return 0;
}

ckdb::Plugin * PYTHON_PLUGIN_EXPORT (PYTHON_PLUGIN_NAME)
{
	// clang-format off
	return elektraPluginExport(PYTHON_PLUGIN_NAME_STR,
		ELEKTRA_PLUGIN_OPEN,  &PYTHON_PLUGIN_FUNCTION(Open),
		ELEKTRA_PLUGIN_CLOSE, &PYTHON_PLUGIN_FUNCTION(Close),
		ELEKTRA_PLUGIN_GET,   &PYTHON_PLUGIN_FUNCTION(Get),
		ELEKTRA_PLUGIN_SET,   &PYTHON_PLUGIN_FUNCTION(Set),
		ELEKTRA_PLUGIN_ERROR, &PYTHON_PLUGIN_FUNCTION(Error),
		ELEKTRA_PLUGIN_END);
}
}
<|endoftext|>


<commit_before>#include "IdDictionary.hpp"

#include <ros/console.h>

using namespace std;

IdDictionary::IdDictionary()
{
	translated = false;
}

bool IdDictionary::contains(int n)
{
	boost::mutex::scoped_lock lock(mutex);

	for (vector<int>::iterator it = ids.begin(); it != ids.end(); it++) {
		if (*it == n) {
			return true;
		}
	}

	return false;
}

void IdDictionary::insert(int n)
{
	if (contains(n)) {
		return;
	}

	if (translated) {
		ROS_ERROR("insert: Ids already translated!");
	}

	boost::mutex::scoped_lock lock(mutex);

	ROS_DEBUG("Inserted id %d", n);
	ids.push_back(n);
}

int IdDictionary::size()
{
	boost::mutex::scoped_lock lock(mutex);

	return ids.size();
}

void IdDictionary::translateIds()
{
	if (translated) {
		return;
	}

	boost::mutex::scoped_lock lock(mutex);

	ROS_DEBUG("Translating dictionary with %d ids", size());

	translated = true;

	std::sort(ids.begin(), ids.end());
	int id = 0;

	for (vector<int>::iterator it = ids.begin(); it != ids.end(); it++, id++) {
		backward[id] = *it;
		forward[*it] = id;
	}
}

bool IdDictionary::isTranslated()
{
	return translated;
}

int IdDictionary::getForward(int n)
{
	if (!translated) {
		ROS_ERROR("getForward: Ids not translated!");
	}

	boost::mutex::scoped_lock lock(mutex);

	if (forward.count(n)) {
		int result = forward[n];
		return result;
	} else {
		ROS_ERROR("getForward: Unknown id %d", n);
		return -1;
	}
}

int IdDictionary::getBackward(int n)
{
	if (!translated) {
		ROS_ERROR("getBackward: Ids not translated!");
	}

	ROS_DEBUG("getBackward: Locking mutex");
	ROS_DEBUG("forward size: %ld, backward size: %ld, vector size: %ld", forward.size(), backward.size(), ids.size());
	boost::mutex::scoped_lock lock(mutex);
	ROS_DEBUG("getBackward: Mutex locked");

	if (backward.count(n)) {
		int result = backward[n];
		return result;
	} else {
		ROS_ERROR("getBackward: Unknown id %d", n);
		return -1;
	}
}<commit_msg>Added extra blocks for scoped locks.<commit_after>#include "IdDictionary.hpp"

#include <ros/console.h>

using namespace std;

IdDictionary::IdDictionary()
{
	translated = false;
}

bool IdDictionary::contains(int n)
{
	{
		boost::mutex::scoped_lock lock(mutex);

		for (vector<int>::iterator it = ids.begin(); it != ids.end(); it++) {
			if (*it == n) {
				return true;
			}
		}

		return false;
	}
}

void IdDictionary::insert(int n)
{
	if (contains(n)) {
		return;
	}

	if (translated) {
		ROS_ERROR("insert: Ids already translated!");
	}

	{
		boost::mutex::scoped_lock lock(mutex);

		ROS_DEBUG("Inserted id %d", n);
		ids.push_back(n);
	}
}

int IdDictionary::size()
{
	{
		boost::mutex::scoped_lock lock(mutex);

		return ids.size();
	}
}

void IdDictionary::translateIds()
{
	if (translated) {
		return;
	}

	{
		boost::mutex::scoped_lock lock(mutex);

		ROS_DEBUG("Translating dictionary with %d ids", size());

		translated = true;

		std::sort(ids.begin(), ids.end());
		int id = 0;

		for (vector<int>::iterator it = ids.begin(); it != ids.end(); it++, id++) {
			backward[id] = *it;
			forward[*it] = id;
		}
	}
}

bool IdDictionary::isTranslated()
{
	return translated;
}

int IdDictionary::getForward(int n)
{
	if (!translated) {
		ROS_ERROR("getForward: Ids not translated!");
	}

	{
		boost::mutex::scoped_lock lock(mutex);

		if (forward.count(n)) {
			int result = forward[n];
			return result;
		} else {
			ROS_ERROR("getForward: Unknown id %d", n);
			return -1;
		}
	}
}

int IdDictionary::getBackward(int n)
{
	if (!translated) {
		ROS_ERROR("getBackward: Ids not translated!");
	}

	ROS_DEBUG("getBackward: Locking mutex");
	ROS_DEBUG("forward size: %ld, backward size: %ld, vector size: %ld", forward.size(), backward.size(), ids.size());
	{
		boost::mutex::scoped_lock lock(mutex);
		ROS_DEBUG("getBackward: Mutex locked");

		if (backward.count(n)) {
			int result = backward[n];
			return result;
		} else {
			ROS_ERROR("getBackward: Unknown id %d", n);
			return -1;
		}
	}
}<|endoftext|>


<commit_before>// Copyright (c) 2011-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <qt/qvalidatedlineedit.h>

#include <qt/bitcoinaddressvalidator.h>
#include <qt/guiconstants.h>

QValidatedLineEdit::QValidatedLineEdit(QWidget *parent)
    : QLineEdit(parent), valid(true), checkValidator(0) {
    connect(this, SIGNAL(textChanged(QString)), this, SLOT(markValid()));
}

void QValidatedLineEdit::setValid(bool _valid) {
    if (_valid == this->valid) {
        return;
    }

    if (_valid) {
        setStyleSheet("");
    } else {
        setStyleSheet(STYLE_INVALID);
    }
    this->valid = _valid;
}

void QValidatedLineEdit::focusInEvent(QFocusEvent *evt) {
    // Clear invalid flag on focus
    setValid(true);

    QLineEdit::focusInEvent(evt);
}

void QValidatedLineEdit::focusOutEvent(QFocusEvent *evt) {
    checkValidity();

    QLineEdit::focusOutEvent(evt);
}

void QValidatedLineEdit::markValid() {
    // As long as a user is typing ensure we display state as valid
    setValid(true);
}

void QValidatedLineEdit::clear() {
    setValid(true);
    QLineEdit::clear();
}

void QValidatedLineEdit::setEnabled(bool enabled) {
    if (!enabled) {
        // A disabled QValidatedLineEdit should be marked valid
        setValid(true);
    } else {
        // Recheck validity when QValidatedLineEdit gets enabled
        checkValidity();
    }

    QLineEdit::setEnabled(enabled);
}

void QValidatedLineEdit::checkValidity() {
    if (text().isEmpty()) {
        setValid(true);
    } else if (hasAcceptableInput()) {
        setValid(true);

        // Check contents on focus out
        if (checkValidator) {
            QString address = text();
            int pos = 0;
            if (checkValidator->validate(address, pos) ==
                QValidator::Acceptable)
                setValid(true);
            else
                setValid(false);
        }
    } else
        setValid(false);

    Q_EMIT validationDidChange(this);
}

void QValidatedLineEdit::setCheckValidator(const QValidator *v) {
    checkValidator = v;
}

bool QValidatedLineEdit::isValid() {
    // use checkValidator in case the QValidatedLineEdit is disabled
    if (checkValidator) {
        QString address = text();
        int pos = 0;
        if (checkValidator->validate(address, pos) == QValidator::Acceptable)
            return true;
    }

    return valid;
}
<commit_msg>Update qt/qvalidatedlinedit.cpp to use Qt5 connect syntax<commit_after>// Copyright (c) 2011-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <qt/qvalidatedlineedit.h>

#include <qt/bitcoinaddressvalidator.h>
#include <qt/guiconstants.h>

QValidatedLineEdit::QValidatedLineEdit(QWidget *parent)
    : QLineEdit(parent), valid(true), checkValidator(0) {
    connect(this, &QValidatedLineEdit::textChanged, this,
            &QValidatedLineEdit::markValid);
}

void QValidatedLineEdit::setValid(bool _valid) {
    if (_valid == this->valid) {
        return;
    }

    if (_valid) {
        setStyleSheet("");
    } else {
        setStyleSheet(STYLE_INVALID);
    }
    this->valid = _valid;
}

void QValidatedLineEdit::focusInEvent(QFocusEvent *evt) {
    // Clear invalid flag on focus
    setValid(true);

    QLineEdit::focusInEvent(evt);
}

void QValidatedLineEdit::focusOutEvent(QFocusEvent *evt) {
    checkValidity();

    QLineEdit::focusOutEvent(evt);
}

void QValidatedLineEdit::markValid() {
    // As long as a user is typing ensure we display state as valid
    setValid(true);
}

void QValidatedLineEdit::clear() {
    setValid(true);
    QLineEdit::clear();
}

void QValidatedLineEdit::setEnabled(bool enabled) {
    if (!enabled) {
        // A disabled QValidatedLineEdit should be marked valid
        setValid(true);
    } else {
        // Recheck validity when QValidatedLineEdit gets enabled
        checkValidity();
    }

    QLineEdit::setEnabled(enabled);
}

void QValidatedLineEdit::checkValidity() {
    if (text().isEmpty()) {
        setValid(true);
    } else if (hasAcceptableInput()) {
        setValid(true);

        // Check contents on focus out
        if (checkValidator) {
            QString address = text();
            int pos = 0;
            if (checkValidator->validate(address, pos) ==
                QValidator::Acceptable)
                setValid(true);
            else
                setValid(false);
        }
    } else
        setValid(false);

    Q_EMIT validationDidChange(this);
}

void QValidatedLineEdit::setCheckValidator(const QValidator *v) {
    checkValidator = v;
}

bool QValidatedLineEdit::isValid() {
    // use checkValidator in case the QValidatedLineEdit is disabled
    if (checkValidator) {
        QString address = text();
        int pos = 0;
        if (checkValidator->validate(address, pos) == QValidator::Acceptable)
            return true;
    }

    return valid;
}
<|endoftext|>