<commit_before>#include "client.hpp"
#include <iostream>
#include <SDL2/SDL.h>
#include <string>

/** For network **/
#include "messagetypes.hpp"
#include "packet.hpp"
#include "systemidentifiers.hpp"

#include "inputdata.hpp"

Client::Client(int argc, char** argv) :
        socket("swordbow-magic"),
        sequence(1),
        renderer(argc, argv),
        systemManager(&componentManager, &deltaTime),
        textureBoundingBox(&componentManager, &renderer),
        textureHashGridSystem(&componentManager, &textureBoundingBox),
        renderSystem(&renderer),
        cameraSystem(&renderer) {

    std::cout << "\n--** STARTING CLIENT **--" << std::endl;

    //Default port
    short port = 47294;

    //Check if port is set
    for(int i = 0; i < argc; i++) {
		if(strcmp(argv[i], "port") == 0) {
			port = std::atoi(argv[i+1]);
		}
	}

    socket.open(port);

    systemManager.add(&textureHashGridSystem);
    systemManager.add(&renderSystem);
    systemManager.add(&cameraSystem);

    //Play some sweet music
	soundEngine.playMusic(Music::NATURE_SOUNDS);
}

Client::~Client() {
    socket.close();
}

void Client::connect(const IpAddress& server) {

    //TODO: The server should inform the client of the servers current
    //sequence number, and the client should set it here with some
    //socket.setRemoteSequenceNumber(server)-call. Otherwise clients
    //that connects to a server might figure some packets to be old

    //Start a thread that checks socket for any recieved data
    receiveThreadRunning = true;
    receiveThread = std::thread(&Client::receive, this);

    this->server = server;

    //Connect-request packet
    using Type = Packet<bool>;
    const Type packet {
        stringhash("swordbow-magic"),
        sequence++,
        MESSAGE_TYPE::CONNECT,
        true,
        sizeof(sizeof(bool))
    };

    socket.send<Type>(server, packet);
}

void Client::disconnect() {

    //Stop receiving data on socket
    receiveThreadRunning = false;
    receiveThread.join();

    //Disconnect-request packet
    using Type = Packet<bool>;
    const Type packet {
        stringhash("swordbow-magic"),
        sequence++,
        MESSAGE_TYPE::DISCONNECT,
        true,
        sizeof(sizeof(bool))
    };

    socket.send<Type>(server, packet);

    server = IpAddress(0, 0, 0, 0, 0); //Indicate not connected to any server
}

void Client::receive() {
    while(receiveThreadRunning) {

        //Receive data from server...
        IpAddress server;
        unsigned char type;
        int bytesRead;
        socket.receive(server, type, bytesRead);

        //If any data was received, check its type and take appropiate action
        if(bytesRead > 0) {

            /** CRITICAL-SECTION **/
            componentsMutex.lock();

            switch(type) {
                case MESSAGE_TYPE::OUTDATED: {
                    std::cout << "This packet is outdated, to late! Sluggish!" << std::endl;
                } break;

                case MESSAGE_TYPE::CONNECT: {
                    //Got my id. Tell camerasystem to follow that id.
                    auto typedPacket = socket.get<Packet<std::pair<ID, System::Identifier>>>(bytesRead);
                    const auto& pair = typedPacket.getData();
                    systemManager.getSystem(pair.second)->add(pair.first);
                } break;
                case MESSAGE_TYPE::MOVECOMPONENTS: {
                    //All movecomponents were received - handle it
                    auto typedPacket = socket.get<Packet<Components<MoveComponent>>>(bytesRead);
                    componentManager.moveComponents.sync(typedPacket.getData());

                    //It is assumed that any receieved movecomponent should
                    //be added to texturehashgridsystem and rendersystem,
                    //because if not, why would the server send them in the first
                    //place?
                    for(auto& pair : typedPacket.getData()) {
                        textureHashGridSystem.add(pair.first);
                        renderSystem.add(pair.first);
                    }

                } break;

                case MESSAGE_TYPE::RENDERCOMPONENTS: {
                    //All rendercomponents were received - handle it
                    auto typedPacket = socket.get<Packet<Components<RenderComponent>>>(bytesRead);
                    componentManager.renderComponents.sync(typedPacket.getData());

                    for(auto& pair : typedPacket.getData()) {
                        textureHashGridSystem.add(pair.first);
                        renderSystem.add(pair.first);
                    }

                } break;

                case MESSAGE_TYPE::MOVECOMPONENTSDIFF: {
                    //Diff movecomponents were received - handle it
                    auto typedPacket = socket.get<Packet<Components<MoveComponent>>>(bytesRead);
                    componentManager.moveComponents.sync(typedPacket.getData());

                    //It makes sence to auto-activate newly received ids of the
                    //movecomponents in rendersystem, since the server only
                    //sends movecomponents on actual difference, the client
                    //should redraw that difference. So former ACTIVATE_ID message
                    //could be implicit with any component-message, which has the
                    //benefit of not mistakingly activating ids before components
                    //are received. Since system.add is a superset of system.activateId
                    //we might aswell assume adding received components to systems
                    //which makes REGISTER_ID_TO_SYSTEM-message obsolete
                    for(auto& pair : typedPacket.getData()) {
                        textureHashGridSystem.add(pair.first);
                        renderSystem.add(pair.first);
                    }

                } break;

                case MESSAGE_TYPE::RENDERCOMPONENTSDIFF: {
                    //Diff rendercomponents were received - handle it
                    auto typedPacket = socket.get<Packet<Components<RenderComponent>>>(bytesRead);
                    componentManager.renderComponents.sync(typedPacket.getData());

                    for(auto& pair : typedPacket.getData()) {
                        textureHashGridSystem.add(pair.first);
                        renderSystem.add(pair.first);
                    }
                } break;

                case MESSAGE_TYPE::PLAY_SOUND: {
                    auto typedPacket = socket.get<Packet<SoundData>>(bytesRead);
                    soundEngine.playSound(typedPacket.getData());
                } break;

                case MESSAGE_TYPE::REGISTER_ID_TO_SYSTEM: {
                    auto typedPacket = socket.get<Packet<std::pair<ID, System::Identifier>>>(bytesRead);
                    const auto& id = typedPacket.getData().first;
                    const auto& systemIdentifier = typedPacket.getData().second;
                    systemManager.getSystem(systemIdentifier)->add(id);
                } break;

                case MESSAGE_TYPE::REMOVE_ID: {
                    auto typedPacket = socket.get<Packet<ID>>(bytesRead);
                    const auto& id = typedPacket.getData();
                    systemManager.getSystem(System::RENDER)->remove(id);
                    systemManager.getSystem(System::HASHGRID_TEXTURE)->remove(id);
                    componentManager.clearComponents(id);
                } break;

                case MESSAGE_TYPE::REMOVE_ID_FROM_SYSTEM: {
                    auto typedPacket = socket.get<Packet<std::pair<ID, System::Identifier>>>(bytesRead);
                    const auto& id = typedPacket.getData().first;
                    const auto& systemIdentifier = typedPacket.getData().second;
                    systemManager.getSystem(systemIdentifier)->remove(id);
                } break;

                case MESSAGE_TYPE::REMOVE_ID_FROM_SYSTEMS: {
                    auto typedPacket = socket.get<Packet<ID>>(bytesRead);
                    const auto& id = typedPacket.getData();
                    systemManager.getSystem(System::RENDER)->remove(id);
                    systemManager.getSystem(System::HASHGRID_TEXTURE)->remove(id);
                } break;

                case MESSAGE_TYPE::ACTIVATE_ID: {
                    auto typedPacket = socket.get<Packet<std::pair<ID, System::Identifier>>>(bytesRead);
                    const auto& id = typedPacket.getData().first;
                    const auto& systemIdentifier = typedPacket.getData().second;
                    systemManager.getSystem(systemIdentifier)->activateId(id);
                } break;

                default: {
                    std::cout << "WARNING: Message without proper type received. This is probably a bug." << std::endl;
                    std::cout << "Either client-side handling for that message isn't implemented";
                    std::cout << " or server sent a message with a bogus messagetype";
                    std::cout << " or the messagetype was wrongly altered somewhere" << std::endl;
                };
            }

            /** END OF CRITICAL SECTION **/
            componentsMutex.unlock();
        }
    }
}

void Client::run() {
    while(running) {
        step();
    }
}

void Client::step() {
    deltaTime.start();

    /** Get input from client **/
    std::queue<int> presses;
    std::queue<int> releases;

    //Fetch all events that ocurred...
    while(SDL_PollEvent(&event) != 0) {
        //Dont consider keyrepeat as keypress
        if(event.key.repeat == 0) {
            //And take appropiate action!
            switch(event.type) {
                case SDL_QUIT: {
                    running = false;
                    break;
                }
                //If this event was a keydown...
                case SDL_KEYDOWN: {
                    presses.push(event.key.keysym.sym);
                } break;

                //If user released a key
                case SDL_KEYUP: {
                    releases.push(event.key.keysym.sym);

                } break;
            }
        }
    }

    //If user either pressed or released a key
    if( !(presses.empty() && releases.empty()) ) {

        //Assemble the InputData that should be sent into a packet
        const InputData inputData{presses, releases};

        using Type = Packet<InputData>;
        const Type packet {
            stringhash("swordbow-magic"),
            sequence++,
            MESSAGE_TYPE::INPUTDATA,
            inputData,
            sizeof(inputData)
        };

        socket.send<Type>(server, packet);
    }

    /** CRITICAL SECTION **/
    componentsMutex.lock();

    /** Update client-side ECS **/
    systemManager.update();

    /** END OF CRITICAL SECTION **/
    componentsMutex.unlock();

    /** Pass output from rendersystem to renderer **/
    renderer.render(renderSystem.getDrawPriorityQueue(), cameraSystem.getCamera());

    deltaTime.stop();
}

int main(int argc, char** argv) {
    Client client(argc, argv);
    client.connect({127, 0, 0, 1, 47293});
    client.run();
    client.disconnect();
}

//
<commit_msg>client disconnect on disconnect-message<commit_after>#include "client.hpp"
#include <iostream>
#include <SDL2/SDL.h>
#include <string>

/** For network **/
#include "messagetypes.hpp"
#include "packet.hpp"
#include "systemidentifiers.hpp"

#include "inputdata.hpp"

Client::Client(int argc, char** argv) :
        socket("swordbow-magic"),
        sequence(1),
        renderer(argc, argv),
        systemManager(&componentManager, &deltaTime),
        textureBoundingBox(&componentManager, &renderer),
        textureHashGridSystem(&componentManager, &textureBoundingBox),
        renderSystem(&renderer),
        cameraSystem(&renderer) {

    std::cout << "\n--** STARTING CLIENT **--" << std::endl;

    //Default port
    short port = 47294;

    //Check if port is set
    for(int i = 0; i < argc; i++) {
		if(strcmp(argv[i], "port") == 0) {
			port = std::atoi(argv[i+1]);
		}
	}

    socket.open(port);

    systemManager.add(&textureHashGridSystem);
    systemManager.add(&renderSystem);
    systemManager.add(&cameraSystem);

    //Play some sweet music
	soundEngine.playMusic(Music::NATURE_SOUNDS);
}

Client::~Client() {
    socket.close();
}

void Client::connect(const IpAddress& server) {

    //TODO: The server should inform the client of the servers current
    //sequence number, and the client should set it here with some
    //socket.setRemoteSequenceNumber(server)-call. Otherwise clients
    //that connects to a server might figure some packets to be old

    //Start a thread that checks socket for any recieved data
    receiveThreadRunning = true;
    receiveThread = std::thread(&Client::receive, this);

    this->server = server;

    //Connect-request packet
    using Type = Packet<bool>;
    const Type packet {
        stringhash("swordbow-magic"),
        sequence++,
        MESSAGE_TYPE::CONNECT,
        true,
        sizeof(sizeof(bool))
    };

    socket.send<Type>(server, packet);
}

void Client::disconnect() {

    //Stop receiving data on socket
    receiveThreadRunning = false;
    receiveThread.join();

    //Disconnect-request packet
    using Type = Packet<bool>;
    const Type packet {
        stringhash("swordbow-magic"),
        sequence++,
        MESSAGE_TYPE::DISCONNECT,
        true,
        sizeof(sizeof(bool))
    };

    socket.send<Type>(server, packet);

    server = IpAddress(0, 0, 0, 0, 0); //Indicate not connected to any server
}

