<commit_before>#include "xml.h"

#include <cstring>
#include <iostream>
#include <string>

#include "../leanify.h"
#include "../utils.h"
#include "base64.h"

using std::cout;
using std::endl;
using std::string;

Xml::Xml(void *p, size_t s /*= 0*/) : Format(p, s)
{
    pugi::xml_parse_result result = doc_.load_buffer(fp_, size_, pugi::parse_default | pugi::parse_declaration | pugi::parse_doctype | pugi::parse_ws_pcdata_single);
    is_valid_ = result;
    encoding_ = result.encoding;
}

namespace
{

void TraverseElements(pugi::xml_node node, std::function<void(pugi::xml_node)> callback)
{
    // cannot use ranged loop here because we need to store the next_sibling before recursion so that if child was removed the loop won't be terminated
    for (pugi::xml_node child = node.first_child(), next; child; child = next)
    {
        next = child.next_sibling();
        TraverseElements(child, callback);
    }

    callback(node);
}

struct xml_memory_writer : pugi::xml_writer
{
    uint8_t *p_write;

    virtual void write(const void* data, size_t size) override
    {
        memcpy(p_write, data, size);
        p_write += size;
    }
};

} // namespace

size_t Xml::Leanify(size_t size_leanified /*= 0*/)
{

    // if the XML is fb2 file
    if (doc_.child("FictionBook"))
    {
        if (is_verbose)
        {
            cout << "FB2 detected." << endl;
        }
        if (depth < max_depth)
        {
            depth++;

            pugi::xml_node root = doc_.child("FictionBook");

            // iterate through all binary element
            for (pugi::xml_node binary = root.child("binary"), next; binary; binary = next)
            {
                next = binary.next_sibling("binary");
                pugi::xml_attribute id = binary.attribute("id");
                if (id == nullptr || id.value() == nullptr || id.value()[0] == 0)
                {
                    root.remove_child(binary);
                    continue;
                }

                PrintFileName(id.value());

                const char *base64_data = binary.child_value();
                if (base64_data == nullptr)
                {
                    cout << "No data found." << endl;
                    continue;
                }
                size_t base64_len = strlen(base64_data);
                // copy to a new location because base64_data is const
                char *new_base64_data = new char[base64_len + 1];
                memcpy(new_base64_data, base64_data, base64_len);

                Base64 b64(new_base64_data, base64_len);
                size_t new_base64_len = b64.Leanify();

                if (new_base64_len < base64_len)
                {
                    new_base64_data[new_base64_len] = 0;
                    binary.text() = new_base64_data;
                }

                delete[] new_base64_data;
            }
            depth--;
        }
    }
    else if (doc_.child("svg"))
    {
        if (is_verbose)
        {
            cout << "SVG detected." << endl;
        }

        // remove XML declaration and doctype
        for (pugi::xml_node child = doc_.first_child(), next; child; child = next)
        {
            next = child.next_sibling();
            if (child.type() == pugi::node_declaration || child.type() == pugi::node_doctype)
            {
                doc_.remove_child(child);
            }
        }

        TraverseElements(doc_.child("svg"), [](pugi::xml_node node)
        {
            for (pugi::xml_attribute attr = node.first_attribute(), next; attr; attr = next)
            {
                next = attr.next_attribute();
                const char* value = attr.value();
                // remove empty attribute
                if (value == nullptr || *value == 0)
                {
                    node.remove_attribute(attr);
                    continue;
                }

                // shrink spaces and newlines in attribute
                // also removes preceding and trailing spaces
                string new_value;
                while (*value)
                {
                    if (*value == ' ' || *value == '\n' || *value == '\t')
                    {
                        do
                        {
                            value++;
                        }
                        while (*value == ' ' || *value == '\n' || *value == '\t');
                        if (*value == 0)
                        {
                            break;
                        }
                        new_value += ' ';
                    }
                    new_value += *value++;
                }
                attr = new_value.c_str() + (new_value[0] == ' ' ? 1 : 0);
            }

            // remove empty text element and container element
            const char* name = node.name();
            if (node.first_child() == nullptr)
            {
                if (strcmp(name, "text") == 0 ||
                    strcmp(name, "tspan") == 0 ||
                    strcmp(name, "a") == 0 ||
                    strcmp(name, "defs") == 0 ||
                    strcmp(name, "g") == 0 ||
                    strcmp(name, "marker") == 0 ||
                    strcmp(name, "mask") == 0 ||
                    strcmp(name, "missing-glyph") == 0 ||
                    strcmp(name, "pattern") == 0 ||
                    strcmp(name, "switch") == 0 ||
                    strcmp(name, "symbol") == 0)
                {
                    node.parent().remove_child(node);
                    return;
                }
            }

            if (strcmp(name, "tref") == 0 && node.attribute("xlink:href") == nullptr)
            {
                node.parent().remove_child(node);
                return;
            }

            if (strcmp(name, "metadata") == 0)
            {
                node.parent().remove_child(node);
                return;
            }
        });
    }

    // print leanified XML to memory
    xml_memory_writer writer;
    fp_ -= size_leanified;
    writer.p_write = fp_;
    doc_.save(writer, nullptr, pugi::format_raw | pugi::format_no_declaration, encoding_);
    size_ = writer.p_write - fp_;
    return size_;
}
<commit_msg>XML: remove redundant virtual<commit_after>#include "xml.h"

#include <cstring>
#include <iostream>
#include <string>

#include "../leanify.h"
#include "../utils.h"
#include "base64.h"

using std::cout;
using std::endl;
using std::string;

Xml::Xml(void *p, size_t s /*= 0*/) : Format(p, s)
{
    pugi::xml_parse_result result = doc_.load_buffer(fp_, size_, pugi::parse_default | pugi::parse_declaration | pugi::parse_doctype | pugi::parse_ws_pcdata_single);
    is_valid_ = result;
    encoding_ = result.encoding;
}

namespace
{

void TraverseElements(pugi::xml_node node, std::function<void(pugi::xml_node)> callback)
{
    // cannot use ranged loop here because we need to store the next_sibling before recursion so that if child was removed the loop won't be terminated
    for (pugi::xml_node child = node.first_child(), next; child; child = next)
    {
        next = child.next_sibling();
        TraverseElements(child, callback);
    }

    callback(node);
}

struct xml_memory_writer : pugi::xml_writer
{
    uint8_t *p_write;

    void write(const void* data, size_t size) override
    {
        memcpy(p_write, data, size);
        p_write += size;
    }
};

} // namespace

size_t Xml::Leanify(size_t size_leanified /*= 0*/)
{

    // if the XML is fb2 file
    if (doc_.child("FictionBook"))
    {
        if (is_verbose)
        {
            cout << "FB2 detected." << endl;
        }
        if (depth < max_depth)
        {
            depth++;

            pugi::xml_node root = doc_.child("FictionBook");

            // iterate through all binary element
            for (pugi::xml_node binary = root.child("binary"), next; binary; binary = next)
            {
                next = binary.next_sibling("binary");
                pugi::xml_attribute id = binary.attribute("id");
                if (id == nullptr || id.value() == nullptr || id.value()[0] == 0)
                {
                    root.remove_child(binary);
                    continue;
                }

                PrintFileName(id.value());

                const char *base64_data = binary.child_value();
                if (base64_data == nullptr)
                {
                    cout << "No data found." << endl;
                    continue;
                }
                size_t base64_len = strlen(base64_data);
                // copy to a new location because base64_data is const
                char *new_base64_data = new char[base64_len + 1];
                memcpy(new_base64_data, base64_data, base64_len);

                Base64 b64(new_base64_data, base64_len);
                size_t new_base64_len = b64.Leanify();

                if (new_base64_len < base64_len)
                {
                    new_base64_data[new_base64_len] = 0;
                    binary.text() = new_base64_data;
                }

                delete[] new_base64_data;
            }
            depth--;
        }
    }
    else if (doc_.child("svg"))
    {
        if (is_verbose)
        {
            cout << "SVG detected." << endl;
        }

        // remove XML declaration and doctype
        for (pugi::xml_node child = doc_.first_child(), next; child; child = next)
        {
            next = child.next_sibling();
            if (child.type() == pugi::node_declaration || child.type() == pugi::node_doctype)
            {
                doc_.remove_child(child);
            }
        }

        TraverseElements(doc_.child("svg"), [](pugi::xml_node node)
        {
            for (pugi::xml_attribute attr = node.first_attribute(), next; attr; attr = next)
            {
                next = attr.next_attribute();
                const char* value = attr.value();
                // remove empty attribute
                if (value == nullptr || *value == 0)
                {
                    node.remove_attribute(attr);
                    continue;
                }

                // shrink spaces and newlines in attribute
                // also removes preceding and trailing spaces
                string new_value;
                while (*value)
                {
                    if (*value == ' ' || *value == '\n' || *value == '\t')
                    {
                        do
                        {
                            value++;
                        }
                        while (*value == ' ' || *value == '\n' || *value == '\t');
                        if (*value == 0)
                        {
                            break;
                        }
                        new_value += ' ';
                    }
                    new_value += *value++;
                }
                attr = new_value.c_str() + (new_value[0] == ' ' ? 1 : 0);
            }

            // remove empty text element and container element
            const char* name = node.name();
            if (node.first_child() == nullptr)
            {
                if (strcmp(name, "text") == 0 ||
                    strcmp(name, "tspan") == 0 ||
                    strcmp(name, "a") == 0 ||
                    strcmp(name, "defs") == 0 ||
                    strcmp(name, "g") == 0 ||
                    strcmp(name, "marker") == 0 ||
                    strcmp(name, "mask") == 0 ||
                    strcmp(name, "missing-glyph") == 0 ||
                    strcmp(name, "pattern") == 0 ||
                    strcmp(name, "switch") == 0 ||
                    strcmp(name, "symbol") == 0)
                {
                    node.parent().remove_child(node);
                    return;
                }
            }

            if (strcmp(name, "tref") == 0 && node.attribute("xlink:href") == nullptr)
            {
                node.parent().remove_child(node);
                return;
            }

            if (strcmp(name, "metadata") == 0)
            {
                node.parent().remove_child(node);
                return;
            }
        });
    }

    // print leanified XML to memory
    xml_memory_writer writer;
    fp_ -= size_leanified;
    writer.p_write = fp_;
    doc_.save(writer, nullptr, pugi::format_raw | pugi::format_no_declaration, encoding_);
    size_ = writer.p_write - fp_;
    return size_;
}
<|endoftext|>


<commit_before>// SwiftShader Software Renderer
//
// Copyright(c) 2005-2013 TransGaming Inc.
//
// All rights reserved. No part of this software may be copied, distributed, transmitted,
// transcribed, stored in a retrieval system, translated into any human or computer
// language by any means, or disclosed to third parties without the explicit written
// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
// or implied, including but not limited to any patent rights, are granted to you.
//

// Config.cpp: Implements the egl::Config class, describing the format, type
// and size for an egl::Surface. Implements EGLConfig and related functionality.
// [EGL 1.4] section 3.4 page 15.

#include "Config.h"

#include "common/debug.h"

#define EGLAPI
#include <EGL/eglext.h>

#include <algorithm>
#include <vector>

using namespace std;

