text:
// Copyright (c) 2012 Christopher Lux <christopherlux@gmail.com>
// Distributed under the Modified BSD License, see license.txt.

#include <cassert>

#include <boost/static_assert.hpp>

#include <scm/gl_core/config.h>

namespace scm {
namespace gl {
namespace util {

inline
unsigned
gl_buffer_targets(const buffer_binding b)
{
    switch (b) {
        case BIND_VERTEX_BUFFER:                return GL_ARRAY_BUFFER;
        case BIND_INDEX_BUFFER:                 return GL_ELEMENT_ARRAY_BUFFER;
        //case BIND_PIXEL_BUFFER:
        case BIND_PIXEL_PACK_BUFFER:            return GL_PIXEL_PACK_BUFFER;
        case BIND_PIXEL_UNPACK_BUFFER:          return GL_PIXEL_UNPACK_BUFFER;
        case BIND_UNIFORM_BUFFER:               return GL_UNIFORM_BUFFER;
        case BIND_TEXTURE_BUFFER:               return GL_TEXTURE_BUFFER;
        case BIND_TRANSFORM_FEEDBACK_BUFFER:    return GL_TRANSFORM_FEEDBACK_BUFFER;
        case BIND_ATOMIC_COUNTER_BUFFER:        return GL_ATOMIC_COUNTER_BUFFER;
        case BIND_STORAGE_BUFFER:               return GL_SHADER_STORAGE_BUFFER;
        default:                                return 0;
    }
}

inline
unsigned
gl_buffer_bindings(const buffer_binding b)
{
    switch (b) {
        case BIND_VERTEX_BUFFER:                return GL_ARRAY_BUFFER_BINDING;
        case BIND_INDEX_BUFFER:                 return GL_ELEMENT_ARRAY_BUFFER_BINDING;
        //case BIND_PIXEL_BUFFER:
        case BIND_PIXEL_PACK_BUFFER:            return GL_PIXEL_PACK_BUFFER_BINDING;
        case BIND_PIXEL_UNPACK_BUFFER:          return GL_PIXEL_UNPACK_BUFFER_BINDING;
        case BIND_UNIFORM_BUFFER:               return GL_UNIFORM_BUFFER_BINDING;
        case BIND_TEXTURE_BUFFER:               return GL_TEXTURE_BINDING_BUFFER;
        case BIND_TRANSFORM_FEEDBACK_BUFFER:    return GL_TRANSFORM_FEEDBACK_BUFFER_BINDING;
        case BIND_ATOMIC_COUNTER_BUFFER:        return GL_ATOMIC_COUNTER_BUFFER_BINDING;
        case BIND_STORAGE_BUFFER:               return GL_SHADER_STORAGE_BUFFER_BINDING;
        default:                                return 0;
    }
}

inline
int
gl_usage_flags(const buffer_usage b)
{
    static int glbufu[] = {
        // write once
        GL_STATIC_DRAW,     // GPU r,  CPU
        GL_STATIC_READ,     // GPU     CPU r
        GL_STATIC_COPY,     // GPU rw, CPU
        // low write frequency
        GL_STREAM_DRAW,     // GPU r,  CPU w
        GL_STREAM_READ,     // GPU w,  CPU r
        GL_STREAM_COPY,     // GPU rw, CPU
        // high write frequency
        GL_DYNAMIC_DRAW,    // GPU r,  CPU w
        GL_DYNAMIC_READ,    // GPU w,  CPU r
        GL_DYNAMIC_COPY     // GPU rw, CPU
    };

    BOOST_STATIC_ASSERT((sizeof(glbufu) / sizeof(int)) == USAGE_COUNT);

    assert((sizeof(glbufu) / sizeof(int)) == USAGE_COUNT);
    assert(USAGE_STATIC_DRAW <= b && b < USAGE_COUNT);

    return glbufu[b];
}

inline
unsigned
gl_buffer_access_mode(const access_mode a)
{
    assert(ACCESS_READ_ONLY <= a && a < ACCESS_COUNT);

    switch (a) {
        case ACCESS_READ_ONLY:                  return GL_MAP_READ_BIT;
        case ACCESS_WRITE_ONLY:                 return GL_MAP_WRITE_BIT;
        case ACCESS_READ_WRITE:                 return GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
        case ACCESS_WRITE_INVALIDATE_RANGE:     return GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT;
        case ACCESS_WRITE_INVALIDATE_BUFFER:    return GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT;
        case ACCESS_WRITE_UNSYNCHRONIZED:       return GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
        default:                                return 0;
    }
}

inline
unsigned
gl_image_access_mode(const access_mode a)
{
    assert(ACCESS_READ_ONLY <= a && a < ACCESS_COUNT);

    switch (a) {
        case ACCESS_READ_ONLY:                  return GL_READ_ONLY;
        case ACCESS_WRITE_ONLY:                 return GL_WRITE_ONLY;
        case ACCESS_READ_WRITE:                 return GL_READ_WRITE;
        default:                                return 0;
    }
}

inline
unsigned
gl_primitive_type(const primitive_type p)
{
    static unsigned types[] = {
        GL_POINTS,                  // PRIMITIVE_POINTS                = 0x00,
        GL_LINES,                   // PRIMITIVE_LINES,
        GL_TRIANGLES                // PRIMITIVE_TRIANGLES
    };

    BOOST_STATIC_ASSERT((sizeof(types) / sizeof(unsigned)) == PRIMITIVE_TYPE_COUNT);

    assert((sizeof(types) / sizeof(unsigned)) == PRIMITIVE_TYPE_COUNT);
    assert(PRIMITIVE_POINTS <= p && p < PRIMITIVE_TYPE_COUNT);

    return types[p];
}

inline
unsigned
gl_primitive_topology(const primitive_topology p)
{
    static unsigned types[] = {
        GL_POINTS,                  // PRIMITIVE_POINT_LIST                = 0x00,
        GL_LINES,                   // PRIMITIVE_LINE_LIST,
        GL_LINE_STRIP,              // PRIMITIVE_LINE_STRIP,
        GL_LINE_LOOP,               // PRIMITIVE_LINE_LOOP,
        GL_LINES_ADJACENCY,         // PRIMITIVE_LINE_LIST_ADJACENCY,
        GL_LINE_STRIP_ADJACENCY,    // PRIMITIVE_LINE_STRIP_ADJACENCY,
        GL_TRIANGLES,               // PRIMITIVE_TRIANGLE_LIST,
        GL_TRIANGLE_STRIP,          // PRIMITIVE_TRIANGLE_STRIP,
        GL_TRIANGLES_ADJACENCY,     // PRIMITIVE_TRIANGLE_LIST_ADJACENCY,
        GL_TRIANGLE_STRIP_ADJACENCY // PRIMITIVE_TRIANGLE_STRIP_ADJACENCY
#if SCM_GL_CORE_OPENGL_CORE_VERSION >= SCM_GL_CORE_OPENGL_CORE_VERSION_400
        ,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_1_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_2_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_3_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_4_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_5_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_6_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_7_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_8_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_9_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_10_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_11_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_12_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_13_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_14_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_15_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_16_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_17_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_18_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_19_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_20_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_21_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_22_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_23_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_24_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_25_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_26_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_27_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_28_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_29_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_30_CONTROL_POINTS,
        GL_PATCHES,                 // PRIMITIVE_PATCH_LIST_31_CONTROL_POINTS,
        GL_PATCHES                  // PRIMITIVE_PATCH_LIST_32_CONTROL_POINTS,
#endif // SCM_GL_CORE_OPENGL_CORE_VERSION < SCM_GL_CORE_OPENGL_CORE_VERSION_400
    };

    BOOST_STATIC_ASSERT((sizeof(types) / sizeof(unsigned)) == PRIMITIVE_TOPOLOGY_COUNT);

    assert((sizeof(types) / sizeof(unsigned)) == PRIMITIVE_TOPOLOGY_COUNT);
    assert(PRIMITIVE_POINT_LIST <= p && p < PRIMITIVE_TOPOLOGY_COUNT);

    return types[p];
}

inline
int
gl_shader_types(const shader_stage s)
{
    static int shader_types[] = {
        GL_VERTEX_SHADER,           // STAGE_VERTEX_SHADER      = 0x00,
        GL_GEOMETRY_SHADER,         // STAGE_GEOMETRY_SHADER
        GL_FRAGMENT_SHADER,         // STAGE_FRAGMENT_SHADER
        GL_COMPUTE_SHADER           // STAGE_COMPUTE_SHADER
#if SCM_GL_CORE_OPENGL_CORE_VERSION >= SCM_GL_CORE_OPENGL_CORE_VERSION_400
        ,
        GL_TESS_EVALUATION_SHADER,  // STAGE_TESS_EVALUATION_SHADER,
        GL_TESS_CONTROL_SHADER      // STAGE_TESS_CONTROL_SHADER
#endif // SCM_GL_CORE_OPENGL_CORE_VERSION >= SCM_GL_CORE_OPENGL_CORE_VERSION_400
    };

    BOOST_STATIC_ASSERT((sizeof(shader_types) / sizeof(int)) == SHADER_STAGE_COUNT);

    assert((sizeof(shader_types) / sizeof(int)) == SHADER_STAGE_COUNT);
    assert(STAGE_VERTEX_SHADER <= s && s < SHADER_STAGE_COUNT);

    return shader_types[s];
}

inline
unsigned
gl_compare_func(const compare_func c)
{
    static unsigned compare_funcs[] = {
        GL_NEVER,                   // COMPARISON_NEVER = 0x00,
        GL_ALWAYS,                  // COMPARISON_ALWAYS,
        GL_LESS,                    // COMPARISON_LESS,
        GL_LEQUAL,                  // COMPARISON_LESS_EQUAL,
        GL_EQUAL,                   // COMPARISON_EQUAL,
        GL_GREATER,                 // COMPARISON_GREATER,
        GL_GEQUAL,                  // COMPARISON_GREATER_EQUAL,
        GL_NOTEQUAL                 // COMPARISON_NOT_EQUAL
    };

    BOOST_STATIC_ASSERT((sizeof(compare_funcs) / sizeof(unsigned)) == COMPARISON_FUNC_COUNT);

    assert((sizeof(compare_funcs) / sizeof(unsigned)) == COMPARISON_FUNC_COUNT);
    assert(COMPARISON_NEVER <= c && c < COMPARISON_FUNC_COUNT);

    return compare_funcs[c];
}

inline
unsigned
gl_stencil_op(const stencil_op s)
{
    static unsigned stencil_ops[] = {
        GL_KEEP,                    // STENCIL_KEEP = 0x00,
        GL_ZERO,                    // STENCIL_ZERO,
        GL_REPLACE,                 // STENCIL_REPLACE,
        GL_INCR,                    // STENCIL_INCR_SAT,
        GL_DECR,                    // STENCIL_DECR_SAT,
        GL_INVERT,                  // STENCIL_INVERT,
        GL_INCR_WRAP,               // STENCIL_INCR_WRAP,
        GL_DECR_WRAP                // STENCIL_DECR_WRAP
    };

    BOOST_STATIC_ASSERT((sizeof(stencil_ops) / sizeof(unsigned)) == STENCIL_OP_COUNT);

    assert((sizeof(stencil_ops) / sizeof(unsigned)) == STENCIL_OP_COUNT);
    assert(STENCIL_KEEP <= s && s < STENCIL_OP_COUNT);

    return stencil_ops[s];
}

inline
unsigned
gl_fill_mode(const fill_mode s)
{
    static unsigned fill_modes[] = {
        GL_FILL,    // FILL_SOLID = 0x00,
        GL_LINE,    // FILL_WIREFRAME
        GL_POINT    // FILL_POINT
    };

    BOOST_STATIC_ASSERT((sizeof(fill_modes) / sizeof(unsigned)) == FILL_MODE_COUNT);

    assert((sizeof(fill_modes) / sizeof(unsigned)) == FILL_MODE_COUNT);
    assert(FILL_SOLID <= s && s < FILL_MODE_COUNT);

    return fill_modes[s];
}

inline
unsigned
gl_cull_mode(const cull_mode s)
{
    static unsigned cull_modes[] = {
        GL_NONE,    // CULL_NONE = 0x00,
        GL_FRONT,   // CULL_FRONT,
        GL_BACK     // CULL_BACK
    };

    BOOST_STATIC_ASSERT((sizeof(cull_modes) / sizeof(unsigned)) == CULL_MODE_COUNT);

    assert((sizeof(cull_modes) / sizeof(unsigned)) == CULL_MODE_COUNT);
    assert(CULL_NONE <= s && s < CULL_MODE_COUNT);

    return cull_modes[s];
}

inline
unsigned
gl_polygon_orientation(const polygon_orientation s)
{
    static unsigned polygon_orientations[] = {
        GL_CW,      // ORIENT_CW = 0x00,
        GL_CCW      // ORIENT_CCW
    };

    BOOST_STATIC_ASSERT((sizeof(polygon_orientations) / sizeof(unsigned)) == POLY_ORIENT_COUNT);

    assert((sizeof(polygon_orientations) / sizeof(unsigned)) == POLY_ORIENT_COUNT);
    assert(ORIENT_CW <= s && s < POLY_ORIENT_COUNT);

    return polygon_orientations[s];
}

inline
unsigned
gl_origin_mode(const enum origin_mode o)
{
    switch (o) {
    case ORIGIN_UPPER_LEFT: return GL_UPPER_LEFT; break;
    case ORIGIN_LOWER_LEFT: return GL_LOWER_LEFT; break;
    default:                assert(0 && (o < ORIGIN_MODE_COUNT));return 0;
    }
}

inline
unsigned
gl_blend_func(const blend_func s)
{
    static unsigned blend_funcs[] = {
        GL_ZERO,                        // FUNC_ZERO = 0x00,
        GL_ONE,                         // FUNC_ONE,
        GL_SRC_COLOR,                   // FUNC_SRC_COLOR,
        GL_ONE_MINUS_SRC_COLOR,         // FUNC_ONE_MINUS_SRC_COLOR,
        GL_DST_COLOR,                   // FUNC_DST_COLOR,
        GL_ONE_MINUS_DST_COLOR,         // FUNC_ONE_MINUS_DST_COLOR,
        GL_SRC_ALPHA,                   // FUNC_SRC_ALPHA,
        GL_ONE_MINUS_SRC_ALPHA,         // FUNC_ONE_MINUS_SRC_ALPHA,
        GL_DST_ALPHA,                   // FUNC_DST_ALPHA,
        GL_ONE_MINUS_DST_ALPHA,         // FUNC_ONE_MINUS_DST_ALPHA,
        GL_CONSTANT_COLOR,              // FUNC_CONSTANT_COLOR,
        GL_ONE_MINUS_CONSTANT_COLOR,    // FUNC_ONE_MINUS_CONSTANT_COLOR,
        GL_CONSTANT_ALPHA,              // FUNC_CONSTANT_ALPHA,
        GL_ONE_MINUS_CONSTANT_ALPHA,    // FUNC_ONE_MINUS_CONSTANT_ALPHA,
        GL_SRC_ALPHA_SATURATE,          // FUNC_SRC_ALPHA_SATURATE,
        GL_SRC1_COLOR,                  // FUNC_SRC1_COLOR,
        GL_ONE_MINUS_SRC1_COLOR,        // FUNC_ONE_MINUS_SRC1_COLOR,
        GL_SRC1_ALPHA,                  // FUNC_SRC1_ALPHA,
        GL_ONE_MINUS_SRC1_ALPHA         // FUNC_ONE_MINUS_SRC1_ALPHA
    };

    BOOST_STATIC_ASSERT((sizeof(blend_funcs) / sizeof(unsigned)) == BLEND_FUNC_COUNT);

    assert((sizeof(blend_funcs) / sizeof(unsigned)) == BLEND_FUNC_COUNT);
    assert(FUNC_ZERO <= s && s < BLEND_FUNC_COUNT);

    return blend_funcs[s];
}

inline
unsigned
gl_blend_equation(const blend_equation s)
{
    static unsigned blend_equations[] = {
        GL_FUNC_ADD,                    // EQ_FUNC_ADD = 0x00,
        GL_FUNC_SUBTRACT,               // EQ_FUNC_SUBTRACT,
        GL_FUNC_REVERSE_SUBTRACT,       // EQ_FUNC_REVERSE_SUBTRACT,
        GL_MIN,                         // EQ_MIN,
        GL_MAX                          // EQ_MAX
    };

    BOOST_STATIC_ASSERT((sizeof(blend_equations) / sizeof(unsigned)) == BLEND_EQ_COUNT);

    assert((sizeof(blend_equations) / sizeof(unsigned)) == BLEND_EQ_COUNT);
    assert(EQ_FUNC_ADD <= s && s < BLEND_EQ_COUNT);

    return blend_equations[s];
}

inline
bool
masked(unsigned in_color_mask, const color_mask in_color) {
    return (0 != (in_color_mask & in_color));
}

inline
unsigned
gl_texture_min_filter_mode(const texture_filter_mode s)
{
    static unsigned texture_min_filter_modes[] = {
        GL_NEAREST,                 // FILTER_MIN_MAG_NEAREST = 0x00,
        GL_NEAREST,                 // FILTER_MIN_NEAREST_MAG_LINEAR,
        GL_LINEAR,                  // FILTER_MIN_LINEAR_MAG_NEAREST,
        GL_LINEAR,                  // FILTER_MIN_MAG_LINEAR,
        GL_NEAREST_MIPMAP_NEAREST,  // FILTER_MIN_MAG_MIP_NEAREST,
        GL_NEAREST_MIPMAP_LINEAR,   // FILTER_MIN_MAG_NEAREST_MIP_LINEAR,
        GL_NEAREST_MIPMAP_NEAREST,  // FILTER_MIN_NEAREST_MAG_LINEAR_MIP_NEAREST,
        GL_NEAREST_MIPMAP_LINEAR,   // FILTER_MIN_NEAREST_MAG_MIP_LINEAR,
        GL_LINEAR_MIPMAP_NEAREST,   // FILTER_MIN_LINEAR_MAG_MIP_NEAREST,
        GL_LINEAR_MIPMAP_LINEAR,    // FILTER_MIN_LINEAR_MAG_NEAREST_MIP_LINEAR,
        GL_LINEAR_MIPMAP_NEAREST,   // FILTER_MIN_MAG_LINEAR_MIP_NEAREST,
        GL_LINEAR_MIPMAP_LINEAR,    // FILTER_MIN_MAG_MIP_LINEAR,
        GL_LINEAR_MIPMAP_LINEAR     // FILTER_ANISOTROPIC
    };

    BOOST_STATIC_ASSERT((sizeof(texture_min_filter_modes) / sizeof(unsigned)) == TEXTURE_FILTER_COUNT);

    assert((sizeof(texture_min_filter_modes) / sizeof(unsigned)) == TEXTURE_FILTER_COUNT);
    assert(FILTER_MIN_MAG_NEAREST <= s && s < TEXTURE_FILTER_COUNT);

    return texture_min_filter_modes[s];
}

inline
unsigned
gl_texture_mag_filter_mode(const texture_filter_mode s)
{
    static unsigned texture_mag_filter_modes[] = {
        GL_NEAREST,  // FILTER_MIN_MAG_NEAREST = 0x00,
        GL_LINEAR,   // FILTER_MIN_NEAREST_MAG_LINEAR,
        GL_NEAREST,  // FILTER_MIN_LINEAR_MAG_NEAREST,
        GL_LINEAR,   // FILTER_MIN_MAG_LINEAR,
        GL_NEAREST,  // FILTER_MIN_MAG_MIP_NEAREST,
        GL_NEAREST,  // FILTER_MIN_MAG_NEAREST_MIP_LINEAR,
        GL_LINEAR,   // FILTER_MIN_NEAREST_MAG_LINEAR_MIP_NEAREST,
        GL_LINEAR,   // FILTER_MIN_NEAREST_MAG_MIP_LINEAR,
        GL_NEAREST,  // FILTER_MIN_LINEAR_MAG_MIP_NEAREST,
        GL_NEAREST,  // FILTER_MIN_LINEAR_MAG_NEAREST_MIP_LINEAR,
        GL_LINEAR,   // FILTER_MIN_MAG_LINEAR_MIP_NEAREST,
        GL_LINEAR,   // FILTER_MIN_MAG_MIP_LINEAR,
        GL_LINEAR    // FILTER_ANISOTROPIC
    };

    BOOST_STATIC_ASSERT((sizeof(texture_mag_filter_modes) / sizeof(unsigned)) == TEXTURE_FILTER_COUNT);

    assert((sizeof(texture_mag_filter_modes) / sizeof(unsigned)) == TEXTURE_FILTER_COUNT);
    assert(FILTER_MIN_MAG_NEAREST <= s && s < TEXTURE_FILTER_COUNT);

    return texture_mag_filter_modes[s];
}

inline
unsigned
gl_wrap_mode(const texture_wrap_mode s)
{
    static unsigned wrap_modes[] = {
        GL_CLAMP_TO_EDGE,   // WRAP_CLAMP_TO_EDGE  = 0x00,
        GL_REPEAT,          // WRAP_REPEAT,
        GL_MIRRORED_REPEAT  // WRAP_MIRRORED_REPEAT
    };

    BOOST_STATIC_ASSERT((sizeof(wrap_modes) / sizeof(unsigned)) == WRAP_MODE_COUNT);

    assert((sizeof(wrap_modes) / sizeof(unsigned)) == WRAP_MODE_COUNT);
    assert(WRAP_CLAMP_TO_EDGE <= s && s < WRAP_MODE_COUNT);

    return wrap_modes[s];
}

inline
unsigned
gl_texture_compare_mode(const texture_compare_mode s)
{
    static unsigned texture_compare_modes[] = {
        GL_NONE,                    // TEXCOMPARE_NONE = 0x00,
        GL_COMPARE_REF_TO_TEXTURE   // TEXCOMPARE_COMPARE_REF_TO_TEXTURE
    };

    BOOST_STATIC_ASSERT((sizeof(texture_compare_modes) / sizeof(unsigned)) == TEXCOMARE_COUNT);

    assert((sizeof(texture_compare_modes) / sizeof(unsigned)) == TEXCOMARE_COUNT);
    assert(TEXCOMPARE_NONE <= s && s < TEXCOMARE_COUNT);

    return texture_compare_modes[s];
}

inline
unsigned
gl_framebuffer_binding(const frame_buffer_binding s)
{
    static unsigned framebuffer_bindings[] = {
        GL_DRAW_FRAMEBUFFER,  // FRAMEBUFFER_DRAW = 0x00,
        GL_READ_FRAMEBUFFER   // FRAMEBUFFER_READ
    };

    BOOST_STATIC_ASSERT((sizeof(framebuffer_bindings) / sizeof(unsigned)) == FRAMEBUFFER_BINDING_COUNT);

    assert((sizeof(framebuffer_bindings) / sizeof(unsigned)) == FRAMEBUFFER_BINDING_COUNT);
    assert(FRAMEBUFFER_DRAW <= s && s < FRAMEBUFFER_BINDING_COUNT);

    return framebuffer_bindings[s];
}

inline
unsigned
gl_framebuffer_binding_point(const frame_buffer_binding s)
{
    static unsigned framebuffer_binding_points[] = {
        GL_DRAW_FRAMEBUFFER_BINDING,  // FRAMEBUFFER_DRAW = 0x00,
        GL_READ_FRAMEBUFFER_BINDING   // FRAMEBUFFER_READ
    };

    BOOST_STATIC_ASSERT((sizeof(framebuffer_binding_points) / sizeof(unsigned)) == FRAMEBUFFER_BINDING_COUNT);

    assert((sizeof(framebuffer_binding_points) / sizeof(unsigned)) == FRAMEBUFFER_BINDING_COUNT);
    assert(FRAMEBUFFER_DRAW <= s && s < FRAMEBUFFER_BINDING_COUNT);

    return framebuffer_binding_points[s];
}

inline
unsigned
gl_frame_buffer_target(const frame_buffer_target s)
{
    static unsigned framebuffer_targets[] = {
        GL_FRONT_LEFT,                // FRAMEBUFFER_FRONT_LEFT      = 0x00,
        GL_FRONT_RIGHT,               // FRAMEBUFFER_FRONT_RIGHT,
        GL_BACK_LEFT,                 // FRAMEBUFFER_BACK_LEFT,
        GL_BACK_RIGHT,                // FRAMEBUFFER_BACK_RIGHT,
        GL_FRONT,                     // FRAMEBUFFER_FRONT,
        GL_BACK,                      // FRAMEBUFFER_BACK,
        GL_LEFT,                      // FRAMEBUFFER_LEFT,
        GL_RIGHT,                     // FRAMEBUFFER_RIGHT,
        GL_FRONT_AND_BACK             // FRAMEBUFFER_FRONT_AND_BACK,
    };

    BOOST_STATIC_ASSERT((sizeof(framebuffer_targets) / sizeof(unsigned)) == FRAMEBUFFER_TARGET_COUNT);

    assert((sizeof(framebuffer_targets) / sizeof(unsigned)) == FRAMEBUFFER_TARGET_COUNT);
    assert(GL_FRONT_LEFT <= s && s < FRAMEBUFFER_TARGET_COUNT);

    return framebuffer_targets[s];
}

inline
debug_source
gl_to_debug_source(unsigned s)
{
    switch (s) {
    case GL_DEBUG_SOURCE_API_ARB:               return DEBUG_SOURCE_API; break;
    case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB:     return DEBUG_SOURCE_WINDOW_SYSTEM; break;
    case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB:   return DEBUG_SOURCE_SHADER_COMPILER; break;
    case GL_DEBUG_SOURCE_THIRD_PARTY_ARB:       return DEBUG_SOURCE_THIRD_PARTY; break;
    case GL_DEBUG_SOURCE_APPLICATION_ARB:       return DEBUG_SOURCE_APPLICATION; break;
    case GL_DEBUG_SOURCE_OTHER_ARB:             return DEBUG_SOURCE_OTHER; break;
    default:                                    return DEBUG_SOURCE_OTHER; break;
    }
}

inline
debug_type
gl_to_debug_type(unsigned t)
{
    switch (t) {
    case GL_DEBUG_TYPE_ERROR_ARB:               return DEBUG_TYPE_ERROR; break;
    case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: return DEBUG_TYPE_DEPRECATED_BEHAVIOR; break;
    case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:  return DEBUG_TYPE_UNDEFINED_BEHAVIOR; break;
    case GL_DEBUG_TYPE_PORTABILITY_ARB:         return DEBUG_TYPE_PORTABILITY; break;
    case GL_DEBUG_TYPE_PERFORMANCE_ARB:         return DEBUG_TYPE_PERFORMANCE; break;
    case GL_DEBUG_TYPE_OTHER_ARB:               return DEBUG_TYPE_OTHER; break;
    default:                                    return DEBUG_TYPE_OTHER; break;
    }
}

inline
debug_severity
gl_to_debug_severity(unsigned s)
{
    switch (s) {
    case GL_DEBUG_SEVERITY_HIGH_ARB:            return DEBUG_SEVERITY_HIGH; break;
    case GL_DEBUG_SEVERITY_MEDIUM_ARB:          return DEBUG_SEVERITY_MEDIUM; break;
    case GL_DEBUG_SEVERITY_LOW_ARB:             return DEBUG_SEVERITY_LOW; break;
    default:                                    return DEBUG_SEVERITY_LOW; break;
    }
}

} // namespace util
} // namespace gl
} // namespace scm