void Client::receive() {
    while(receiveThreadRunning) {

        //Receive data from server...
        IpAddress server;
        unsigned char type;
        int bytesRead;
        socket.receive(server, type, bytesRead);

        //If any data was received, check its type and take appropiate action
        if(bytesRead > 0) {

            /** CRITICAL-SECTION **/
            componentsMutex.lock();

            switch(type) {
                case MESSAGE_TYPE::OUTDATED: {
                    std::cout << "This packet is outdated, to late! Sluggish!" << std::endl;
                } break;

                case MESSAGE_TYPE::CONNECT: {
                    //Got my id. Tell camerasystem to follow that id.
                    auto typedPacket = socket.get<Packet<std::pair<ID, System::Identifier>>>(bytesRead);
                    const auto& pair = typedPacket.getData();
                    systemManager.getSystem(pair.second)->add(pair.first);
                } break;

                //Server will send this to client for a couple of reasons.
                //In any case the client shouldn't be connected to the server.
                case MESSAGE_TYPE::DISCONNECT: {
                    disconnect();
                } break;

                case MESSAGE_TYPE::MOVECOMPONENTS: {
                    //All movecomponents were received - handle it
                    auto typedPacket = socket.get<Packet<Components<MoveComponent>>>(bytesRead);
                    componentManager.moveComponents.sync(typedPacket.getData());

                    //It is assumed that any receieved movecomponent should
                    //be added to texturehashgridsystem and rendersystem,
                    //because if not, why would the server send them in the first
                    //place?
                    for(auto& pair : typedPacket.getData()) {
                        textureHashGridSystem.add(pair.first);
                        renderSystem.add(pair.first);
                    }

                } break;

                case MESSAGE_TYPE::RENDERCOMPONENTS: {
                    //All rendercomponents were received - handle it
                    auto typedPacket = socket.get<Packet<Components<RenderComponent>>>(bytesRead);
                    componentManager.renderComponents.sync(typedPacket.getData());

                    for(auto& pair : typedPacket.getData()) {
                        textureHashGridSystem.add(pair.first);
                        renderSystem.add(pair.first);
                    }

                } break;

                case MESSAGE_TYPE::MOVECOMPONENTSDIFF: {
                    //Diff movecomponents were received - handle it
                    auto typedPacket = socket.get<Packet<Components<MoveComponent>>>(bytesRead);
                    componentManager.moveComponents.sync(typedPacket.getData());

                    //It makes sence to auto-activate newly received ids of the
                    //movecomponents in rendersystem, since the server only
                    //sends movecomponents on actual difference, the client
                    //should redraw that difference. So former ACTIVATE_ID message
                    //could be implicit with any component-message, which has the
                    //benefit of not mistakingly activating ids before components
                    //are received. Since system.add is a superset of system.activateId
                    //we might aswell assume adding received components to systems
                    //which makes REGISTER_ID_TO_SYSTEM-message obsolete
                    for(auto& pair : typedPacket.getData()) {
                        textureHashGridSystem.add(pair.first);
                        renderSystem.add(pair.first);
                    }

                } break;

                case MESSAGE_TYPE::RENDERCOMPONENTSDIFF: {
                    //Diff rendercomponents were received - handle it
                    auto typedPacket = socket.get<Packet<Components<RenderComponent>>>(bytesRead);
                    componentManager.renderComponents.sync(typedPacket.getData());

                    for(auto& pair : typedPacket.getData()) {
                        textureHashGridSystem.add(pair.first);
                        renderSystem.add(pair.first);
                    }
                } break;

                case MESSAGE_TYPE::PLAY_SOUND: {
                    auto typedPacket = socket.get<Packet<SoundData>>(bytesRead);
                    soundEngine.playSound(typedPacket.getData());
                } break;

                case MESSAGE_TYPE::REGISTER_ID_TO_SYSTEM: {
                    auto typedPacket = socket.get<Packet<std::pair<ID, System::Identifier>>>(bytesRead);
                    const auto& id = typedPacket.getData().first;
                    const auto& systemIdentifier = typedPacket.getData().second;
                    systemManager.getSystem(systemIdentifier)->add(id);
                } break;

                case MESSAGE_TYPE::REMOVE_ID: {
                    auto typedPacket = socket.get<Packet<ID>>(bytesRead);
                    const auto& id = typedPacket.getData();
                    systemManager.getSystem(System::RENDER)->remove(id);
                    systemManager.getSystem(System::HASHGRID_TEXTURE)->remove(id);
                    componentManager.clearComponents(id);
                } break;

                case MESSAGE_TYPE::REMOVE_ID_FROM_SYSTEM: {
                    auto typedPacket = socket.get<Packet<std::pair<ID, System::Identifier>>>(bytesRead);
                    const auto& id = typedPacket.getData().first;
                    const auto& systemIdentifier = typedPacket.getData().second;
                    systemManager.getSystem(systemIdentifier)->remove(id);
                } break;

                case MESSAGE_TYPE::REMOVE_ID_FROM_SYSTEMS: {
                    auto typedPacket = socket.get<Packet<ID>>(bytesRead);
                    const auto& id = typedPacket.getData();
                    systemManager.getSystem(System::RENDER)->remove(id);
                    systemManager.getSystem(System::HASHGRID_TEXTURE)->remove(id);
                } break;

                case MESSAGE_TYPE::ACTIVATE_ID: {
                    auto typedPacket = socket.get<Packet<std::pair<ID, System::Identifier>>>(bytesRead);
                    const auto& id = typedPacket.getData().first;
                    const auto& systemIdentifier = typedPacket.getData().second;
                    systemManager.getSystem(systemIdentifier)->activateId(id);
                } break;

                default: {
                    std::cout << "WARNING: Message without proper type received. This is probably a bug." << std::endl;
                    std::cout << "Either client-side handling for that message isn't implemented";
                    std::cout << " or server sent a message with a bogus messagetype";
                    std::cout << " or the messagetype was wrongly altered somewhere" << std::endl;
                };
            }

            /** END OF CRITICAL SECTION **/
            componentsMutex.unlock();
        }
    }
}

void Client::run() {
    while(running) {
        step();
    }
}

void Client::step() {
    deltaTime.start();

    /** Get input from client **/
    std::queue<int> presses;
    std::queue<int> releases;

    //Fetch all events that ocurred...
    while(SDL_PollEvent(&event) != 0) {
        //Dont consider keyrepeat as keypress
        if(event.key.repeat == 0) {
            //And take appropiate action!
            switch(event.type) {
                case SDL_QUIT: {
                    running = false;
                    break;
                }
                //If this event was a keydown...
                case SDL_KEYDOWN: {
                    presses.push(event.key.keysym.sym);
                } break;

                //If user released a key
                case SDL_KEYUP: {
                    releases.push(event.key.keysym.sym);

                } break;
            }
        }
    }

    //If user either pressed or released a key
    if( !(presses.empty() && releases.empty()) ) {

        //Assemble the InputData that should be sent into a packet
        const InputData inputData{presses, releases};

        using Type = Packet<InputData>;
        const Type packet {
            stringhash("swordbow-magic"),
            sequence++,
            MESSAGE_TYPE::INPUTDATA,
            inputData,
            sizeof(inputData)
        };

        socket.send<Type>(server, packet);
    }

    /** CRITICAL SECTION **/
    componentsMutex.lock();

    /** Update client-side ECS **/
    systemManager.update();

    /** END OF CRITICAL SECTION **/
    componentsMutex.unlock();

    /** Pass output from rendersystem to renderer **/
    renderer.render(renderSystem.getDrawPriorityQueue(), cameraSystem.getCamera());

    deltaTime.stop();
}

int main(int argc, char** argv) {
    Client client(argc, argv);
    client.connect({127, 0, 0, 1, 47293});
    client.run();
    client.disconnect();
}

//
<|endoftext|>


<commit_before>#ifndef context_hh_INCLUDED
#define context_hh_INCLUDED

#include "selection.hh"
#include "optional.hh"
#include "flags.hh"

namespace Kakoune
{

class Window;
class Buffer;
class Client;
class Scope;
class InputHandler;
class UserInterface;
class DisplayLine;
class KeymapManager;
class AliasRegistry;

// bool that can be set (to true) multiple times, and will
// be false only when unset the same time;
struct NestedBool
{
    void set() { m_count++; }
    void unset() { kak_assert(m_count > 0); m_count--; }

    operator bool() const { return m_count > 0; }
private:
    int m_count = 0;
};

struct ScopedSetBool
{
    ScopedSetBool(NestedBool& nested_bool, bool condition = true)
        : m_nested_bool(nested_bool), m_condition(condition)
    {
        if (m_condition)
            m_nested_bool.set();
    }

    ~ScopedSetBool()
    {
        if (m_condition)
            m_nested_bool.unset();
    }

private:
    NestedBool& m_nested_bool;
    bool m_condition;
};

struct JumpList
{
    void push(SelectionList jump);
    const SelectionList& forward();
    const SelectionList& backward(const SelectionList& current);
    void forget_buffer(Buffer& buffer);

    friend bool operator==(const JumpList& lhs, const JumpList& rhs)
    {
        return lhs.m_jumps == rhs.m_jumps and lhs.m_current == rhs.m_current;
    }

    friend bool operator!=(const JumpList& lhs, const JumpList& rhs) { return not (lhs == rhs); }

private:
    using Contents = Vector<SelectionList, MemoryDomain::Selections>;
    Contents           m_jumps;
    size_t m_current = 0;
};

// A Context is used to access non singleton objects for various services
// in commands.
//
// The Context object links a Client, a Window, an InputHandler and a
// SelectionList. It may represent an interactive user window, a hook
// execution or a macro replay context.
class Context
{
public:
    enum class Flags
    {
        None = 0,
        Transient = 1,
    };

    Context(InputHandler& input_handler, SelectionList selections,
            Flags flags, String name = "");

    struct EmptyContextFlag {};
    explicit Context(EmptyContextFlag);
    ~Context();

    Context(const Context&) = delete;
    Context& operator=(const Context&) = delete;

    Buffer& buffer() const;
    bool has_buffer() const { return (bool)m_selections; }

    Window& window() const;
    bool has_window() const { return (bool)m_window; }

    Client& client() const;
    bool has_client() const { return (bool)m_client; }

    InputHandler& input_handler() const;
    bool has_input_handler() const { return (bool)m_input_handler; }

    SelectionList& selections();
    const SelectionList& selections() const;
    Vector<String>  selections_content() const;

    // Return potentially out of date selections
    SelectionList& selections_write_only();

    void change_buffer(Buffer& buffer);

    void set_client(Client& client);
    void set_window(Window& window);

    Scope& scope() const;

    OptionManager& options() const { return scope().options(); }
    HookManager& hooks()     const { return scope().hooks(); }
    KeymapManager& keymaps() const { return scope().keymaps(); }
    AliasRegistry& aliases() const { return scope().aliases(); }

    void print_status(DisplayLine status) const;

    StringView main_sel_register_value(StringView reg) const;

    const String& name() const { return m_name; }
    void set_name(String name) { m_name = std::move(name); }

    bool is_editing() const { return m_edition_level!= 0; }
    void disable_undo_handling() { m_edition_level = -1; }

    NestedBool& hooks_disabled() { return m_hooks_disabled; }
    const NestedBool& hooks_disabled() const { return m_hooks_disabled; }

    NestedBool& keymaps_disabled() { return m_keymaps_disabled; }
    const NestedBool& keymaps_disabled() const { return m_keymaps_disabled; }

    NestedBool& history_disabled() { return m_history_disabled; }
    const NestedBool& history_disabled() const { return m_history_disabled; }

    Flags flags() const { return m_flags; }

    JumpList& jump_list() { return m_jump_list; }
    void push_jump() { m_jump_list.push(selections()); }

private:
    void begin_edition();
    void end_edition();
    int m_edition_level = 0;

    friend struct ScopedEdition;

    Flags m_flags;

    SafePtr<InputHandler> m_input_handler;
    SafePtr<Window>       m_window;
    SafePtr<Client>       m_client;

    Optional<SelectionList> m_selections;

    String m_name;

    JumpList m_jump_list;

    NestedBool m_hooks_disabled;
    NestedBool m_keymaps_disabled;
    NestedBool m_history_disabled;
};

template<>
struct WithBitOps<Context::Flags> : std::true_type {};

struct ScopedEdition
{
    ScopedEdition(Context& context)
        : m_context(context), m_buffer(&context.buffer())
    { m_context.begin_edition(); }