namespace egl
{
Config::Config(const DisplayMode &displayMode, EGLint minInterval, EGLint maxInterval, sw::Format renderTargetFormat, sw::Format depthStencilFormat, EGLint multiSample)
    : mDisplayMode(displayMode), mRenderTargetFormat(renderTargetFormat), mDepthStencilFormat(depthStencilFormat), mMultiSample(multiSample)
{
    mBindToTextureRGB = EGL_FALSE;
    mBindToTextureRGBA = EGL_FALSE;

    switch (renderTargetFormat)
    {
      case sw::FORMAT_A1R5G5B5:
        mBufferSize = 16;
        mRedSize = 5;
        mGreenSize = 5;
        mBlueSize = 5;
        mAlphaSize = 1;
        break;
      case sw::FORMAT_A2R10G10B10:
        mBufferSize = 32;
        mRedSize = 10;
        mGreenSize = 10;
        mBlueSize = 10;
        mAlphaSize = 2;
        break;
      case sw::FORMAT_A8R8G8B8:
        mBufferSize = 32;
        mRedSize = 8;
        mGreenSize = 8;
        mBlueSize = 8;
        mAlphaSize = 8;
        mBindToTextureRGBA = true;
        break;
      case sw::FORMAT_R5G6B5:
        mBufferSize = 16;
        mRedSize = 5;
        mGreenSize = 6;
        mBlueSize = 5;
        mAlphaSize = 0;
        break;
      case sw::FORMAT_X8R8G8B8:
        mBufferSize = 32;
        mRedSize = 8;
        mGreenSize = 8;
        mBlueSize = 8;
        mAlphaSize = 0;
        mBindToTextureRGB = true;
        break;
      default:
        UNREACHABLE();   // Other formats should not be valid
    }

    mLuminanceSize = 0;
    mAlphaMaskSize = 0;
    mColorBufferType = EGL_RGB_BUFFER;
    mConfigCaveat = isSlowConfig() ? EGL_SLOW_CONFIG : EGL_NONE;
    mConfigID = 0;
    mConformant = EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT;

	switch (depthStencilFormat)
	{
	case sw::FORMAT_NULL:
		mDepthSize = 0;
		mStencilSize = 0;
		break;
//  case sw::FORMAT_D16_LOCKABLE:
//      mDepthSize = 16;
//      mStencilSize = 0;
//      break;
	case sw::FORMAT_D32:
		mDepthSize = 32;
		mStencilSize = 0;
		break;
//	case sw::FORMAT_D15S1:
//		mDepthSize = 15;
//		mStencilSize = 1;
//		break;
	case sw::FORMAT_D24S8:
		mDepthSize = 24;
		mStencilSize = 8;
		break;
	case sw::FORMAT_D24X8:
		mDepthSize = 24;
		mStencilSize = 0;
		break;
//	case sw::FORMAT_D24X4S4:
//		mDepthSize = 24;
//		mStencilSize = 4;
//		break;
	case sw::FORMAT_D16:
		mDepthSize = 16;
		mStencilSize = 0;
		break;
//  case sw::FORMAT_D32F_LOCKABLE:
//      mDepthSize = 32;
//      mStencilSize = 0;
//      break;
//  case sw::FORMAT_D24FS8:
//      mDepthSize = 24;
//      mStencilSize = 8;
//      break;
	  default:
		UNREACHABLE();
	}

    mLevel = 0;
    mMatchNativePixmap = EGL_NONE;
    mMaxPBufferWidth = 4096;
    mMaxPBufferHeight = 4096;
    mMaxPBufferPixels = mMaxPBufferWidth * mMaxPBufferHeight;
    mMaxSwapInterval = maxInterval;
    mMinSwapInterval = minInterval;
    mNativeRenderable = EGL_FALSE;
    mNativeVisualID = 0;
    mNativeVisualType = 0;
    mRenderableType = EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT;
    mSampleBuffers = multiSample ? 1 : 0;
    mSamples = multiSample;
    mSurfaceType = EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
    mTransparentType = EGL_NONE;
    mTransparentRedValue = 0;
    mTransparentGreenValue = 0;
    mTransparentBlueValue = 0;
}

EGLConfig Config::getHandle() const
{
    return (EGLConfig)(size_t)mConfigID;
}

bool Config::isSlowConfig() const
{
	return mRenderTargetFormat != sw::FORMAT_X8R8G8B8 && mRenderTargetFormat != sw::FORMAT_A8R8G8B8;
}

SortConfig::SortConfig(const EGLint *attribList)
    : mWantRed(false), mWantGreen(false), mWantBlue(false), mWantAlpha(false), mWantLuminance(false)
{
    scanForWantedComponents(attribList);
}

void SortConfig::scanForWantedComponents(const EGLint *attribList)
{
    // [EGL] section 3.4.1 page 24
    // Sorting rule #3: by larger total number of color bits, not considering
    // components that are 0 or don't-care.
    for(const EGLint *attr = attribList; attr[0] != EGL_NONE; attr += 2)
    {
        if(attr[1] != 0 && attr[1] != EGL_DONT_CARE)
        {
            switch (attr[0])
            {
              case EGL_RED_SIZE:       mWantRed = true; break;
              case EGL_GREEN_SIZE:     mWantGreen = true; break;
              case EGL_BLUE_SIZE:      mWantBlue = true; break;
              case EGL_ALPHA_SIZE:     mWantAlpha = true; break;
              case EGL_LUMINANCE_SIZE: mWantLuminance = true; break;
            }
        }
    }
}

EGLint SortConfig::wantedComponentsSize(const Config &config) const
{
    EGLint total = 0;

    if(mWantRed)       total += config.mRedSize;
    if(mWantGreen)     total += config.mGreenSize;
    if(mWantBlue)      total += config.mBlueSize;
    if(mWantAlpha)     total += config.mAlphaSize;
    if(mWantLuminance) total += config.mLuminanceSize;

    return total;
}

bool SortConfig::operator()(const Config *x, const Config *y) const
{
    return (*this)(*x, *y);
}

bool SortConfig::operator()(const Config &x, const Config &y) const
{
    #define SORT(attribute)                        \
        if(x.attribute != y.attribute)             \
        {                                          \
            return x.attribute < y.attribute;      \
        }

    META_ASSERT(EGL_NONE < EGL_SLOW_CONFIG && EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG);
    SORT(mConfigCaveat);

    META_ASSERT(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER);
    SORT(mColorBufferType);

    // By larger total number of color bits, only considering those that are requested to be > 0.
    EGLint xComponentsSize = wantedComponentsSize(x);
    EGLint yComponentsSize = wantedComponentsSize(y);
    if(xComponentsSize != yComponentsSize)
    {
        return xComponentsSize > yComponentsSize;
    }

    SORT(mBufferSize);
    SORT(mSampleBuffers);
    SORT(mSamples);
    SORT(mDepthSize);
    SORT(mStencilSize);
    SORT(mAlphaMaskSize);
    SORT(mNativeVisualType);
    SORT(mConfigID);

    #undef SORT

    return false;
}

// We'd like to use SortConfig to also eliminate duplicate configs.
// This works as long as we never have two configs with different per-RGB-component layouts,
// but the same total.
// 5551 and 565 are different because R+G+B is different.
// 5551 and 555 are different because bufferSize is different.
const EGLint ConfigSet::mSortAttribs[] =
{
    EGL_RED_SIZE, 1,
    EGL_GREEN_SIZE, 1,
    EGL_BLUE_SIZE, 1,
    EGL_LUMINANCE_SIZE, 1,
    // BUT NOT ALPHA
    EGL_NONE
};

ConfigSet::ConfigSet()
    : mSet(SortConfig(mSortAttribs))
{
}

void ConfigSet::add(const DisplayMode &displayMode, EGLint minSwapInterval, EGLint maxSwapInterval, sw::Format renderTargetFormat, sw::Format depthStencilFormat, EGLint multiSample)
{
    Config config(displayMode, minSwapInterval, maxSwapInterval, renderTargetFormat, depthStencilFormat, multiSample);

    mSet.insert(config);
}

size_t ConfigSet::size() const
{
    return mSet.size();
}

bool ConfigSet::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig)
{
    vector<const Config*> passed;
    passed.reserve(mSet.size());

    for(Iterator config = mSet.begin(); config != mSet.end(); config++)
    {
        bool match = true;
        const EGLint *attribute = attribList;

        while(attribute[0] != EGL_NONE)
        {
            switch(attribute[0])
            {
            case EGL_BUFFER_SIZE:                match = config->mBufferSize >= attribute[1];                      break;
            case EGL_ALPHA_SIZE:                 match = config->mAlphaSize >= attribute[1];                       break;
            case EGL_BLUE_SIZE:                  match = config->mBlueSize >= attribute[1];                        break;
            case EGL_GREEN_SIZE:                 match = config->mGreenSize >= attribute[1];                       break;
            case EGL_RED_SIZE:                   match = config->mRedSize >= attribute[1];                         break;
            case EGL_DEPTH_SIZE:                 match = config->mDepthSize >= attribute[1];                       break;
            case EGL_STENCIL_SIZE:               match = config->mStencilSize >= attribute[1];                     break;
            case EGL_CONFIG_CAVEAT:              match = config->mConfigCaveat == attribute[1];                    break;
            case EGL_CONFIG_ID:                  match = config->mConfigID == attribute[1];                        break;
            case EGL_LEVEL:                      match = config->mLevel >= attribute[1];                           break;
            case EGL_NATIVE_RENDERABLE:          match = config->mNativeRenderable == attribute[1];                break;
            case EGL_NATIVE_VISUAL_ID:           match = config->mNativeVisualID == attribute[1];                  break;
            case EGL_NATIVE_VISUAL_TYPE:         match = config->mNativeVisualType == attribute[1];                break;
            case EGL_SAMPLES:                    match = config->mSamples >= attribute[1];                         break;
            case EGL_SAMPLE_BUFFERS:             match = config->mSampleBuffers >= attribute[1];                   break;
            case EGL_SURFACE_TYPE:               match = (config->mSurfaceType & attribute[1]) == attribute[1];    break;
            case EGL_TRANSPARENT_TYPE:           match = config->mTransparentType == attribute[1];                 break;
            case EGL_TRANSPARENT_BLUE_VALUE:     match = config->mTransparentBlueValue == attribute[1];            break;
            case EGL_TRANSPARENT_GREEN_VALUE:    match = config->mTransparentGreenValue == attribute[1];           break;
            case EGL_TRANSPARENT_RED_VALUE:      match = config->mTransparentRedValue == attribute[1];             break;
            case EGL_BIND_TO_TEXTURE_RGB:        match = config->mBindToTextureRGB == attribute[1];                break;
            case EGL_BIND_TO_TEXTURE_RGBA:       match = config->mBindToTextureRGBA == attribute[1];               break;
            case EGL_MIN_SWAP_INTERVAL:          match = config->mMinSwapInterval == attribute[1];                 break;
            case EGL_MAX_SWAP_INTERVAL:          match = config->mMaxSwapInterval == attribute[1];                 break;
            case EGL_LUMINANCE_SIZE:             match = config->mLuminanceSize >= attribute[1];                   break;
            case EGL_ALPHA_MASK_SIZE:            match = config->mAlphaMaskSize >= attribute[1];                   break;
            case EGL_COLOR_BUFFER_TYPE:          match = config->mColorBufferType == attribute[1];                 break;
            case EGL_RENDERABLE_TYPE:            match = (config->mRenderableType & attribute[1]) == attribute[1]; break;
            case EGL_MATCH_NATIVE_PIXMAP:        match = false; UNIMPLEMENTED();                                   break;
            case EGL_CONFORMANT:                 match = (config->mConformant & attribute[1]) == attribute[1];     break;
            case EGL_MAX_PBUFFER_WIDTH:          match = config->mMaxPBufferWidth >= attribute[1];                 break;
            case EGL_MAX_PBUFFER_HEIGHT:         match = config->mMaxPBufferHeight >= attribute[1];                break;
            case EGL_MAX_PBUFFER_PIXELS:         match = config->mMaxPBufferPixels >= attribute[1];                break;
			case EGL_RECORDABLE_ANDROID:         match = false; /* UNIMPLEMENTED(); */                             break;
			case EGL_FRAMEBUFFER_TARGET_ANDROID: match = false; /* UNIMPLEMENTED(); */                             break;
			default:
				UNIMPLEMENTED();
				match = false;
            }

            if(!match)
            {
                break;
            }

            attribute += 2;
        }

        if(match)
        {
            passed.push_back(&*config);
        }
    }

    if(configs)
    {
        sort(passed.begin(), passed.end(), SortConfig(attribList));

        EGLint index;
        for(index = 0; index < configSize && index < static_cast<EGLint>(passed.size()); index++)
        {
            configs[index] = passed[index]->getHandle();
        }

        *numConfig = index;
    }
    else
    {
        *numConfig = static_cast<EGLint>(passed.size());
    }

    return true;
}