ext: inl

max_stars_repo_name: Nyran/schism

max_issues_repo_name: Nyran/schism

max_forks_repo_name: Nyran/schism


text:
#ifndef VEXCL_MBA_HPP
#define VEXCL_MBA_HPP

/*
The MIT License

Copyright (c) 2012-2018 Denis Demidov <dennis.demidov@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

/**
 * \file   vexcl/mba.hpp
 * \author Denis Demidov <dennis.demidov@gmail.com>
 * \brief  Scattered data interpolation with multilevel B-Splines.
 */

#include <vector>
#include <array>
#include <sstream>
#include <memory>
#include <algorithm>
#include <numeric>
#include <type_traits>
#include <cassert>

#include <boost/tuple/tuple.hpp>
#include <boost/fusion/adapted/boost_tuple.hpp>

#include <vexcl/operations.hpp>

// Include boost.preprocessor header if variadic templates are not available.
// Also include it if we use gcc v4.6.
// This is required due to bug http://gcc.gnu.org/bugzilla/show_bug.cgi?id=35722
#if defined(BOOST_NO_VARIADIC_TEMPLATES) || (defined(__GNUC__) && !defined(__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ == 6)
#  include <boost/preprocessor/repetition.hpp>
#  ifndef VEXCL_MAX_ARITY
#    define VEXCL_MAX_ARITY BOOST_PROTO_MAX_ARITY
#  endif
#endif
namespace vex {

struct mba_terminal {};

typedef vector_expression<
    typename boost::proto::terminal< mba_terminal >::type
    > mba_terminal_expression;

template <class MBA, class ExprTuple>
struct mba_interp : public mba_terminal_expression {
    typedef typename MBA::value_type value_type;