    ~ScopedEdition() { m_context.end_edition(); }

    Context& context() const { return m_context; }
private:
    Context& m_context;
    SafePtr<Buffer> m_buffer;
};

}
#endif // context_hh_INCLUDED
<commit_msg>Small formatting fixup<commit_after>#ifndef context_hh_INCLUDED
#define context_hh_INCLUDED

#include "selection.hh"
#include "optional.hh"
#include "flags.hh"

namespace Kakoune
{

class Window;
class Buffer;
class Client;
class Scope;
class InputHandler;
class UserInterface;
class DisplayLine;
class KeymapManager;
class AliasRegistry;

// bool that can be set (to true) multiple times, and will
// be false only when unset the same time;
struct NestedBool
{
    void set() { m_count++; }
    void unset() { kak_assert(m_count > 0); m_count--; }

    operator bool() const { return m_count > 0; }
private:
    int m_count = 0;
};

struct ScopedSetBool
{
    ScopedSetBool(NestedBool& nested_bool, bool condition = true)
        : m_nested_bool(nested_bool), m_condition(condition)
    {
        if (m_condition)
            m_nested_bool.set();
    }

    ~ScopedSetBool()
    {
        if (m_condition)
            m_nested_bool.unset();
    }

private:
    NestedBool& m_nested_bool;
    bool m_condition;
};

struct JumpList
{
    void push(SelectionList jump);
    const SelectionList& forward();
    const SelectionList& backward(const SelectionList& current);
    void forget_buffer(Buffer& buffer);

    friend bool operator==(const JumpList& lhs, const JumpList& rhs)
    {
        return lhs.m_jumps == rhs.m_jumps and lhs.m_current == rhs.m_current;
    }

    friend bool operator!=(const JumpList& lhs, const JumpList& rhs) { return not (lhs == rhs); }

private:
    using Contents = Vector<SelectionList, MemoryDomain::Selections>;
    Contents m_jumps;
    size_t m_current = 0;
};

// A Context is used to access non singleton objects for various services
// in commands.
//
// The Context object links a Client, a Window, an InputHandler and a
// SelectionList. It may represent an interactive user window, a hook
// execution or a macro replay context.
class Context
{
public:
    enum class Flags
    {
        None = 0,
        Transient = 1,
    };

    Context(InputHandler& input_handler, SelectionList selections,
            Flags flags, String name = "");

    struct EmptyContextFlag {};
    explicit Context(EmptyContextFlag);
    ~Context();

    Context(const Context&) = delete;
    Context& operator=(const Context&) = delete;

    Buffer& buffer() const;
    bool has_buffer() const { return (bool)m_selections; }

    Window& window() const;
    bool has_window() const { return (bool)m_window; }

    Client& client() const;
    bool has_client() const { return (bool)m_client; }

    InputHandler& input_handler() const;
    bool has_input_handler() const { return (bool)m_input_handler; }

    SelectionList& selections();
    const SelectionList& selections() const;
    Vector<String>  selections_content() const;

    // Return potentially out of date selections
    SelectionList& selections_write_only();

    void change_buffer(Buffer& buffer);

    void set_client(Client& client);
    void set_window(Window& window);

    Scope& scope() const;

    OptionManager& options() const { return scope().options(); }
    HookManager& hooks()     const { return scope().hooks(); }
    KeymapManager& keymaps() const { return scope().keymaps(); }
    AliasRegistry& aliases() const { return scope().aliases(); }

    void print_status(DisplayLine status) const;

    StringView main_sel_register_value(StringView reg) const;

    const String& name() const { return m_name; }
    void set_name(String name) { m_name = std::move(name); }

    bool is_editing() const { return m_edition_level!= 0; }
    void disable_undo_handling() { m_edition_level = -1; }

    NestedBool& hooks_disabled() { return m_hooks_disabled; }
    const NestedBool& hooks_disabled() const { return m_hooks_disabled; }

    NestedBool& keymaps_disabled() { return m_keymaps_disabled; }
    const NestedBool& keymaps_disabled() const { return m_keymaps_disabled; }

    NestedBool& history_disabled() { return m_history_disabled; }
    const NestedBool& history_disabled() const { return m_history_disabled; }

    Flags flags() const { return m_flags; }

    JumpList& jump_list() { return m_jump_list; }
    void push_jump() { m_jump_list.push(selections()); }

private:
    void begin_edition();
    void end_edition();
    int m_edition_level = 0;

    friend struct ScopedEdition;

    Flags m_flags;

    SafePtr<InputHandler> m_input_handler;
    SafePtr<Window>       m_window;
    SafePtr<Client>       m_client;

    Optional<SelectionList> m_selections;

    String m_name;

    JumpList m_jump_list;

    NestedBool m_hooks_disabled;
    NestedBool m_keymaps_disabled;
    NestedBool m_history_disabled;
};

template<>
struct WithBitOps<Context::Flags> : std::true_type {};

struct ScopedEdition
{
    ScopedEdition(Context& context)
        : m_context(context), m_buffer(&context.buffer())
    { m_context.begin_edition(); }

    ~ScopedEdition() { m_context.end_edition(); }

    Context& context() const { return m_context; }
private:
    Context& m_context;
    SafePtr<Buffer> m_buffer;
};

}
#endif // context_hh_INCLUDED
<|endoftext|>


<commit_before>#include <string>

// chilitags
#include <DetectChilitags.hpp>
#include <Objects.hpp>

// opencv2
#include <opencv2/core/core.hpp>

// ROS
#include <ros/ros.h>
#include <tf/transform_broadcaster.h>
#include <image_transport/image_transport.h>
#include <image_geometry/pinhole_camera_model.h>
#include <cv_bridge/cv_bridge.h>

#ifdef WITH_KNOWLEDGE
#include <liboro/oro.h>
#include <liboro/socket_connector.h>
#endif

using namespace std;
using namespace cv;

class ChilitagsDetector
{
public:
    ChilitagsDetector(ros::NodeHandle& rosNode, const string& camera_frame, const string& configFilename, double squareSize, double gain = 0.9) :
            rosNode(rosNode),
            it(rosNode),
            camera_frame(camera_frame),
            detector(&inputImage),
            firstUncalibratedImage(true),
#ifdef WITH_KNOWLEDGE
            connector("localhost", "6969"),
#endif
            objects(cv::noArray(), cv::noArray(), configFilename, squareSize, gain)
    {
#ifdef WITH_KNOWLEDGE
        try {
            kb = oro::Ontology::createWithConnector(connector);
        } catch (oro::OntologyServerException ose) {
            ROS_ERROR_STREAM("Could not connect to the knowledge base: " << ose.what());
            exit(1);
        }
#endif
        sub = it.subscribeCamera("image", 1, &ChilitagsDetector::findMarkers, this);
    }

private:

#ifdef WITH_KNOWLEDGE
    oro::SocketConnector connector;
    oro::Ontology* kb;
#endif

    ros::NodeHandle& rosNode;
    image_transport::ImageTransport it;
    image_transport::CameraSubscriber sub;

    tf::TransformBroadcaster br;
    tf::Transform transform;
    string camera_frame;

    image_geometry::PinholeCameraModel cameramodel;
    Mat cameraMatrix, distCoeffs;
    bool firstUncalibratedImage;

    Mat inputImage;
    chilitags::DetectChilitags detector;
    chilitags::Objects objects;
    set<string> objectsSeen;

    void setROSTransform(Matx44d trans, tf::Transform& transform)
    {
        transform.setOrigin( tf::Vector3( trans(0,3) / 1000,
                                        trans(1,3) / 1000,
                                        trans(2,3) / 1000) );

        tf::Quaternion qrot;
        tf::Matrix3x3 mrot(
            trans(0,0), trans(0,1), trans(0,2),
            trans(1,0), trans(1,1), trans(1,2),
            trans(2,0), trans(2,1), trans(2,2));
        mrot.getRotation(qrot);
        transform.setRotation(qrot);
    }

    void findMarkers(const sensor_msgs::ImageConstPtr& msg, const sensor_msgs::CameraInfoConstPtr& camerainfo)
    {
        // updating the camera model is cheap if not modified
        cameramodel.fromCameraInfo(camerainfo);
        // publishing uncalibrated images? -> return (according to CameraInfo message documentation,
        // K[0] == 0.0 <=> uncalibrated).
        if(cameramodel.intrinsicMatrix()(0,0) == 0.0) {
            if(firstUncalibratedImage) {
                ROS_ERROR("Camera publishes uncalibrated images. Can not detect markers.");
                ROS_WARN("Detection will start over again when camera info is available.");
            }
            firstUncalibratedImage = false;
            return;
        }
        firstUncalibratedImage = true;
        // TODO: can we avoid to re-set the calibration matrices for every frame? ie,
        // how to know that the camera info has changed?
        objects.resetCalibration(cameramodel.intrinsicMatrix(),
                                    cameramodel.distortionCoeffs());

        // hopefully no copy here:
        //  - assignement operator of cv::Mat does not copy the data
        //  - toCvShare does no copy if the default (source) encoding is used.
        inputImage = cv_bridge::toCvShare(msg)->image;

         /********************************************************************
         *                      Markers detection                           *
         ********************************************************************/
        detector.update();

        auto foundObjects = objects.all();
        ROS_DEBUG_STREAM(foundObjects.size() << " objects found.");

        /****************************************************************
        *                Publish TF transforms                          *
        *****************************************************************/

#ifdef WITH_KNOWLEDGE
        auto previouslySeen(objectsSeen);
#endif
        objectsSeen.clear();

        for (auto& kv : foundObjects) {

            objectsSeen.insert(kv.first);
            setROSTransform(kv.second,
                            transform);

            br.sendTransform(
                    tf::StampedTransform(transform,
                                         ros::Time::now(),
                                         camera_frame,
                                         kv.first));
        }

#ifdef WITH_KNOWLEDGE
        set<oro::Statement> stmts;
        for(const auto& obj : objectsSeen) {
            stmts.insert(obj + " isVisible true");
            stmts.insert(obj + " rdf:type FiducialMarker");
        }
        if (!stmts.empty()) kb->add(stmts);

        stmts.clear();
        for (const auto& pobj : previouslySeen) {
            if (objectsSeen.find(pobj) == objectsSeen.end()) {
                stmts.insert(pobj + " isVisible true");
            }
        }
        if (!stmts.empty()) kb->remove(stmts);
#endif

    }
};

int main(int argc, char* argv[])
{
    //ROS initialization
    ros::init(argc, argv, "ros_markers");
    ros::NodeHandle rosNode;
    ros::NodeHandle _private_node("~");

    // load parameters
    string configFilename;
    _private_node.param<string>("markers_configuration", configFilename, "");
    double squareSize, gain;
    _private_node.param<double>("default_marker_size", squareSize, 50.);
    _private_node.param<double>("gain", gain, 0.9);

    string camera_frame;
    _private_node.param<string>("camera_frame_id", camera_frame, "camera");

    if (configFilename.empty() && squareSize == 0.) {
        ROS_ERROR_STREAM("Either a marker configuration file or a default marker size\n" <<
                         "must be passed as parameter (both are also ok).");
        return(1);
    }

    // initialize the detector by subscribing to the camera video stream
    ChilitagsDetector detector(rosNode, camera_frame, configFilename, squareSize, gain);
    ROS_INFO("ros_markers is ready. Marker locations will be published on TF when detected.");

    ros::spin();

    return 0;
}

<commit_msg>[tentative] Future date markers transformation<commit_after>#include <string>

// chilitags
#include <DetectChilitags.hpp>
#include <Objects.hpp>

// opencv2
#include <opencv2/core/core.hpp>

// ROS
#include <ros/ros.h>
#include <tf/transform_broadcaster.h>
#include <image_transport/image_transport.h>
#include <image_geometry/pinhole_camera_model.h>
#include <cv_bridge/cv_bridge.h>

#ifdef WITH_KNOWLEDGE
#include <liboro/oro.h>
#include <liboro/socket_connector.h>
#endif

using namespace std;
using namespace cv;

// how many second in the *future* the markers transformation should be published?
// this allow to compensate for the 'slowness' of tag detection, but introduce
// some lag in TF.
#define TRANSFORM_FUTURE_DATING 0.5