const egl::Config *ConfigSet::get(EGLConfig configHandle)
{
    for(Iterator config = mSet.begin(); config != mSet.end(); config++)
    {
        if(config->getHandle() == configHandle)
        {
            return &(*config);
        }
    }

    return NULL;
}
}
<commit_msg>Indicate support for Android EGL surface config attributes.<commit_after>// SwiftShader Software Renderer
//
// Copyright(c) 2005-2013 TransGaming Inc.
//
// All rights reserved. No part of this software may be copied, distributed, transmitted,
// transcribed, stored in a retrieval system, translated into any human or computer
// language by any means, or disclosed to third parties without the explicit written
// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
// or implied, including but not limited to any patent rights, are granted to you.
//

// Config.cpp: Implements the egl::Config class, describing the format, type
// and size for an egl::Surface. Implements EGLConfig and related functionality.
// [EGL 1.4] section 3.4 page 15.

#include "Config.h"

#include "common/debug.h"

#define EGLAPI
#include <EGL/eglext.h>

#include <algorithm>
#include <vector>

using namespace std;

namespace egl
{
Config::Config(const DisplayMode &displayMode, EGLint minInterval, EGLint maxInterval, sw::Format renderTargetFormat, sw::Format depthStencilFormat, EGLint multiSample)
    : mDisplayMode(displayMode), mRenderTargetFormat(renderTargetFormat), mDepthStencilFormat(depthStencilFormat), mMultiSample(multiSample)
{
    mBindToTextureRGB = EGL_FALSE;
    mBindToTextureRGBA = EGL_FALSE;

    switch (renderTargetFormat)
    {
      case sw::FORMAT_A1R5G5B5:
        mBufferSize = 16;
        mRedSize = 5;
        mGreenSize = 5;
        mBlueSize = 5;
        mAlphaSize = 1;
        break;
      case sw::FORMAT_A2R10G10B10:
        mBufferSize = 32;
        mRedSize = 10;
        mGreenSize = 10;
        mBlueSize = 10;
        mAlphaSize = 2;
        break;
      case sw::FORMAT_A8R8G8B8:
        mBufferSize = 32;
        mRedSize = 8;
        mGreenSize = 8;
        mBlueSize = 8;
        mAlphaSize = 8;
        mBindToTextureRGBA = true;
        break;
      case sw::FORMAT_R5G6B5:
        mBufferSize = 16;
        mRedSize = 5;
        mGreenSize = 6;
        mBlueSize = 5;
        mAlphaSize = 0;
        break;
      case sw::FORMAT_X8R8G8B8:
        mBufferSize = 32;
        mRedSize = 8;
        mGreenSize = 8;
        mBlueSize = 8;
        mAlphaSize = 0;
        mBindToTextureRGB = true;
        break;
      default:
        UNREACHABLE();   // Other formats should not be valid
    }

    mLuminanceSize = 0;
    mAlphaMaskSize = 0;
    mColorBufferType = EGL_RGB_BUFFER;
    mConfigCaveat = isSlowConfig() ? EGL_SLOW_CONFIG : EGL_NONE;
    mConfigID = 0;
    mConformant = EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT;

	switch (depthStencilFormat)
	{
	case sw::FORMAT_NULL:
		mDepthSize = 0;
		mStencilSize = 0;
		break;
//  case sw::FORMAT_D16_LOCKABLE:
//      mDepthSize = 16;
//      mStencilSize = 0;
//      break;
	case sw::FORMAT_D32:
		mDepthSize = 32;
		mStencilSize = 0;
		break;
//	case sw::FORMAT_D15S1:
//		mDepthSize = 15;
//		mStencilSize = 1;
//		break;
	case sw::FORMAT_D24S8:
		mDepthSize = 24;
		mStencilSize = 8;
		break;
	case sw::FORMAT_D24X8:
		mDepthSize = 24;
		mStencilSize = 0;
		break;
//	case sw::FORMAT_D24X4S4:
//		mDepthSize = 24;
//		mStencilSize = 4;
//		break;
	case sw::FORMAT_D16:
		mDepthSize = 16;
		mStencilSize = 0;
		break;
//  case sw::FORMAT_D32F_LOCKABLE:
//      mDepthSize = 32;
//      mStencilSize = 0;
//      break;
//  case sw::FORMAT_D24FS8:
//      mDepthSize = 24;
//      mStencilSize = 8;
//      break;
	  default:
		UNREACHABLE();
	}

    mLevel = 0;
    mMatchNativePixmap = EGL_NONE;
    mMaxPBufferWidth = 4096;
    mMaxPBufferHeight = 4096;
    mMaxPBufferPixels = mMaxPBufferWidth * mMaxPBufferHeight;
    mMaxSwapInterval = maxInterval;
    mMinSwapInterval = minInterval;
    mNativeRenderable = EGL_FALSE;
    mNativeVisualID = 0;
    mNativeVisualType = 0;
    mRenderableType = EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT;
    mSampleBuffers = multiSample ? 1 : 0;
    mSamples = multiSample;
    mSurfaceType = EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
    mTransparentType = EGL_NONE;
    mTransparentRedValue = 0;
    mTransparentGreenValue = 0;
    mTransparentBlueValue = 0;
}

EGLConfig Config::getHandle() const
{
    return (EGLConfig)(size_t)mConfigID;
}

bool Config::isSlowConfig() const
{
	return mRenderTargetFormat != sw::FORMAT_X8R8G8B8 && mRenderTargetFormat != sw::FORMAT_A8R8G8B8;
}

SortConfig::SortConfig(const EGLint *attribList)
    : mWantRed(false), mWantGreen(false), mWantBlue(false), mWantAlpha(false), mWantLuminance(false)
{
    scanForWantedComponents(attribList);
}

void SortConfig::scanForWantedComponents(const EGLint *attribList)
{
    // [EGL] section 3.4.1 page 24
    // Sorting rule #3: by larger total number of color bits, not considering
    // components that are 0 or don't-care.
    for(const EGLint *attr = attribList; attr[0] != EGL_NONE; attr += 2)
    {
        if(attr[1] != 0 && attr[1] != EGL_DONT_CARE)
        {
            switch (attr[0])
            {
              case EGL_RED_SIZE:       mWantRed = true; break;
              case EGL_GREEN_SIZE:     mWantGreen = true; break;
              case EGL_BLUE_SIZE:      mWantBlue = true; break;
              case EGL_ALPHA_SIZE:     mWantAlpha = true; break;
              case EGL_LUMINANCE_SIZE: mWantLuminance = true; break;
            }
        }
    }
}

EGLint SortConfig::wantedComponentsSize(const Config &config) const
{
    EGLint total = 0;

    if(mWantRed)       total += config.mRedSize;
    if(mWantGreen)     total += config.mGreenSize;
    if(mWantBlue)      total += config.mBlueSize;
    if(mWantAlpha)     total += config.mAlphaSize;
    if(mWantLuminance) total += config.mLuminanceSize;

    return total;
}

bool SortConfig::operator()(const Config *x, const Config *y) const
{
    return (*this)(*x, *y);
}

bool SortConfig::operator()(const Config &x, const Config &y) const
{
    #define SORT(attribute)                        \
        if(x.attribute != y.attribute)             \
        {                                          \
            return x.attribute < y.attribute;      \
        }

    META_ASSERT(EGL_NONE < EGL_SLOW_CONFIG && EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG);
    SORT(mConfigCaveat);

    META_ASSERT(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER);
    SORT(mColorBufferType);

    // By larger total number of color bits, only considering those that are requested to be > 0.
    EGLint xComponentsSize = wantedComponentsSize(x);
    EGLint yComponentsSize = wantedComponentsSize(y);
    if(xComponentsSize != yComponentsSize)
    {
        return xComponentsSize > yComponentsSize;
    }

    SORT(mBufferSize);
    SORT(mSampleBuffers);
    SORT(mSamples);
    SORT(mDepthSize);
    SORT(mStencilSize);
    SORT(mAlphaMaskSize);
    SORT(mNativeVisualType);
    SORT(mConfigID);

    #undef SORT

    return false;
}

// We'd like to use SortConfig to also eliminate duplicate configs.
// This works as long as we never have two configs with different per-RGB-component layouts,
// but the same total.
// 5551 and 565 are different because R+G+B is different.
// 5551 and 555 are different because bufferSize is different.
const EGLint ConfigSet::mSortAttribs[] =
{
    EGL_RED_SIZE, 1,
    EGL_GREEN_SIZE, 1,
    EGL_BLUE_SIZE, 1,
    EGL_LUMINANCE_SIZE, 1,
    // BUT NOT ALPHA
    EGL_NONE
};

ConfigSet::ConfigSet()
    : mSet(SortConfig(mSortAttribs))
{
}

void ConfigSet::add(const DisplayMode &displayMode, EGLint minSwapInterval, EGLint maxSwapInterval, sw::Format renderTargetFormat, sw::Format depthStencilFormat, EGLint multiSample)
{
    Config config(displayMode, minSwapInterval, maxSwapInterval, renderTargetFormat, depthStencilFormat, multiSample);

    mSet.insert(config);
}

size_t ConfigSet::size() const
{
    return mSet.size();
}

bool ConfigSet::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig)
{
    vector<const Config*> passed;
    passed.reserve(mSet.size());

    for(Iterator config = mSet.begin(); config != mSet.end(); config++)
    {
        bool match = true;
        const EGLint *attribute = attribList;

        while(attribute[0] != EGL_NONE)
        {
            switch(attribute[0])
            {
            case EGL_BUFFER_SIZE:                match = config->mBufferSize >= attribute[1];                      break;
            case EGL_ALPHA_SIZE:                 match = config->mAlphaSize >= attribute[1];                       break;
            case EGL_BLUE_SIZE:                  match = config->mBlueSize >= attribute[1];                        break;
            case EGL_GREEN_SIZE:                 match = config->mGreenSize >= attribute[1];                       break;
            case EGL_RED_SIZE:                   match = config->mRedSize >= attribute[1];                         break;
            case EGL_DEPTH_SIZE:                 match = config->mDepthSize >= attribute[1];                       break;
            case EGL_STENCIL_SIZE:               match = config->mStencilSize >= attribute[1];                     break;
            case EGL_CONFIG_CAVEAT:              match = config->mConfigCaveat == attribute[1];                    break;
            case EGL_CONFIG_ID:                  match = config->mConfigID == attribute[1];                        break;
            case EGL_LEVEL:                      match = config->mLevel >= attribute[1];                           break;
            case EGL_NATIVE_RENDERABLE:          match = config->mNativeRenderable == attribute[1];                break;
            case EGL_NATIVE_VISUAL_ID:           match = config->mNativeVisualID == attribute[1];                  break;
            case EGL_NATIVE_VISUAL_TYPE:         match = config->mNativeVisualType == attribute[1];                break;
            case EGL_SAMPLES:                    match = config->mSamples >= attribute[1];                         break;
            case EGL_SAMPLE_BUFFERS:             match = config->mSampleBuffers >= attribute[1];                   break;
            case EGL_SURFACE_TYPE:               match = (config->mSurfaceType & attribute[1]) == attribute[1];    break;
            case EGL_TRANSPARENT_TYPE:           match = config->mTransparentType == attribute[1];                 break;
            case EGL_TRANSPARENT_BLUE_VALUE:     match = config->mTransparentBlueValue == attribute[1];            break;
            case EGL_TRANSPARENT_GREEN_VALUE:    match = config->mTransparentGreenValue == attribute[1];           break;
            case EGL_TRANSPARENT_RED_VALUE:      match = config->mTransparentRedValue == attribute[1];             break;
            case EGL_BIND_TO_TEXTURE_RGB:        match = config->mBindToTextureRGB == attribute[1];                break;
            case EGL_BIND_TO_TEXTURE_RGBA:       match = config->mBindToTextureRGBA == attribute[1];               break;
            case EGL_MIN_SWAP_INTERVAL:          match = config->mMinSwapInterval == attribute[1];                 break;
            case EGL_MAX_SWAP_INTERVAL:          match = config->mMaxSwapInterval == attribute[1];                 break;
            case EGL_LUMINANCE_SIZE:             match = config->mLuminanceSize >= attribute[1];                   break;
            case EGL_ALPHA_MASK_SIZE:            match = config->mAlphaMaskSize >= attribute[1];                   break;
            case EGL_COLOR_BUFFER_TYPE:          match = config->mColorBufferType == attribute[1];                 break;
            case EGL_RENDERABLE_TYPE:            match = (config->mRenderableType & attribute[1]) == attribute[1]; break;
            case EGL_MATCH_NATIVE_PIXMAP:        match = false; UNIMPLEMENTED();                                   break;
            case EGL_CONFORMANT:                 match = (config->mConformant & attribute[1]) == attribute[1];     break;
            case EGL_MAX_PBUFFER_WIDTH:          match = config->mMaxPBufferWidth >= attribute[1];                 break;
            case EGL_MAX_PBUFFER_HEIGHT:         match = config->mMaxPBufferHeight >= attribute[1];                break;
            case EGL_MAX_PBUFFER_PIXELS:         match = config->mMaxPBufferPixels >= attribute[1];                break;
            case EGL_RECORDABLE_ANDROID:         match = true; /* UNIMPLEMENTED(); EGL_ANDROID_recordable */       break;
            case EGL_FRAMEBUFFER_TARGET_ANDROID: match = true; /* UNIMPLEMENTED(); EGL_ANDROID_framebuffer_target */ break;
			default:
				UNIMPLEMENTED();
				match = false;
            }

            if(!match)
            {
                break;
            }

            attribute += 2;
        }

        if(match)
        {
            passed.push_back(&*config);
        }
    }

    if(configs)
    {
        sort(passed.begin(), passed.end(), SortConfig(attribList));

        EGLint index;
        for(index = 0; index < configSize && index < static_cast<EGLint>(passed.size()); index++)
        {
            configs[index] = passed[index]->getHandle();
        }

        *numConfig = index;
    }
    else
    {
        *numConfig = static_cast<EGLint>(passed.size());
    }

    return true;
}