    const MBA      &cloud;
    const ExprTuple coord;

    mba_interp(const MBA &cloud, const ExprTuple coord)
        : cloud(cloud), coord(coord) {}
};

namespace detail {
    // Compile time value of N^M.
    template <size_t N, size_t M>
    struct power : std::integral_constant<size_t, N * power<N, M-1>::value> {};

    template <size_t N>
    struct power<N, 0> : std::integral_constant<size_t, 1> {};

    // Nested loop counter of compile-time size (M loops of size N).
    template <size_t N, size_t M>
    class scounter {
        public:
            scounter() : idx(0) {
                std::fill(i.begin(), i.end(), static_cast<size_t>(0));
            }

            size_t operator[](size_t d) const {
                return i[d];
            }

            scounter& operator++() {
                for(size_t d = M; d--; ) {
                    if (++i[d] < N) break;
                    i[d] = 0;
                }

                ++idx;

                return *this;
            }

            operator size_t() const {
                return idx;
            }

            bool valid() const {
                return idx < power<N, M>::value;
            }
        private:
            size_t idx;
            std::array<size_t, M> i;
    };

    // Nested loop counter of run-time size (M loops of given sizes).
    template <size_t M>
    class dcounter {
        public:
            dcounter(const std::array<size_t, M> &N)
                : idx(0),
                  size(std::accumulate(N.begin(), N.end(),
                            static_cast<size_t>(1), std::multiplies<size_t>())),
                  N(N)
            {
                std::fill(i.begin(), i.end(), static_cast<size_t>(0));
            }

            size_t operator[](size_t d) const {
                return i[d];
            }

            dcounter& operator++() {
                for(size_t d = M; d--; ) {
                    if (++i[d] < N[d]) break;
                    i[d] = 0;
                }

                ++idx;

                return *this;
            }

            operator size_t() const {
                return idx;
            }

            bool valid() const {
                return idx < size;
            }
        private:
            size_t idx, size;
            std::array<size_t, M> N, i;
    };
} // namespace detail

/// Scattered data interpolation with multilevel B-Splines.
template <size_t NDIM, typename real = double>
class mba {
    public:
        typedef real value_type;
        typedef std::array<real,   NDIM> point;
        typedef std::array<size_t, NDIM> index;

        static const size_t ndim = NDIM;

        std::vector< backend::command_queue >       queue;
        std::vector< backend::device_vector<real> > phi;
        point xmin, hinv;
        index n, stride;

        /** Creates the approximation functor.
         * `cmin` and `cmax` specify the domain boundaries, `coo` and `val`
         * contain coordinates and values of the data points. `grid` is the
         * initial control grid size. The approximation hierarchy will have at
         * most `levels` and will stop when the desired approximation precision
         * `tol` will be reached.
         */
        mba(
                const std::vector<backend::command_queue> &queue,
                const point &cmin, const point &cmax,
                const std::vector<point> &coo, std::vector<real> val,
                std::array<size_t, NDIM> grid, size_t levels = 8, real tol = 1e-8
           ) : queue(queue)
        {
            init(cmin, cmax, coo.begin(), coo.end(), val.begin(), grid, levels, tol);
        }

        /** Creates the approximation functor.
         * `cmin` and `cmax` specify the domain boundaries. Coordinates and
         * values of the data points are passed as iterator ranges. `grid` is
         * the initial control grid size. The approximation hierarchy will have
         * at most `levels` and will stop when the desired approximation
         * precision `tol` will be reached.
         */
        template <class CooIter, class ValIter>
        mba(
                const std::vector<backend::command_queue> &queue,
                const point &cmin, const point &cmax,
                CooIter coo_begin, CooIter coo_end, ValIter val_begin,
                std::array<size_t, NDIM> grid, size_t levels = 8, real tol = 1e-8
           ) : queue(queue)
        {
            init(cmin, cmax, coo_begin, coo_end, val_begin, grid, levels, tol);
        }

#if !defined(BOOST_NO_VARIADIC_TEMPLATES) && ((!defined(__GNUC__) || (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ > 6)) || defined(__clang__))
        /// Provide interpolated values at given coordinates.
        template <class... Expr>
        auto operator()(const Expr&... expr) const ->
            mba_interp< mba, boost::tuple<const Expr&...> >
        {
            static_assert(sizeof...(Expr) == NDIM, "Wrong number of parameters");
            return mba_interp< mba, boost::tuple<const Expr&...> >(*this, boost::tie(expr...));
        }
#else

#define VEXCL_FUNCALL_OPERATOR(z, n, data)                                     \
  template <BOOST_PP_ENUM_PARAMS(n, class Expr)>                               \
  mba_interp<mba, boost::tuple<BOOST_PP_ENUM_BINARY_PARAMS(                    \
                      n, const Expr, &BOOST_PP_INTERCEPT)> >                   \
  operator()(BOOST_PP_ENUM_BINARY_PARAMS(n, const Expr, &expr)) {              \
    return mba_interp<mba, boost::tuple<BOOST_PP_ENUM_BINARY_PARAMS(           \
                               n, const Expr, &BOOST_PP_INTERCEPT)> >(         \
        *this, boost::tie(BOOST_PP_ENUM_PARAMS(n, expr)));                     \
  }

BOOST_PP_REPEAT_FROM_TO(1, 10, VEXCL_FUNCALL_OPERATOR, ~)

#undef VEXCL_FUNCALL_OPERATOR
#endif
    private:
        template <class CooIter, class ValIter>
        void init(
                const point &cmin, const point &cmax,
                CooIter coo_begin, CooIter coo_end, ValIter val_begin,
                std::array<size_t, NDIM> grid, size_t levels = 8, real tol = 1e-8
                )
        {
            for(size_t k = 0; k < NDIM; ++k)
                assert(grid[k] > 1);

            double res0 = std::accumulate(
                    val_begin, val_begin + (coo_end - coo_begin),
                    static_cast<real>(0),
                    [](real sum, real v) { return sum + v * v; }
                    );

            std::unique_ptr<lattice> psi(
                    new lattice(cmin, cmax, grid, coo_begin, coo_end, val_begin)
                    );
            double res = psi->update_data(coo_begin, coo_end, val_begin);
#ifdef VEXCL_MBA_VERBOSE
            std::cout << "level  0: res = " << std::scientific << res << std::endl;
#endif

            for (size_t k = 1; (res > res0 * tol) && (k < levels); ++k) {
                for(size_t d = 0; d < NDIM; ++d) grid[d] = 2 * grid[d] - 1;

                std::unique_ptr<lattice> f(
                        new lattice(cmin, cmax, grid, coo_begin, coo_end, val_begin)
                        );
                res = f->update_data(coo_begin, coo_end, val_begin);
#ifdef VEXCL_MBA_VERBOSE
                std::cout << "level " << k << std::scientific << ": res = " << res << std::endl;
#endif

                f->append_refined(*psi);
                psi = std::move(f);
            }

            xmin   = psi->xmin;
            hinv   = psi->hinv;
            n      = psi->n;
            stride = psi->stride;

            phi.reserve(queue.size());

            for(auto q = queue.begin(); q != queue.end(); ++q)
                phi.push_back( backend::device_vector<real>(
                            *q, psi->phi.size(), psi->phi.data(), backend::MEM_READ_ONLY
                            ) );
        }