class ChilitagsDetector
{
public:
    ChilitagsDetector(ros::NodeHandle& rosNode, const string& camera_frame, const string& configFilename, double squareSize, double gain = 0.9) :
            rosNode(rosNode),
            it(rosNode),
            camera_frame(camera_frame),
            detector(&inputImage),
            firstUncalibratedImage(true),
#ifdef WITH_KNOWLEDGE
            connector("localhost", "6969"),
#endif
            objects(cv::noArray(), cv::noArray(), configFilename, squareSize, gain)
    {
#ifdef WITH_KNOWLEDGE
        try {
            kb = oro::Ontology::createWithConnector(connector);
        } catch (oro::OntologyServerException ose) {
            ROS_ERROR_STREAM("Could not connect to the knowledge base: " << ose.what());
            exit(1);
        }
#endif
        sub = it.subscribeCamera("image", 1, &ChilitagsDetector::findMarkers, this);
    }

private:

#ifdef WITH_KNOWLEDGE
    oro::SocketConnector connector;
    oro::Ontology* kb;
#endif

    ros::NodeHandle& rosNode;
    image_transport::ImageTransport it;
    image_transport::CameraSubscriber sub;

    tf::TransformBroadcaster br;
    tf::Transform transform;
    string camera_frame;

    image_geometry::PinholeCameraModel cameramodel;
    Mat cameraMatrix, distCoeffs;
    bool firstUncalibratedImage;

    Mat inputImage;
    chilitags::DetectChilitags detector;
    chilitags::Objects objects;
    set<string> objectsSeen;

    void setROSTransform(Matx44d trans, tf::Transform& transform)
    {
        transform.setOrigin( tf::Vector3( trans(0,3) / 1000,
                                        trans(1,3) / 1000,
                                        trans(2,3) / 1000) );

        tf::Quaternion qrot;
        tf::Matrix3x3 mrot(
            trans(0,0), trans(0,1), trans(0,2),
            trans(1,0), trans(1,1), trans(1,2),
            trans(2,0), trans(2,1), trans(2,2));
        mrot.getRotation(qrot);
        transform.setRotation(qrot);
    }

    void findMarkers(const sensor_msgs::ImageConstPtr& msg, const sensor_msgs::CameraInfoConstPtr& camerainfo)
    {
        // updating the camera model is cheap if not modified
        cameramodel.fromCameraInfo(camerainfo);
        // publishing uncalibrated images? -> return (according to CameraInfo message documentation,
        // K[0] == 0.0 <=> uncalibrated).
        if(cameramodel.intrinsicMatrix()(0,0) == 0.0) {
            if(firstUncalibratedImage) {
                ROS_ERROR("Camera publishes uncalibrated images. Can not detect markers.");
                ROS_WARN("Detection will start over again when camera info is available.");
            }
            firstUncalibratedImage = false;
            return;
        }
        firstUncalibratedImage = true;
        // TODO: can we avoid to re-set the calibration matrices for every frame? ie,
        // how to know that the camera info has changed?
        objects.resetCalibration(cameramodel.intrinsicMatrix(),
                                    cameramodel.distortionCoeffs());

        // hopefully no copy here:
        //  - assignement operator of cv::Mat does not copy the data
        //  - toCvShare does no copy if the default (source) encoding is used.
        inputImage = cv_bridge::toCvShare(msg)->image;

         /********************************************************************
         *                      Markers detection                           *
         ********************************************************************/
        detector.update();

        auto foundObjects = objects.all();
        ROS_DEBUG_STREAM(foundObjects.size() << " objects found.");

        /****************************************************************
        *                Publish TF transforms                          *
        *****************************************************************/

#ifdef WITH_KNOWLEDGE
        auto previouslySeen(objectsSeen);
#endif
        objectsSeen.clear();

        for (auto& kv : foundObjects) {

            objectsSeen.insert(kv.first);
            setROSTransform(kv.second,
                            transform);

            br.sendTransform(
                    tf::StampedTransform(transform,
                                         ros::Time::now() + ros::Duration(TRANSFORM_FUTURE_DATING),
                                         camera_frame,
                                         kv.first));
        }

#ifdef WITH_KNOWLEDGE
        set<oro::Statement> stmts;
        for(const auto& obj : objectsSeen) {
            stmts.insert(obj + " isVisible true");
            stmts.insert(obj + " rdf:type FiducialMarker");
        }
        if (!stmts.empty()) kb->add(stmts);

        stmts.clear();
        for (const auto& pobj : previouslySeen) {
            if (objectsSeen.find(pobj) == objectsSeen.end()) {
                stmts.insert(pobj + " isVisible true");
            }
        }
        if (!stmts.empty()) kb->remove(stmts);
#endif

    }
};

int main(int argc, char* argv[])
{
    //ROS initialization
    ros::init(argc, argv, "ros_markers");
    ros::NodeHandle rosNode;
    ros::NodeHandle _private_node("~");

    // load parameters
    string configFilename;
    _private_node.param<string>("markers_configuration", configFilename, "");
    double squareSize, gain;
    _private_node.param<double>("default_marker_size", squareSize, 50.);
    _private_node.param<double>("gain", gain, 0.9);

    string camera_frame;
    _private_node.param<string>("camera_frame_id", camera_frame, "camera");

    if (configFilename.empty() && squareSize == 0.) {
        ROS_ERROR_STREAM("Either a marker configuration file or a default marker size\n" <<
                         "must be passed as parameter (both are also ok).");
        return(1);
    }

    // initialize the detector by subscribing to the camera video stream
    ChilitagsDetector detector(rosNode, camera_frame, configFilename, squareSize, gain);
    ROS_INFO("ros_markers is ready. Marker locations will be published on TF when detected.");

    ros::spin();

    return 0;
}

<|endoftext|>


<commit_before>#include <freertos/FreeRTOS.h>
#include <freertos/queue.h>
#include <nvs_flash.h>

#include "Motors_Controller.h"
#include "IMU_Detector.h"
#include "Mahony_Filter.h"
#include "Complementary_Filter.h"
#include "WiFi_Controller.h"

using namespace flyhero;

Motors_Controller &motors_controller = Motors_Controller::Instance();
QueueHandle_t wifi_log_data_queue;

void wifi_task(void *args);
void imu_task(void *args);

extern "C" void app_main(void)
{
    // Initialize NVS
    esp_err_t nvs_status = nvs_flash_init();

    if (nvs_status == ESP_ERR_NVS_NO_FREE_PAGES)
    {
        ESP_ERROR_CHECK(nvs_flash_erase());
        nvs_status = nvs_flash_init();
    }

    ESP_ERROR_CHECK(nvs_status);

    LEDs::Init();

    motors_controller.Init();

    wifi_log_data_queue = xQueueCreate(2, sizeof(WiFi_Controller::Out_Datagram_Data));

    xTaskCreatePinnedToCore(wifi_task, "WiFi task", 4096, NULL, 2, NULL, 1);
    xTaskCreatePinnedToCore(imu_task, "IMU task", 4096, NULL, 2, NULL, 0);

    while (true);
}

void imu_task(void *args)
{
    IMU::Sensor_Data accel, gyro;
    IMU::Euler_Angles mahony_euler, complementary_euler;

    IMU *imu;
    ESP_ERROR_CHECK(IMU_Detector::Detect_IMU(&imu));

    Mahony_Filter mahony(2, 0.1f, imu->Get_Sample_Rate());
    Complementary_Filter complementary(0.995f, imu->Get_Sample_Rate());

    imu->Init();

    WiFi_Controller::Out_Datagram_Data log_data;

    timeval start, end;
    uint8_t i = 0;

    while (true)
    {
        if (imu->Data_Ready())
        {
            gettimeofday(&end, NULL);

            imu->Read_Data(accel, gyro);

            mahony.Compute(accel, gyro, mahony_euler);
            complementary.Compute(accel, gyro, complementary_euler);

            i++;

            if (i == 100)
            {
                log_data.euler[0] = mahony_euler;
                log_data.euler[1] = complementary_euler;
                log_data.free_time = end.tv_usec - start.tv_usec;

                xQueueSend(wifi_log_data_queue, &log_data, 0);
                i = 0;
            }

            motors_controller.Update_Motors(mahony_euler);

            gettimeofday(&start, NULL);
        }
    }
}

void wifi_task(void *args)
{
    WiFi_Controller &wifi = WiFi_Controller::Instance();

    WiFi_Controller::In_Datagram_Data in_datagram_data;
    WiFi_Controller::Out_Datagram_Data out_datagram_data;

    wifi.Init();

    while (true)
    {
        if (wifi.Receive(in_datagram_data))
        {
            motors_controller.Set_Throttle(in_datagram_data.throttle);
            motors_controller.Set_PID_Constants(Roll, 1, 0, 0);
            motors_controller.Set_PID_Constants(Pitch, 1, 0, 0);
        }

        if (xQueueReceive(wifi_log_data_queue, &out_datagram_data, 0) == pdTRUE)
        {
            wifi.Send(out_datagram_data);
        }
    }
}
<commit_msg>(The Eye): Changes in UDP protocol (CPU free time bytes)<commit_after>#include <freertos/FreeRTOS.h>
#include <freertos/queue.h>
#include <nvs_flash.h>

#include "Motors_Controller.h"
#include "IMU_Detector.h"
#include "Mahony_Filter.h"
#include "Complementary_Filter.h"
#include "WiFi_Controller.h"

using namespace flyhero;

Motors_Controller &motors_controller = Motors_Controller::Instance();
QueueHandle_t wifi_log_data_queue;

void wifi_task(void *args);
void imu_task(void *args);

extern "C" void app_main(void)
{
    // Initialize NVS
    esp_err_t nvs_status = nvs_flash_init();

    if (nvs_status == ESP_ERR_NVS_NO_FREE_PAGES)
    {
        ESP_ERROR_CHECK(nvs_flash_erase());
        nvs_status = nvs_flash_init();
    }

    ESP_ERROR_CHECK(nvs_status);

    LEDs::Init();

    motors_controller.Init();

    wifi_log_data_queue = xQueueCreate(2, sizeof(WiFi_Controller::Out_Datagram_Data));

    xTaskCreatePinnedToCore(wifi_task, "WiFi task", 4096, NULL, 2, NULL, 1);
    xTaskCreatePinnedToCore(imu_task, "IMU task", 4096, NULL, 2, NULL, 0);

    while (true);
}

void imu_task(void *args)
{
    IMU::Sensor_Data accel, gyro;
    IMU::Euler_Angles mahony_euler, complementary_euler;

    IMU *imu;
    ESP_ERROR_CHECK(IMU_Detector::Detect_IMU(&imu));

    Mahony_Filter mahony(2, 0.1f, imu->Get_Sample_Rate());
    Complementary_Filter complementary(0.995f, imu->Get_Sample_Rate());

    imu->Init();

    WiFi_Controller::Out_Datagram_Data log_data;

    timeval start, end;
    uint8_t i = 0;

    while (true)
    {
        if (imu->Data_Ready())
        {
            gettimeofday(&end, NULL);

            imu->Read_Data(accel, gyro);

            mahony.Compute(accel, gyro, mahony_euler);
            complementary.Compute(accel, gyro, complementary_euler);

            i++;

            if (i == 100)
            {
                log_data.euler[0] = mahony_euler;
                log_data.euler[1] = complementary_euler;

                long int delta = (end.tv_usec > start.tv_usec ? end.tv_usec - start.tv_usec
                                                    : 1000000 - end.tv_usec + start.tv_usec);

                log_data.free_time = delta * imu->Get_Sample_Rate() * 0.01f;

                xQueueSend(wifi_log_data_queue, &log_data, 0);
                i = 0;
            }

            motors_controller.Update_Motors(mahony_euler);

            gettimeofday(&start, NULL);
        }
    }
}