const egl::Config *ConfigSet::get(EGLConfig configHandle)
{
    for(Iterator config = mSet.begin(); config != mSet.end(); config++)
    {
        if(config->getHandle() == configHandle)
        {
            return &(*config);
        }
    }

    return NULL;
}
}
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2020 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once

#include "util/Compiler.h"
#include "util/Expiry.hxx"

#include <iterator>

#include <assert.h>

/**
 * Pick an address using a #sticky_hash_t module the list size.  If
 * that address is failed, pick the next one.
 */
template<typename List>
gcc_pure
const auto &
PickModulo(Expiry now, const List &list, sticky_hash_t sticky_hash) noexcept
{
	const size_t n = std::size(list);
	assert(n >= 2);

	const size_t modulo = sticky_hash % n;
	bool allow_fade = true;

	const auto selected = std::next(std::begin(list), modulo);
	const auto end = std::end(list);

	auto i = selected;
	do {
		if (list.Check(now, *i, allow_fade))
			break;

		/* only the first iteration is allowed to override
		   FAILURE_FADE */
		allow_fade = false;

		++i;
		if (i == end)
			i = std::begin(list);
	} while (i != selected);

	/* all addresses failed: */
	return *i;
}
<commit_msg>cluster/PickModulo: add missing include<commit_after>/*
 * Copyright 2007-2020 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once

#include "StickyHash.hxx"
#include "util/Compiler.h"
#include "util/Expiry.hxx"

#include <iterator>

#include <assert.h>

/**
 * Pick an address using a #sticky_hash_t module the list size.  If
 * that address is failed, pick the next one.
 */
template<typename List>
gcc_pure
const auto &
PickModulo(Expiry now, const List &list, sticky_hash_t sticky_hash) noexcept
{
	const size_t n = std::size(list);
	assert(n >= 2);

	const size_t modulo = sticky_hash % n;
	bool allow_fade = true;

	const auto selected = std::next(std::begin(list), modulo);
	const auto end = std::end(list);

	auto i = selected;
	do {
		if (list.Check(now, *i, allow_fade))
			break;

		/* only the first iteration is allowed to override
		   FAILURE_FADE */
		allow_fade = false;

		++i;
		if (i == end)
			i = std::begin(list);
	} while (i != selected);

	/* all addresses failed: */
	return *i;
}
<|endoftext|>


<commit_before>#include "enginesync.h"

#include <QApplication>
#include <QFile>
#include <QFileInfo>
#include <QDir>
#include <QDebug>

#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <boost/foreach.hpp>

#include "lib_json/json.h"

#include "processinfo.h"
#include "common.h"
#include "qutils.h"
#include "tempfiles.h"

using namespace boost::interprocess;
using namespace std;

EngineSync::EngineSync(Analyses *analyses, QObject *parent = 0)
	: QObject(parent)
{
	_analyses = analyses;
	_engineStarted = false;

	_log = NULL;
	_ppi = 96;

	connect(_analyses, SIGNAL(analysisAdded(Analysis*)), this, SLOT(sendMessages()));
	connect(_analyses, SIGNAL(analysisOptionsChanged(Analysis*)), this, SLOT(sendMessages()));

	// delay start so as not to increase program start up time
	QTimer::singleShot(100, this, SLOT(deleteOrphanedTempFiles()));
}

EngineSync::~EngineSync()
{
	if (_engineStarted)
	{
		for (int i = 0; i < _slaveProcesses.size(); i++)
		{
			_slaveProcesses[i]->terminate();
			_slaveProcesses[i]->kill();
		}

		tempfiles_deleteAll();
	}

	shared_memory_object::remove(_memoryName.c_str());
}

void EngineSync::start()
{
	if (_engineStarted)
		return;

	_engineStarted = true;

	try {

		unsigned long pid = ProcessInfo::currentPID();

		stringstream ss;
		ss << "JASP-IPC-" << pid;

		_memoryName = ss.str();

		_channels.push_back(new IPCChannel(_memoryName, 0));

#ifdef QT_NO_DEBUG
		_channels.push_back(new IPCChannel(_memoryName, 1));
		_channels.push_back(new IPCChannel(_memoryName, 2));
		_channels.push_back(new IPCChannel(_memoryName, 3));
#endif

	}
	catch (interprocess_exception e)
	{
		qDebug() << "interprocess exception! " << e.what() << "\n";
		throw e;
	}

	for (uint i = 0; i < _channels.size(); i++)
	{
		_analysesInProgress.push_back(NULL);
		startSlaveProcess(i);
	}

	QTimer *timer;

	timer = new QTimer(this);
	connect(timer, SIGNAL(timeout()), this, SLOT(process()));
	timer->start(50);

	timer = new QTimer(this);
	connect(timer, SIGNAL(timeout()), this, SLOT(heartbeatTempFiles()));
	timer->start(30000);
}

bool EngineSync::engineStarted()
{
	return _engineStarted;
}

void EngineSync::setLog(ActivityLog *log)
{
	_log = log;
}

void EngineSync::setPPI(int ppi)
{
	_ppi = ppi;
}

void EngineSync::sendToProcess(int processNo, Analysis *analysis)
{
#ifdef QT_DEBUG
	std::cout << "send " << analysis->id() << " to process " << processNo << "\n";
	std::cout.flush();
#endif

	string perform;

	if (analysis->status() == Analysis::Empty)
	{
		perform = "init";
		analysis->setStatus(Analysis::Initing);
	}
	else if (analysis->status() == Analysis::Aborting)
	{
		perform = "abort";
		analysis->setStatus(Analysis::Aborted);
	}
	else
	{
		perform = "run";
		analysis->setStatus(Analysis::Running);
	}

	_analysesInProgress[processNo] = analysis;

	Json::Value json = Json::Value(Json::objectValue);

	json["id"] = analysis->id();
	json["perform"] = perform;

	if (analysis->status() != Analysis::Aborted)
	{
		json["name"] = analysis->name();
		json["options"] = analysis->options()->asJSON();

		Json::Value settings;
		settings["ppi"] = _ppi;

		json["settings"] = settings;
	}

	string str = json.toStyledString();

	_channels[processNo]->send(str);

#ifndef QT_NO_DEBUG
	cout << str << "\n";
	cout.flush();
#endif

}

void EngineSync::process()
{
	for (int i = 0; i < _channels.size(); i++)
	{
		Analysis *analysis = _analysesInProgress[i];

		if (analysis == NULL)
			continue;

		IPCChannel *channel = _channels[i];
		string data;

		if (channel->receive(data))
		{
#ifdef QT_DEBUG
			std::cout << "message received\n";
			std::cout << data << "\n";
			std::cout.flush();
#endif

			Json::Reader reader;
			Json::Value json;
			reader.parse(data, json);

			int id = json.get("id", -1).asInt();
			Json::Value results = json.get("results", Json::nullValue);
			string status = json.get("status", "error").asString();

			if (status == "error")
			{
				analysis->setStatus(Analysis::Complete);
				analysis->setResults(results);
				_analysesInProgress[i] = NULL;
				sendMessages();

				if (_log != NULL)
				{
					QString errorMessage = tq(results.get("errorMessage", "").asString());
					QString info = QString("%1,%2").arg(id).arg(errorMessage);
					_log->log("Analysis Error", info);
				}
			}
			else if (status == "complete")
			{
				analysis->setStatus(Analysis::Complete);
				analysis->setResults(results);
				_analysesInProgress[i] = NULL;
				sendMessages();
			}
			else if (status == "running" && analysis->status() == Analysis::Initing)
			{
				analysis->setStatus(Analysis::Running);
				analysis->setResults(results);
			}
			else if (analysis->status() == Analysis::Running)
			{
				analysis->setResults(results);
			}
			else if (analysis->status() == Analysis::Initing)
			{
				if (analysis->isAutorun())
					analysis->setStatus(Analysis::Inited);
				else
					analysis->setStatus(Analysis::InitedAndWaiting);

				analysis->setResults(results);
				_analysesInProgress[i] = NULL;
				sendMessages();
			}
			else
			{
				sendMessages();
			}
		}

	}
}

void EngineSync::sendMessages()
{
#ifdef QT_DEBUG
	std::cout << "send messages\n";
	std::cout.flush();
#endif

	for (int i = 0; i < _analysesInProgress.size(); i++) // this loop handles changes in running analyses
	{
		Analysis *analysis = _analysesInProgress[i];
		if (analysis != NULL)
		{
			if (analysis->status() == Analysis::Empty)
			{
				sendToProcess(i, analysis);
			}
			else if (analysis->status() == Analysis::Aborting)
			{
				sendToProcess(i, analysis);
				_analysesInProgress[i] = NULL;
			}
		}
	}

	for (Analyses::iterator itr = _analyses->begin(); itr != _analyses->end(); itr++)
	{
		Analysis *analysis = *itr;
		if (analysis == NULL)
			continue;

		if (analysis->status() == Analysis::Empty)
		{
			bool sent = false;

			for (int i = 0; i < _analysesInProgress.size(); i++)
			{
				if (_analysesInProgress[i] == NULL)
				{
					sendToProcess(i, analysis);
					sent = true;
					break;
				}
			}

			if (sent == false)  // no free processes left
				return;
		}
		else if (analysis->status() == Analysis::Inited)
		{
#ifndef QT_DEBUG
			for (int i = 1; i < _analysesInProgress.size(); i++) // don't perform 'runs' on process 0, only inits.
#else
			for (int i = 0; i < _analysesInProgress.size(); i++)
#endif
			{
				if (_analysesInProgress[i] == NULL)
				{
					sendToProcess(i, analysis);
					break;
				}
			}
		}
	}

}