        // Control lattice.
        struct lattice {
            point xmin, hinv;
            index n, stride;
            std::vector<real> phi;

            template <class CooIter, class ValIter>
            lattice(
                    const point &cmin, const point &cmax, std::array<size_t, NDIM> grid,
                    CooIter coo_begin, CooIter coo_end, ValIter val_begin
                   ) : xmin(cmin), n(grid)
            {
                for(size_t d = 0; d < NDIM; ++d) {
                    hinv[d] = (grid[d] - 1) / (cmax[d] - cmin[d]);
                    xmin[d] -= 1 / hinv[d];
                    n[d]    += 2;
                }

                stride[NDIM - 1] = 1;
                for(size_t d = NDIM - 1; d--; )
                    stride[d] = stride[d + 1] * n[d + 1];

                std::vector<real> delta(n[0] * stride[0], 0.0);
                std::vector<real> omega(n[0] * stride[0], 0.0);

                auto p = coo_begin;
                auto v = val_begin;
                for(; p != coo_end; ++p, ++v) {
                    if (!contained(cmin, cmax, *p)) continue;

                    index i;
                    point s;

                    for(size_t d = 0; d < NDIM; ++d) {
                        real u = ((*p)[d] - xmin[d]) * hinv[d];
                        i[d] = static_cast<size_t>(std::floor(u) - 1);
                        s[d] = u - std::floor(u);
                    }

                    std::array<real, detail::power<4, NDIM>::value> w;
                    real sw2 = 0;

                    for(detail::scounter<4, NDIM> d; d.valid(); ++d) {
                        real buf = 1;
                        for(size_t k = 0; k < NDIM; ++k)
                            buf *= B(d[k], s[k]);

                        w[d] = buf;
                        sw2 += buf * buf;
                    }

                    for(detail::scounter<4, NDIM> d; d.valid(); ++d) {
                        real phi = (*v) * w[d] / sw2;

                        size_t idx = 0;
                        for(size_t k = 0; k < NDIM; ++k) {
                            assert(i[k] + d[k] < n[k]);

                            idx += (i[k] + d[k]) * stride[k];
                        }

                        real w2 = w[d] * w[d];

                        assert(idx < delta.size());

                        delta[idx] += w2 * phi;
                        omega[idx] += w2;
                    }
                }

                phi.resize(omega.size());

                for(auto w = omega.begin(), d = delta.begin(), f = phi.begin();
                        w != omega.end();
                        ++w, ++d, ++f
                   )
                {
                    if (std::fabs(*w) < 1e-32)
                        *f = 0;
                    else
                        *f = (*d) / (*w);
                }
            }

            // Get interpolated value at given position.
            real operator()(const point &p) const {
                index i;
                point s;

                for(size_t d = 0; d < NDIM; ++d) {
                    real u = (p[d] - xmin[d]) * hinv[d];
                    i[d] = static_cast<size_t>(std::floor(u) - 1);
                    s[d] = u - std::floor(u);
                }

                real f = 0;

                for(detail::scounter<4, NDIM> d; d.valid(); ++d) {
                    real w = 1;
                    for(size_t k = 0; k < NDIM; ++k)
                        w *= B(d[k], s[k]);

                    f += w * get(i, d);
                }

                return f;
            }

            // Subtract interpolated values from data points.
            template <class CooIter, class ValIter>
            real update_data(
                    CooIter coo_begin, CooIter coo_end, ValIter val_begin
                    ) const
            {
                auto c = coo_begin;
                auto v = val_begin;

                real res = 0;

                for(; c != coo_end; ++c, ++v) {
                    *v -= (*this)(*c);

                    res += (*v) * (*v);
                }

                return res;
            }

            // Refine r and append it to the current control lattice.
            void append_refined(const lattice &r) {
                static const std::array<real, 5> s = {{
                    0.125, 0.500, 0.750, 0.500, 0.125
                }};

                for(detail::dcounter<NDIM> i(r.n); i.valid(); ++i) {
                    real f = r.phi[i];
                    for(detail::scounter<5, NDIM> d; d.valid(); ++d) {
                        index j;
                        bool skip = false;
                        size_t idx = 0;
                        for(size_t k = 0; k < NDIM; ++k) {
                            j[k] = 2 * i[k] + d[k] - 3;
                            if (j[k] >= n[k]) { skip = true; break; }

                            idx += j[k] * stride[k];
                        }

                        if (skip) continue;

                        real c = 1;
                        for(size_t k = 0; k < NDIM; ++k) c *= s[d[k]];

                        phi[idx] += f * c;
                    }
                }
            }

            private:
                // Value of k-th B-Spline at t.
                static inline real B(size_t k, real t) {
                    assert(0 <= t && t < 1);
                    assert(k < 4);

                    switch (k) {
                        case 0:
                            return (t * (t * (-t + 3) - 3) + 1) / 6;
                        case 1:
                            return (t * t * (3 * t - 6) + 4) / 6;
                        case 2:
                            return (t * (t * (-3 * t + 3) + 3) + 1) / 6;
                        case 3:
                        default:
                            return t * t * t / 6;
                    }
                }

                // x is within [xmin, xmax].
                static bool contained(
                        const point &xmin, const point &xmax, const point &x)
                {
                    for(size_t d = 0; d < NDIM; ++d) {
                        static const real eps = 1e-12;

                        if (x[d] - eps <  xmin[d]) return false;
                        if (x[d] + eps >= xmax[d]) return false;
                    }

                    return true;
                }

                // Get value of phi at index (i + d).
                template <class Shift>
                inline real get(const index &i, const Shift &d) const {
                    size_t idx = 0;

                    for(size_t k = 0; k < NDIM; ++k) {
                        size_t j = i[k] + d[k];

                        if (j >= n[k]) return 0;
                        idx += j * stride[k];
                    }

                    return phi[idx];
                }
        };
};

namespace traits {

template <>
struct is_vector_expr_terminal< mba_terminal > : std::true_type {};

template <>
struct proto_terminal_is_value< mba_terminal > : std::true_type {};

template <class MBA, class ExprTuple>
struct terminal_preamble< mba_interp<MBA, ExprTuple> > {
    static void get(backend::source_generator &src,
            const mba_interp<MBA, ExprTuple>&,
            const backend::command_queue&, const std::string &prm_name,
            detail::kernel_generator_state_ptr)
    {
        typedef typename MBA::value_type real;

        std::string B = prm_name + "_B";

        src.begin_function<real>(B + "0");
        src.begin_function_parameters();
        src.template parameter<real>("t");
        src.end_function_parameters();
        src.new_line() << "return (t * (t * (-t + 3) - 3) + 1) / 6;";
        src.end_function();

        src.begin_function<real>(B + "1");
        src.begin_function_parameters();
        src.template parameter<real>("t");
        src.end_function_parameters();
        src.new_line() << "return (t * t * (3 * t - 6) + 4) / 6;";
        src.end_function();

        src.begin_function<real>(B + "2");
        src.begin_function_parameters();
        src.template parameter<real>("t");
        src.end_function_parameters();
        src.new_line() << "return (t * (t * (-3 * t + 3) + 3) + 1) / 6;";
        src.end_function();

        src.begin_function<real>(B + "3");
        src.begin_function_parameters();
        src.template parameter<real>("t");
        src.end_function_parameters();
        src.new_line() << "return t * t * t / 6;";
        src.end_function();

        src.begin_function<real>(prm_name + "_mba");
        src.begin_function_parameters();

        for(size_t k = 0; k < MBA::ndim; ++k)
            src.template parameter<real>("x") << k;

        for(size_t k = 0; k < MBA::ndim; ++k) {
            src.template parameter<real>("c" + std::to_string(k));
            src.template parameter<real>("h" + std::to_string(k));
            src.parameter<size_t>("n" + std::to_string(k));
            src.parameter<size_t>("m" + std::to_string(k));
        }

        src.template parameter< global_ptr<const real> >("phi");
        src.end_function_parameters();
        src.new_line() << type_name<real>() << " u;";
        for(size_t k = 0; k < MBA::ndim; ++k) {
            src.new_line() << "u = (x" << k << " - c" << k << ") * h" << k << ";";
            src.new_line() << type_name<size_t>() << " i" << k << " = floor(u) - 1;";
            src.new_line() << type_name<real>() << " s" << k << " = u - floor(u);";
        }
        src.new_line() << type_name<real>() << " f = 0;";
        src.new_line() << type_name<size_t>() << " j, idx;";

        for(detail::scounter<4,MBA::ndim> d; d.valid(); ++d) {
            src.new_line() << "idx = 0;";
            for(size_t k = 0; k < MBA::ndim; ++k) {
                src.new_line() << "j = i" << k << " + " << d[k] << ";";
                src.new_line() << "if (j < n" << k << ")";
                src.open("{").new_line() << "idx += j * m" << k << ";";
            }

            src.new_line() << "f += ";
            for(size_t k = 0; k < MBA::ndim; ++k) {
                if (k) src << " * ";
                src << B << d[k] << "(s" << k << ")";
            }

            src << " * phi[idx];";

            for(size_t k = 0; k < MBA::ndim; ++k)
                src.close("}");
        }
        src.new_line() << "return f;";
        src.end_function();
    }
};

template <class MBA, class ExprTuple>
struct kernel_param_declaration< mba_interp<MBA, ExprTuple> > {
    static void get(backend::source_generator &src,
            const mba_interp<MBA, ExprTuple> &term,
            const backend::command_queue &queue, const std::string &prm_name,
            detail::kernel_generator_state_ptr state)
    {
        typedef typename MBA::value_type real;
        boost::fusion::for_each(term.coord, prmdecl(src, queue, prm_name, state));

        for(size_t k = 0; k < MBA::ndim; ++k) {
            src.template parameter<real>(prm_name + "_c" + std::to_string(k));
            src.template parameter<real>(prm_name + "_h" + std::to_string(k));
            src.parameter<size_t>(prm_name + "_n" + std::to_string(k));
            src.parameter<size_t>(prm_name + "_m" + std::to_string(k));
        }

        src.parameter< global_ptr<const real> >(prm_name + "_phi");
    }

    struct prmdecl {
        backend::source_generator &s;
        const backend::command_queue &queue;
        const std::string &prm_name;
        detail::kernel_generator_state_ptr state;
        mutable int pos;

        prmdecl(backend::source_generator &s,
                const backend::command_queue &queue, const std::string &prm_name,
                detail::kernel_generator_state_ptr state
            ) : s(s), queue(queue), prm_name(prm_name), state(state), pos(0)
        {}

        template <class Expr>
        void operator()(const Expr &expr) const {
            std::ostringstream prefix;
            prefix << prm_name << "_x" << pos;
            detail::declare_expression_parameter ctx(s, queue, prefix.str(), state);
            detail::extract_terminals()(boost::proto::as_child(expr), ctx);

            pos++;
        }
    };
};

template <class MBA, class ExprTuple>
struct local_terminal_init< mba_interp<MBA, ExprTuple> > {
    static void get(backend::source_generator &src,
            const mba_interp<MBA, ExprTuple> &term,
            const backend::command_queue &queue, const std::string &prm_name,
            detail::kernel_generator_state_ptr state)
    {
        boost::fusion::for_each(term.coord, local_init(src, queue, prm_name, state));
    }

    struct local_init {
        backend::source_generator &s;
        const backend::command_queue &queue;
        const std::string &prm_name;
        detail::kernel_generator_state_ptr state;
        mutable int pos;