void wifi_task(void *args)
{
    WiFi_Controller &wifi = WiFi_Controller::Instance();

    WiFi_Controller::In_Datagram_Data in_datagram_data;
    WiFi_Controller::Out_Datagram_Data out_datagram_data;

    wifi.Init();

    while (true)
    {
        if (wifi.Receive(in_datagram_data))
        {
            motors_controller.Set_Throttle(in_datagram_data.throttle);
            motors_controller.Set_PID_Constants(Roll, 1, 0, 0);
            motors_controller.Set_PID_Constants(Pitch, 1, 0, 0);
        }

        if (xQueueReceive(wifi_log_data_queue, &out_datagram_data, 0) == pdTRUE)
        {
            wifi.Send(out_datagram_data);
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015-2018 Muhammad Tayyab Akram
 *
 * 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.
 */

#include <Parser/ArabicShaping.h>

#include "AlbumTester.h"
#include "FontTester.h"
#include "JoiningTypeLookupTester.h"
#include "ListTester.h"
#include "LocatorTester.h"
#include "PatternTester.h"
#include "SchemeTester.h"
#include "TextProcessorTester.h"

using namespace std;
using namespace SheenFigure::Parser;
using namespace SheenFigure::Tester;

int main(int argc, const char * argv[])
{
    const char *dir = argv[1];

    ArabicShaping arabicShaping(dir);
    JoiningTypeLookupTester joiningTypeLookupTester(arabicShaping);
    ListTester listTester;
    AlbumTester albumTester;
    LocatorTester locatorTester;
    FontTester fontTester;
    PatternTester patternTester;
    SchemeTester schemeTester;
    TextProcessorTester textProcessorTester;

    albumTester.test();
    fontTester.test();
    joiningTypeLookupTester.test();
    listTester.test();
    locatorTester.test();
    patternTester.test();
    schemeTester.test();
    textProcessorTester.test();

    return 0;
}
<commit_msg>[test] Called misc tester from main function<commit_after>/*
 * Copyright (C) 2015-2018 Muhammad Tayyab Akram
 *
 * 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.
 */

#include <Parser/ArabicShaping.h>

#include "AlbumTester.h"
#include "FontTester.h"
#include "JoiningTypeLookupTester.h"
#include "ListTester.h"
#include "LocatorTester.h"
#include "MiscTester.h"
#include "PatternTester.h"
#include "SchemeTester.h"
#include "TextProcessorTester.h"

using namespace std;
using namespace SheenFigure::Parser;
using namespace SheenFigure::Tester;

int main(int argc, const char * argv[])
{
    const char *dir = argv[1];

    ArabicShaping arabicShaping(dir);
    JoiningTypeLookupTester joiningTypeLookupTester(arabicShaping);
    ListTester listTester;
    AlbumTester albumTester;
    LocatorTester locatorTester;
    FontTester fontTester;
    PatternTester patternTester;
    SchemeTester schemeTester;
    TextProcessorTester textProcessorTester;
    MiscTester miscTester;

    albumTester.test();
    fontTester.test();
    joiningTypeLookupTester.test();
    listTester.test();
    locatorTester.test();
    patternTester.test();
    schemeTester.test();
    textProcessorTester.test();
    miscTester.test();

    return 0;
}
<|endoftext|>


<commit_before>#include <iostream>

#include "driver.h"

extern FILE *yyin;
extern void *yy_scan_string(const char *yy_str, yyscan_t yyscanner);
extern void yyset_in(FILE *_in_str, yyscan_t yyscanner);
extern int yylex_init(yyscan_t *scanner);
extern int yylex_destroy (yyscan_t yyscanner);

namespace bpftrace {

Driver::Driver(BPFtrace &bpftrace) : bpftrace_(bpftrace)
{
  yylex_init(&scanner_);
  parser_ = std::make_unique<Parser>(*this, scanner_);
}

Driver::~Driver()
{
  yylex_destroy(scanner_);
}

int Driver::parse_stdin()
{
  return parser_->parse();
}

int Driver::parse_str(const std::string &script)
{
  yy_scan_string(script.c_str(), scanner_);
  int result = parser_->parse();
  return result;
}

int Driver::parse_file(const std::string &f)
{
  FILE *file;
  if (!(file = fopen(f.c_str(), "r"))) {
    std::cerr << "Error: Could not open file '" << f << "'" << std::endl;
    return -1;
  }
  yyset_in(file, scanner_);
  int result = parser_->parse();
  fclose(file);
  return result;
}

void Driver::error(const location &l, const std::string &m)
{
  std::cerr << l << ": " << m << std::endl;
}

void Driver::error(const std::string &m)
{
  std::cerr << m << std::endl;
}

} // namespace bpftrace
<commit_msg>More information in error message when failing to open script file<commit_after>#include <iostream>

#include "driver.h"

extern FILE *yyin;
extern void *yy_scan_string(const char *yy_str, yyscan_t yyscanner);
extern void yyset_in(FILE *_in_str, yyscan_t yyscanner);
extern int yylex_init(yyscan_t *scanner);
extern int yylex_destroy (yyscan_t yyscanner);

namespace bpftrace {

Driver::Driver(BPFtrace &bpftrace) : bpftrace_(bpftrace)
{
  yylex_init(&scanner_);
  parser_ = std::make_unique<Parser>(*this, scanner_);
}

Driver::~Driver()
{
  yylex_destroy(scanner_);
}

int Driver::parse_stdin()
{
  return parser_->parse();
}

int Driver::parse_str(const std::string &script)
{
  yy_scan_string(script.c_str(), scanner_);
  int result = parser_->parse();
  return result;
}

int Driver::parse_file(const std::string &f)
{
  FILE *file;
  if (!(file = fopen(f.c_str(), "r"))) {
    auto msg = "Error opening file '" + f + "'";
    perror(msg.c_str());
    return -1;
  }
  yyset_in(file, scanner_);
  int result = parser_->parse();
  fclose(file);
  return result;
}

void Driver::error(const location &l, const std::string &m)
{
  std::cerr << l << ": " << m << std::endl;
}

void Driver::error(const std::string &m)
{
  std::cerr << m << std::endl;
}

} // namespace bpftrace
<|endoftext|>


<commit_before>/***********************************************************************
 *                                                                   _
 *       _____  _                           ____  _                 |_|
 *      |  _  |/ \   ____  ____ __ ___     / ___\/ \   __   _  ____  _
 *      | |_| || |  / __ \/ __ \\ '_  \ _ / /    | |___\ \ | |/ __ \| |
 *      |  _  || |__. ___/. ___/| | | ||_|\ \___ |  _  | |_| |. ___/| |
 *      |_/ \_|\___/\____|\____||_| |_|    \____/|_| |_|_____|\____||_|
 *
 *      ================================================================
 *                 More than a coder, More than a designer
 *      ================================================================
 *
 *
 *      - Document: image.cpp
 *      - Author: aleen42
 *      - Description: image class for all the image obj
 *      - Create Time: Nov 29th, 2015
 *      - Update Time: Feb 18th, 2016
 *
 **********************************************************************/

#include "opencv_main.h"
#include "common.h"

class Image
{
protected:
	Mat img;											// the container of the image
	const char* path;									// the local path of the image

	/* calculate the angle according to 3 points */
	double angle(Point pt1, Point pt2, Point pt0) {
		double dx1 = pt1.x - pt0.x;
		double dy1 = pt1.y - pt0.y;
		double dx2 = pt2.x - pt0.x;
		double dy2 = pt2.y - pt0.y;
		return (dx1 * dx2 + dy1 * dy2) / sqrt((dx1 * dx1 + dy1 * dy1) * (dx2 * dx2 + dy2 * dy2) + 1e-10);
	}

	/* show the detection of squares */
	void debugSquares(vector<vector<Point> > points) {

		for (int i = 0; i < points[0].size(); i++) {
			printf("Point%d: (%d, %d)\n", i, points[0][i].x, points[0][i].y);
		}

		drawContours(img, points, 0, Scalar(255, 0, 0), 1, 8, vector<Vec4i>(), 0, Point());
		// for (int i = 0; i < points.size(); i++) {
		// 	/* draw contour */
		// 	drawContours(img, points, i, Scalar(255, 0, 0), 1, 8, vector<Vec4i>(), 0, Point());

		// 	/* draw bounding rect */
		// 	Rect rect = boundingRect(Mat(points[i]));
		// 	rectangle(img, rect.tl(), rect.br(), cv::Scalar(255, 0, 0), 2, 8, 0);

		// 	/* draw rotated rect */
		// 	RotatedRect minRect = minAreaRect(Mat(points[i]));
		// 	Point2f rect_points[4];
		// 	minRect.points(rect_points);
		// 	for (int j = 0; j < 4; j++) {
		// 		line(img, rect_points[j], rect_points[(j + 1) % 4], Scalar(0, 0, 255), 1, 8);
		// 	}
		// }
	}
public:
	/* constructors of the class */
	Image() {}
	Image(Mat img) : img(img){}

	/* read the image from a local path */
	void readImage(const char* path) {
		/* set the path */
		this->path = path;
		/* read the image according to the path */
		this->img = imread(path);
		/* check existence */
		if (this->img.empty()) {
			ostringstream os;
			os << "Cannot load image from" << path;
			Common::errorPrint(os.str().c_str());
			/* exit */
			exit(-1);
		}
	}

	/* threshold algorithm */
	void thresholdImage(THRESHOLD_TYPE type) {
		Mat gray;
		const double threshold_value = 0.0;
		const double max_binary_value = 255.0;

		/* convert gray */
		cvtColor(this->img, gray, CV_BGR2GRAY);

		threshold(gray, this->img, threshold_value, max_binary_value, type);
	}

	/* detect squares algorithm by karlphillip */
	vector<vector<Point> > detectSquare(bool debug = false) {
		/* blur will enhance edge detection */
		Mat blurred(this->img);

		medianBlur(this->img, blurred, 9);

		Mat gray0(blurred.size(), CV_8U), gray;

		/* reserved Points array */
		vector<vector<Point> > reserved;
		/* contours Points array*/
		vector<vector<Point> > contours;

		/* find squares in every color plane of the image */
		for (int c = 0; c < 3; c++) {
			int ch[] = { c, 0 };

			/* canny ratio which is recommended as 3 by Canny */
			int ratio = 2;
			int lowThreshold = 10;

			mixChannels(&blurred, 1, &gray0, 1, ch, 1);

			/* try several threshold level */
			const int threshold_level = 2;
			for (int l = 0; l < threshold_level; l++) {
				/* Use Canny instead of zero threshold level */
				/* Canny helps to catch squares with gradient shading */
				if (l == 0) {
					Canny(gray0, gray, lowThreshold, ratio * lowThreshold, 3);

					/* Dilage helps to remove potential holes between edge segments */
					dilate(gray, gray, Mat(), Point(-1, -1));
				} else {
					gray = gray0 >= (l + 1) * 255 / threshold_level;
				}

				vector<Vec4i> hierarchy;
				/* find contours and store them in a list */
				findContours(gray, contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

				/* draw contours to improve accuracy */
				for (size_t i = 0; i < contours.size(); i++) {
					drawContours(this->img, contours, i, Scalar(0, 0, 0), 1, 8, hierarchy, 0, Point());
				}

				/* test contours */
				vector<Point> approx;
				for (size_t i = 0; i < contours.size(); i++) {
					/* approximate contour with accuracy proportional to the contour perimeter */
					approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true) * 0.02, true);

					/*
					 * Note: absolute value of an area is used becuase
					 *       area may be positive or negative, in accordance
					 *		 with the contour orientation
					 */
					// cout << "size: " << approx.size() << endl;
					// cout << "area: " << fabs(contourArea(Mat(approx))) << endl;
					if (approx.size() == 4 && fabs(contourArea(Mat(approx))) > 1000 && isContourConvex(Mat(approx))) {
						double maxCosine = 0;

						for (int j = 2; j < 5; j++) {
							double cosine = fabs(angle(approx[j % 4], approx[j - 2], approx[j - 1]));
							maxCosine = MAX(maxCosine, cosine);
						}

						reserved.push_back(approx);

						//if (maxCosine < 0.3) {
						//	reserved.push_back(approx);
						//}
					}
				}
			}
		}

		/* check debug option */
 		if (debug && reserved.size() > 0) {
			debugSquares(reserved);
		}

		return reserved;
	}

	/* detect corner */
	vector<Point2f> detectCorner(const char* quantity, bool debug = false, const char* path = "data.json") {
		/* clock */
		time_t start = clock();

		vector<Point2f> Corners;

		/* parameters */
		const int maxCorners = atoi(quantity);
		const double qualityLevels = 0.001;
		const double minDistance = 10;
		const int blockSize = 10;
		const bool useHarrisDetector = false;
		const int r = 5;

		Mat gray;
		cvtColor(this->img, gray, COLOR_BGR2GRAY);

		goodFeaturesToTrack(gray, Corners, maxCorners, qualityLevels, minDistance, Mat(), blockSize, useHarrisDetector);

		cJSON* pointsArray = cJSON_CreateArray();

		for (size_t i = 0; i < Corners.size(); i++) {
			if (debug) {
				ostringstream os;
				os << " (" << Corners[i].x << ", " << Corners[i].y << ")";
				circle(this->img, Corners[i], r, Scalar(255, 255, 255), 2, 8);
				putText(this->img, os.str(), Corners[i], FONT_HERSHEY_SCRIPT_SIMPLEX, 0.6, Scalar(0, 0, 255), 1, 8);
			}

			/* create json */
			cJSON* item = cJSON_CreateObject();
			cJSON_AddNumberToObject(item, "x", (double)Corners[i].x / this->img.cols);
			cJSON_AddNumberToObject(item, "y", (double)Corners[i].y / this->img.rows);

			cJSON_AddItemToArray(pointsArray, item);
		}

		time_t end = clock();
		cJSON* data = cJSON_CreateObject();
		const char* duration = (Common::doubleToStr(double(end - start) / CLOCKS_PER_SEC) + "s").c_str();
		cJSON_AddStringToObject(data, "time", duration);

		cJSON_AddNumberToObject(data, "width", this->img.cols);
		cJSON_AddNumberToObject(data, "height", this->img.rows);

		/* write the data.json */
		ofstream file;
		file.open(path, ios::out);

		if (file.is_open()) {
			file << cJSON_Print(pointsArray);
			cJSON_AddItemToObject(data, "data", pointsArray);
			file.close();
		}

		Common::successPrint(data);

		return Corners;
	}

	void fastDetectCorner(bool debug = false) {
		vector<KeyPoint> keyPoints;

		FAST(this->img, keyPoints, 10, true, FastFeatureDetector::TYPE_7_12);

		if (debug) {
			drawKeypoints(this->img, keyPoints, this->img, Scalar(255, 255, 255), DrawMatchesFlags::DRAW_OVER_OUTIMG);
		}
	}

	/* write the image to the local path */
	void writeImage(const char* path) {
		/* save the image */
		imwrite(path, this->img);
	}

	/* a mothod to show the image */
	void showImage() {
		/* open the image */
		imshow("image", this->img);
		/* wait for the return */
		waitKey();
	}

	/* container */
	/* image */
	Mat getImage() {
		return this->img;
	}

	/* properties */
	/* width */
	int getWidth() {
		return this->img.cols;
	}

	/* height */
	int getHeight() {
		return this->img.rows;
	}

	/* size */
	Size getSize() {
		return this->img.size();
	}

	/* pointer to the matrix */
	uchar* getPtr(int n) {
		return this->img.ptr<uchar>(n);
	}
};
<commit_msg>update<commit_after>/***********************************************************************
 *                                                                   _
 *       _____  _                           ____  _                 |_|
 *      |  _  |/ \   ____  ____ __ ___     / ___\/ \   __   _  ____  _
 *      | |_| || |  / __ \/ __ \\ '_  \ _ / /    | |___\ \ | |/ __ \| |
 *      |  _  || |__. ___/. ___/| | | ||_|\ \___ |  _  | |_| |. ___/| |
 *      |_/ \_|\___/\____|\____||_| |_|    \____/|_| |_|_____|\____||_|
 *
 *      ================================================================
 *                 More than a coder, More than a designer
 *      ================================================================
 *
 *
 *      - Document: image.cpp
 *      - Author: aleen42
 *      - Description: image class for all the image obj
 *      - Create Time: Nov 29th, 2015
 *      - Update Time: Feb 18th, 2016
 *
 **********************************************************************/

#include "opencv_main.h"
#include "common.h"

class Image
{
protected:
	Mat img;											// the container of the image
	const char* path;									// the local path of the image

	/* calculate the angle according to 3 points */
	double angle(Point pt1, Point pt2, Point pt0) {
		double dx1 = pt1.x - pt0.x;
		double dy1 = pt1.y - pt0.y;
		double dx2 = pt2.x - pt0.x;
		double dy2 = pt2.y - pt0.y;
		return (dx1 * dx2 + dy1 * dy2) / sqrt((dx1 * dx1 + dy1 * dy1) * (dx2 * dx2 + dy2 * dy2) + 1e-10);
	}

	/* show the detection of squares */
	void debugSquares(vector<vector<Point> > points) {

		for (int i = 0; i < points[0].size(); i++) {
			printf("Point%d: (%d, %d)\n", i, points[0][i].x, points[0][i].y);
		}

		drawContours(img, points, 0, Scalar(255, 0, 0), 1, 8, vector<Vec4i>(), 0, Point());
		// for (int i = 0; i < points.size(); i++) {
		// 	/* draw contour */
		// 	drawContours(img, points, i, Scalar(255, 0, 0), 1, 8, vector<Vec4i>(), 0, Point());

		// 	/* draw bounding rect */
		// 	Rect rect = boundingRect(Mat(points[i]));
		// 	rectangle(img, rect.tl(), rect.br(), cv::Scalar(255, 0, 0), 2, 8, 0);

		// 	/* draw rotated rect */
		// 	RotatedRect minRect = minAreaRect(Mat(points[i]));
		// 	Point2f rect_points[4];
		// 	minRect.points(rect_points);
		// 	for (int j = 0; j < 4; j++) {
		// 		line(img, rect_points[j], rect_points[(j + 1) % 4], Scalar(0, 0, 255), 1, 8);
		// 	}
		// }
	}
public:
	/* constructors of the class */
	Image() {}
	Image(Mat img) : img(img){}

	/* read the image from a local path */
	void readImage(const char* path) {
		/* set the path */
		this->path = path;
		/* read the image according to the path */
		this->img = imread(path);
		/* check existence */
		if (this->img.empty()) {
			ostringstream os;
			os << "Cannot load image from" << path;
			Common::errorPrint(os.str().c_str());
			/* exit */
			exit(-1);
		}
	}

	/* threshold algorithm */
	void thresholdImage(THRESHOLD_TYPE type) {
		Mat gray;
		const double threshold_value = 0.0;
		const double max_binary_value = 255.0;

		/* convert gray */
		cvtColor(this->img, gray, CV_BGR2GRAY);

		threshold(gray, this->img, threshold_value, max_binary_value, type);
	}

	/* detect squares algorithm by karlphillip */
	vector<vector<Point> > detectSquare(bool debug = false) {
		/* blur will enhance edge detection */
		Mat blurred(this->img);

		medianBlur(this->img, blurred, 9);

		Mat gray0(blurred.size(), CV_8U), gray;

		/* reserved Points array */
		vector<vector<Point> > reserved;
		/* contours Points array*/
		vector<vector<Point> > contours;

		/* find squares in every color plane of the image */
		for (int c = 0; c < 3; c++) {
			int ch[] = { c, 0 };

			/* canny ratio which is recommended as 3 by Canny */
			int ratio = 2;
			int lowThreshold = 10;

			mixChannels(&blurred, 1, &gray0, 1, ch, 1);

			/* try several threshold level */
			const int threshold_level = 2;
			for (int l = 0; l < threshold_level; l++) {
				/* Use Canny instead of zero threshold level */
				/* Canny helps to catch squares with gradient shading */
				if (l == 0) {
					Canny(gray0, gray, lowThreshold, ratio * lowThreshold, 3);

					/* Dilage helps to remove potential holes between edge segments */
					dilate(gray, gray, Mat(), Point(-1, -1));
				} else {
					gray = gray0 >= (l + 1) * 255 / threshold_level;
				}

				vector<Vec4i> hierarchy;
				/* find contours and store them in a list */
				findContours(gray, contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

				/* draw contours to improve accuracy */
				for (size_t i = 0; i < contours.size(); i++) {
					drawContours(this->img, contours, i, Scalar(0, 0, 0), 1, 8, hierarchy, 0, Point());
				}

				/* test contours */
				vector<Point> approx;
				for (size_t i = 0; i < contours.size(); i++) {
					/* approximate contour with accuracy proportional to the contour perimeter */
					approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true) * 0.02, true);

					/*
					 * Note: absolute value of an area is used becuase
					 *       area may be positive or negative, in accordance
					 *		 with the contour orientation
					 */
					// cout << "size: " << approx.size() << endl;
					// cout << "area: " << fabs(contourArea(Mat(approx))) << endl;
					if (approx.size() == 4 && fabs(contourArea(Mat(approx))) > 1000 && isContourConvex(Mat(approx))) {
						double maxCosine = 0;

						for (int j = 2; j < 5; j++) {
							double cosine = fabs(angle(approx[j % 4], approx[j - 2], approx[j - 1]));
							maxCosine = MAX(maxCosine, cosine);
						}

						reserved.push_back(approx);

						//if (maxCosine < 0.3) {
						//	reserved.push_back(approx);
						//}
					}
				}
			}
		}

		/* check debug option */
 		if (debug && reserved.size() > 0) {
			debugSquares(reserved);
		}

		return reserved;
	}

	/* detect corner */
	vector<Point2f> detectCorner(const char* quantity, bool debug = false, const char* path = "data.json") {
		/* clock */
		time_t start = clock();

		vector<Point2f> Corners;

		/* parameters */
		const int maxCorners = atoi(quantity);
		const double qualityLevels = 0.001;
		const double minDistance = 10;
		const int blockSize = 10;
		const bool useHarrisDetector = false;
		const int r = 5;

		Mat gray;
		cvtColor(this->img, gray, COLOR_BGR2GRAY);

		goodFeaturesToTrack(gray, Corners, maxCorners, qualityLevels, minDistance, Mat(), blockSize, useHarrisDetector);

		cJSON* pointsArray = cJSON_CreateArray();

		for (size_t i = 0; i < Corners.size(); i++) {
			if (debug) {
				ostringstream os;
				os << " (" << Corners[i].x << ", " << Corners[i].y << ")";
				circle(this->img, Corners[i], r, Scalar(255, 255, 255), 2, 8);
				putText(this->img, os.str(), Corners[i], FONT_HERSHEY_SCRIPT_SIMPLEX, 0.6, Scalar(0, 0, 255), 1, 8);
			}

			/* create json */
			cJSON* item = cJSON_CreateObject();
			cJSON_AddNumberToObject(item, "xPrecent", (double)Corners[i].x / this->img.cols);
			cJSON_AddNumberToObject(item, "yPrecent", (double)Corners[i].y / this->img.rows);
			cJSON_AddNumberToObject(item, "x", Corners[i].x);
			cJSON_AddNumberToObject(item, "y", Corners[i].y);

			cJSON_AddItemToArray(pointsArray, item);
		}

		time_t end = clock();
		cJSON* data = cJSON_CreateObject();
		const char* duration = (Common::doubleToStr(double(end - start) / CLOCKS_PER_SEC) + "s").c_str();
		cJSON_AddStringToObject(data, "time", duration);

		cJSON_AddNumberToObject(data, "width", this->img.cols);
		cJSON_AddNumberToObject(data, "height", this->img.rows);

		/* write the data.json */
		ofstream file;
		file.open(path, ios::out);

		if (file.is_open()) {
			file << cJSON_Print(pointsArray);
			cJSON_AddItemToObject(data, "data", pointsArray);
			file.close();
		}

		Common::successPrint(data);

		return Corners;
	}

	void fastDetectCorner(bool debug = false) {
		vector<KeyPoint> keyPoints;

		FAST(this->img, keyPoints, 10, true, FastFeatureDetector::TYPE_7_12);

		if (debug) {
			drawKeypoints(this->img, keyPoints, this->img, Scalar(255, 255, 255), DrawMatchesFlags::DRAW_OVER_OUTIMG);
		}
	}

	/* write the image to the local path */
	void writeImage(const char* path) {
		/* save the image */
		imwrite(path, this->img);
	}

	/* a mothod to show the image */
	void showImage() {
		/* open the image */
		imshow("image", this->img);
		/* wait for the return */
		waitKey();
	}

	/* container */
	/* image */
	Mat getImage() {
		return this->img;
	}

	/* properties */
	/* width */
	int getWidth() {
		return this->img.cols;
	}

	/* height */
	int getHeight() {
		return this->img.rows;
	}

	/* size */
	Size getSize() {
		return this->img.size();
	}

	/* pointer to the matrix */
	uchar* getPtr(int n) {
		return this->img.ptr<uchar>(n);
	}
};
<|endoftext|>


<commit_before>#include "ConstructionTools.h"
using namespace llvm;
CLIPSValueBuilder::CLIPSValueBuilder(std::string nm, std::string ty, FunctionNamer& namer) : CLIPSObjectBuilder(nm, ty, namer) { }
void CLIPSValueBuilder::setType(KnowledgeConstruction *kc, Type* t) {
	PointerAddress ptr = (PointerAddress)t;
   FunctionNamer& namer = getNamer();
   if(namer.pointerRegistered(ptr)) {
      addField("Type", namer.nameFromPointer(ptr));
   } else {
      addField("Type", kc->route(t, namer));
   }
}

void CLIPSValueBuilder::addFields(Value* val, KnowledgeConstruction *kc, char* parent) {
	CLIPSObjectBuilder::addFields((PointerAddress)val, kc, parent);
	setType(kc, val->getType());
	addField("Name", val->getName());
	if(val->isDereferenceablePointer()) addTrueField("IsDereferenceablePointer");
	if(val->hasValueHandle()) addTrueField("HasValueHandle");
	if(val->hasOneUse()) {
      addTrueField("HasOneUse");
      addField("NumberOfUses", 1);
   } else {
      addField("NumberOfUses", val->getNumUses());
   }
}

void CLIPSValueBuilder::build(Value* val, KnowledgeConstruction *kc, char* parent) {
	open();
	addFields(val, kc, parent);
	close();
	std::string &str = getCompletedString();
	kc->addToKnowledgeBase((PointerAddress)val, str);
}
<commit_msg>Fixed an issue with a temporary reference in the build method of ValueBuilder<commit_after>#include "ConstructionTools.h"
using namespace llvm;
CLIPSValueBuilder::CLIPSValueBuilder(std::string nm, std::string ty, FunctionNamer& namer) : CLIPSObjectBuilder(nm, ty, namer) { }
void CLIPSValueBuilder::setType(KnowledgeConstruction *kc, Type* t) {
	PointerAddress ptr = (PointerAddress)t;
   FunctionNamer& namer = getNamer();
   if(namer.pointerRegistered(ptr)) {
      addField("Type", namer.nameFromPointer(ptr));
   } else {
      addField("Type", kc->route(t, namer));
   }
}

void CLIPSValueBuilder::addFields(Value* val, KnowledgeConstruction *kc, char* parent) {
	CLIPSObjectBuilder::addFields((PointerAddress)val, kc, parent);
	setType(kc, val->getType());
	addField("Name", val->getName());
	if(val->isDereferenceablePointer()) addTrueField("IsDereferenceablePointer");
	if(val->hasValueHandle()) addTrueField("HasValueHandle");
	if(val->hasOneUse()) {
      addTrueField("HasOneUse");
      addField("NumberOfUses", 1);
   } else {
      addField("NumberOfUses", val->getNumUses());
   }
}

void CLIPSValueBuilder::build(Value* val, KnowledgeConstruction *kc, char* parent) {
	open();
	addFields(val, kc, parent);
	close();
	std::string str = getCompletedString();
	kc->addToKnowledgeBase((PointerAddress)val, str);
}
<|endoftext|>


<commit_before>/*
 * groups.cpp
 *
 *  Created on: 4 Apr 2016
 *      Author: nick
 */

#include <map>
#include <iterator>
#include "misc.h"
#include "groups.h"
#include "mpi.h"
#include "ndm.h"
#include "pthread.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

static std::map<int, SpecificGroup*> groups;
static NDM_Group groupCurrentId;
static int myGlobalRank, globalSize;
static pthread_mutex_t currentGroupId_mutex;

static void addGroupToDirectory(NDM_Group, int, int, int*);

void initialiseGroupDirectory() {
  pthread_mutex_init(&currentGroupId_mutex, NULL);
  MPI_Comm_rank(MPI_COMM_WORLD, &myGlobalRank);
  MPI_Comm_size(MPI_COMM_WORLD, &globalSize);
  groupCurrentId = NDM_GLOBAL_GROUP + 1;
  int* groupRanks = (int*)malloc(sizeof(int) * globalSize);
  int i;
  for (i = 0; i < globalSize; i++) groupRanks[i] = i;
  addGroupToDirectory(NDM_GLOBAL_GROUP, globalSize, myGlobalRank, groupRanks);
}

static void addGroupToDirectory(NDM_Group group, int groupSize, int myGroupRank, int* groupRanks) {
  SpecificGroup* newGroup = new SpecificGroup(group, groupSize, myGroupRank, groupRanks, 1);
  groups.insert(groups.end(), std::pair<int, SpecificGroup*>(group, newGroup));
}

NDM_Group addGroup(int numberEntries, int* groupRanks) {
  int* allocatedGroupRanks = (int*)malloc(sizeof(int) * numberEntries);
  memcpy(allocatedGroupRanks, groupRanks, sizeof(int) * numberEntries);
  int myRank = -1, i;
  for (i = 0; i < numberEntries; i++) {
    if (groupRanks[i] == myGlobalRank) myRank = i;
  }
  pthread_mutex_lock(&currentGroupId_mutex);
  int specificGroupId = groupCurrentId++;
  pthread_mutex_unlock(&currentGroupId_mutex);
  addGroupToDirectory(specificGroupId, numberEntries, myRank, allocatedGroupRanks);
  return specificGroupId;
}

NDM_Group createVirtualRanksInGroup(NDM_Group baseGroup, int numberVirtualRanksPerGroup) {
  std::map<int, SpecificGroup*>::iterator it = groups.find(baseGroup);
  if (it != groups.end()) {
    pthread_mutex_lock(&currentGroupId_mutex);
    int specificGroupId = groupCurrentId++;
    pthread_mutex_unlock(&currentGroupId_mutex);
    int* groupRanks = (int*)malloc(sizeof(int) * it->second->getGroupSize() * numberVirtualRanksPerGroup);
    int i, j;
    for (i = 0; i < it->second->getGroupSize(); i++) {
      for (j = 0; j < numberVirtualRanksPerGroup; j++) {
        groupRanks[(i * numberVirtualRanksPerGroup) + j] = it->second->getGroupEntries()[i];
      }
    }
    SpecificGroup* newGroup =
        new SpecificGroup(specificGroupId, it->second->getGroupSize() * numberVirtualRanksPerGroup,
                          it->second->getGroupEntries()[it->second->getMyGroupRank()], groupRanks, numberVirtualRanksPerGroup);
    groups.insert(groups.end(), std::pair<int, SpecificGroup*>(specificGroupId, newGroup));
    return specificGroupId;
  } else {
    raiseError("Existing base group not found");
    return -1;
  }
}

NDM_Group createContiguousGroupWithStride(NDM_Group baseGroup, int number_contiguous_ranks, int stride) {
  std::map<int, SpecificGroup*>::iterator it = groups.find(baseGroup);
  if (it != groups.end()) {
    pthread_mutex_lock(&currentGroupId_mutex);
    int specificGroupId = groupCurrentId++;
    pthread_mutex_unlock(&currentGroupId_mutex);
    int myBaseRank = it->second->getMyGroupRank(), myRank = -1;
    int numberOfGroups = ceil((double)it->second->getGroupSize() / (number_contiguous_ranks + stride));
    int correction = (number_contiguous_ranks * stride) - it->second->getGroupSize();
    if (correction > number_contiguous_ranks) correction = number_contiguous_ranks;
    int numberOfProcesses = (numberOfGroups * number_contiguous_ranks) - correction;
    int* groupRanks = (int*)malloc(sizeof(int) * numberOfProcesses);
    int i, j = 0;
    for (i = 0; i < it->second->getGroupSize(); i++) {
      if (i % (number_contiguous_ranks + stride) >= stride) {
        groupRanks[j] = it->second->getGroupEntries()[i];
        if (i == myBaseRank) myRank = j;
        j++;
      }
    }
    SpecificGroup* newGroup = new SpecificGroup(specificGroupId, numberOfProcesses, myRank, groupRanks, 1);
    groups.insert(groups.end(), std::pair<int, SpecificGroup*>(specificGroupId, newGroup));
    return specificGroupId;
  } else {
    raiseError("Existing base group not found");
    return -1;
  }
}

NDM_Group extractGroupBasedOnSizeAndRank(NDM_Group baseGroup, int size, int myrank) {
  std::map<int, SpecificGroup*>::iterator it = groups.find(baseGroup);
  if (it != groups.end()) {
    pthread_mutex_lock(&currentGroupId_mutex);
    int specificGroupId = groupCurrentId++;
    pthread_mutex_unlock(&currentGroupId_mutex);

    int* groupRanks = (int*)malloc(sizeof(int) * size);
    int i, startingPoint = size * (myrank / size),
           endPoint = it->second->getGroupSize() < startingPoint + size ? it->second->getGroupSize() : startingPoint + size;
    for (i = startingPoint; i < endPoint; i++) {
      groupRanks[i - startingPoint] = it->second->getGroupEntries()[i];
    }
    SpecificGroup* newGroup = new SpecificGroup(specificGroupId, size, myrank - startingPoint, groupRanks, 1);
    groups.insert(groups.end(), std::pair<int, SpecificGroup*>(specificGroupId, newGroup));
    return specificGroupId;
  } else {
    raiseError("Existing base group not found");
    return -1;
  }
}

int getLocalNthGroupRank(NDM_Group group, int n) {
  if (n < 0) raiseError("Negative group ranks is not allowed");
  std::map<int, SpecificGroup*>::iterator it = groups.find(group);
  if (it != groups.end()) {
    int myGroupRank = it->second->getMyGroupRank();
    int i, occurances = 0;
    for (i = 0; i < it->second->getGroupSize(); i++) {
      if (it->second->getGroupEntries()[i] == myGroupRank) {
        if (occurances == n) return i;
        occurances++;
      }
    }
  } else {
    raiseError("Group not found");
  }
  return -1;
}

int getNumberDistinctProcesses(NDM_Group group) {
  if (group == NDM_GLOBAL_GROUP) {
    return globalSize;
  } else {
    std::map<int, SpecificGroup*>::iterator it = groups.find(group);
    if (it != groups.end()) {
      return it->second->getGroupSize() / it->second->getRanksPerProcess();
    } else {
      raiseError("Group not found");
    }
  }
  return -1;
}

int translateRankFromGroup(NDM_Group group, int groupRank) {
  if (groupRank < 0) raiseError("Negative group ranks is not allowed");
  if (group == NDM_GLOBAL_GROUP) {
    if (groupRank >= globalSize) raiseError("Group rank exceeds group size");
    return groupRank;
  } else {
    std::map<int, SpecificGroup*>::iterator it = groups.find(group);
    if (it != groups.end()) {
      if (groupRank >= it->second->getGroupSize()) raiseError("Group rank exceeds group size");
      return it->second->getGroupToGlobalRank(groupRank);
    } else {
      raiseError("Group not found");
    }
  }
  return -1;
}

int isRankLocalToGroup(NDM_Group group, int rank) {
  if (rank < 0) raiseError("Negative group ranks is not allowed");
  std::map<int, SpecificGroup*>::iterator it = groups.find(group);
  if (it != groups.end()) {
    if (rank >= it->second->getGroupSize()) raiseError("Group rank exceeds group size");
    return it->second->getGroupToGlobalRank(rank) == it->second->getMyGroupRank();
  } else {
    raiseError("Group not found");
  }
  return 0;
}

int getGroupLocalSize(NDM_Group group) {
  std::map<int, SpecificGroup*>::iterator it = groups.find(group);
  if (it != groups.end()) {
    return it->second->getRanksPerProcess();
  } else {
    raiseError("Group not found");
  }
  return -1;
}

int getMyGroupRank(NDM_Group group) {
  std::map<int, SpecificGroup*>::iterator it = groups.find(group);
  if (it != groups.end()) {
    return it->second->getMyGroupRank();
  } else {
    raiseError("Group not found");
  }
  return -1;
}

int getGroupSize(NDM_Group group) {
  std::map<int, SpecificGroup*>::iterator it = groups.find(group);
  if (it != groups.end()) {
    return it->second->getGroupSize();
  } else {
    raiseError("Group not found");
  }
  return -1;
}
<commit_msg>Bug fix for group correction<commit_after>/*
 * groups.cpp
 *
 *  Created on: 4 Apr 2016
 *      Author: nick
 */

#include <map>
#include <iterator>
#include "misc.h"
#include "groups.h"
#include "mpi.h"
#include "ndm.h"
#include "pthread.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

static std::map<int, SpecificGroup*> groups;
static NDM_Group groupCurrentId;
static int myGlobalRank, globalSize;
static pthread_mutex_t currentGroupId_mutex;

static void addGroupToDirectory(NDM_Group, int, int, int*);

void initialiseGroupDirectory() {
  pthread_mutex_init(&currentGroupId_mutex, NULL);
  MPI_Comm_rank(MPI_COMM_WORLD, &myGlobalRank);
  MPI_Comm_size(MPI_COMM_WORLD, &globalSize);
  groupCurrentId = NDM_GLOBAL_GROUP + 1;
  int* groupRanks = (int*)malloc(sizeof(int) * globalSize);
  int i;
  for (i = 0; i < globalSize; i++) groupRanks[i] = i;
  addGroupToDirectory(NDM_GLOBAL_GROUP, globalSize, myGlobalRank, groupRanks);
}

static void addGroupToDirectory(NDM_Group group, int groupSize, int myGroupRank, int* groupRanks) {
  SpecificGroup* newGroup = new SpecificGroup(group, groupSize, myGroupRank, groupRanks, 1);
  groups.insert(groups.end(), std::pair<int, SpecificGroup*>(group, newGroup));
}

NDM_Group addGroup(int numberEntries, int* groupRanks) {
  int* allocatedGroupRanks = (int*)malloc(sizeof(int) * numberEntries);
  memcpy(allocatedGroupRanks, groupRanks, sizeof(int) * numberEntries);
  int myRank = -1, i;
  for (i = 0; i < numberEntries; i++) {
    if (groupRanks[i] == myGlobalRank) myRank = i;
  }
  pthread_mutex_lock(&currentGroupId_mutex);
  int specificGroupId = groupCurrentId++;
  pthread_mutex_unlock(&currentGroupId_mutex);
  addGroupToDirectory(specificGroupId, numberEntries, myRank, allocatedGroupRanks);
  return specificGroupId;
}

NDM_Group createVirtualRanksInGroup(NDM_Group baseGroup, int numberVirtualRanksPerGroup) {
  std::map<int, SpecificGroup*>::iterator it = groups.find(baseGroup);
  if (it != groups.end()) {
    pthread_mutex_lock(&currentGroupId_mutex);
    int specificGroupId = groupCurrentId++;
    pthread_mutex_unlock(&currentGroupId_mutex);
    int* groupRanks = (int*)malloc(sizeof(int) * it->second->getGroupSize() * numberVirtualRanksPerGroup);
    int i, j;
    for (i = 0; i < it->second->getGroupSize(); i++) {
      for (j = 0; j < numberVirtualRanksPerGroup; j++) {
        groupRanks[(i * numberVirtualRanksPerGroup) + j] = it->second->getGroupEntries()[i];
      }
    }
    SpecificGroup* newGroup =
        new SpecificGroup(specificGroupId, it->second->getGroupSize() * numberVirtualRanksPerGroup,
                          it->second->getGroupEntries()[it->second->getMyGroupRank()], groupRanks, numberVirtualRanksPerGroup);
    groups.insert(groups.end(), std::pair<int, SpecificGroup*>(specificGroupId, newGroup));
    return specificGroupId;
  } else {
    raiseError("Existing base group not found");
    return -1;
  }
}

NDM_Group createContiguousGroupWithStride(NDM_Group baseGroup, int number_contiguous_ranks, int stride) {
  std::map<int, SpecificGroup*>::iterator it = groups.find(baseGroup);
  if (it != groups.end()) {
    pthread_mutex_lock(&currentGroupId_mutex);
    int specificGroupId = groupCurrentId++;
    pthread_mutex_unlock(&currentGroupId_mutex);
    int myBaseRank = it->second->getMyGroupRank(), myRank = -1;
    int numberOfGroups = ceil((double)it->second->getGroupSize() / (number_contiguous_ranks + stride));
    int correction = ((number_contiguous_ranks + stride) * numberOfGroups) - it->second->getGroupSize();
    if (correction > number_contiguous_ranks) correction = number_contiguous_ranks;
    int numberOfProcesses = (numberOfGroups * number_contiguous_ranks) - correction;
    int* groupRanks = (int*)malloc(sizeof(int) * numberOfProcesses);
    int i, j = 0;
    for (i = 0; i < it->second->getGroupSize(); i++) {
      if (i % (number_contiguous_ranks + stride) >= stride) {
        groupRanks[j] = it->second->getGroupEntries()[i];
        if (i == myBaseRank) myRank = j;
        j++;
      }
    }
    SpecificGroup* newGroup = new SpecificGroup(specificGroupId, numberOfProcesses, myRank, groupRanks, 1);
    groups.insert(groups.end(), std::pair<int, SpecificGroup*>(specificGroupId, newGroup));
    return specificGroupId;
  } else {
    raiseError("Existing base group not found");
    return -1;
  }
}

NDM_Group extractGroupBasedOnSizeAndRank(NDM_Group baseGroup, int size, int myrank) {
  std::map<int, SpecificGroup*>::iterator it = groups.find(baseGroup);
  if (it != groups.end()) {
    pthread_mutex_lock(&currentGroupId_mutex);
    int specificGroupId = groupCurrentId++;
    pthread_mutex_unlock(&currentGroupId_mutex);

    int* groupRanks = (int*)malloc(sizeof(int) * size);
    int i, startingPoint = size * (myrank / size),
           endPoint = it->second->getGroupSize() < startingPoint + size ? it->second->getGroupSize() : startingPoint + size;
    for (i = startingPoint; i < endPoint; i++) {
      groupRanks[i - startingPoint] = it->second->getGroupEntries()[i];
    }
    SpecificGroup* newGroup = new SpecificGroup(specificGroupId, size, myrank - startingPoint, groupRanks, 1);
    groups.insert(groups.end(), std::pair<int, SpecificGroup*>(specificGroupId, newGroup));
    return specificGroupId;
  } else {
    raiseError("Existing base group not found");
    return -1;
  }
}

int getLocalNthGroupRank(NDM_Group group, int n) {
  if (n < 0) raiseError("Negative group ranks is not allowed");
  std::map<int, SpecificGroup*>::iterator it = groups.find(group);
  if (it != groups.end()) {
    int myGroupRank = it->second->getMyGroupRank();
    int i, occurances = 0;
    for (i = 0; i < it->second->getGroupSize(); i++) {
      if (it->second->getGroupEntries()[i] == myGroupRank) {
        if (occurances == n) return i;
        occurances++;
      }
    }
  } else {
    raiseError("Group not found");
  }
  return -1;
}

int getNumberDistinctProcesses(NDM_Group group) {
  if (group == NDM_GLOBAL_GROUP) {
    return globalSize;
  } else {
    std::map<int, SpecificGroup*>::iterator it = groups.find(group);
    if (it != groups.end()) {
      return it->second->getGroupSize() / it->second->getRanksPerProcess();
    } else {
      raiseError("Group not found");
    }
  }
  return -1;
}

int translateRankFromGroup(NDM_Group group, int groupRank) {
  if (groupRank < 0) raiseError("Negative group ranks is not allowed");
  if (group == NDM_GLOBAL_GROUP) {
    if (groupRank >= globalSize) raiseError("Group rank exceeds group size");
    return groupRank;
  } else {
    std::map<int, SpecificGroup*>::iterator it = groups.find(group);
    if (it != groups.end()) {
      if (groupRank >= it->second->getGroupSize()) raiseError("Group rank exceeds group size");
      return it->second->getGroupToGlobalRank(groupRank);
    } else {
      raiseError("Group not found");
    }
  }
  return -1;
}

int isRankLocalToGroup(NDM_Group group, int rank) {
  if (rank < 0) raiseError("Negative group ranks is not allowed");
  std::map<int, SpecificGroup*>::iterator it = groups.find(group);
  if (it != groups.end()) {
    if (rank >= it->second->getGroupSize()) raiseError("Group rank exceeds group size");
    return it->second->getGroupToGlobalRank(rank) == it->second->getMyGroupRank();
  } else {
    raiseError("Group not found");
  }
  return 0;
}

int getGroupLocalSize(NDM_Group group) {
  std::map<int, SpecificGroup*>::iterator it = groups.find(group);
  if (it != groups.end()) {
    return it->second->getRanksPerProcess();
  } else {
    raiseError("Group not found");
  }
  return -1;
}

int getMyGroupRank(NDM_Group group) {
  std::map<int, SpecificGroup*>::iterator it = groups.find(group);
  if (it != groups.end()) {
    return it->second->getMyGroupRank();
  } else {
    raiseError("Group not found");
  }
  return -1;
}

int getGroupSize(NDM_Group group) {
  std::map<int, SpecificGroup*>::iterator it = groups.find(group);
  if (it != groups.end()) {
    return it->second->getGroupSize();
  } else {
    raiseError("Group not found");
  }
  return -1;
}
<|endoftext|>


<commit_before>/*****************************************************************************
 * Copyright (C) 2011-2016 Michael Ira Krufky
 *
 * Author: Michael Ira Krufky <mkrufky@linuxtv.org>
 *
 * 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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include "desc_4d.h"

#include "dvbpsi/dr_4d.h" /* short event descriptor */

#include "functions.h"

#define CLASS_MODULE "[short event]"

#define dPrintf(fmt, arg...) __dPrintf(DBG_DESC, fmt, ##arg)

using namespace dvbtee::decode;
using namespace valueobj;

static std::string DESC_NAME = "DR[4D]";

#define DESC_TAG 0x4d

desc_4d::desc_4d(Decoder *parent, dvbpsi_descriptor_t *p_descriptor)
 : Descriptor(parent, DESC_NAME, p_descriptor)
{
	if (!desc_check_tag(getTag(), DESC_TAG)) return;

	dvbpsi_short_event_dr_t* dr = dvbpsi_DecodeShortEventDr(p_descriptor);
	if (desc_dr_failed(dr)) return;

	unsigned char name[256];
	unsigned char text[256];
	unsigned char lang[4] = { 0 };

	for (unsigned int i = 0; i < 3; i++) lang[i] = dr->i_iso_639_code[i];
	get_descriptor_text(dr->i_event_name, dr->i_event_name_length, name);
	get_descriptor_text(dr->i_text, dr->i_text_length, text);

	set("lang", std::string((const char*)lang));
	const char* escaped = escape_quotes((char*)name);
	set("name", std::string(escaped));
	free(escaped);
	escaped = escape_quotes((char*)text);
	set("text", std::string(escaped));
	free(escaped);

	dPrintf("%s", toJson().c_str());

	setValid(true);
}

desc_4d::~desc_4d()
{
	//
}

REGISTER_DESCRIPTOR_FACTORY(DESC_TAG, desc_4d)
<commit_msg>desc_4d: fix error: ‘free’ was not declared in this scope<commit_after>/*****************************************************************************
 * Copyright (C) 2011-2016 Michael Ira Krufky
 *
 * Author: Michael Ira Krufky <mkrufky@linuxtv.org>
 *
 * 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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include <stdlib.h>

#include "desc_4d.h"

#include "dvbpsi/dr_4d.h" /* short event descriptor */

#include "functions.h"

#define CLASS_MODULE "[short event]"

#define dPrintf(fmt, arg...) __dPrintf(DBG_DESC, fmt, ##arg)

using namespace dvbtee::decode;
using namespace valueobj;

static std::string DESC_NAME = "DR[4D]";

#define DESC_TAG 0x4d

desc_4d::desc_4d(Decoder *parent, dvbpsi_descriptor_t *p_descriptor)
 : Descriptor(parent, DESC_NAME, p_descriptor)
{
	if (!desc_check_tag(getTag(), DESC_TAG)) return;

	dvbpsi_short_event_dr_t* dr = dvbpsi_DecodeShortEventDr(p_descriptor);
	if (desc_dr_failed(dr)) return;

	unsigned char name[256];
	unsigned char text[256];
	unsigned char lang[4] = { 0 };

	for (unsigned int i = 0; i < 3; i++) lang[i] = dr->i_iso_639_code[i];
	get_descriptor_text(dr->i_event_name, dr->i_event_name_length, name);
	get_descriptor_text(dr->i_text, dr->i_text_length, text);

	set("lang", std::string((const char*)lang));
	const char* escaped = escape_quotes((char*)name);
	set("name", std::string(escaped));
	free(escaped);
	escaped = escape_quotes((char*)text);
	set("text", std::string(escaped));
	free(escaped);

	dPrintf("%s", toJson().c_str());

	setValid(true);
}

desc_4d::~desc_4d()
{
	//
}

REGISTER_DESCRIPTOR_FACTORY(DESC_TAG, desc_4d)
<|endoftext|>