void EngineSync::startSlaveProcess(int no)
{
	QDir programDir = QFileInfo( QCoreApplication::applicationFilePath() ).absoluteDir();
	QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
	QString engineExe = QFileInfo( QCoreApplication::applicationFilePath() ).absoluteDir().absoluteFilePath("JASPEngine");

	QStringList args;
	args << QString::number(no);

#ifdef __WIN32__

#if defined(ARCH_32)
#define ARCH_SUBPATH "i386"
#else
#define ARCH_SUBPATH "x64"
#endif

	env.insert("PATH", programDir.absoluteFilePath("R\\library\\RInside\\libs\\" ARCH_SUBPATH) + ";" + programDir.absoluteFilePath("R\\library\\Rcpp\\libs\\" ARCH_SUBPATH) + ";" + programDir.absoluteFilePath("R\\bin\\" ARCH_SUBPATH));
	env.insert("R_HOME", programDir.absoluteFilePath("R"));

	unsigned long processId = ProcessInfo::currentPID();
    args << QString::number(processId);

#undef ARCH_SUBPATH

#elif __APPLE__
	env.insert("R_HOME", programDir.absoluteFilePath("../Frameworks/R.framework/Versions/3.1/Resources"));
#else
    env.insert("LD_LIBRARY_PATH", programDir.absoluteFilePath("R/lib") + ";" + programDir.absoluteFilePath("R/library/RInside/lib") + ";" + programDir.absoluteFilePath("R/library/Rcpp/lib"));
	env.insert("R_HOME", programDir.absoluteFilePath("R"));
#endif

	QProcess *slave = new QProcess(this);
	slave->setProcessEnvironment(env);
	slave->start(engineExe, args);

	_slaveProcesses.push_back(slave);

	connect(slave, SIGNAL(readyReadStandardOutput()), this, SLOT(subProcessStandardOutput()));
	connect(slave, SIGNAL(readyReadStandardError()), this, SLOT(subProcessStandardError()));
	connect(slave, SIGNAL(error(QProcess::ProcessError)), this, SLOT(subProcessError(QProcess::ProcessError)));
	connect(slave, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(subprocessFinished(int,QProcess::ExitStatus)));
	connect(slave, SIGNAL(started()), this, SLOT(subProcessStarted()));
}

void EngineSync::deleteOrphanedTempFiles()
{
	tempfiles_deleteOrphans();
}

void EngineSync::heartbeatTempFiles()
{
	tempfiles_heartbeat();
}

void EngineSync::subProcessStandardOutput()
{
	QProcess *process = qobject_cast<QProcess *>(this->sender());
	QByteArray data = process->readAllStandardOutput();
	qDebug() << QString(data);
}

void EngineSync::subProcessStandardError()
{
	QProcess *process = qobject_cast<QProcess *>(this->sender());
	qDebug() << process->readAllStandardError();
}

void EngineSync::subProcessStarted()
{
	qDebug() << "subprocess started";
}

void EngineSync::subProcessError(QProcess::ProcessError error)
{
	emit engineTerminated();

	qDebug() << "subprocess error" << error;
}

void EngineSync::subprocessFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
	qDebug() << "subprocess finished" << exitCode;
}

<commit_msg>Fix to analysis status transition<commit_after>#include "enginesync.h"

#include <QApplication>
#include <QFile>
#include <QFileInfo>
#include <QDir>
#include <QDebug>

#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <boost/foreach.hpp>

#include "lib_json/json.h"

#include "processinfo.h"
#include "common.h"
#include "qutils.h"
#include "tempfiles.h"

using namespace boost::interprocess;
using namespace std;

EngineSync::EngineSync(Analyses *analyses, QObject *parent = 0)
	: QObject(parent)
{
	_analyses = analyses;
	_engineStarted = false;

	_log = NULL;
	_ppi = 96;

	connect(_analyses, SIGNAL(analysisAdded(Analysis*)), this, SLOT(sendMessages()));
	connect(_analyses, SIGNAL(analysisOptionsChanged(Analysis*)), this, SLOT(sendMessages()));

	// delay start so as not to increase program start up time
	QTimer::singleShot(100, this, SLOT(deleteOrphanedTempFiles()));
}

EngineSync::~EngineSync()
{
	if (_engineStarted)
	{
		for (int i = 0; i < _slaveProcesses.size(); i++)
		{
			_slaveProcesses[i]->terminate();
			_slaveProcesses[i]->kill();
		}

		tempfiles_deleteAll();
	}

	shared_memory_object::remove(_memoryName.c_str());
}

void EngineSync::start()
{
	if (_engineStarted)
		return;

	_engineStarted = true;

	try {

		unsigned long pid = ProcessInfo::currentPID();

		stringstream ss;
		ss << "JASP-IPC-" << pid;

		_memoryName = ss.str();

		_channels.push_back(new IPCChannel(_memoryName, 0));

#ifdef QT_NO_DEBUG
		_channels.push_back(new IPCChannel(_memoryName, 1));
		_channels.push_back(new IPCChannel(_memoryName, 2));
		_channels.push_back(new IPCChannel(_memoryName, 3));
#endif

	}
	catch (interprocess_exception e)
	{
		qDebug() << "interprocess exception! " << e.what() << "\n";
		throw e;
	}

	for (uint i = 0; i < _channels.size(); i++)
	{
		_analysesInProgress.push_back(NULL);
		startSlaveProcess(i);
	}

	QTimer *timer;

	timer = new QTimer(this);
	connect(timer, SIGNAL(timeout()), this, SLOT(process()));
	timer->start(50);

	timer = new QTimer(this);
	connect(timer, SIGNAL(timeout()), this, SLOT(heartbeatTempFiles()));
	timer->start(30000);
}

bool EngineSync::engineStarted()
{
	return _engineStarted;
}

void EngineSync::setLog(ActivityLog *log)
{
	_log = log;
}

void EngineSync::setPPI(int ppi)
{
	_ppi = ppi;
}

void EngineSync::sendToProcess(int processNo, Analysis *analysis)
{
#ifdef QT_DEBUG
	std::cout << "send " << analysis->id() << " to process " << processNo << "\n";
	std::cout.flush();
#endif

	string perform;

	if (analysis->status() == Analysis::Empty)
	{
		perform = "init";
		analysis->setStatus(Analysis::Initing);
	}
	else if (analysis->status() == Analysis::Aborting)
	{
		perform = "abort";
		analysis->setStatus(Analysis::Aborted);
	}
	else
	{
		perform = "run";
		analysis->setStatus(Analysis::Running);
	}

	_analysesInProgress[processNo] = analysis;

	Json::Value json = Json::Value(Json::objectValue);

	json["id"] = analysis->id();
	json["perform"] = perform;

	if (analysis->status() != Analysis::Aborted)
	{
		json["name"] = analysis->name();
		json["options"] = analysis->options()->asJSON();

		Json::Value settings;
		settings["ppi"] = _ppi;

		json["settings"] = settings;
	}

	string str = json.toStyledString();

	_channels[processNo]->send(str);

#ifndef QT_NO_DEBUG
	cout << str << "\n";
	cout.flush();
#endif

}

void EngineSync::process()
{
	for (int i = 0; i < _channels.size(); i++)
	{
		Analysis *analysis = _analysesInProgress[i];

		if (analysis == NULL)
			continue;

		IPCChannel *channel = _channels[i];
		string data;

		if (channel->receive(data))
		{
#ifdef QT_DEBUG
			std::cout << "message received\n";
			std::cout << data << "\n";
			std::cout.flush();
#endif

			Json::Reader reader;
			Json::Value json;
			reader.parse(data, json);

			int id = json.get("id", -1).asInt();
			Json::Value results = json.get("results", Json::nullValue);
			string status = json.get("status", "error").asString();

			if (status == "error")
			{
				analysis->setStatus(Analysis::Complete);
				analysis->setResults(results);
				_analysesInProgress[i] = NULL;
				sendMessages();

				if (_log != NULL)
				{
					QString errorMessage = tq(results.get("errorMessage", "").asString());
					QString info = QString("%1,%2").arg(id).arg(errorMessage);
					_log->log("Analysis Error", info);
				}
			}
			else if (status == "complete")
			{
				analysis->setStatus(Analysis::Complete);
				analysis->setResults(results);
				_analysesInProgress[i] = NULL;
				sendMessages();
			}
			else if (status == "inited")
			{
				if (analysis->isAutorun())
					analysis->setStatus(Analysis::Inited);
				else
					analysis->setStatus(Analysis::InitedAndWaiting);

				analysis->setResults(results);
				_analysesInProgress[i] = NULL;
				sendMessages();
			}
			else if (status == "running" && analysis->status() == Analysis::Initing)
			{
				analysis->setStatus(Analysis::Running);
				analysis->setResults(results);
			}
			else if (analysis->status() == Analysis::Running)
			{
				analysis->setResults(results);
			}
			else
			{
				sendMessages();
			}
		}

	}
}

void EngineSync::sendMessages()
{
#ifdef QT_DEBUG
	std::cout << "send messages\n";
	std::cout.flush();
#endif

	for (int i = 0; i < _analysesInProgress.size(); i++) // this loop handles changes in running analyses
	{
		Analysis *analysis = _analysesInProgress[i];
		if (analysis != NULL)
		{
			if (analysis->status() == Analysis::Empty)
			{
				sendToProcess(i, analysis);
			}
			else if (analysis->status() == Analysis::Aborting)
			{
				sendToProcess(i, analysis);
				_analysesInProgress[i] = NULL;
			}
		}
	}

	for (Analyses::iterator itr = _analyses->begin(); itr != _analyses->end(); itr++)
	{
		Analysis *analysis = *itr;
		if (analysis == NULL)
			continue;

		if (analysis->status() == Analysis::Empty)
		{
			bool sent = false;

			for (int i = 0; i < _analysesInProgress.size(); i++)
			{
				if (_analysesInProgress[i] == NULL)
				{
					sendToProcess(i, analysis);
					sent = true;
					break;
				}
			}

			if (sent == false)  // no free processes left
				return;
		}
		else if (analysis->status() == Analysis::Inited)
		{
#ifndef QT_DEBUG
			for (int i = 1; i < _analysesInProgress.size(); i++) // don't perform 'runs' on process 0, only inits.
#else
			for (int i = 0; i < _analysesInProgress.size(); i++)
#endif
			{
				if (_analysesInProgress[i] == NULL)
				{
					sendToProcess(i, analysis);
					break;
				}
			}
		}
	}

}

void EngineSync::startSlaveProcess(int no)
{
	QDir programDir = QFileInfo( QCoreApplication::applicationFilePath() ).absoluteDir();
	QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
	QString engineExe = QFileInfo( QCoreApplication::applicationFilePath() ).absoluteDir().absoluteFilePath("JASPEngine");

	QStringList args;
	args << QString::number(no);

#ifdef __WIN32__

#if defined(ARCH_32)
#define ARCH_SUBPATH "i386"
#else
#define ARCH_SUBPATH "x64"
#endif

	env.insert("PATH", programDir.absoluteFilePath("R\\library\\RInside\\libs\\" ARCH_SUBPATH) + ";" + programDir.absoluteFilePath("R\\library\\Rcpp\\libs\\" ARCH_SUBPATH) + ";" + programDir.absoluteFilePath("R\\bin\\" ARCH_SUBPATH));
	env.insert("R_HOME", programDir.absoluteFilePath("R"));

	unsigned long processId = ProcessInfo::currentPID();
    args << QString::number(processId);

#undef ARCH_SUBPATH

#elif __APPLE__
	env.insert("R_HOME", programDir.absoluteFilePath("../Frameworks/R.framework/Versions/3.1/Resources"));
#else
    env.insert("LD_LIBRARY_PATH", programDir.absoluteFilePath("R/lib") + ";" + programDir.absoluteFilePath("R/library/RInside/lib") + ";" + programDir.absoluteFilePath("R/library/Rcpp/lib"));
	env.insert("R_HOME", programDir.absoluteFilePath("R"));
#endif

	QProcess *slave = new QProcess(this);
	slave->setProcessEnvironment(env);
	slave->start(engineExe, args);

	_slaveProcesses.push_back(slave);

	connect(slave, SIGNAL(readyReadStandardOutput()), this, SLOT(subProcessStandardOutput()));
	connect(slave, SIGNAL(readyReadStandardError()), this, SLOT(subProcessStandardError()));
	connect(slave, SIGNAL(error(QProcess::ProcessError)), this, SLOT(subProcessError(QProcess::ProcessError)));
	connect(slave, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(subprocessFinished(int,QProcess::ExitStatus)));
	connect(slave, SIGNAL(started()), this, SLOT(subProcessStarted()));
}