        local_init(backend::source_generator &s,
                const backend::command_queue &queue, const std::string &prm_name,
                detail::kernel_generator_state_ptr state
            ) : s(s), queue(queue), prm_name(prm_name), state(state), pos(0)
        {}

        template <class Expr>
        void operator()(const Expr &expr) const {
            std::ostringstream prefix;
            prefix << prm_name << "_x" << pos;

            detail::output_local_preamble init_ctx(s, queue, prefix.str(), state);
            boost::proto::eval(boost::proto::as_child(expr), init_ctx);

            pos++;
        }
    };
};

template <class MBA, class ExprTuple>
struct partial_vector_expr< mba_interp<MBA, ExprTuple> > {
    static void get(backend::source_generator &src,
            const mba_interp<MBA, ExprTuple> &term,
            const backend::command_queue &queue, const std::string &prm_name,
            detail::kernel_generator_state_ptr state)
    {
        src << prm_name << "_mba(";

        boost::fusion::for_each(term.coord, buildexpr(src, queue, prm_name, state));

        for(size_t k = 0; k < MBA::ndim; ++k) {
            src << ", " << prm_name << "_c" << k
                << ", " << prm_name << "_h" << k
                << ", " << prm_name << "_n" << k
                << ", " << prm_name << "_m" << k;
        }

        src << ", " << prm_name << "_phi)";
    }

    struct buildexpr {
        backend::source_generator &s;
        const backend::command_queue &queue;
        const std::string &prm_name;
        detail::kernel_generator_state_ptr state;
        mutable int pos;

        buildexpr(backend::source_generator &s,
                const backend::command_queue &queue, const std::string &prm_name,
                detail::kernel_generator_state_ptr state
            ) : s(s), queue(queue), prm_name(prm_name), state(state), pos(0)
        {}

        template <class Expr>
        void operator()(const Expr &expr) const {
            if(pos) s << ", ";

            std::ostringstream prefix;
            prefix << prm_name << "_x" << pos;

            detail::vector_expr_context ctx(s, queue, prefix.str(), state);
            boost::proto::eval(boost::proto::as_child(expr), ctx);

            pos++;
        }
    };
};

template <class MBA, class ExprTuple>
struct kernel_arg_setter< mba_interp<MBA, ExprTuple> > {
    static void set(const mba_interp<MBA, ExprTuple> &term,
            backend::kernel &kernel, unsigned part, size_t index_offset,
            detail::kernel_generator_state_ptr state)
    {

        boost::fusion::for_each(term.coord,
                setargs(kernel, part, index_offset, state));

        for(size_t k = 0; k < MBA::ndim; ++k) {
            kernel.push_arg(term.cloud.xmin[k]);
            kernel.push_arg(term.cloud.hinv[k]);
            kernel.push_arg(term.cloud.n[k]);
            kernel.push_arg(term.cloud.stride[k]);
        }
        kernel.push_arg(term.cloud.phi[part]);
    }

    struct setargs {
        backend::kernel &kernel;
        unsigned part;
        size_t index_offset;
        detail::kernel_generator_state_ptr state;

        setargs(
                backend::kernel &kernel, unsigned part, size_t index_offset,
                detail::kernel_generator_state_ptr state
               )
            : kernel(kernel), part(part), index_offset(index_offset), state(state)
        {}

        template <class Expr>
        void operator()(const Expr &expr) const {
            detail::set_expression_argument ctx(kernel, part, index_offset, state);
            detail::extract_terminals()( boost::proto::as_child(expr), ctx);
        }
    };
};

template <class MBA, class ExprTuple>
struct expression_properties< mba_interp<MBA, ExprTuple> > {
    static void get(const mba_interp<MBA, ExprTuple> &term,
            std::vector<backend::command_queue> &queue_list,
            std::vector<size_t> &partition,
            size_t &size
            )
    {
        boost::fusion::for_each(term.coord, extrprop(queue_list, partition, size));
    }

    struct extrprop {
        std::vector<backend::command_queue> &queue_list;
        std::vector<size_t> &partition;
        size_t &size;

        extrprop(std::vector<backend::command_queue> &queue_list,
            std::vector<size_t> &partition, size_t &size
            ) : queue_list(queue_list), partition(partition), size(size)
        {}

        template <class Expr>
        void operator()(const Expr &expr) const {
            if (queue_list.empty()) {
                detail::get_expression_properties prop;
                detail::extract_terminals()(boost::proto::as_child(expr), prop);

                queue_list = prop.queue;
                partition  = prop.part;
                size       = prop.size;
            }
        }
    };
};

} //namespace traits

} // namespace vex

#endif

ext: hpp

max_stars_repo_name: lkusch/Kratos

max_issues_repo_name: lkusch/Kratos

max_forks_repo_name: lkusch/Kratos


text:
#include "GL/glew.h"
#include "GLFW/glfw3.h"
#include "base.h"

#include <Eigen/Eigen>

int main()
{

	return 0;
}

ext: cpp

max_stars_repo_name: rxlfnng/PolyMeshProc

max_issues_repo_name: rxlfnng/PolyMeshProc

max_forks_repo_name: rxlfnng/PolyMeshProc


text:
// Copyright Maarten L. Hekkelman, Radboud University 2008-2011.
//   Distributed under the Boost Software License, Version 1.0.
//       (See accompanying file LICENSE_1_0.txt or copy at
//             http://www.boost.org/LICENSE_1_0.txt)

#include "mas.h"

#if defined(_MSC_VER)
#include <conio.h>
#include <ctype.h>
#endif

#include <iostream>

#include <boost/format.hpp>
#include <boost/foreach.hpp>
#define foreach BOOST_FOREACH
#include <boost/bind.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/date_time/date_clock_device.hpp>

#include "dssp.h"
#include "structure.h"

using namespace std;

string ResidueToDSSPLine(const MResidue& residue)
{
/*
	This is the header line for the residue lines in a DSSP file:

  #  RESIDUE AA STRUCTURE BP1 BP2  ACC     N-H-->O    O-->H-N    N-H-->O    O-->H-N    TCO  KAPPA ALPHA  PHI   PSI    X-CA   Y-CA   Z-CA

 */
	boost::format kDSSPResidueLine(
	"%5.5d%5.5d%1.1s%1.1s %c  %c %c%c%c%c%c%c%c%4.4d%4.4d%c%4.4d %11s%11s%11s%11s  %6.3f%6.1f%6.1f%6.1f%6.1f %6.1f %6.1f %6.1f");

	const MAtom& ca = residue.GetCAlpha();

	char code = kResidueInfo[residue.GetType()].code;
	if (residue.GetType() == kCysteine and residue.GetSSBridgeNr() != 0)
		code = 'a' + ((residue.GetSSBridgeNr() - 1) % 26);

	char ss;
	switch (residue.GetSecondaryStructure())
	{
		case alphahelix:	ss = 'H'; break;
		case betabridge:	ss = 'B'; break;
		case strand:		ss = 'E'; break;
		case helix_3:		ss = 'G'; break;
		case helix_5:		ss = 'I'; break;
		case turn:			ss = 'T'; break;
		case bend:			ss = 'S'; break;
		case loop:			ss = ' '; break;
	}

	char helix[3];
	for (uint32 stride = 3; stride <= 5; ++stride)
	{
		switch (residue.GetHelixFlag(stride))
		{
			case helixNone:			helix[stride - 3] = ' '; break;
			case helixStart:		helix[stride - 3] = '>'; break;
			case helixEnd:			helix[stride - 3] = '<'; break;
			case helixStartAndEnd:	helix[stride - 3] = 'X'; break;
			case helixMiddle:		helix[stride - 3] = '0' + stride; break;
		}
	}

	char bend = ' ';
	if (residue.IsBend())
		bend = 'S';

	double alpha;
	char chirality;
	tr1::tie(alpha,chirality) = residue.Alpha();

	uint32 bp[2] = {};
	char bridgelabel[2] = { ' ', ' ' };
	for (uint32 i = 0; i < 2; ++i)
	{
		MBridgeParner p = residue.GetBetaPartner(i);
		if (p.residue != nullptr)
		{
			bp[i] = p.residue->GetNumber();
			bp[i] %= 10000;	// won't fit otherwise...
			bridgelabel[i] = 'A' + p.ladder % 26;
			if (p.parallel)
				bridgelabel[i] = tolower(bridgelabel[i]);
		}
	}

	char sheet = ' ';
	if (residue.GetSheet() != 0)
		sheet = 'A' + (residue.GetSheet() - 1) % 26;

	string NHO[2], ONH[2];
	const HBond* acceptors = residue.Acceptor();
	const HBond* donors = residue.Donor();
	for (uint32 i = 0; i < 2; ++i)
	{
		NHO[i] = ONH[i] = "0, 0.0";

		if (acceptors[i].residue != nullptr)
		{
			int32 d = acceptors[i].residue->GetNumber() - residue.GetNumber();
			NHO[i] = (boost::format("%d,%3.1f") % d % acceptors[i].energy).str();
		}

		if (donors[i].residue != nullptr)
		{
			int32 d = donors[i].residue->GetNumber() - residue.GetNumber();
			ONH[i] = (boost::format("%d,%3.1f") % d % donors[i].energy).str();
		}
	}

	return (kDSSPResidueLine % residue.GetNumber() % ca.mResSeq % ca.mICode % ca.mChainID % code %
		ss % helix[0] % helix[1] % helix[2] % bend % chirality % bridgelabel[0] % bridgelabel[1] %
		bp[0] % bp[1] % sheet % floor(residue.Accessibility() + 0.5) %
		NHO[0] % ONH[0] % NHO[1] % ONH[1] %
		residue.TCO() % residue.Kappa() % alpha % residue.Phi() % residue.Psi() %
		ca.mLoc.mX % ca.mLoc.mY % ca.mLoc.mZ).str();
}