void EngineSync::deleteOrphanedTempFiles()
{
	tempfiles_deleteOrphans();
}

void EngineSync::heartbeatTempFiles()
{
	tempfiles_heartbeat();
}

void EngineSync::subProcessStandardOutput()
{
	QProcess *process = qobject_cast<QProcess *>(this->sender());
	QByteArray data = process->readAllStandardOutput();
	qDebug() << QString(data);
}

void EngineSync::subProcessStandardError()
{
	QProcess *process = qobject_cast<QProcess *>(this->sender());
	qDebug() << process->readAllStandardError();
}

void EngineSync::subProcessStarted()
{
	qDebug() << "subprocess started";
}

void EngineSync::subProcessError(QProcess::ProcessError error)
{
	emit engineTerminated();

	qDebug() << "subprocess error" << error;
}

void EngineSync::subprocessFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
	qDebug() << "subprocess finished" << exitCode;
}

<|endoftext|>


<commit_before>#pragma once

#include <string>
#include <cassert>
#include <vector>
#include <list>
#include <utility>
#include "syntax.hpp"

namespace popo {
namespace semantic {

    enum struct function_numbers{
        //special form
        DEFINE = -1,
        LAMBDA = -2,
        QUOTA = -3,
        IF = -4,

        //built in function
        PLUS = -5,
        MINUS = -6,
        MULTIPLY = -7,
        DIVIDE = -8,
    };

    // symbol table
    enum struct entry_type { value, function, not_found};
    struct symbol_table_entry {

        public:
            symbol_table_entry(entry_type t) : type_(t){};
            symbol_table_entry() : type_(entry_type::not_found){};

        public:
            entry_type type_;
    };

    struct function_entry : public symbol_table_entry {

        public:
            function_entry(int arg_num, int entry_num)
                : symbol_table_entry(entry_type::function),
                  argument_num_(arg_num),
                  table_entry_num_(entry_num) {};

            function_entry(int arg_num, function_numbers num)
                : function_entry(arg_num, static_cast<int>(num)){};

        public:
            int argument_num_;
            int table_entry_num_;
    };

    struct value_entry : public symbol_table_entry {

        public:
            enum struct value_type { INT, STRING, SYMBOL, };

        public:
            value_entry(std::string n, value_type t)
                : symbol_table_entry(entry_type::value), type_(t)
            {
                if (t == value_type::STRING) {
                    v_string = n;
                } else if (t == value_type::SYMBOL) {
                    v_symbol = n;
                }
            };

            value_entry(int n, value_type t)
                : symbol_table_entry(entry_type::value), type_(t)
            {
                v_int = n;
            };

        private:
            union {
                int v_int;
                std::string v_string;
                std::string v_symbol;
            };
            value_type type_;
    };

    const std::pair<std::string, function_entry> special_form[] = {
        std::pair<std::string, function_entry>(
            "define", function_entry(2, function_numbers::DEFINE)),
        // (define symbol atom | list | function)
        std::pair<std::string, function_entry>(
            "lambda", function_entry(2, function_numbers::LAMBDA)),
        // (lambda list list) -> function
        std::pair<std::string, function_entry>(
            "quota", function_entry(1, function_numbers::QUOTA)),
        // (quota list) -> list
        std::pair<std::string, function_entry>(
            "if", function_entry(2, function_numbers::IF))
        // (if t | nil | function function)
    };

    const std::pair<std::string, function_entry> built_in_function[] = {
        std::pair<std::string ,function_entry>(
                "+", function_entry(2, function_numbers::PLUS)),

        std::pair<std::string ,function_entry>(
                "-", function_entry(2, function_numbers::MINUS)),

        std::pair<std::string ,function_entry>(
                "*", function_entry(2, function_numbers::MULTIPLY)),

        std::pair<std::string ,function_entry>(
                "/", function_entry(2, function_numbers::DIVIDE))
    };

    template <typename Iteratable>
    class semantic_analyser {

    public:
        semantic_analyser(const Iteratable& itr)
            : parser_(itr), symbol_table(), function_table()
        {
            for (auto&& sf : special_form) {
                symbol_table.table_stack.push_front(sf);
            }

            for (auto&& bf : built_in_function) {
                symbol_table.table_stack.push_front(bf);
            }

            analyse();
        };

    private:
        auto analyse() -> void
        {
            auto function_name =
                static_cast<syntax::string_node*>(
                    static_cast<syntax::cons_node*>(parser_.s_exp_parse().get())
                        ->car.get())->val;

            auto pair = search_function(function_name);
            assert(entry_type::not_found != pair.second.type_);

            //TODO:
        }

        auto search_function(std::string func_name)
            -> std::pair<std::string, symbol_table_entry>
        {
            for(auto& data: symbol_table.table_stack){
                std::cout << data.first << std::endl;
                if(data.first == func_name){
                    return data;
                }
            }

            return std::make_pair("", symbol_table_entry());
        }

    private:
        syntax::s_expression_parser<Iteratable> parser_;

        struct symbol_table_stack
        {
            public:
                symbol_table_stack() : table_stack(), local_symbol_num(0) {};

            public:
                std::list<std::pair<std::string, symbol_table_entry>> table_stack;
                int local_symbol_num;
        } symbol_table;

        std::vector<std::unique_ptr<syntax::cons_node>> function_table;
    };

}  // namespace semantic
}  // namespace popo
<commit_msg>fix analyser<commit_after>#pragma once

#include <string>
#include <cassert>
#include <vector>
#include <list>
#include <utility>
#include "syntax.hpp"

namespace popo {
namespace semantic {

    enum struct function_numbers{
        //special form
        DEFINE = -1,
        LAMBDA = -2,
        QUOTA = -3,
        IF = -4,

        //built in function
        PLUS = -5,
        MINUS = -6,
        MULTIPLY = -7,
        DIVIDE = -8,
    };

    // symbol table
    enum struct entry_type { value, function, not_found};
    struct symbol_table_entry {

        public:
            symbol_table_entry(entry_type t) : type_(t){};
            symbol_table_entry() : type_(entry_type::not_found){};
            virtual ~symbol_table_entry() {};

        public:
            entry_type type_;
    };

    struct function_entry : public symbol_table_entry {

        public:
            function_entry(int arg_num, int entry_num)
                : symbol_table_entry(entry_type::function),
                  argument_num_(arg_num),
                  table_entry_num_(entry_num) {};

            function_entry(int arg_num, function_numbers num)
                : function_entry(arg_num, static_cast<int>(num)){};

            virtual ~function_entry(){};

        public:
            int argument_num_;
            int table_entry_num_;
    };

    struct value_entry : public symbol_table_entry {

        public:
            enum struct value_type { INT, STRING, SYMBOL, };

        public:
            value_entry(std::string n, value_type t)
                : symbol_table_entry(entry_type::value), type_(t)
            {
                if (t == value_type::STRING) {
                    v_string = n;
                } else if (t == value_type::SYMBOL) {
                    v_symbol = n;
                }
            };

            value_entry(int n, value_type t)
                : symbol_table_entry(entry_type::value), type_(t)
            {
                v_int = n;
            };

            virtual ~value_entry() {};

        private:
            union {
                int v_int;
                std::string v_string;
                std::string v_symbol;
            };
            value_type type_;
    };

    const std::pair<std::string, function_entry> special_form[] = {
        std::pair<std::string, function_entry>(
            "define", function_entry(2, function_numbers::DEFINE)),
        // (define symbol atom | list | function)
        std::pair<std::string, function_entry>(
            "lambda", function_entry(2, function_numbers::LAMBDA)),
        // (lambda list list) -> function
        std::pair<std::string, function_entry>(
            "quota", function_entry(1, function_numbers::QUOTA)),
        // (quota list) -> list
        std::pair<std::string, function_entry>(
            "if", function_entry(2, function_numbers::IF))
        // (if t | nil | function function)
    };

    const std::pair<std::string, function_entry> built_in_function[] = {
        std::pair<std::string ,function_entry>(
                "+", function_entry(2, function_numbers::PLUS)),

        std::pair<std::string ,function_entry>(
                "-", function_entry(2, function_numbers::MINUS)),

        std::pair<std::string ,function_entry>(
                "*", function_entry(2, function_numbers::MULTIPLY)),

        std::pair<std::string ,function_entry>(
                "/", function_entry(2, function_numbers::DIVIDE))
    };

    template <typename Iteratable>
    class semantic_analyser {

    public:
        semantic_analyser(const Iteratable& itr)
            : parser_(itr), symbol_table(), function_table()
        {
            for (auto&& sf : special_form) {
                symbol_table.table_stack.push_front(sf);
            }

            for (auto&& bf : built_in_function) {
                symbol_table.table_stack.push_front(bf);
            }

            analyse();
        };

    private:

        auto check_argument_num(const syntax::expr_node* cons, int argc)
            -> bool
        {
            if (syntax::node_type::nil == cons->type && 0 == argc) {
                return true;
            } else if (argc < 0) {
                return false;
            }

            if(syntax::node_type::nil == cons->type){

                if(argc == 0){
                    return true;
                }
                else {
                    return false;
                }
            }
            else if(argc < 0){
                return false;
            }

            return check_argument_num(static_cast<const syntax::cons_node*>(cons)->cdr.get(), argc--);
        }

        auto analyse() -> void
        {

            std::unique_ptr<syntax::cons_node> cons(
                static_cast<syntax::cons_node*>(
                    parser_.s_exp_parse().release()));

            // type check
            assert(syntax::node_type::string == cons->car->type);

            auto function_name =
                static_cast<syntax::string_node*>(cons->car.get())->val;

            auto pair = search_function(function_name);
            // check function definition
            assert(entry_type::function == pair.second.type_);

            //TODO しらべる below code
//             auto arg_num = dynamic_cast<function_entry&>(pair.second).argument_num_;
//             std::cout << "arg: " << arg_num << std::endl;
            // argument check of number
//             assert(check_argument_num(cons.get(), arg_num));

            // TODO:
        }

        auto search_function(std::string func_name)
            -> std::pair<std::string, symbol_table_entry>
        {
            for(auto& data: symbol_table.table_stack){
//                 std::cout << data.second.argument_num_ << std::endl;
                if(data.first == func_name){
                    return data;
                }
            }

            return std::make_pair("", symbol_table_entry());
        }

    private:
        syntax::s_expression_parser<Iteratable> parser_;

        struct symbol_table_stack
        {
            public:
                symbol_table_stack() : table_stack(), local_symbol_num(0) {};

            public:
                std::list<std::pair<std::string, symbol_table_entry>> table_stack;
                int local_symbol_num;
        } symbol_table;

        std::vector<std::unique_ptr<syntax::cons_node>> function_table;
    };

}  // namespace semantic
}  // namespace popo
<|endoftext|>


<commit_before>// Copyright 2012 Alessio Sclocco <a.sclocco@vu.nl>
//
// 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 <fstream>
#include <vector>
#include <string>
#include <cmath>
#include <H5Cpp.h>