void WriteDSSP(MProtein& protein, ostream& os)
{
	const string kFirstLine("==== Secondary Structure Definition by the program DSSP, CMBI version by M.L. Hekkelman/2010-10-21 ==== ");
	boost::format kHeaderLine("%1% %|127t|%2%");

	using namespace boost::gregorian;

	uint32 nrOfResidues, nrOfChains, nrOfSSBridges, nrOfIntraChainSSBridges, nrOfHBonds;
	uint32 nrOfHBondsPerDistance[11] = {};

	protein.GetStatistics(nrOfResidues, nrOfChains, nrOfSSBridges, nrOfIntraChainSSBridges, nrOfHBonds, nrOfHBondsPerDistance);

	date today = day_clock::local_day();

	os << kHeaderLine % (kFirstLine + "DATE=" + to_iso_extended_string(today)) % '.' << endl;
	os << kHeaderLine % "REFERENCE W. KABSCH AND C.SANDER, BIOPOLYMERS 22 (1983) 2577-2637" % '.' << endl;
	os << kHeaderLine % protein.GetHeader() % '.' << endl;
	if (not protein.GetCompound().empty())
		os << kHeaderLine % protein.GetCompound() % '.' << endl;
	if (not protein.GetSource().empty())
		os << kHeaderLine % protein.GetSource() % '.' << endl;
	if (not protein.GetAuthor().empty())
		os << kHeaderLine % protein.GetAuthor() % '.' << endl;

	double accessibleSurface = 0;	// calculate accessibility as
	foreach (const MChain* chain, protein.GetChains())
	{
		foreach (const MResidue* residue, chain->GetResidues())
			accessibleSurface += residue->Accessibility();
	}

	os << boost::format("%5.5d%3.3d%3.3d%3.3d%3.3d TOTAL NUMBER OF RESIDUES, NUMBER OF CHAINS, NUMBER OF SS-BRIDGES(TOTAL,INTRACHAIN,INTERCHAIN) %|127t|%c") %
   		nrOfResidues % nrOfChains % nrOfSSBridges % nrOfIntraChainSSBridges % (nrOfSSBridges - nrOfIntraChainSSBridges) % '.' << endl;
   	os << kHeaderLine % (boost::format("%8.1f   ACCESSIBLE SURFACE OF PROTEIN (ANGSTROM**2)") % accessibleSurface) % '.' << endl;

	// hydrogenbond summary

	os << kHeaderLine % (
		boost::format("%5.5d%5.1f   TOTAL NUMBER OF HYDROGEN BONDS OF TYPE O(I)-->H-N(J)  , SAME NUMBER PER 100 RESIDUES")
			% nrOfHBonds % (nrOfHBonds * 100.0 / nrOfResidues)) % '.' << endl;

	uint32 nrOfHBondsInParallelBridges = protein.GetNrOfHBondsInParallelBridges();
	os << kHeaderLine % (
		boost::format("%5.5d%5.1f   TOTAL NUMBER OF HYDROGEN BONDS IN     PARALLEL BRIDGES, SAME NUMBER PER 100 RESIDUES")
			% nrOfHBondsInParallelBridges % (nrOfHBondsInParallelBridges * 100.0 / nrOfResidues)) % '.' << endl;

	uint32 nrOfHBondsInAntiparallelBridges = protein.GetNrOfHBondsInAntiparallelBridges();
	os << kHeaderLine % (
		boost::format("%5.5d%5.1f   TOTAL NUMBER OF HYDROGEN BONDS IN ANTIPARALLEL BRIDGES, SAME NUMBER PER 100 RESIDUES")
			% nrOfHBondsInAntiparallelBridges % (nrOfHBondsInAntiparallelBridges * 100.0 / nrOfResidues)) % '.' << endl;

	boost::format kHBondsLine("%5.5d%5.1f   TOTAL NUMBER OF HYDROGEN BONDS OF TYPE O(I)-->H-N(I%c%1.1d), SAME NUMBER PER 100 RESIDUES");
   	for (int32 k = 0; k < 11; ++k)
	{
		os << kHeaderLine % (kHBondsLine % nrOfHBondsPerDistance[k] % (nrOfHBondsPerDistance[k] * 100.0 / nrOfResidues) % (k - 5 < 0 ? '-' : '+') % abs(k - 5)) % '.' << endl;
	}

	// histograms...

	uint32 histogram[kHistogramSize];
	os << "  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30     *** HISTOGRAMS OF ***           ." << endl;

	protein.GetResiduesPerAlphaHelixHistogram(histogram);
	for (uint32 i = 0; i < kHistogramSize; ++i)
		os << boost::format("%3.3d") % histogram[i];
	os << "    RESIDUES PER ALPHA HELIX         ." << endl;

	protein.GetParallelBridgesPerLadderHistogram(histogram);
	for (uint32 i = 0; i < kHistogramSize; ++i)
		os << boost::format("%3.3d") % histogram[i];
	os << "    PARALLEL BRIDGES PER LADDER      ." << endl;

	protein.GetAntiparallelBridgesPerLadderHistogram(histogram);
	for (uint32 i = 0; i < kHistogramSize; ++i)
		os << boost::format("%3.3d") % histogram[i];
	os << "    ANTIPARALLEL BRIDGES PER LADDER  ." << endl;

	protein.GetLaddersPerSheetHistogram(histogram);
	for (uint32 i = 0; i < kHistogramSize; ++i)
		os << boost::format("%3.3d") % histogram[i];
	os << "    LADDERS PER SHEET                ." << endl;

	// per residue information

	os << "  #  RESIDUE AA STRUCTURE BP1 BP2  ACC     N-H-->O    O-->H-N    N-H-->O    O-->H-N    TCO  KAPPA ALPHA  PHI   PSI    X-CA   Y-CA   Z-CA " << endl;
	boost::format kDSSPResidueLine(
		"%5.5d        !%c             0   0    0      0, 0.0     0, 0.0     0, 0.0     0, 0.0   0.000 360.0 360.0 360.0 360.0    0.0    0.0    0.0");

	vector<const MResidue*> residues;

	foreach (const MChain* chain, protein.GetChains())
	{
		foreach (const MResidue* residue, chain->GetResidues())
			residues.push_back(residue);
	}

	// keep residues sorted by residue number as assigned during reading the PDB file
	sort(residues.begin(), residues.end(), boost::bind(&MResidue::GetNumber, _1) < boost::bind(&MResidue::GetNumber, _2));

	const MResidue* last = nullptr;
	foreach (const MResidue* residue, residues)
	{
		// insert a break line whenever we detect missing residues
		// can be the transition to a different chain, or missing residues in the current chain
		if (last != nullptr and last->GetNumber() + 1 != residue->GetNumber())
		{
			char breaktype = ' ';
			if (last->GetChainID() != residue->GetChainID())
				breaktype = '*';
			os << (kDSSPResidueLine % (last->GetNumber() + 1) % breaktype) << endl;
		}
		os << ResidueToDSSPLine(*residue) << endl;
		last = residue;
	}
}

max_stars_repo_name: genomecuration/JAMp

max_issues_repo_name: genomecuration/JAMp

max_forks_repo_name: genomecuration/JAMp


text:
//-----------------------------------------------------------------------------
// Copyright (c) 2015-2018 Benjamin Buch
//
// https://github.com/bebuch/disposer
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
//-----------------------------------------------------------------------------
#include <disposer/config/parse_config.hpp>

#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>

#include <istream>
#include <map>

BOOST_FUSION_ADAPT_STRUCT(
	disposer::types::parse::specialized_parameter,
	type,
	value
)

BOOST_FUSION_ADAPT_STRUCT(
	disposer::types::parse::parameter,
	key,
	generic_value,
	specialized_values
)

BOOST_FUSION_ADAPT_STRUCT(
	disposer::types::parse::parameter_set,
	name,
	parameters
)

BOOST_FUSION_ADAPT_STRUCT(
	disposer::types::parse::in,
	name,
	transfer,
	variable
)

BOOST_FUSION_ADAPT_STRUCT(
	disposer::types::parse::out,
	name,
	variable
)

BOOST_FUSION_ADAPT_STRUCT(
	disposer::types::parse::wait_on,
	number,
	type_name
)

BOOST_FUSION_ADAPT_STRUCT(
	disposer::types::parse::parameters,
	parameter_sets,
	parameters
)

BOOST_FUSION_ADAPT_STRUCT(
	disposer::types::parse::module,
	type_name,
	wait_ons,
	parameters,
	inputs,
	outputs
)

BOOST_FUSION_ADAPT_STRUCT(
	disposer::types::parse::chain,
	name,
	id_generator,
	modules
)

BOOST_FUSION_ADAPT_STRUCT(
	disposer::types::parse::component,
	name,
	type_name,
	parameters
)

BOOST_FUSION_ADAPT_STRUCT(
	disposer::types::parse::config,
	sets,
	components,
	chains
)

namespace disposer::parser{

	class syntax_error: public std::logic_error{
	public:
		syntax_error(std::string&& message, std::string::iterator pos):
			std::logic_error(std::move(message)),
			pos_(pos)
			{}

		std::string::iterator pos()const{ return pos_; }

	private:
		std::string::iterator const pos_;
	};

	namespace x3 = boost::spirit::x3;

	using x3::lit;
	using x3::char_;
	using x3::eol;
	using x3::eoi;

	struct transfer_: x3::symbols< in_transfer >{
		transfer_(){
			add
				("&", in_transfer::copy)
				("<", in_transfer::move);
		}
	} transfer;

	/// \brief Parser for line counting
	template < typename Iterator >
	std::size_t line_count(Iterator first, Iterator last){
		namespace x3 = boost::spirit::x3;
		using x3::eol;

		std::size_t n = 1;
		auto const inc = [&n](x3::unused_type){ ++n; };

		x3::phrase_parse(first, last,
			x3::no_skip[ *(*(x3::omit[char_] - eol) >> eol[inc]) ],
			x3::space);

		return n;
	}

	/// \brief Get text from the last line
	template < typename Iterator >
	std::string get_error_line_before(Iterator first, Iterator pos){
		namespace x3 = boost::spirit::x3;
		using x3::eol;

		auto line_start = std::find_if(
			std::make_reverse_iterator(pos),
			std::make_reverse_iterator(first),
			[](char c){ return c == '\n' || c == '\r'; }).base();

		return std::string(line_start, pos);
	}

	/// \brief Get text from the first line
	template < typename Iterator >
	std::string get_error_line_after(Iterator pos, Iterator last){
		namespace x3 = boost::spirit::x3;
		using x3::eol;

		auto line_end = std::find_if(
			pos, last, [](char c){ return c == '\n' || c == '\r'; });

		if(last == line_end){
			return std::string(pos, line_end);
		}else{
			return std::string(pos, line_end) + '\n';
		}
	}

	template < typename Derived >
	struct error_base{
		template < typename Iter, typename Exception, typename Context >
		x3::error_handler_result on_error(
			Iter& /*first*/, Iter const& /*last*/,
			Exception const& x, Context const& /*context*/
		){
			throw syntax_error(
				static_cast< Derived const& >(*this).message(), x.where());
		}
	};

	namespace type = types::parse;

	struct space_tag;
	x3::rule< space_tag > const space("space");

	struct space_lines_tag;
	x3::rule< space_lines_tag > const space_lines("space_lines");

	struct separator_tag;
	x3::rule< separator_tag > const separator("separator");

	struct comment_tag;
	x3::rule< comment_tag > const comment("comment");

	struct keyword_spaces_tag;
	x3::rule< keyword_spaces_tag, std::string > const
		keyword_spaces("keyword_spaces");

	struct value_spaces_tag;
	x3::rule< value_spaces_tag, std::string > const
		value_spaces("value_spaces");

	auto const space_def =
		lit(' ') | '\t'
	;

	auto const space_lines_def =
		*(*space >> eol)
	;

	auto const separator_def =
		*space >> (eol >> space_lines >> -comment)
	;

	auto const comment_def =
		*space >> (lit('#') | ';') >> *(char_ - eol) >> separator
	;

	auto const keyword_spaces_def =
		+(char_(' ') | char_('\t')) >> !(eol | '=')
	;

	auto const value_spaces_def =
		+(char_(' ') | char_('\t')) >> !(eol | eoi)
	;

	struct keyword_tag;
	x3::rule< keyword_tag, std::string > const keyword("keyword");

	struct value_tag;
	x3::rule< value_tag, std::string > const value("value");

	auto const keyword_def =
		(char_ - space - '=' - eol) >>
		*(keyword_spaces | +(char_ - space - eol - '='))
	;

	auto const value_def =
		(char_ - space - eol) >>
		*(value_spaces | +(char_ - space - eol))
	;

	struct sets_param_specialization_tag;
	x3::rule< sets_param_specialization_tag, type::specialized_parameter > const
		sets_param_specialization("sets_param_specialization");

	struct sets_param_tag;
	x3::rule< sets_param_tag, type::parameter > const
		sets_param("sets_param");

	struct sets_param_prevent_tag;
	x3::rule< sets_param_prevent_tag > const
		sets_param_prevent("sets_param_prevent");

	struct sets_param_list_tag;
	x3::rule< sets_param_list_tag, std::vector< type::parameter > > const
		sets_param_list("sets_param_list");

	struct sets_set_tag;
	x3::rule< sets_set_tag, type::parameter_set > const
		sets_set("sets_set");

	struct sets_set_list_tag;
	x3::rule< sets_set_list_tag, type::parameter_sets > const
		sets_set_list("sets_set_list");

	struct sets_set_list_checked_tag;
	x3::rule< sets_set_list_checked_tag, type::parameter_sets > const
		sets_set_list_checked("sets_set_list_checked");

	struct sets_config_tag;
	x3::rule< sets_config_tag, type::parameter_sets > const
		sets_config("sets_config");

	auto const sets_param_specialization_def =
		"\t\t\t" > keyword > *space > '=' > *space > value > separator
	;

	auto const sets_param_def =
		("\t\t" >> sets_param_prevent >> keyword)
		> -(*space >> ('=' > *space > value))
		> separator > *sets_param_specialization
	;

	auto const sets_param_prevent_def =
		x3::expect[!("parameter_set" >> *space >> '=')]
	;

	auto const sets_param_list_def =
		x3::expect[+sets_param]
	;

	auto const sets_set_def =
		'\t' > keyword > separator > sets_param_list
	;

	auto const sets_set_list_def =
		x3::expect[+sets_set]
	;

	auto const sets_set_list_checked_def =
		sets_set_list > &x3::expect[(lit("component") | "chain") >> separator]
	;

	auto const sets_config_def =
		("parameter_set" > separator > sets_set_list_checked) |
		&x3::expect[(lit("component") | "chain") >> separator]
	;

	struct sets_param_specialization_tag:
		error_base< sets_param_specialization_tag >
	{
		const char* message()const{
			return "a parameter specialization '\t\t\ttype = value\n'";
		}
	};

	struct sets_param_tag: error_base< sets_param_tag >{
		const char* message()const{
			return "a parameter '\t\tname [= value]\n' with name != "
				"'parameter_set'";
		}
	};

	struct sets_param_prevent_tag: error_base< sets_param_prevent_tag >{
		const char* message()const{
			return "a parameter, but a parameter name "
				"('\t\tname [= value]\n') must not be 'parameter_set'";
		}
	};

	struct sets_param_list_tag: error_base< sets_param_list_tag >{
		const char* message()const{
			return "at least one parameter line '\t\tname [= value]\n' "
				"with name != 'parameter_set'";
		}
	};

	struct sets_set_tag: error_base< sets_set_tag >{
		const char* message()const{
			return "a parameter set line '\tname\n'";
		}
	};

	struct sets_set_list_tag: error_base< sets_set_list_tag >{
		const char* message()const{
			return "at least one parameter set line '\tname\n'";
		}
	};

	struct sets_set_list_checked_tag: error_base< sets_set_list_checked_tag >{
		const char* message()const{
			return "a parameter set line '\tname\n' or a parameter definition "
				"('\t\tname [= value]\n') or a parameter specialization "
				"'\t\t\ttype = value\n' or keyword line 'component\n' or "
				"keyword line 'chain\n'";
		}
	};

	struct sets_config_tag: error_base< sets_config_tag >{
		template < typename Iter, typename Exception, typename Context >
		x3::error_handler_result on_error(
			Iter& first, Iter const& last,
			Exception const& x, Context const& context
		){
			msg_ = "keyword line 'parameter_set\n'";
			if(x.which() != "separator"){
				msg_ += " or keyword line 'component\n' or keyword line "
					"'chain\n'";
			}
			return error_base::on_error(first, last, x, context);
		}

		const char* message()const{
			return msg_.c_str();
		}

		std::string msg_;
	};

	struct module_params_tag;
	x3::rule< module_params_tag, type::parameters > const
		module_params("module_params");

	struct module_params_checked_tag;
	x3::rule< module_params_checked_tag, type::parameters > const
		module_params_checked("module_params_checked");

	struct module_set_ref_tag;
	x3::rule< module_set_ref_tag, std::string > const
		module_set_ref("module_set_ref");

	struct module_wait_on_tag;
	x3::rule< module_wait_on_tag, type::wait_on > const
		module_wait_on("module_wait_on");

	struct module_param_specialization_tag;
	x3::rule< module_param_specialization_tag, type::specialized_parameter >
		 const module_param_specialization("module_param_specialization");

	struct module_param_prevent_tag;
	x3::rule< module_param_prevent_tag > const
		module_param_prevent("module_param_prevent");

	struct module_param_tag;
	x3::rule< module_param_tag, type::parameter > const
		module_param("module_param");

	struct input_tag;
	x3::rule< input_tag, type::in > const input("input");

	struct output_tag;
	x3::rule< output_tag, type::out > const output("output");

	struct input_params_tag;
	x3::rule< input_params_tag, std::vector< type::in > >
		const input_params("input_params");

	struct output_params_tag;
	x3::rule< output_params_tag, std::vector< type::out > >
		const output_params("output_params");

	struct inputs_tag;
	x3::rule< inputs_tag, std::vector< type::in > > const
		inputs("inputs");

	struct outputs_tag;
	x3::rule< outputs_tag, std::vector< type::out > > const
		outputs("outputs");

	struct module_tag;
	x3::rule< module_tag, type::module > const
		module("module");

	struct chain_tag;
	x3::rule< chain_tag, type::chain > const chain("chain");

	struct chain_config_tag;
	x3::rule< chain_config_tag, type::chain > const
		chain_config("chain_config");

	struct chain_params_tag;
	x3::rule< chain_params_tag, std::vector< type::module > >
		const chain_params("chain_params");

	struct id_generator_tag;
	x3::rule< id_generator_tag, std::string > const
		id_generator("id_generator");

	struct chains_params_tag;
	x3::rule< chains_params_tag, type::chains > const
		chains_params("chains_params");

	struct chains_tag;
	x3::rule< chains_tag, type::chains > const
		chains("chains");

	struct component_params_checked_tag;
	x3::rule< component_params_checked_tag, type::parameters > const
		component_params_checked("component_params_checked");

	struct component_set_ref_tag;
	x3::rule< component_set_ref_tag, std::string > const
		component_set_ref("component_set_ref");

	struct component_param_specialization_tag;
	x3::rule< component_param_specialization_tag, type::specialized_parameter >
		const component_param_specialization("component_param_specialization");

	struct component_param_prevent_tag;
	x3::rule< component_param_prevent_tag > const
		component_param_prevent("component_param_prevent");

	struct component_param_tag;
	x3::rule< component_param_tag, type::parameter > const
		component_param("component_param");

	struct component_tag;
	x3::rule< component_tag, type::component > const
		component("component");

	struct component_config_tag;
	x3::rule< component_config_tag, type::component > const
		component_config("component_config");

	struct component_list_tag;
	x3::rule< component_list_tag, type::components > const
		component_list("component_list");

	struct component_list_checked_tag;
	x3::rule< component_list_checked_tag, type::components > const
		component_list_checked("component_list_checked");

	struct components_tag;
	x3::rule< components_tag, type::components > const
		components("components");

	auto const module_params_def =
		"\t\t\tparameter" > separator > module_params_checked
	;

	auto const module_params_checked_def =
		&x3::expect[module_set_ref | module_param] >>
		(*module_set_ref >> *module_param)
	;

	auto const module_set_ref_def =
		// wait for = before throw because a parameter name
		// might begin with parameter_set
		("\t\t\t\tparameter_set" >> *space >> '=')
		> *space > value > separator
	;

	auto const module_wait_on_def =
		"\t\t\twait_on" > *space > '='
		> *space > x3::ulong_ > ':' > value > separator
	;

	auto const module_param_specialization_def =
		"\t\t\t\t\t" > keyword > *space > '=' > *space > value > separator
	;

	auto const module_param_prevent_def =
		x3::expect[!("parameter_set" >> *space >> '=')]
	;

	auto const module_param_def =
		("\t\t\t\t" >> module_param_prevent >> keyword)
		> -(*space >> ('=' > *space > value))
		> separator > *module_param_specialization
	;

	auto const input_def =
		"\t\t\t\t" > (keyword >> *space) >
			('=' >> *space) > transfer > value > separator
	;

	auto const output_def =
		"\t\t\t\t" > (keyword >> *space) >
			('=' >> *space) > '>' > value > separator
	;

	auto const input_params_def =
		x3::expect[+input]
	;

	auto const output_params_def =
		x3::expect[+output]
	;

	auto const inputs_def =
		("\t\t\t<-" > separator) >>
		input_params
	;

	auto const outputs_def =
		("\t\t\t->" > separator) >>
		output_params
	;

	auto const module_def =
		("\t\t" > keyword > separator) >>
		*module_wait_on >>
		-module_params >>
		-inputs >>
		-outputs
	;

	auto const id_generator_def =
		('=' >> *space) > value
	;

	auto const chain_params_def =
		x3::expect[+module]
	;

	auto const chain_def =
		('\t' > (keyword >> *space) > -id_generator > separator) >>
		chain_params
	;

	auto const chain_config_def = x3::no_skip[x3::expect[
		space_lines >> -comment >> chain
	]];

	auto const chains_params_def =
		x3::expect[+chain]
	;

	auto const chains_def =
		(x3::expect["chain"] > separator) >>
		chains_params
	;

	auto const component_params_checked_def =
		&x3::expect[component_set_ref | component_param] >>
		(*component_set_ref >> *component_param)
	;

	auto const component_set_ref_def =
		("\t\tparameter_set" >> *space >> '=')
		> *space > value > separator
	;

	auto const component_param_specialization_def =
		"\t\t\t" > keyword > *space > '=' > *space > value > separator
	;

	auto const component_param_prevent_def =
		x3::expect[!("parameter_set" >> *space >> '=')]
	;

	auto const component_param_def =
		("\t\t" >> component_param_prevent >> keyword)
		> -(*space >> ('=' > *space > value))
		> separator > *component_param_specialization
	;

	auto const component_def =
		("\t" > keyword > *space > '=' > *space > value > separator) >>
		component_params_checked
	;

	auto const component_config_def = x3::no_skip[x3::expect[
		space_lines >> -comment >> component
	]];

	auto const component_list_def =
		x3::expect[+component]
	;

	auto const component_list_checked_def =
		component_list > &x3::expect["chain" >> separator]
	;

	auto const components_def =
		("component" > separator > component_list_checked) |
		&x3::expect["chain" >> separator]

	;

	struct config_tag;
	x3::rule< config_tag, type::config >
		const config("config");

	auto const config_def = x3::no_skip[x3::expect[
		space_lines >> -comment >>
		-sets_config >> -components >> chains
	]];

	struct module_params_tag: error_base< module_params_tag >{
		const char* message()const{
			return "keyword line '\t\t\tparameter\n'";
		}
	};

	struct module_params_checked_tag: error_base< module_params_checked_tag >{
		const char* message()const{
			return "at least one parameter set reference line "
				"'\t\t\t\tparameter_set = name\n', where 'parameter_set' is a "
				"keyword and 'name' the name of the referenced parameter set "
				"or one parameter '\t\t\t\tname [= value]\n'";
		}
	};

	struct module_set_ref_tag: error_base< module_set_ref_tag >{
		const char* message()const{
			return "a parameter set reference line "
				"'\t\t\t\tparameter_set = name\n', where 'parameter_set' is a "
				"keyword and 'name' the name of the referenced parameter set";
		}
	};

	struct module_wait_on_tag: error_base< module_wait_on_tag >{
		const char* message()const{
			return "a wait_on reference line "
				"'\t\t\twait_on = number:module\n', where 'wait_on' is a "
				"keyword, 'number' is the (with 1 beginning) number of the "
				"referenced module in the current chain and 'module' is the "
				"type name of the referenced module";
		}
	};

	struct modules_params_tag: error_base< modules_params_tag >{
		const char* message()const{
			return "at least one module line '\tname = module\n'";
		}
	};

	struct module_param_prevent_tag: error_base< module_param_prevent_tag >{
		const char* message()const{
			return "another parameter, but a parameter name "
				"('\t\t\t\tname [= value]\n') must not be 'parameter_set'";
		}
	};

	struct module_param_specialization_tag
		: error_base< module_param_specialization_tag >
	{
		const char* message()const{
			return "a parameter specialization '\t\t\t\t\ttype = value\n'";
		}
	};

	struct module_param_tag: error_base< module_param_tag >{
		const char* message()const{
			return "a parameter '\t\t\t\tname [= value]\n' with name != "
				"'parameter_set'";
		}
	};

	struct input_tag: error_base< input_tag >{
		const char* message()const{
			return "input map '\t\t\t\tinput = {< or &}variable'";
		}
	};

	struct output_tag: error_base< output_tag >{
		const char* message()const{
			return "output map '\t\t\t\toutput = >variable'";
		}
	};

	struct input_params_tag: error_base< input_params_tag >{
		const char* message()const{
			return "at least one input map "
				"'\t\t\t\tinput = {< or &}variable'";
		}
	};

	struct output_params_tag: error_base< output_params_tag >{
		const char* message()const{
			return "at least one output map "
				"'\t\t\t\toutput = >variable'";
		}
	};