#include <Observation.hpp>
#include <utils.hpp>

#ifndef READ_DATA_HPP
#define READ_DATA_HPP

namespace AstroData {

template< typename T > void readSIGPROC(Observation & observation, const unsigned int bytestoSkip, std::string inputFilename, std::vector< std::vector< T > * > & data, unsigned int firstSecond = 0);
template< typename T > void readLOFAR(std::string headerFilename, std::string rawFilename, Observation & observation, std::vector< std::vector< T > * > & data, unsigned int nrSeconds = 0, unsigned int firstSecond = 0);

// Implementation

template< typename T > void readSIGPROC(Observation & observation, unsigned int bytesToSkip, std::string inputFilename, std::vector< std::vector< T > * > & data, unsigned int firstSecond) {
	std::ifstream inputFile;
	const unsigned int BUFFER_DIM = 4;
	char * buffer = new char [BUFFER_DIM];

	inputFile.open(inputFilename.c_str(), std::ios::binary);
	inputFile.sync_with_stdio(false);
	inputFile.seekg(bytesToSkip, std::ios::beg);
	for ( unsigned int second = 0; second < observation.getNrSeconds(); second++ ) {
		data.at(second) = new std::vector< T >(observation.getNrSamplesPerPaddedSecond() * observation.getNrChannels());

		for ( unsigned int sample = 0; sample < observation.getNrSamplesPerSecond(); sample++ ) {
			for ( unsigned int channel = observation.getNrChannels(); channel > 0; channel-- ) {
				inputFile.read(buffer, BUFFER_DIM);
        data.at(second)[(static_cast< long long unsigned int >(channel - 1) * observation.getNrSamplesPerPaddedSecond()) + sample] = *(reinterpret_cast< T * >(buffer));
			}
		}
	}
	inputFile.close();

	delete [] buffer;
}

template< typename T > void readLOFAR(std::string headerFilename, std::string rawFilename, Observation & observation, std::vector< std::vector< T > * > & data, unsigned int nrSeconds, unsigned int firstSecond) {
  unsigned int nrSubbands, nrChannels;
  float minFreq, channelBandwidth;
	// Read the HDF5 file with the metadata
	H5::H5File headerFile = H5::H5File(headerFilename, H5F_ACC_RDONLY);
	H5::FloatType typeDouble = H5::FloatType(H5::PredType::NATIVE_DOUBLE);
	double valueDouble = 0.0;
	H5::IntType typeUInt = H5::IntType(H5::PredType::NATIVE_UINT);
	unsigned int valueUInt = 0;

	H5::Group currentNode = headerFile.openGroup("/");
	currentNode.openAttribute("OBSERVATION_FREQUENCY_MIN").read(typeDouble, reinterpret_cast< void * >(&valueDouble));
  minFreq = valueDouble;
	currentNode = currentNode.openGroup(currentNode.getObjnameByIdx(0));
	currentNode.openAttribute("TOTAL_INTEGRATION_TIME").read(typeDouble, reinterpret_cast< void * >(&valueDouble));
	double totalIntegrationTime = valueDouble;
	currentNode.openAttribute("NOF_BEAMS").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
	observation.setNrBeams(valueUInt);
	currentNode = currentNode.openGroup(currentNode.getObjnameByIdx(0));
	currentNode.openAttribute("NOF_SAMPLES").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
	unsigned int totalSamples = valueUInt;
	currentNode.openAttribute("NOF_STATIONS").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
	observation.setNrStations(valueUInt);
	currentNode.openAttribute("CHANNELS_PER_SUBBAND").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
	nrChannels = valueUInt;
	currentNode.openAttribute("CHANNEL_WIDTH").read(typeDouble, reinterpret_cast< void * >(&valueDouble));
  channelBandwidth = valueDouble / 1000000;
	H5::DataSet currentData = currentNode.openDataSet("STOKES_0");
	currentData.openAttribute("NOF_SUBBANDS").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
	nrSubbands = valueUInt;
	headerFile.close();

	observation.setNrSamplesPerSecond(static_cast< unsigned int >(totalSamples / totalIntegrationTime));
	if ( nrSeconds == 0 ) {
		observation.setNrSeconds(static_cast< unsigned int >(totalIntegrationTime));
	} else {
		if ( static_cast< unsigned int >(totalIntegrationTime) >= (firstSecond + nrSeconds) ) {
			observation.setNrSeconds(nrSeconds);
		} else {
			observation.setNrSeconds(static_cast< unsigned int >(totalIntegrationTime) - firstSecond);
		}
	}
  observation.setFrequencyRange(nrSubbands * nrChannels, minFreq, channelBandwidth);

	// Read the raw file with the actual data
	std::ifstream rawFile;
	rawFile.open(rawFilename.c_str(), std::ios::binary);
	rawFile.sync_with_stdio(false);
	if ( firstSecond > 0 ) {
		rawFile.seekg(firstSecond * observation.getNrSamplesPerSecond() * nrSubbands * nrChannels, std::ios::beg);
	}
	data.resize(observation.getNrSeconds());

	char * word = new char [4];
	for ( unsigned int second = 0; second < observation.getNrSeconds(); second++ ) {
		data.at(second) = new std::vector< T >(observation.getNrChannels() * observation.getNrSamplesPerPaddedSecond());
		for ( unsigned int sample = 0; sample < observation.getNrSamplesPerSecond(); sample++ ) {
			for ( unsigned int subband = 0; subband < nrSubbands; subband++ ) {
				for ( unsigned int channel = 0; channel < nrChannels; channel++ ) {
					rawFile.read(word, 4);
          isa::utils::bigEndianToLittleEndian(word);
          data.at(second)[(static_cast< long long unsigned int >(second) * observation.getNrSamplesPerSecond()) + sample] = *(reinterpret_cast< T * >(word));
				}
			}
		}
	}
	rawFile.close();
	delete [] word;
}

} // AstroData

#endif // READ_DATA_HPP

<commit_msg>Convert the pointer to an object for the assignments.<commit_after>// Copyright 2012 Alessio Sclocco <a.sclocco@vu.nl>
//
// 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 <fstream>
#include <vector>
#include <string>
#include <cmath>
#include <H5Cpp.h>

#include <Observation.hpp>
#include <utils.hpp>

#ifndef READ_DATA_HPP
#define READ_DATA_HPP

namespace AstroData {

template< typename T > void readSIGPROC(Observation & observation, const unsigned int bytestoSkip, std::string inputFilename, std::vector< std::vector< T > * > & data, unsigned int firstSecond = 0);
template< typename T > void readLOFAR(std::string headerFilename, std::string rawFilename, Observation & observation, std::vector< std::vector< T > * > & data, unsigned int nrSeconds = 0, unsigned int firstSecond = 0);

// Implementation

template< typename T > void readSIGPROC(Observation & observation, unsigned int bytesToSkip, std::string inputFilename, std::vector< std::vector< T > * > & data, unsigned int firstSecond) {
	std::ifstream inputFile;
	const unsigned int BUFFER_DIM = 4;
	char * buffer = new char [BUFFER_DIM];

	inputFile.open(inputFilename.c_str(), std::ios::binary);
	inputFile.sync_with_stdio(false);
	inputFile.seekg(bytesToSkip, std::ios::beg);
	for ( unsigned int second = 0; second < observation.getNrSeconds(); second++ ) {
		data.at(second) = new std::vector< T >(observation.getNrSamplesPerPaddedSecond() * observation.getNrChannels());

		for ( unsigned int sample = 0; sample < observation.getNrSamplesPerSecond(); sample++ ) {
			for ( unsigned int channel = observation.getNrChannels(); channel > 0; channel-- ) {
				inputFile.read(buffer, BUFFER_DIM);
        *(data.at(second))[(static_cast< long long unsigned int >(channel - 1) * observation.getNrSamplesPerPaddedSecond()) + sample] = *(reinterpret_cast< T * >(buffer));
			}
		}
	}
	inputFile.close();

	delete [] buffer;
}

template< typename T > void readLOFAR(std::string headerFilename, std::string rawFilename, Observation & observation, std::vector< std::vector< T > * > & data, unsigned int nrSeconds, unsigned int firstSecond) {
  unsigned int nrSubbands, nrChannels;
  float minFreq, channelBandwidth;
	// Read the HDF5 file with the metadata
	H5::H5File headerFile = H5::H5File(headerFilename, H5F_ACC_RDONLY);
	H5::FloatType typeDouble = H5::FloatType(H5::PredType::NATIVE_DOUBLE);
	double valueDouble = 0.0;
	H5::IntType typeUInt = H5::IntType(H5::PredType::NATIVE_UINT);
	unsigned int valueUInt = 0;

	H5::Group currentNode = headerFile.openGroup("/");
	currentNode.openAttribute("OBSERVATION_FREQUENCY_MIN").read(typeDouble, reinterpret_cast< void * >(&valueDouble));
  minFreq = valueDouble;
	currentNode = currentNode.openGroup(currentNode.getObjnameByIdx(0));
	currentNode.openAttribute("TOTAL_INTEGRATION_TIME").read(typeDouble, reinterpret_cast< void * >(&valueDouble));
	double totalIntegrationTime = valueDouble;
	currentNode.openAttribute("NOF_BEAMS").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
	observation.setNrBeams(valueUInt);
	currentNode = currentNode.openGroup(currentNode.getObjnameByIdx(0));
	currentNode.openAttribute("NOF_SAMPLES").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
	unsigned int totalSamples = valueUInt;
	currentNode.openAttribute("NOF_STATIONS").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
	observation.setNrStations(valueUInt);
	currentNode.openAttribute("CHANNELS_PER_SUBBAND").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
	nrChannels = valueUInt;
	currentNode.openAttribute("CHANNEL_WIDTH").read(typeDouble, reinterpret_cast< void * >(&valueDouble));
  channelBandwidth = valueDouble / 1000000;
	H5::DataSet currentData = currentNode.openDataSet("STOKES_0");
	currentData.openAttribute("NOF_SUBBANDS").read(typeUInt, reinterpret_cast< void * >(&valueUInt));
	nrSubbands = valueUInt;
	headerFile.close();

	observation.setNrSamplesPerSecond(static_cast< unsigned int >(totalSamples / totalIntegrationTime));
	if ( nrSeconds == 0 ) {
		observation.setNrSeconds(static_cast< unsigned int >(totalIntegrationTime));
	} else {
		if ( static_cast< unsigned int >(totalIntegrationTime) >= (firstSecond + nrSeconds) ) {
			observation.setNrSeconds(nrSeconds);
		} else {
			observation.setNrSeconds(static_cast< unsigned int >(totalIntegrationTime) - firstSecond);
		}
	}
  observation.setFrequencyRange(nrSubbands * nrChannels, minFreq, channelBandwidth);

	// Read the raw file with the actual data
	std::ifstream rawFile;
	rawFile.open(rawFilename.c_str(), std::ios::binary);
	rawFile.sync_with_stdio(false);
	if ( firstSecond > 0 ) {
		rawFile.seekg(firstSecond * observation.getNrSamplesPerSecond() * nrSubbands * nrChannels, std::ios::beg);
	}
	data.resize(observation.getNrSeconds());

	char * word = new char [4];
	for ( unsigned int second = 0; second < observation.getNrSeconds(); second++ ) {
		data.at(second) = new std::vector< T >(observation.getNrChannels() * observation.getNrSamplesPerPaddedSecond());
		for ( unsigned int sample = 0; sample < observation.getNrSamplesPerSecond(); sample++ ) {
			for ( unsigned int subband = 0; subband < nrSubbands; subband++ ) {
				for ( unsigned int channel = 0; channel < nrChannels; channel++ ) {
					rawFile.read(word, 4);
          isa::utils::bigEndianToLittleEndian(word);
          *(data.at(second))[(static_cast< long long unsigned int >(second) * observation.getNrSamplesPerSecond()) + sample] = *(reinterpret_cast< T * >(word));
				}
			}
		}
	}
	rawFile.close();
	delete [] word;
}

} // AstroData