	struct inputs_tag: error_base< inputs_tag >{
		const char* message()const{
			return "keyword line '\t\t\t<-\n'";
		}
	};

	struct outputs_tag: error_base< outputs_tag >{
		const char* message()const{
			return "keyword line '\t\t\t->\n'";
		}
	};

	struct module_tag: error_base< module_tag >{
		const char* message()const{
			return "a module line '\t\tmodule\n'";
		}
	};

	struct chains_params_tag: error_base< chains_params_tag >{
		const char* message()const{
			return "at least one chain line '\tname [= id_generator]\n'";
		}
	};

	struct id_generator_tag: error_base< id_generator_tag >{
		const char* message()const{
			return "a chain line with id_generator '\tname = id_generator\n'";
		}
	};

	struct chains_tag: error_base< chains_tag >{
		const char* message()const{
			return "keyword line 'chain\n'";
		}
	};

	struct component_params_checked_tag
		: error_base< component_params_checked_tag >
	{
		const char* message()const{
			return "at least one parameter set reference line "
				"'\t\t\tparameter_set = name\n', where 'parameter_set' is a "
				"keyword and 'name' the name of the referenced parameter set "
				"or one parameter '\t\t\tname [= value]\n'";
		}
	};

	struct component_set_ref_tag: error_base< component_set_ref_tag >{
		const char* message()const{
			return "a parameter set reference line "
				"'\t\t\tparameter_set = name\n', where 'parameter_set' is a "
				"keyword and 'name' the name of the referenced parameter set";
		}
	};

	struct component_param_prevent_tag
		: error_base< component_param_prevent_tag >
	{
		const char* message()const{
			return "another parameter, but a parameter name "
				"('\t\tname [= value]\n') must not be 'parameter_set'";
		}
	};

	struct component_param_specialization_tag
		: error_base< component_param_specialization_tag >
	{
		const char* message()const{
			return "a parameter specialization '\t\t\ttype = value\n'";
		}
	};

	struct component_tag: error_base< component_tag >{
		const char* message()const{
			return "a component line '\tname = component\n'";
		}
	};

	struct component_param_tag: error_base< component_param_tag >{
		const char* message()const{
			return "a parameter '\t\tname [= value]\n' with name != "
				"'parameter_set'";
		}
	};

	struct component_list_tag: error_base< component_list_tag >{
		const char* message()const{
			return "at least one component line '\tname = component\n'";
		}
	};

	struct component_list_checked_tag: error_base< component_list_checked_tag >{
		const char* message()const{
			return "a parameter set line '\tname\n' or a parameter definition "
				"('\t\tname [= value]\n') or a parameter specialization "
				"'\t\t\ttype = value\n' or keyword line 'component\n' or "
				"keyword line 'chain\n'";
		}
	};

	struct components_tag: error_base< components_tag >{
		template < typename Iter, typename Exception, typename Context >
		x3::error_handler_result on_error(
			Iter& first, Iter const& last,
			Exception const& x, Context const& context
		){
			msg_ = "keyword line 'component\n'";
			if(x.which() != "separator"){
				msg_ += " or keyword line 'chain\n'";
			}
			return error_base::on_error(first, last, x, context);
		}

		const char* message()const{
			return msg_.c_str();
		}

		std::string msg_;
	};

	struct config_tag: error_base< config_tag >{
		const char* message()const{
			return "keyword line 'parameter_set\n' or keyword line "
				"'component\n' or keyword line 'chain\n'";
		}
	};

	BOOST_SPIRIT_DEFINE(space)
	BOOST_SPIRIT_DEFINE(space_lines)
	BOOST_SPIRIT_DEFINE(separator)
	BOOST_SPIRIT_DEFINE(comment)
	BOOST_SPIRIT_DEFINE(keyword_spaces)
	BOOST_SPIRIT_DEFINE(value_spaces)
	BOOST_SPIRIT_DEFINE(keyword)
	BOOST_SPIRIT_DEFINE(value)
	BOOST_SPIRIT_DEFINE(sets_param_specialization)
	BOOST_SPIRIT_DEFINE(sets_param)
	BOOST_SPIRIT_DEFINE(sets_param_prevent)
	BOOST_SPIRIT_DEFINE(sets_param_list)
	BOOST_SPIRIT_DEFINE(sets_set)
	BOOST_SPIRIT_DEFINE(sets_set_list)
	BOOST_SPIRIT_DEFINE(sets_set_list_checked)
	BOOST_SPIRIT_DEFINE(sets_config)
	BOOST_SPIRIT_DEFINE(module_param_specialization)
	BOOST_SPIRIT_DEFINE(module_param)
	BOOST_SPIRIT_DEFINE(module_param_prevent)
	BOOST_SPIRIT_DEFINE(module_params)
	BOOST_SPIRIT_DEFINE(module_params_checked)
	BOOST_SPIRIT_DEFINE(module_set_ref)
	BOOST_SPIRIT_DEFINE(module_wait_on)
	BOOST_SPIRIT_DEFINE(input)
	BOOST_SPIRIT_DEFINE(output)
	BOOST_SPIRIT_DEFINE(inputs)
	BOOST_SPIRIT_DEFINE(outputs)
	BOOST_SPIRIT_DEFINE(input_params)
	BOOST_SPIRIT_DEFINE(output_params)
	BOOST_SPIRIT_DEFINE(module)
	BOOST_SPIRIT_DEFINE(chain_params)
	BOOST_SPIRIT_DEFINE(chain)
	BOOST_SPIRIT_DEFINE(chain_config)
	BOOST_SPIRIT_DEFINE(id_generator)
	BOOST_SPIRIT_DEFINE(chains_params)
	BOOST_SPIRIT_DEFINE(chains)
	BOOST_SPIRIT_DEFINE(component_params_checked)
	BOOST_SPIRIT_DEFINE(component_set_ref)
	BOOST_SPIRIT_DEFINE(component_param_specialization)
	BOOST_SPIRIT_DEFINE(component_param_prevent)
	BOOST_SPIRIT_DEFINE(component_param)
	BOOST_SPIRIT_DEFINE(component)
	BOOST_SPIRIT_DEFINE(component_config)
	BOOST_SPIRIT_DEFINE(component_list)
	BOOST_SPIRIT_DEFINE(component_list_checked)
	BOOST_SPIRIT_DEFINE(components)
	BOOST_SPIRIT_DEFINE(config)

	auto const grammar = config;

	auto const component_grammar = component_config;

	auto const chain_grammar = chain_config;

}

namespace disposer{

	template < typename Grammar >
	typename Grammar::attribute_type parse(
		std::istream& is,
		Grammar const& grammar
	){
		namespace x3 = boost::spirit::x3;

		std::string str{
			std::istreambuf_iterator< char >{is},
			std::istreambuf_iterator< char >{}
		};

		typename Grammar::attribute_type config;

		auto iter = str.begin();
		auto end = str.end();

		x3::ascii::space_type space;

		try{
			bool const match =
				phrase_parse(iter, end, grammar, space, config);

			if(!match || iter != end){
				auto const line_number = parser::line_count(str.begin(), iter);
				auto const before =
					parser::get_error_line_before(str.begin(), iter);
				auto const after = parser::get_error_line_after(iter, end);
				std::ostringstream os;
				os << "Syntax error at line " << line_number << ", pos "
					<< before.size() << ": '" << before << after
					<< "', incomplete parsing (programming error!)";
				throw std::runtime_error(os.str());
			}

			return config;
		}catch(parser::syntax_error const& e){
			auto const line_number = parser::line_count(str.begin(), e.pos());
			auto const before =
				parser::get_error_line_before(str.begin(), e.pos());
			auto const after = parser::get_error_line_after(e.pos(), end);

			std::ostringstream os;
			os << "Syntax error at line " << line_number << ", pos "
				<< before.size() << ": '" << before << after
				<< "', expected " << e.what();

			throw std::runtime_error(os.str());
		}
	}

	types::parse::config parse(std::istream& is){
		return parse(is, parser::grammar);
	}

	types::parse::component parse_component(std::istream& is){
		return parse(is, parser::component_grammar);
	}

	types::parse::chain parse_chain(std::istream& is){
		return parse(is, parser::chain_grammar);
	}

}

max_stars_repo_name: bebuch/disposer

max_issues_repo_name: bebuch/disposer

max_forks_repo_name: bebuch/disposer


text:
#pragma once
#include <dlfcn.h>
#include <string>
#include <set>
#include <atomic>
#include <boost/filesystem.hpp>

#include "Module.hpp"
#include "interfaces/logger.hpp"

using namespace spina::interfaces;

namespace spina {
	class ModuleHandler {
		private:
			const string name = "ModuleHandler";
			string _filename;
			Logger _logger;

			void* _module_so            = nullptr;
			Module_ctor*  createModule  = nullptr;
			Module_dctor* destroyModule = nullptr;

			inline bool openLibraryFile();
			inline int  loadLibrarySymbols();

		public:
			// This is public so Spina can use it nicely.
			Module* module = nullptr;
			const ModuleInfo* moduleInfo;

			atomic<bool> _moduleLoaded{false};
			atomic<bool> _moduleInit  {false};

			inline ModuleHandler(const string& filename) {_filename = filename;};
			//TODO: Deconstructor
			inline bool loadLibrary();
			inline void unloadLibrary();

			inline bool initModule();
			inline void deinitModule();

			inline bool isLoaded() const;
	};

	// const string ModuleHandler::name = "ModuleHandler";

	bool ModuleHandler::openLibraryFile() {
		// Here we use dlopen to load the dynamic library (that is, a compiled module)
		_module_so = dlopen(_filename.c_str(), RTLD_NOW | RTLD_GLOBAL);
		if (!_module_so) {
			_logger.err(name, dlerror());
			return false;
		}
		return true;
	};

	int ModuleHandler::loadLibrarySymbols() {
		// Here we use dlsym to hook into exported functions of the module
		// One to load the module class and one to unload it
		createModule = (Module_ctor*)dlsym(_module_so, "createModule");
		if (!createModule) {
			_logger.err(name, dlerror());
			return 1;
		}
		_logger.log(name, "Resolved loadModule", true);

		destroyModule = (Module_dctor*)dlsym(_module_so, "destroyModule");
		if (!destroyModule) {
			return 2;
		}
		_logger.log(name, "Resolved unloadModule", true);

		return 0;
	}

	bool ModuleHandler::loadLibrary() {
		// In the threads we load the binary and hook into it's exported functions.
		// We use the load function to create an instance of it's Module-derived class
		// We then set up an interface with the module using our input/output sockets
		//  which are a management Rep and Req socket for commands in and out
		//  and a chain-building pair of Pub and Sub sockets for message passing.
		// Now we run it's run() function in a new thread and push that on to our list.
		if (! openLibraryFile()) {
			_logger.err(name, "Failiure " + boost::filesystem::basename(_filename) + "..");
			return false;
		}
		_logger.log(name, "Opened file " + boost::filesystem::basename(_filename) + "..", true);

		if (loadLibrarySymbols() != 0) {
			_logger.err(name, "Failiure " + boost::filesystem::basename(_filename) + "..");
			return false;
		}
		_logger.log(name, "Functions resolved", true);

		_moduleLoaded.store(true);
		return _moduleLoaded;
	};

	void ModuleHandler::unloadLibrary() {
		if (_moduleInit.load()) {
			deinitModule();
		}

		if (dlclose(_module_so) != 0) {
			_logger.err(name, "Could not dlclose module file");
		}

		_moduleLoaded.store(false);
	};

	bool ModuleHandler::initModule() {
		if (!_moduleInit) {
			module = createModule();
			if (module) {
				moduleInfo = module->getinfo();
				_moduleInit.store(true);
			}
		}

		return _moduleInit.load();
	};

	void ModuleHandler::deinitModule() {
		if (_moduleInit.load() && module) {
			delete module;
			module = nullptr;
			_moduleInit.store(false);
		}
	};
}

max_stars_repo_name: Joeasaurus/spina

max_issues_repo_name: Joeasaurus/spina

max_forks_repo_name: Joeasaurus/spina