#endif // READ_DATA_HPP

<|endoftext|>


<commit_before>/*
	Flexisip, a flexible SIP proxy server with media capabilities.
	Copyright (C) 2010-2015  Belledonne Communications SARL, All rights reserved.

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Affero General Public License as
	published by the Free Software Foundation, either version 3 of the
	License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef eventlogs_hh
#define eventlogs_hh

#include <sofia-sip/sip.h>
#include <sofia-sip/sip_protos.h>

#include "../common.hh"
#include <string>
#include <memory>
#include <queue>
#include <mutex>

class EventLog {
	friend class FilesystemEventLogWriter;
	friend class DataBaseEventLogWriter;
	friend class EventLogDb;

public:

	EventLog(const sip_t *sip);
	virtual ~EventLog();
	void setCompleted();
	void setStatusCode(int sip_status, const char *reason);
	bool isCompleted() const {
		return mCompleted;
	}

protected:

	su_home_t mHome;
	sip_from_t *mFrom;
	sip_to_t *mTo;
	sip_user_agent_t *mUA;
	time_t mDate;
	int mStatusCode;
	std::string mReason;
	bool mCompleted;
	std::string mCallId;
	class Init {
	public:
		Init();
	};
	static Init evStaticInit;
};

class RegistrationLog : public EventLog {
	friend class FilesystemEventLogWriter;
	friend class DataBaseEventLogWriter;
	friend class RegistrationLogDb;

public:

	// Explicit values are necessary for soci. Do not change this.
	enum Type {
		Register = 0,
		Unregister = 1,
		Expired = 2
	};

	RegistrationLog(const sip_t *sip, const sip_contact_t *contacts);

private:
	Type mType;
	sip_contact_t *mContacts;
};

class CallLog : public EventLog {
	friend class FilesystemEventLogWriter;
	friend class DataBaseEventLogWriter;
	friend class CallLogDb;

public:
	CallLog(const sip_t *sip);
	void setCancelled();

private:
	bool mCancelled;
};

class MessageLog : public EventLog {
	friend class FilesystemEventLogWriter;
	friend class DataBaseEventLogWriter;
	friend class MessageLogDb;

public:

	// Explicit values is necessary for soci. Do not change this.
	enum ReportType {
		ReceivedFromUser = 0,
		DeliveredToUser = 1
	};

	MessageLog(const sip_t *sip, ReportType report);
	void setDestination(const url_t *dest);

private:

	ReportType mReportType;
	url_t *mUri; // destination uri of message
};

class AuthLog: public EventLog {
	friend class FilesystemEventLogWriter;
	friend class DataBaseEventLogWriter;
	friend class AuthLogDb;

public:

	AuthLog(const sip_t *sip, bool userExists);

private:

	void setOrigin(const sip_via_t *via);

	url_t *mOrigin;
	std::string mMethod;
	bool mUserExists;
};

class CallQualityStatisticsLog: public EventLog {
	friend class FilesystemEventLogWriter;
	friend class DataBaseEventLogWriter;
	friend class CallQualityStatisticsLogDb;

public:

	CallQualityStatisticsLog(const sip_t *sip);

private:

	// Note on `soci`: The `char *` support is dead since 2008...
	// See: https://github.com/SOCI/soci/commit/25c704ac4cb7bb0135dabc2421a1281fb868a511
	// It's necessary to create a hard copy with a `string`.
	std::string mReport;
};

class EventLogWriter {
public:

	virtual void write(const std::shared_ptr<EventLog> &evlog) = 0;
	virtual ~EventLogWriter();
};

class FilesystemEventLogWriter: public EventLogWriter {
public:

	FilesystemEventLogWriter(const std::string &rootpath);
	virtual void write(const std::shared_ptr<EventLog> &evlog);
	bool isReady() const;

private:

	int openPath(const url_t *uri, const char *kind, time_t curtime, int errorcode = 0);
	void writeRegistrationLog(const std::shared_ptr<RegistrationLog> &evlog);
	void writeCallLog(const std::shared_ptr<CallLog> &clog);
	void writeCallQualityStatisticsLog(const std::shared_ptr<CallQualityStatisticsLog> &mlog);
	void writeMessageLog(const std::shared_ptr<MessageLog> &mlog);
	void writeAuthLog(const std::shared_ptr<AuthLog> &alog);
	void writeErrorLog(const std::shared_ptr<EventLog> &log, const char *kind, const std::string &logstr);
	std::string mRootPath;
	bool mIsReady;
};

#if ENABLE_SOCI

#include <soci.h>
#include "utils/threadpool.hh"

class DataBaseEventLogWriter: public EventLogWriter {
public:

	enum Backend {
		Mysql = 0,
		Sqlite3 = 1,
		Postgresql = 2
	};

	DataBaseEventLogWriter(
		const std::string &backendString, const std::string &connectionString,
		int maxQueueSize, int nbThreadsMax
	);
	~DataBaseEventLogWriter();

	virtual void write(const std::shared_ptr<EventLog> &evlog);
	bool isReady() const;

private:

	void initTables(Backend backend);

	static void writeEventLog(const std::shared_ptr<EventLog> &evlog, int typeId, soci::session &sql);

	void writeRegistrationLog(const std::shared_ptr<RegistrationLog> &evlog);
	void writeCallLog(const std::shared_ptr<CallLog> &evlog);
	void writeMessageLog(const std::shared_ptr<MessageLog> &evlog);
	void writeAuthLog(const std::shared_ptr<AuthLog> &evlog);
	void writeCallQualityStatisticsLog(const std::shared_ptr<CallQualityStatisticsLog> &evlog);

	void writeEventFromQueue();

	bool mIsReady;
	std::mutex mMutex;
	std::queue<std::shared_ptr<EventLog>> mListLogs;

	soci::connection_pool *mConnectionPool;
	ThreadPool *mThreadPool;

	size_t mMaxQueueSize;

	std::string mInsertReq[5];
};

#endif

#endif
<commit_msg>Disable deprecation warnings while including soci.h with GCC<commit_after>/*
	Flexisip, a flexible SIP proxy server with media capabilities.
	Copyright (C) 2010-2015  Belledonne Communications SARL, All rights reserved.

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Affero General Public License as
	published by the Free Software Foundation, either version 3 of the
	License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef eventlogs_hh
#define eventlogs_hh

#include <sofia-sip/sip.h>
#include <sofia-sip/sip_protos.h>

#include "../common.hh"
#include <string>
#include <memory>
#include <queue>
#include <mutex>

class EventLog {
	friend class FilesystemEventLogWriter;
	friend class DataBaseEventLogWriter;
	friend class EventLogDb;

public:

	EventLog(const sip_t *sip);
	virtual ~EventLog();
	void setCompleted();
	void setStatusCode(int sip_status, const char *reason);
	bool isCompleted() const {
		return mCompleted;
	}

protected:

	su_home_t mHome;
	sip_from_t *mFrom;
	sip_to_t *mTo;
	sip_user_agent_t *mUA;
	time_t mDate;
	int mStatusCode;
	std::string mReason;
	bool mCompleted;
	std::string mCallId;
	class Init {
	public:
		Init();
	};
	static Init evStaticInit;
};

class RegistrationLog : public EventLog {
	friend class FilesystemEventLogWriter;
	friend class DataBaseEventLogWriter;
	friend class RegistrationLogDb;

public:

	// Explicit values are necessary for soci. Do not change this.
	enum Type {
		Register = 0,
		Unregister = 1,
		Expired = 2
	};

	RegistrationLog(const sip_t *sip, const sip_contact_t *contacts);

private:
	Type mType;
	sip_contact_t *mContacts;
};

class CallLog : public EventLog {
	friend class FilesystemEventLogWriter;
	friend class DataBaseEventLogWriter;
	friend class CallLogDb;

public:
	CallLog(const sip_t *sip);
	void setCancelled();

private:
	bool mCancelled;
};

class MessageLog : public EventLog {
	friend class FilesystemEventLogWriter;
	friend class DataBaseEventLogWriter;
	friend class MessageLogDb;

public:

	// Explicit values is necessary for soci. Do not change this.
	enum ReportType {
		ReceivedFromUser = 0,
		DeliveredToUser = 1
	};

	MessageLog(const sip_t *sip, ReportType report);
	void setDestination(const url_t *dest);

private:

	ReportType mReportType;
	url_t *mUri; // destination uri of message
};

class AuthLog: public EventLog {
	friend class FilesystemEventLogWriter;
	friend class DataBaseEventLogWriter;
	friend class AuthLogDb;

public:

	AuthLog(const sip_t *sip, bool userExists);

private:

	void setOrigin(const sip_via_t *via);

	url_t *mOrigin;
	std::string mMethod;
	bool mUserExists;
};

class CallQualityStatisticsLog: public EventLog {
	friend class FilesystemEventLogWriter;
	friend class DataBaseEventLogWriter;
	friend class CallQualityStatisticsLogDb;

public:

	CallQualityStatisticsLog(const sip_t *sip);

private:

	// Note on `soci`: The `char *` support is dead since 2008...
	// See: https://github.com/SOCI/soci/commit/25c704ac4cb7bb0135dabc2421a1281fb868a511
	// It's necessary to create a hard copy with a `string`.
	std::string mReport;
};

class EventLogWriter {
public:

	virtual void write(const std::shared_ptr<EventLog> &evlog) = 0;
	virtual ~EventLogWriter();
};

class FilesystemEventLogWriter: public EventLogWriter {
public:

	FilesystemEventLogWriter(const std::string &rootpath);
	virtual void write(const std::shared_ptr<EventLog> &evlog);
	bool isReady() const;

private:

	int openPath(const url_t *uri, const char *kind, time_t curtime, int errorcode = 0);
	void writeRegistrationLog(const std::shared_ptr<RegistrationLog> &evlog);
	void writeCallLog(const std::shared_ptr<CallLog> &clog);
	void writeCallQualityStatisticsLog(const std::shared_ptr<CallQualityStatisticsLog> &mlog);
	void writeMessageLog(const std::shared_ptr<MessageLog> &mlog);
	void writeAuthLog(const std::shared_ptr<AuthLog> &alog);
	void writeErrorLog(const std::shared_ptr<EventLog> &log, const char *kind, const std::string &logstr);
	std::string mRootPath;
	bool mIsReady;
};

#if ENABLE_SOCI

#ifdef __GNUG__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
#include <soci.h>
#ifdef __GNUG__
#pragma GCC diagnostic pop
#endif

#include "utils/threadpool.hh"

class DataBaseEventLogWriter: public EventLogWriter {
public:

	enum Backend {
		Mysql = 0,
		Sqlite3 = 1,
		Postgresql = 2
	};

	DataBaseEventLogWriter(
		const std::string &backendString, const std::string &connectionString,
		int maxQueueSize, int nbThreadsMax
	);
	~DataBaseEventLogWriter();

	virtual void write(const std::shared_ptr<EventLog> &evlog);
	bool isReady() const;

private:

	void initTables(Backend backend);

	static void writeEventLog(const std::shared_ptr<EventLog> &evlog, int typeId, soci::session &sql);

	void writeRegistrationLog(const std::shared_ptr<RegistrationLog> &evlog);
	void writeCallLog(const std::shared_ptr<CallLog> &evlog);
	void writeMessageLog(const std::shared_ptr<MessageLog> &evlog);
	void writeAuthLog(const std::shared_ptr<AuthLog> &evlog);
	void writeCallQualityStatisticsLog(const std::shared_ptr<CallQualityStatisticsLog> &evlog);

	void writeEventFromQueue();

	bool mIsReady;
	std::mutex mMutex;
	std::queue<std::shared_ptr<EventLog>> mListLogs;

	soci::connection_pool *mConnectionPool;
	ThreadPool *mThreadPool;

	size_t mMaxQueueSize;

	std::string mInsertReq[5];
};

#endif

#endif
<|endoftext|>