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

#include "include/HyperEdge.hh"
#include "include/HyperVertex.hh"
#include <boost/foreach.hpp>

HyperEdge::HyperEdge(const boost::shared_ptr<HypergrapheAbstrait>& ptrHypergraphe, unsigned int& identifier) :
	_ptrHypergraphe( ptrHypergraphe ),
	_identifier( identifier ){

}

void
HyperEdge::addHyperVertex(boost::shared_ptr<HyperVertex>& hyperVertex) {
	if( !containVertex(hyperVertex) ) {
		_listHyperVertex.push_back( hyperVertex );
	};
}

void
HyperEdge::setHyperVertexList(LibType::ListHyperVertex& listHyperVertex) {
	_listHyperVertex = listHyperVertex;
}

const unsigned int
HyperEdge::getEffectif() const {
	return _listHyperVertex.size();
}

const unsigned int&
HyperEdge::getIdentifier() const {
	return _identifier;
}

bool HyperEdge::operator==(const boost::shared_ptr<HyperEdge>& hyperEdge) const {
	return _identifier==hyperEdge->getIdentifier();
}

bool
HyperEdge::operator<(const boost::shared_ptr<HyperEdge>& hyperEdge) const {
	return _identifier < hyperEdge->getIdentifier();
}

bool
HyperEdge::operator>(const boost::shared_ptr<HyperEdge>& hyperEdge) const {
	return _identifier > hyperEdge->getIdentifier();
}

bool HyperEdge::containVertex(boost::shared_ptr<HyperVertex>& hyperVertex) const {

	int i = 0;
	const int N = _listHyperVertex.size();
	bool ret = false;

	#pragma omp parallel for schedule(dynamic)
	for( i=0 ; i<N ; i++ ) {
		if( _listHyperVertex[i]==hyperVertex) {
			ret = true;
		};
	};

	return ret;
}

LibType::ListHyperVertex&
HyperEdge::getHyperVertexList() {
	return _listHyperVertex;
}

const LibType::ListHyperVertex&
HyperEdge::getHyperVertexList() const {
	return _listHyperVertex;
}

max_stars_repo_name: ehzawad/HyperGraphLib

max_issues_repo_name: ehzawad/HyperGraphLib

max_forks_repo_name: ehzawad/HyperGraphLib


text:
// Copyright 2020 The Defold Foundation
// Licensed under the Defold License version 1.0 (the "License"); you may not use
// this file except in compliance with the License.
//
// You may obtain a copy of the License, together with FAQs at
// https://www.defold.com/license
//
// 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 <stdint.h>
#define JC_TEST_IMPLEMENTATION
#include <jc_test/jc_test.h>

#include <dlib/log.h>

#include "graphics.h"
#include "graphics_private.h"
#include "null/graphics_null_private.h"

#define APP_TITLE "GraphicsTest"
#define WIDTH 8u
#define HEIGHT 4u

using namespace dmVMath;

class dmGraphicsTest : public jc_test_base_class
{
protected:
    struct ResizeData
    {
        uint32_t m_Width;
        uint32_t m_Height;
    };

    struct CloseData
    {
        bool m_ShouldClose;
    };

    dmGraphics::HContext m_Context;
    dmGraphics::WindowResult m_WindowResult;
    ResizeData m_ResizeData;
    CloseData m_CloseData;

    static void OnWindowResize(void* user_data, uint32_t width, uint32_t height)
    {
        ResizeData* data = (ResizeData*)user_data;
        data->m_Width = width;
        data->m_Height = height;
    }

    static bool OnWindowClose(void* user_data)
    {
        CloseData* data = (CloseData*)user_data;
        return data->m_ShouldClose;
    }

    virtual void SetUp()
    {
        dmGraphics::Initialize();
        m_Context = dmGraphics::NewContext(dmGraphics::ContextParams());
        dmGraphics::WindowParams params;
        params.m_ResizeCallback = OnWindowResize;
        params.m_ResizeCallbackUserData = &m_ResizeData;
        params.m_CloseCallback = OnWindowClose;
        params.m_CloseCallbackUserData = &m_CloseData;
        params.m_Title = APP_TITLE;
        params.m_Width = WIDTH;
        params.m_Height = HEIGHT;
        params.m_Fullscreen = false;
        params.m_PrintDeviceInfo = false;
        m_WindowResult = dmGraphics::OpenWindow(m_Context, &params);
        m_ResizeData.m_Width = 0;
        m_ResizeData.m_Height = 0;
    }

    virtual void TearDown()
    {
        dmGraphics::CloseWindow(m_Context);
        dmGraphics::DeleteContext(m_Context);
    }
};

TEST_F(dmGraphicsTest, NewDeleteContext)
{
    ASSERT_NE((void*)0, m_Context);
    ASSERT_EQ(dmGraphics::WINDOW_RESULT_OK, m_WindowResult);
}

TEST_F(dmGraphicsTest, DoubleNewContext)
{
    ASSERT_NE((void*)0, m_Context);
    ASSERT_EQ((dmGraphics::HContext)0, dmGraphics::NewContext(dmGraphics::ContextParams()));
}

TEST_F(dmGraphicsTest, DoubleOpenWindow)
{
    dmGraphics::WindowParams params;
    params.m_Title = APP_TITLE;
    params.m_Width = WIDTH;
    params.m_Height = HEIGHT;
    params.m_Fullscreen = false;
    params.m_PrintDeviceInfo = false;
    ASSERT_EQ(dmGraphics::WINDOW_RESULT_ALREADY_OPENED, dmGraphics::OpenWindow(m_Context, &params));
}

TEST_F(dmGraphicsTest, CloseWindow)
{
    dmGraphics::CloseWindow(m_Context);
    dmGraphics::CloseWindow(m_Context);
}

TEST_F(dmGraphicsTest, CloseOpenWindow)
{
    dmGraphics::CloseWindow(m_Context);
    dmGraphics::WindowParams params;
    params.m_Title = APP_TITLE;
    params.m_Width = WIDTH;
    params.m_Height = HEIGHT;
    params.m_Fullscreen = false;
    params.m_PrintDeviceInfo = true;
    dmLog::Setlevel(dmLog::LOG_SEVERITY_INFO);
    ASSERT_EQ(dmGraphics::WINDOW_RESULT_OK, dmGraphics::OpenWindow(m_Context, &params));
    dmLog::Setlevel(dmLog::LOG_SEVERITY_WARNING);
}

TEST_F(dmGraphicsTest, TestWindowState)
{
    ASSERT_TRUE(dmGraphics::GetWindowState(m_Context, dmGraphics::WINDOW_STATE_OPENED) ? true : false);
    dmGraphics::CloseWindow(m_Context);
    ASSERT_FALSE(dmGraphics::GetWindowState(m_Context, dmGraphics::WINDOW_STATE_OPENED));
}

TEST_F(dmGraphicsTest, TestWindowSize)
{
    ASSERT_EQ(m_Context->m_Width, dmGraphics::GetWidth(m_Context));
    ASSERT_EQ(m_Context->m_Height, dmGraphics::GetHeight(m_Context));
    ASSERT_EQ(m_Context->m_WindowWidth, dmGraphics::GetWindowWidth(m_Context));
    ASSERT_EQ(m_Context->m_WindowHeight, dmGraphics::GetWindowHeight(m_Context));
    uint32_t width = WIDTH * 2;
    uint32_t height = HEIGHT * 2;
    dmGraphics::SetWindowSize(m_Context, width, height);
    ASSERT_EQ(width, dmGraphics::GetWidth(m_Context));
    ASSERT_EQ(height, dmGraphics::GetHeight(m_Context));
    ASSERT_EQ(width, dmGraphics::GetWindowWidth(m_Context));
    ASSERT_EQ(height, dmGraphics::GetWindowHeight(m_Context));
    ASSERT_EQ(width, m_ResizeData.m_Width);
    ASSERT_EQ(height, m_ResizeData.m_Height);
}

TEST_F(dmGraphicsTest, TestDefaultTextureFilters)
{
    dmGraphics::TextureFilter min_filter;
    dmGraphics::TextureFilter mag_filter;
    dmGraphics::GetDefaultTextureFilters(m_Context, min_filter, mag_filter);
    ASSERT_EQ(dmGraphics::TEXTURE_FILTER_LINEAR_MIPMAP_NEAREST, min_filter);
    ASSERT_EQ(dmGraphics::TEXTURE_FILTER_LINEAR, mag_filter);
}
TEST_F(dmGraphicsTest, Flip)
{
    dmGraphics::Flip(m_Context);
}

TEST_F(dmGraphicsTest, Clear)
{
    const uint32_t flags = dmGraphics::BUFFER_TYPE_COLOR_BIT | dmGraphics::BUFFER_TYPE_DEPTH_BIT | dmGraphics::BUFFER_TYPE_STENCIL_BIT;
    dmGraphics::Clear(m_Context, flags, 1, 1, 1, 1, 1.0f, 1);
    uint32_t width = WIDTH;
    uint32_t height = HEIGHT;
    uint32_t data_size = sizeof(uint32_t) * width * height;
    uint32_t* data = new uint32_t[width * height];
    memset(data, 1, data_size);
    ASSERT_EQ(0, memcmp(data, m_Context->m_CurrentFrameBuffer->m_ColorBuffer, data_size));
    delete [] data;
    width *= 2;
    height *= 2;
    data = new uint32_t[width * height];
    data_size = sizeof(uint32_t) * width * height;
    memset(data, 1, data_size);
    dmGraphics::SetWindowSize(m_Context, width, height);
    dmGraphics::Clear(m_Context, flags, 1, 1, 1, 1, 1.0f, 1);
    ASSERT_EQ(0, memcmp(data, m_Context->m_CurrentFrameBuffer->m_ColorBuffer, data_size));
    delete [] data;
}

TEST_F(dmGraphicsTest, VertexBuffer)
{
    char data[16];
    memset(data, 1, sizeof(data));
    dmGraphics::HVertexBuffer vertex_buffer = dmGraphics::NewVertexBuffer(m_Context, 16, data, dmGraphics::BUFFER_USAGE_STREAM_DRAW);
    dmGraphics::VertexBuffer* vb = (dmGraphics::VertexBuffer*)vertex_buffer;
    ASSERT_EQ(0, memcmp(data, vb->m_Buffer, sizeof(data)));

    memset(data, 2, sizeof(data));
    dmGraphics::SetVertexBufferData(vertex_buffer, sizeof(data), data, dmGraphics::BUFFER_USAGE_STREAM_DRAW);
    ASSERT_EQ(0, memcmp(data, vb->m_Buffer, sizeof(data)));

    memset(&data[4], 3, 4);
    dmGraphics::SetVertexBufferSubData(vertex_buffer, 4, 4, &data[4]);
    ASSERT_EQ(0, memcmp(data, vb->m_Buffer, sizeof(data)));

    // Invalid range
    memset(&data[14], 4, 1);
    dmGraphics::SetVertexBufferSubData(vertex_buffer, 14, 4, data);
    ASSERT_NE(0, memcmp(data, vb->m_Buffer, sizeof(data)));

    memset(data, 4, 4);
    void* copy = dmGraphics::MapVertexBuffer(vertex_buffer, dmGraphics::BUFFER_ACCESS_READ_WRITE);
    memcpy(copy, data, sizeof(data));
    ASSERT_NE(0, memcmp(data, vb->m_Buffer, sizeof(data)));
    ASSERT_TRUE(dmGraphics::UnmapVertexBuffer(vertex_buffer));
    ASSERT_EQ(0, memcmp(data, vb->m_Buffer, sizeof(data)));

    // Smaller size
    dmGraphics::SetVertexBufferData(vertex_buffer, 1, 0x0, dmGraphics::BUFFER_USAGE_STREAM_DRAW);
    ASSERT_EQ(1u, vb->m_Size);

    // Bigger size
    dmGraphics::SetVertexBufferData(vertex_buffer, 4, data, dmGraphics::BUFFER_USAGE_STREAM_DRAW);
    ASSERT_EQ(4u, vb->m_Size);
    ASSERT_EQ(0, memcmp(data, vb->m_Buffer, 4));

    dmGraphics::DeleteVertexBuffer(vertex_buffer);
}

TEST_F(dmGraphicsTest, IndexBuffer)
{
    char data[16];
    memset(data, 1, sizeof(data));
    dmGraphics::HIndexBuffer index_buffer = dmGraphics::NewIndexBuffer(m_Context, 16, data, dmGraphics::BUFFER_USAGE_STREAM_DRAW);
    dmGraphics::IndexBuffer* ib = (dmGraphics::IndexBuffer*)index_buffer;
    ASSERT_EQ(0, memcmp(data, ib->m_Buffer, sizeof(data)));

    memset(data, 2, sizeof(data));
    dmGraphics::SetIndexBufferData(index_buffer, sizeof(data), data, dmGraphics::BUFFER_USAGE_STREAM_DRAW);
    ASSERT_EQ(0, memcmp(data, ib->m_Buffer, sizeof(data)));

    memset(&data[4], 3, 4);
    dmGraphics::SetIndexBufferSubData(index_buffer, 4, 4, &data[4]);
    ASSERT_EQ(0, memcmp(data, ib->m_Buffer, sizeof(data)));

    // Invalid range
    memset(&data[14], 4, 1);
    dmGraphics::SetIndexBufferSubData(index_buffer, 14, 4, data);
    ASSERT_NE(0, memcmp(data, ib->m_Buffer, sizeof(data)));

    memset(data, 4, 4);
    void* copy = dmGraphics::MapIndexBuffer(index_buffer, dmGraphics::BUFFER_ACCESS_READ_WRITE);
    memcpy(copy, data, sizeof(data));
    ASSERT_NE(0, memcmp(data, ib->m_Buffer, sizeof(data)));
    ASSERT_TRUE(dmGraphics::UnmapVertexBuffer(index_buffer));
    ASSERT_EQ(0, memcmp(data, ib->m_Buffer, sizeof(data)));

    // Smaller size
    dmGraphics::SetIndexBufferData(index_buffer, 1, 0x0, dmGraphics::BUFFER_USAGE_STREAM_DRAW);
    ASSERT_EQ(1u, ib->m_Size);

    // Bigger size
    dmGraphics::SetIndexBufferData(index_buffer, 4, data, dmGraphics::BUFFER_USAGE_STREAM_DRAW);
    ASSERT_EQ(4u, ib->m_Size);
    ASSERT_EQ(0, memcmp(data, ib->m_Buffer, 4));

    dmGraphics::DeleteIndexBuffer(index_buffer);
}

TEST_F(dmGraphicsTest, VertexDeclaration)
{
    float v[] = { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f };
    dmGraphics::HVertexBuffer vertex_buffer = dmGraphics::NewVertexBuffer(m_Context, sizeof(v), (void*)v, dmGraphics::BUFFER_USAGE_STREAM_DRAW);

    dmGraphics::VertexElement ve[2] =
    {
        {"position", 0, 3, dmGraphics::TYPE_FLOAT, false },
        {"uv", 1, 2, dmGraphics::TYPE_FLOAT, false }
    };
    dmGraphics::HVertexDeclaration vertex_declaration = dmGraphics::NewVertexDeclaration(m_Context, ve, 2);

    dmGraphics::EnableVertexDeclaration(m_Context, vertex_declaration, vertex_buffer);

    float p[] = { 0.0f, 1.0f, 2.0f, 5.0f, 6.0f, 7.0f };
    ASSERT_EQ(sizeof(p) / 2, m_Context->m_VertexStreams[0].m_Size);
    ASSERT_EQ(0, memcmp(p, m_Context->m_VertexStreams[0].m_Source, 3 * sizeof(float)));
    float uv[] = { 3.0f, 4.0f, 8.0f, 9.0f };
    ASSERT_EQ(sizeof(uv) / 2, m_Context->m_VertexStreams[1].m_Size);
    ASSERT_EQ(0, memcmp(uv, m_Context->m_VertexStreams[1].m_Source, 2 * sizeof(float)));

    dmGraphics::DisableVertexDeclaration(m_Context, vertex_declaration);

    ASSERT_EQ(0u, m_Context->m_VertexStreams[0].m_Size);
    ASSERT_EQ(0u, m_Context->m_VertexStreams[1].m_Size);

    dmGraphics::DeleteVertexDeclaration(vertex_declaration);
    dmGraphics::DeleteVertexBuffer(vertex_buffer);
}

TEST_F(dmGraphicsTest, Drawing)
{
    float v[] = { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f };
    uint32_t i[] = { 0, 1, 2, 2, 1, 0 };

    dmGraphics::VertexElement ve[] =
    {
        {"position", 0, 3, dmGraphics::TYPE_FLOAT, false },
        {"uv", 1, 2, dmGraphics::TYPE_FLOAT, false }
    };
    dmGraphics::HVertexDeclaration vd = dmGraphics::NewVertexDeclaration(m_Context, ve, 2);
    dmGraphics::HVertexBuffer vb = dmGraphics::NewVertexBuffer(m_Context, sizeof(v), v, dmGraphics::BUFFER_USAGE_STREAM_DRAW);
    dmGraphics::HIndexBuffer ib = dmGraphics::NewIndexBuffer(m_Context, sizeof(i), i, dmGraphics::BUFFER_USAGE_STREAM_DRAW);

    dmGraphics::EnableVertexDeclaration(m_Context, vd, vb);
    dmGraphics::DrawElements(m_Context, dmGraphics::PRIMITIVE_TRIANGLES, 0, 3, dmGraphics::TYPE_UNSIGNED_INT, ib);
    dmGraphics::DisableVertexDeclaration(m_Context, vd);

    dmGraphics::EnableVertexDeclaration(m_Context, vd, vb);
    dmGraphics::DrawElements(m_Context, dmGraphics::PRIMITIVE_TRIANGLES, 3, 3, dmGraphics::TYPE_UNSIGNED_INT, ib);
    dmGraphics::DisableVertexDeclaration(m_Context, vd);

    dmGraphics::EnableVertexDeclaration(m_Context, vd, vb);
    dmGraphics::Draw(m_Context, dmGraphics::PRIMITIVE_TRIANGLES, 0, 3);
    dmGraphics::DisableVertexDeclaration(m_Context, vd);

    dmGraphics::DeleteIndexBuffer(ib);
    dmGraphics::DeleteVertexBuffer(vb);
    dmGraphics::DeleteVertexDeclaration(vd);
}

static inline dmGraphics::ShaderDesc::Shader MakeDDFShader(const char* data, uint32_t count)
{
    dmGraphics::ShaderDesc::Shader ddf;
    memset(&ddf,0,sizeof(ddf));
    ddf.m_Source.m_Data  = (uint8_t*)data;
    ddf.m_Source.m_Count = count;
    return ddf;
}

TEST_F(dmGraphicsTest, TestProgram)
{
    const char* vertex_data = ""
            "uniform mediump mat4 view_proj;\n"
            "uniform mediump mat4 world;\n"

            "attribute mediump vec4 position;\n"
            "attribute mediump vec2 texcoord0;\n"

            "varying mediump vec2 var_texcoord0;\n"

            "void main()\n"
            "{\n"
            "    // NOTE: world isn't used here. Sprite positions are already transformed\n"
            "    // prior to rendering but the world-transform is set for sorting.\n"
            "   gl_Position = view_proj * vec4(position.xyz, 1.0);\n"
            "   var_texcoord0 = texcoord0;\n"
            "}\n";
    const char* fragment_data = ""
            "varying mediump vec4 position;\n"
            "varying mediump vec2 var_texcoord0;\n"

            "uniform lowp sampler2D texture_sampler;\n"
            "uniform lowp vec4 tint;\n"

            "void main()\n"
            "{\n"
            "    // Pre-multiply alpha since all runtime textures already are\n"
            "    lowp vec4 tint_pm = vec4(tint.xyz * tint.w, tint.w);\n"
            "    gl_FragColor = texture2D(texture_sampler, var_texcoord0.xy) * tint_pm;\n"
            "}\n";

    dmGraphics::ShaderDesc::Shader vs_shader = MakeDDFShader(vertex_data, (uint32_t) strlen(vertex_data));
    dmGraphics::ShaderDesc::Shader fs_shader = MakeDDFShader(fragment_data, (uint32_t) strlen(fragment_data));

    dmGraphics::HVertexProgram vp = dmGraphics::NewVertexProgram(m_Context, &vs_shader);
    dmGraphics::HFragmentProgram fp = dmGraphics::NewFragmentProgram(m_Context, &fs_shader);
    dmGraphics::HProgram program = dmGraphics::NewProgram(m_Context, vp, fp);
    ASSERT_EQ(4u, dmGraphics::GetUniformCount(program));
    ASSERT_EQ(0, dmGraphics::GetUniformLocation(program, "view_proj"));
    ASSERT_EQ(1, dmGraphics::GetUniformLocation(program, "world"));
    ASSERT_EQ(2, dmGraphics::GetUniformLocation(program, "texture_sampler"));
    ASSERT_EQ(3, dmGraphics::GetUniformLocation(program, "tint"));
    char buffer[64];
    dmGraphics::Type type;
    int32_t size;
    dmGraphics::GetUniformName(program, 0, buffer, 64, &type, &size);
    ASSERT_STREQ("view_proj", buffer);
    ASSERT_EQ(dmGraphics::TYPE_FLOAT_MAT4, type);
    dmGraphics::GetUniformName(program, 1, buffer, 64, &type, &size);
    ASSERT_STREQ("world", buffer);
    ASSERT_EQ(dmGraphics::TYPE_FLOAT_MAT4, type);
    dmGraphics::GetUniformName(program, 2, buffer, 64, &type, &size);
    ASSERT_STREQ("texture_sampler", buffer);
    ASSERT_EQ(dmGraphics::TYPE_SAMPLER_2D, type);
    dmGraphics::GetUniformName(program, 3, buffer, 64, &type, &size);
    ASSERT_STREQ("tint", buffer);
    ASSERT_EQ(dmGraphics::TYPE_FLOAT_VEC4, type);

    dmGraphics::EnableProgram(m_Context, program);
    Vector4 constant(1.0f, 2.0f, 3.0f, 4.0f);
    dmGraphics::SetConstantV4(m_Context, &constant, 1, 0);
    Vector4 matrix[4] = {   Vector4(1.0f, 2.0f, 3.0f, 4.0f),
                            Vector4(5.0f, 6.0f, 7.0f, 8.0f),
                            Vector4(9.0f, 10.0f, 11.0f, 12.0f),
                            Vector4(13.0f, 14.0f, 15.0f, 16.0f) };
    dmGraphics::SetConstantM4(m_Context, matrix, 4);
    char* program_data = new char[1024];
    *program_data = 0;
    vs_shader = MakeDDFShader(program_data, 1024);
    dmGraphics::ReloadVertexProgram(vp, &vs_shader);
    delete [] program_data;
    program_data = new char[1024];
    *program_data = 0;
    fs_shader = MakeDDFShader(program_data, 1024);
    dmGraphics::ReloadFragmentProgram(fp, &fs_shader);
    delete [] program_data;
    dmGraphics::DisableProgram(m_Context);
    dmGraphics::DeleteProgram(m_Context, program);
    dmGraphics::DeleteVertexProgram(vp);
    dmGraphics::DeleteFragmentProgram(fp);
}

TEST_F(dmGraphicsTest, TestViewport)
{
    dmGraphics::SetViewport(m_Context, 0, 0, WIDTH, HEIGHT);
}

TEST_F(dmGraphicsTest, TestTexture)
{
    dmGraphics::TextureCreationParams creation_params;
    dmGraphics::TextureParams params;

    creation_params.m_Width = WIDTH;
    creation_params.m_Height = HEIGHT;
    creation_params.m_OriginalWidth = WIDTH;
    creation_params.m_OriginalHeight = HEIGHT;

    params.m_DataSize = WIDTH * HEIGHT;
    params.m_Data = new char[params.m_DataSize];
    params.m_Width = WIDTH;
    params.m_Height = HEIGHT;
    params.m_Format = dmGraphics::TEXTURE_FORMAT_LUMINANCE;
    dmGraphics::HTexture texture = dmGraphics::NewTexture(m_Context, creation_params);
    dmGraphics::SetTexture(texture, params);

    delete [] (char*)params.m_Data;
    ASSERT_EQ(WIDTH, dmGraphics::GetTextureWidth(texture));
    ASSERT_EQ(HEIGHT, dmGraphics::GetTextureHeight(texture));
    ASSERT_EQ(WIDTH, dmGraphics::GetOriginalTextureWidth(texture));
    ASSERT_EQ(HEIGHT, dmGraphics::GetOriginalTextureHeight(texture));
    dmGraphics::EnableTexture(m_Context, 0, texture);
    dmGraphics::DisableTexture(m_Context, 0, texture);
    dmGraphics::DeleteTexture(texture);
}

TEST_F(dmGraphicsTest, TestSetTextureBounds)
{
    dmGraphics::TextureCreationParams creation_params;
    dmGraphics::TextureParams params;

    creation_params.m_Width = WIDTH;
    creation_params.m_Height = HEIGHT;
    creation_params.m_OriginalWidth = WIDTH;
    creation_params.m_OriginalHeight = HEIGHT;

    params.m_DataSize  = WIDTH * HEIGHT;
    params.m_Data      = new char[params.m_DataSize];
    params.m_Width     = WIDTH;
    params.m_Height    = HEIGHT;
    params.m_Format    = dmGraphics::TEXTURE_FORMAT_LUMINANCE;
    params.m_SubUpdate = true;
    params.m_X         = WIDTH / 2;
    params.m_Y         = HEIGHT / 2;

    dmGraphics::HTexture texture = dmGraphics::NewTexture(m_Context, creation_params);
    ASSERT_DEATH(dmGraphics::SetTexture(texture, params),"");

    delete [] (char*)params.m_Data;

    params.m_X         = 0;
    params.m_Y         = 0;
    params.m_Width     = WIDTH + 1;
    params.m_Height    = HEIGHT + 1;
    params.m_DataSize  = params.m_Width * params.m_Height;
    params.m_Data      = new char[params.m_DataSize];

    ASSERT_DEATH(dmGraphics::SetTexture(texture, params),"");

    delete [] (char*)params.m_Data;

    dmGraphics::DeleteTexture(texture);
}

TEST_F(dmGraphicsTest, TestMaxTextureSize)
{
    ASSERT_NE(dmGraphics::GetMaxTextureSize(m_Context), 0);
}

TEST_F(dmGraphicsTest, TestTextureDefautlOriginalDimension)
{
    dmGraphics::TextureCreationParams creation_params;
    dmGraphics::TextureParams params;

    creation_params.m_Width = WIDTH;
    creation_params.m_Height = HEIGHT;

    params.m_DataSize = WIDTH * HEIGHT;
    params.m_Data = new char[params.m_DataSize];
    params.m_Width = WIDTH;
    params.m_Height = HEIGHT;
    params.m_Format = dmGraphics::TEXTURE_FORMAT_LUMINANCE;
    dmGraphics::HTexture texture = dmGraphics::NewTexture(m_Context, creation_params);
    dmGraphics::SetTexture(texture, params);

    delete [] (char*)params.m_Data;
    ASSERT_EQ(WIDTH, dmGraphics::GetTextureWidth(texture));
    ASSERT_EQ(HEIGHT, dmGraphics::GetTextureHeight(texture));
    ASSERT_EQ(WIDTH, dmGraphics::GetOriginalTextureWidth(texture));
    ASSERT_EQ(HEIGHT, dmGraphics::GetOriginalTextureHeight(texture));
    dmGraphics::EnableTexture(m_Context, 0, texture);
    dmGraphics::DisableTexture(m_Context, 0, texture);
    dmGraphics::DeleteTexture(texture);
}

TEST_F(dmGraphicsTest, TestRenderTarget)
{
    dmGraphics::TextureCreationParams creation_params[dmGraphics::MAX_BUFFER_TYPE_COUNT];
    dmGraphics::TextureParams params[dmGraphics::MAX_BUFFER_TYPE_COUNT];
    for (uint32_t i = 0; i < dmGraphics::MAX_BUFFER_TYPE_COUNT; ++i)
    {
        creation_params[i].m_Width = WIDTH;
        creation_params[i].m_Height = HEIGHT;
        params[i].m_Width = WIDTH;
        params[i].m_Height = HEIGHT;
    }
    assert(dmGraphics::MAX_BUFFER_TYPE_COUNT == 3);
    params[dmGraphics::GetBufferTypeIndex(dmGraphics::BUFFER_TYPE_COLOR_BIT)].m_Format   = dmGraphics::TEXTURE_FORMAT_LUMINANCE;
    params[dmGraphics::GetBufferTypeIndex(dmGraphics::BUFFER_TYPE_DEPTH_BIT)].m_Format   = dmGraphics::TEXTURE_FORMAT_DEPTH;
    params[dmGraphics::GetBufferTypeIndex(dmGraphics::BUFFER_TYPE_STENCIL_BIT)].m_Format = dmGraphics::TEXTURE_FORMAT_STENCIL;

    uint32_t flags = dmGraphics::BUFFER_TYPE_COLOR_BIT | dmGraphics::BUFFER_TYPE_DEPTH_BIT | dmGraphics::BUFFER_TYPE_STENCIL_BIT;
    dmGraphics::HRenderTarget target = dmGraphics::NewRenderTarget(m_Context, flags, creation_params, params);
    dmGraphics::SetRenderTarget(m_Context, target, 0);
    dmGraphics::Clear(m_Context, flags, 1, 1, 1, 1, 1.0f, 1);

    uint32_t width = WIDTH;
    uint32_t height = HEIGHT;
    uint32_t data_size = sizeof(uint32_t) * width * height;
    char* data = new char[data_size];
    memset(data, 1, data_size);
    ASSERT_EQ(0, memcmp(data, m_Context->m_CurrentFrameBuffer->m_ColorBuffer, data_size));
    delete [] data;
    width *= 2;
    height *= 2;
    data_size = sizeof(uint32_t) * width * height;
    data = new char[data_size];
    memset(data, 1, data_size);
    dmGraphics::SetRenderTargetSize(target, width, height);

    uint32_t target_width, target_height;
    GetRenderTargetSize(target, dmGraphics::BUFFER_TYPE_COLOR_BIT, target_width, target_height);
    ASSERT_EQ(width, target_width);
    ASSERT_EQ(height, target_height);
    GetRenderTargetSize(target, dmGraphics::BUFFER_TYPE_DEPTH_BIT, target_width, target_height);
    ASSERT_EQ(width, target_width);
    ASSERT_EQ(height, target_height);
    GetRenderTargetSize(target, dmGraphics::BUFFER_TYPE_STENCIL_BIT, target_width, target_height);
    ASSERT_EQ(width, target_width);
    ASSERT_EQ(height, target_height);

    dmGraphics::Clear(m_Context, flags, 1, 1, 1, 1, 1.0f, 1);
    ASSERT_EQ(0, memcmp(data, m_Context->m_CurrentFrameBuffer->m_ColorBuffer, data_size));
    delete [] data;

    dmGraphics::SetRenderTarget(m_Context, 0x0, 0);
    dmGraphics::DeleteRenderTarget(target);
}

TEST_F(dmGraphicsTest, TestGetRTAttachment)
{
    dmGraphics::TextureCreationParams creation_params[dmGraphics::MAX_BUFFER_TYPE_COUNT];
    dmGraphics::TextureParams params[dmGraphics::MAX_BUFFER_TYPE_COUNT];
    for (uint32_t i = 0; i < dmGraphics::MAX_BUFFER_TYPE_COUNT; ++i)
    {
        creation_params[i].m_Width = WIDTH;
        creation_params[i].m_Height = HEIGHT;
        params[i].m_Width = WIDTH;
        params[i].m_Height = HEIGHT;
    }
    assert(dmGraphics::MAX_BUFFER_TYPE_COUNT == 3);
    params[dmGraphics::GetBufferTypeIndex(dmGraphics::BUFFER_TYPE_COLOR_BIT)].m_Format   = dmGraphics::TEXTURE_FORMAT_LUMINANCE;
    params[dmGraphics::GetBufferTypeIndex(dmGraphics::BUFFER_TYPE_DEPTH_BIT)].m_Format   = dmGraphics::TEXTURE_FORMAT_DEPTH;
    params[dmGraphics::GetBufferTypeIndex(dmGraphics::BUFFER_TYPE_STENCIL_BIT)].m_Format = dmGraphics::TEXTURE_FORMAT_STENCIL;

    uint32_t flags = dmGraphics::BUFFER_TYPE_COLOR_BIT | dmGraphics::BUFFER_TYPE_DEPTH_BIT | dmGraphics::BUFFER_TYPE_STENCIL_BIT;
    dmGraphics::HRenderTarget target = dmGraphics::NewRenderTarget(m_Context, flags, creation_params, params);
    dmGraphics::SetRenderTarget(m_Context, target, 0);
    dmGraphics::Clear(m_Context, flags, 1, 1, 1, 1, 1.0f, 1);

    dmGraphics::HTexture texture = dmGraphics::GetRenderTargetAttachment(target, dmGraphics::ATTACHMENT_DEPTH);
    ASSERT_EQ((dmGraphics::HTexture)0x0, texture);

    texture = dmGraphics::GetRenderTargetAttachment(target, dmGraphics::ATTACHMENT_STENCIL);
    ASSERT_EQ((dmGraphics::HTexture)0x0, texture);

    texture = dmGraphics::GetRenderTargetAttachment(target, dmGraphics::ATTACHMENT_COLOR);
    ASSERT_NE((dmGraphics::HTexture)0x0, texture);

    char* texture_data = 0x0;
    dmGraphics::HandleResult res = dmGraphics::GetTextureHandle(0x0, (void**)&texture_data);
    ASSERT_EQ(dmGraphics::HANDLE_RESULT_ERROR, res);

    res = dmGraphics::GetTextureHandle(texture, (void**)&texture_data);
    ASSERT_EQ(dmGraphics::HANDLE_RESULT_OK, res);
    ASSERT_NE((char*)0x0, texture_data);

    uint32_t data_size = sizeof(uint32_t) * WIDTH * HEIGHT;
    char* data = new char[data_size];
    memset(data, 1, data_size);
    ASSERT_EQ(0, memcmp(data, texture_data, data_size));
    delete [] data;

    dmGraphics::SetRenderTarget(m_Context, 0x0, 0);
    dmGraphics::DeleteRenderTarget(target);
}

TEST_F(dmGraphicsTest, TestMasks)
{
    dmGraphics::SetColorMask(m_Context, false, false, false, false);
    ASSERT_FALSE(m_Context->m_RedMask);
    ASSERT_FALSE(m_Context->m_GreenMask);
    ASSERT_FALSE(m_Context->m_BlueMask);
    ASSERT_FALSE(m_Context->m_AlphaMask);
    dmGraphics::SetColorMask(m_Context, true, true, true, true);
    ASSERT_TRUE(m_Context->m_RedMask);
    ASSERT_TRUE(m_Context->m_GreenMask);
    ASSERT_TRUE(m_Context->m_BlueMask);
    ASSERT_TRUE(m_Context->m_AlphaMask);

    dmGraphics::SetDepthMask(m_Context, false);
    ASSERT_FALSE(m_Context->m_DepthMask);
    dmGraphics::SetDepthMask(m_Context, true);
    ASSERT_TRUE(m_Context->m_DepthMask);

    dmGraphics::SetStencilMask(m_Context, 0u);
    ASSERT_EQ(0u, m_Context->m_StencilMask);
    dmGraphics::SetStencilMask(m_Context, ~0u);
    ASSERT_EQ(~0u, m_Context->m_StencilMask);
    dmGraphics::SetDepthFunc(m_Context, dmGraphics::COMPARE_FUNC_ALWAYS);
    ASSERT_EQ(dmGraphics::COMPARE_FUNC_ALWAYS, m_Context->m_DepthFunc);
    dmGraphics::SetDepthFunc(m_Context, dmGraphics::COMPARE_FUNC_NEVER);
    ASSERT_EQ(dmGraphics::COMPARE_FUNC_NEVER, m_Context->m_DepthFunc);

    dmGraphics::SetStencilFunc(m_Context, dmGraphics::COMPARE_FUNC_ALWAYS, 0xffffffff, 0x0);
    ASSERT_EQ(dmGraphics::COMPARE_FUNC_ALWAYS, m_Context->m_StencilFunc);
    ASSERT_EQ(0xffffffff, m_Context->m_StencilFuncRef);
    ASSERT_EQ(0x0, m_Context->m_StencilFuncMask);
    dmGraphics::SetStencilFunc(m_Context, dmGraphics::COMPARE_FUNC_NEVER, 0x0, 0xffffffff);
    ASSERT_EQ(dmGraphics::COMPARE_FUNC_NEVER, m_Context->m_StencilFunc);
    ASSERT_EQ(0x0, m_Context->m_StencilFuncRef);
    ASSERT_EQ(0xffffffff, m_Context->m_StencilFuncMask);

    dmGraphics::SetStencilOp(m_Context, dmGraphics::STENCIL_OP_KEEP, dmGraphics::STENCIL_OP_REPLACE, dmGraphics::STENCIL_OP_INVERT);
    ASSERT_EQ(dmGraphics::STENCIL_OP_KEEP, m_Context->m_StencilOpSFail);
    ASSERT_EQ(dmGraphics::STENCIL_OP_REPLACE, m_Context->m_StencilOpDPFail);
    ASSERT_EQ(dmGraphics::STENCIL_OP_INVERT, m_Context->m_StencilOpDPPass);
    dmGraphics::SetStencilOp(m_Context, dmGraphics::STENCIL_OP_INVERT, dmGraphics::STENCIL_OP_KEEP, dmGraphics::STENCIL_OP_REPLACE);
    ASSERT_EQ(dmGraphics::STENCIL_OP_INVERT, m_Context->m_StencilOpSFail);
    ASSERT_EQ(dmGraphics::STENCIL_OP_KEEP, m_Context->m_StencilOpDPFail);
    ASSERT_EQ(dmGraphics::STENCIL_OP_REPLACE, m_Context->m_StencilOpDPPass);
}

TEST_F(dmGraphicsTest, TestCloseCallback)
{
    // Stay open
    m_CloseData.m_ShouldClose = 0;
    // Request close
    m_Context->m_RequestWindowClose = 1;
    dmGraphics::Flip(m_Context);
    ASSERT_TRUE(dmGraphics::GetWindowState(m_Context, dmGraphics::WINDOW_STATE_OPENED) ? true : false);
    // Accept close
    m_CloseData.m_ShouldClose = 1;
    dmGraphics::Flip(m_Context);
    ASSERT_FALSE(dmGraphics::GetWindowState(m_Context, dmGraphics::WINDOW_STATE_OPENED));
}

TEST_F(dmGraphicsTest, TestTextureSupport)
{
    ASSERT_TRUE(dmGraphics::IsTextureFormatSupported(m_Context, dmGraphics::TEXTURE_FORMAT_LUMINANCE));
    ASSERT_FALSE(dmGraphics::IsTextureFormatSupported(m_Context, dmGraphics::TEXTURE_FORMAT_RGBA_BC7));
}

TEST_F(dmGraphicsTest, TestTextureFormatBPP)
{
    for(uint32_t i = 0; i < dmGraphics::TEXTURE_FORMAT_COUNT; ++i)
    {
        ASSERT_NE(0, dmGraphics::GetTextureFormatBitsPerPixel((dmGraphics::TextureFormat) i));
    }
}

int main(int argc, char **argv)
{
    jc_test_init(&argc, argv);
    return jc_test_run_all();
}

ext: cpp


text:
//
// file DiamondOverlay.cc
// David Cosgrove
// AstraZeneca
// 23rd January 2007
//

#include <iterator>
#include <iostream>

#include "stddefs.H"
#include "DiamondOverlay.H"

#include <boost/lexical_cast.hpp>

namespace DACLIB {
  void eigen_solve_4b4f( float **a , float &value , float *vector );
}

using namespace std;

namespace DACLIB {

  // ****************************************************************************
  DiamondOverlay::DiamondOverlay( const vector<float> &fixed ,
                                  const vector<float> &moving ) :
    rot_matrix_( 0 ) , p_( 0 ) , e_zero_( -1.0 ) , e_( -1.0 ){

    if( fixed.size() != moving.size() ) {
      throw DiamondOverlayError( "fixed and moving vectors must be same size." );
    }

    fixed_ = fixed;
    moving_ = moving;

  }

  // ****************************************************************************
  DiamondOverlay::DiamondOverlay( const vector<float> &fixed ,
                                  const vector<float> &moving ,
                                  const vector<float> &weights ) :
    rot_matrix_( 0 ) , p_( 0 ) , e_zero_( -1.0 ) , e_( -1.0 ) {

    if( fixed.size() != moving.size() ) {
      throw DiamondOverlayError( "fixed and moving vectors must be same size." );
    }

    fixed_ = fixed;
    moving_ = moving;
    weights_ = weights;

  }

  // ****************************************************************************
  DiamondOverlay::DiamondOverlay( const float *fixed , const float *moving ,
                                  int num_points ) :
    rot_matrix_( 0 ) , p_( 0 ) , e_zero_( -1.0 ) , e_( -1.0 ) {

    fixed_ = vector<float>( fixed , fixed + 3 * num_points );
    moving_ = vector<float>( moving , moving + 3 * num_points );

  }

  // ****************************************************************************
  DiamondOverlay::DiamondOverlay( const float *fixed , const float *moving ,
                                  const float *weights , int num_points ) :
    rot_matrix_( 0 ) , p_( 0 ) , e_zero_( -1.0 ) , e_( -1.0 ) {

    fixed_ = vector<float>( fixed , fixed + 3 * num_points );
    moving_ = vector<float>( moving , moving + 3 * num_points );
    weights_ = vector<float>( weights , weights + num_points );

  }

  // ****************************************************************************
  // individual sets of coords.
  DiamondOverlay::DiamondOverlay( const vector<vector<float> > &fixed ,
                                  const vector<vector<float> > &moving ) :
    rot_matrix_( 0 ) , p_( 0 ) , e_zero_( -1.0 ) , e_( -1.0 ) {

    fixed_.reserve( 3 * fixed.size() );
    moving_.reserve( 3 * moving.size() );
    for( int i = 0 , is = fixed.size() ; i < is ; ++i ) {
      if( fixed[i].size() != 3 ) {
        throw DiamondOverlayError( "Bad coords in fixed coords." );
      }
      if( moving[i].size() != 3 ) {
        throw DiamondOverlayError( "Bad coords in moving coords." );
      }

      fixed_.insert( fixed_.end() , fixed[i].begin() , fixed[i].end() );
      moving_.insert( moving_.end() , moving[i].begin() , moving[i].end() );
    }

  }

  // ****************************************************************************
  // individual sets of coords.
  DiamondOverlay::DiamondOverlay( const vector<vector<float> > &fixed ,
                                  const vector<vector<float> > &moving ,
                                  const vector<float> &weights ) :
    rot_matrix_( 0 ) , p_( 0 ) , e_zero_( -1.0 ) , e_( -1.0 ) {

    fixed_.reserve( 3 * fixed.size() );
    moving_.reserve( 3 * moving.size() );
    for( int i = 0 , is = fixed.size() ; i < is ; ++i ) {
      if( fixed[i].size() != 3 ) {
        throw DiamondOverlayError( "Bad coords in fixed coords." );
      }
      if( moving[i].size() != 3 ) {
        throw DiamondOverlayError( "Bad coords in moving coords." );
      }

      fixed_.insert( fixed_.end() , fixed[i].begin() , fixed[i].end() );
      moving_.insert( moving_.end() , moving[i].begin() , moving[i].end() );
    }

    weights_ = weights;

  }

  // ****************************************************************************
  DiamondOverlay::~DiamondOverlay() {

    DACLIB::destroy_square_matrix( rot_matrix_ );
    DACLIB::destroy_square_matrix( p_ );

  }

  // ****************************************************************************
  // calculate the initial residual error
  void DiamondOverlay::calc_e_zero() {

    e_zero_ = 0.0F;
    for( int i = 0 , is = fixed_.size() ; i < is ; i += 3 ) {
      float sq_dist = sq_distance( &fixed_[i] , &moving_[i] );
      if( !weights_.empty() ) {
        sq_dist *= weights_[i/3];
      }
      e_zero_ += sq_dist;
    }

  }

  // ****************************************************************************
  // assemble the M matrix (eq. 16, D88). It is not a symmetric matrix.
  void DiamondOverlay::calc_m( float m[3][3] ) {

    for( int i = 0 ; i < 3 ; ++i ) {
      for( int j = 0 ; j < 3 ; ++j ) {
        m[i][j] = 0.0;
        for( int k = 0 , ks = fixed_.size() ; k < ks ; k += 3 ) {
          if( weights_.empty() ) {
            m[i][j] += moving_[k+i] * fixed_[k+j];
          } else {
            m[i][j] += moving_[k+i] * fixed_[k+j] * weights_[k/3];
	  }
        }
      }
    }

  }

  // ****************************************************************************
  // calculate matrix Q, equation 17, D88.
  void DiamondOverlay::calc_q( const float m[3][3] , float q[3][3] ) {

    float alpha = m[0][0] + m[1][1] + m[2][2];

    for( int i = 0 ; i < 3 ; ++i ) {
      for( int j = 0 ; j < 3 ; ++j ) {
        q[i][j] = m[i][j] + m[j][i];
      }
      q[i][i] -= 2.0 * alpha;
    }

  }

  // ****************************************************************************
  // calculate matrix Q, equation 17, D88.
  void DiamondOverlay::calc_e() {

    if( !rot_matrix_ ) {
      calc_rot_matrix();
    }

    float res[4];
    float e;

    res[0] = p_[0][0] * vector_[0] + p_[0][1] * vector_[1] +
        p_[0][2] * vector_[2] + p_[0][3] * vector_[3];

    res[1] = p_[1][0] * vector_[0] + p_[1][1] * vector_[1] +
        p_[1][2] * vector_[2] + p_[1][3] * vector_[3];

    res[2] = p_[2][0] * vector_[0] + p_[2][1] * vector_[1] +
        p_[2][2] * vector_[2] + p_[2][3] * vector_[3];

    res[3] = p_[3][0] * vector_[0] + p_[3][1] * vector_[1] +
        p_[3][2] * vector_[2] + p_[3][3] * vector_[3];

    e = vector_[0] * res[0] + vector_[1] * res[1] + vector_[2] * res[2] +
        vector_[3] * res[3];

    e_ = e_zero_ - 2.0F * e;

  }

  // ****************************************************************************
  // make sure that there are at least 3 distinct sets of coordinates
  // for at least 1 of the input coord sets.  This includes cases
  // where 2 coords are on top of each other. Throws exception if not
  void DiamondOverlay::check_input_coords() const {

    if( !(at_least_3_coords( fixed_ ) && at_least_3_coords( moving_ )) ) {
      throw DiamondOverlayError( "Not enough distinct coords for overlay" );
    }

  }

  // ****************************************************************************
  // checks given coords for problem above.
  bool DiamondOverlay::at_least_3_coords( const std::vector<float> &cds ) const {

    vector<float> eff_cds = cds;
    bool it_changed( false );

    do {
      it_changed = false;
      for( int i = 0 , is = eff_cds.size() - 3 ; i < is ; i +=3 ) {
        for( int j = i + 3 , js = is + 3 ; j < js ; j += 3 ) {
          if( sq_distance( &cds[i] , &cds[j] ) < 1.0e-3 ) {
            eff_cds.erase( eff_cds.begin() + i , eff_cds.begin() + i + 3 );
            it_changed = true;
            break;
          }
        }
        if( it_changed ) {
          break;
        }
      }

    } while( it_changed && eff_cds.size() > 6 );

    return( eff_cds.size() > 6 );

  }

  // ****************************************************************************
  void DiamondOverlay::calc_p() {

    float m[3][3] , q[3][3];

    calc_e_zero();
    calc_m( m );
    calc_q( m , q );

    // compute v, eq. 18, D88.
    float v[3];
    v[0] = m[1][2] - m[2][1];
    v[1] = m[2][0] - m[0][2];
    v[2] = m[0][1] - m[1][0];

    // now do p
    DACLIB::make_square_matrix( p_ , 4 );

    for( int i = 0 ; i < 3 ; ++i ) {
      for( int j = 0 ; j < 3 ; ++j ) {
        p_[i][j] = q[i][j];
      }
    }

    p_[0][3] = p_[3][0] = v[0];
    p_[1][3] = p_[3][1] = v[1];
    p_[2][3] = p_[3][2] = v[2];
    p_[3][3] = 0.0;

  }

  // ****************************************************************************
  // build the rotation matrix, using eq. 7, D88.
  void DiamondOverlay::calc_rot_matrix() {

    check_input_coords();
    if( !p_ ) {
      calc_p();
    }

    if( !rot_matrix_ ) {
      DACLIB::make_square_matrix( rot_matrix_ , 3 );
    }

    float value;

    // eigen_solve destroys the matrix it works on, so do it on a copy
    static float **p_tmp = 0;
    if( !p_tmp ) {
      DACLIB::make_square_matrix( p_tmp , 4 );
    }

    copy( p_[0] , p_[0] + 16 , p_tmp[0] );
    DACLIB::eigen_solve_4b4f( p_tmp , value , vector_ );

    for( int i = 0 ; i < 4 ; ++i ) {
      try{
        boost::lexical_cast<float>( vector_[i] );
      } catch( boost::bad_lexical_cast &e ) {
        throw DiamondOverlayError( "Failed to find to valid overlay." );
      }
    }

    // use the notation of eq. 1, D88.
    const float lambda = vector_[0];
    const float mu = vector_[1];
    const float nu = vector_[2];
    const float sigma = vector_[3];
    const float mu_sq = mu * mu;
    const float lambda_sq = lambda * lambda;
    const float ups_sq = nu * nu;
    const float sigma_sq = sigma * sigma;

    float *rr = rot_matrix_[0];
    rr[0] = lambda_sq - mu_sq - ups_sq + sigma_sq;
    rr[4] = -lambda_sq + mu_sq - ups_sq + sigma_sq;
    rr[8] = -lambda_sq - mu_sq + ups_sq + sigma_sq;
    rr[3] = 2.0 * ( lambda * mu + nu * sigma );
    rr[6] = 2.0 * ( lambda * nu - mu * sigma );
    rr[1] = 2.0 * ( lambda * mu - nu * sigma );
    rr[7] = 2.0 * ( mu * nu + lambda * sigma );
    rr[2] = 2.0 * ( lambda * nu + mu * sigma );
    rr[5] = 2.0 * ( mu * nu - lambda * sigma );

  }

  // ****************************************************************************
  void DiamondOverlay::get_rot_matrix( float rot[3][3] ) {

    if( !p_ || !rot_matrix_ ) {
      calc_rot_matrix();
    }

    // don't assume that rot is created with DACLIB::make_square_matrix, though
    // we know that rot_matrix__ was.
    float *rr = rot_matrix_[0];
    rot[0][0] = rr[0];
    rot[0][1] = rr[1];
    rot[0][2] = rr[2];
    rot[1][0] = rr[3];
    rot[1][1] = rr[4];
    rot[1][2] = rr[5];
    rot[2][0] = rr[6];
    rot[2][1] = rr[7];
    rot[2][2] = rr[8];

  }

  // ****************************************************************************
  void DiamondOverlay::get_p( float **p ) {

    if( !p_ ) {
      calc_p();
    }

    // don't assume that p is created with DACLIB::make_square_matrix, though
    // we know that p_ was.
    float *pp = p_[0];
    p[0][0] = pp[0];
    p[0][1] = pp[1];
    p[0][2] = pp[2];
    p[0][3] = pp[3];

    p[1][0] = pp[4];
    p[1][1] = pp[5];
    p[1][2] = pp[6];
    p[1][3] = pp[7];

    p[2][0] = pp[8];
    p[2][1] = pp[9];
    p[2][2] = pp[10];
    p[2][3] = pp[11];

    p[3][0] = pp[12];
    p[3][1] = pp[13];
    p[3][2] = pp[14];
    p[3][3] = pp[15];

  }

  // ****************************************************************************
  float DiamondOverlay::get_e_zero() {

    if( e_zero_ < 0.0F ) {
      calc_e_zero();
    }

    return e_zero_;

  }

  // ****************************************************************************
  float DiamondOverlay::get_e() {
    if( e_ < 0.0F ) {
      calc_e() ;
    }

    return e_;

  }

} // end of namespace DACLIB

ext: cc

max_stars_repo_name: OpenEye-Contrib/Triphic

max_issues_repo_name: OpenEye-Contrib/Triphic

max_forks_repo_name: OpenEye-Contrib/Triphic


text:
/**
 * Copyright (c) 2017 Melown Technologies SE
 *
 * 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 COPYRIGHT HOLDER 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.
 */
#ifndef utility_filesed_hpp_included_
#define utility_filesed_hpp_included_

#include <utility>
#include <boost/filesystem/path.hpp>

namespace utility {

/** Simple wrapper around file descriptor.
 */
class Filedes {
public:
    Filedes() : fd_(-1) {}
    explicit Filedes(int fd) : fd_(fd) {}

    Filedes(int fd, const boost::filesystem::path &path)
        : fd_(fd), path_(path)
    {}

    Filedes(Filedes &&other)
        : fd_(other.fd_), path_(std::move(other.path_))
    {
        other.fd_ = -1;
    }

    Filedes& operator=(Filedes &&other) {
        std::swap(fd_, other.fd_);
        path_ = std::move(other.path_);
        return *this;
    }

    ~Filedes();

    int get() const { return fd_; }
    const boost::filesystem::path& path() const { return path_; }

    operator int() const { return get(); }
    operator bool() const { return fd_ >= 0; }

    int release() {
        auto fd(fd_);
        fd_ = -1;
        path_.clear();
        return fd;
    }

    /** Closes underlying file descriptor and invalidates this object.
     */
    void close();

    void closeOnExec(bool value);

    /** Duplicates file descriptor (via dup).;
     */
    Filedes dup() const;

    /** Check fd validity.
     */
    bool valid() const;

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

private:
    int fd_;
    boost::filesystem::path path_;
};

} // namespace utility

#endif // utility_filesed_hpp_included_

ext: hpp

max_stars_repo_name: HanochZhu/vts-browser-unity-plugin

max_issues_repo_name: HanochZhu/vts-browser-unity-plugin

max_forks_repo_name: HanochZhu/vts-browser-unity-plugin


text:
/*
// Copyright (c) 2000-2009, Texas Engineering Experiment Station (TEES), a
// component of the Texas A&M University System.

// All rights reserved.

// The information and source code contained herein is the exclusive
// property of TEES and may not be disclosed, examined or reproduced
// in whole or in part without explicit written authorization from TEES.
*/

#ifndef STAPL_RUNTIME_COMMUNICATOR_MPI_COMMUNICATOR_HPP
#define STAPL_RUNTIME_COMMUNICATOR_MPI_COMMUNICATOR_HPP

#include "../config.hpp"
#include "communicator.hpp"
#include "../exception.hpp"
#include "../instrumentation.hpp"
#include "../message.hpp"
#include "../runqueue.hpp"
#include "../concurrency/concurrency.hpp"
#include "../concurrency/task_queue.hpp"
#include "../utility/option.hpp"
#include "../utility/string.hpp"
#include <algorithm>
#include <functional>
#include <iterator>
#include <mutex>
#include <numeric>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
#include <boost/unordered_map.hpp>
#include <boost/range/size.hpp>
#ifndef MPICH_IGNORE_CXX_SEEK
// Force MPICH not to define SEEK_SET, SEEK_CUR and SEEK_END
# define MPICH_IGNORE_CXX_SEEK 1
#endif
#include <mpi.h>

#ifndef STAPL_RUNTIME_MPI_RECV_MIN
/// Default minimum number of buffers that wait on an @c MPI_Irecv().
# define STAPL_RUNTIME_MPI_RECV_MIN 8
#endif

#ifndef STAPL_RUNTIME_MPI_RECV_MAX
/// Default maximum number of buffers that wait on an @c MPI_Irecv().
# define STAPL_RUNTIME_MPI_RECV_MAX 128
#endif

#ifndef STAPL_RUNTIME_MPI_SEND_MAX
/// Default maximum number of buffers that wait on an @c MPI_Isend().
# define STAPL_RUNTIME_MPI_SEND_MAX 2048
#endif

namespace stapl {

namespace runtime {

//////////////////////////////////////////////////////////////////////
/// @brief Returns the number of processes per node, based on how many processes
///        are co-scheduled with process @c 0.
///
/// This function acts also as an implicit barrier.
///
/// @warning This function will estimate incorrectly if the machine is not used
///          in the same way on all nodes.
///
/// @ingroup processCommunication
//////////////////////////////////////////////////////////////////////
inline unsigned int get_processes_per_node(MPI_Comm comm)
{
  int rank = MPI_PROC_NULL;
  MPI_Comm_rank(comm, &rank);

  int len = MPI_MAX_PROCESSOR_NAME;
  char name[MPI_MAX_PROCESSOR_NAME];
  MPI_Get_processor_name(name, &len);

  char root_name[MPI_MAX_PROCESSOR_NAME];
  int  root_len = 0;
  char* str     = root_name;

  if (rank==0) {
    str      = name;
    root_len = len;
  }
  MPI_Bcast(&root_len, 1, MPI_INT, 0, comm);   // send string length
  MPI_Bcast(str, root_len, MPI_CHAR, 0, comm); // send string
  if (rank!=0) {
    root_name[root_len] = '\0';
  }

  // find number of ranks/node based on the number of ranks coscheduled with
  // rank 0
  int num_procs_per_node = (std::strcmp(name, str)==0);
  MPI_Allreduce(MPI_IN_PLACE, &num_procs_per_node, 1, MPI_INT, MPI_SUM, comm);

  return num_procs_per_node;
}

//////////////////////////////////////////////////////////////////////
/// @brief Implements a communicator based on MPI-2.
///
/// The number of processes to use is determined by the underlying MPI
/// implementation. Usually, this is set by the <tt>mpiexec -n</tt> command,
/// although some implementations use command line flags.
///
/// Assumptions:
/// -# MPI errors are fatal (i.e., abort), as specified by the standard.
/// -# homogeneous runtime environment (i.e., all MPI processes are running on
///    the same platform).
/// -# MPI is not thread-safe.
///
/// @ingroup processCommunication
//////////////////////////////////////////////////////////////////////
class mpi_communicator
{
public:
  using size_type = std::size_t;

private:
  /// Minimum number of buffers that wait an @c MPI_Irecv() to be completed.
  static size_type sm_recv_min;
  /// Maximum number of buffers that wait an @c MPI_Irecv() to be completed.
  static size_type sm_recv_max;
  /// Maximum number of buffers that wait an @c MPI_Isend() to be completed.
  static size_type sm_send_max;
  /// @c true if the MPI layer was initialized by the runtime.
  static bool      sm_mpi_initialized;

public:
  //////////////////////////////////////////////////////////////////////
  /// @brief Returns @c true if the environment is initialized.
  //////////////////////////////////////////////////////////////////////
  static bool environment_is_initialized(void) noexcept
  {
    int flag = 0;
    MPI_Initialized(&flag);
    return (flag!=0);
  }

  //////////////////////////////////////////////////////////////////////
  /// @brief Initializes the environment.
  ///
  /// @c MPI_Init_thread() with the required thread support will be called if
  /// the MPI library has not been initialized yet (i.e @c MPI_Initialized()
  /// returns false).
  ///
  /// Through the @p opts object the user can set
  /// @c STAPL_RUNTIME_MPI_RECV_MIN and @c STAPL_RUNTIME_MPI_RECV_MAX for
  /// the minimum and maximum number of pending @c MPI_Irecv() as well as
  /// @c STAPL_RUNTIME_MPI_SEND_MAX for the maximum number of @c MPI_Isend()
  /// before the communicator is considered overloaded.
  ///
  /// @param opts @ref option object passed from the user.
  ///
  /// @warning If the MPI library does not support the required thread support,
  ///          then a failure will occur. Adjust your MPI library accordingly.
  //////////////////////////////////////////////////////////////////////
  static void environment_initialize(option const& opts)
  {
    // initialize MPI and find thread support
    const int required = (concurrency::hardware_concurrency()>1
                            ? MPI_THREAD_SERIALIZED
                            : MPI_THREAD_SINGLE);
    int provided       = MPI_THREAD_SINGLE;
    sm_mpi_initialized = !environment_is_initialized();
    if (sm_mpi_initialized) {
      if (opts.has_argv())
        MPI_Init_thread(&opts.get_argc(), &opts.get_argv(),
                        required, &provided);
      else
        MPI_Init_thread(nullptr, nullptr, required, &provided);
    }
    else {
      MPI_Query_thread(&provided);
    }
    if (provided<required)
      STAPL_RUNTIME_ERROR("MPI does not provide the requested thread support.");

    // load environment variables
    sm_recv_min = opts.get<size_type>("STAPL_RUNTIME_MPI_RECV_MIN",
                                      STAPL_RUNTIME_MPI_RECV_MIN);
    if (sm_recv_min==0)
      STAPL_RUNTIME_ERROR("STAPL_RUNTIME_MPI_RECV_MIN cannot be 0.");

    sm_recv_max = opts.get<size_type>("STAPL_RUNTIME_MPI_RECV_MAX",
                                      STAPL_RUNTIME_MPI_RECV_MAX);
    if (sm_recv_max<sm_recv_min)
      STAPL_RUNTIME_ERROR("STAPL_RUNTIME_MPI_RECV_MAX cannot be less than "
                          "STAPL_RUNTIME_MPI_RECV_MIN.");

    sm_send_max = opts.get<size_type>("STAPL_RUNTIME_MPI_SEND_MAX",
                                      STAPL_RUNTIME_MPI_SEND_MAX);
    if (sm_send_max==0)
      STAPL_RUNTIME_ERROR("STAPL_RUNTIME_MPI_SEND_MAX cannot be 0.");
  }

  //////////////////////////////////////////////////////////////////////
  /// @brief Finalizes the environment.
  ///
  /// @c MPI_Finalize() will be called if the runtime was responsible for
  /// initializing the MPI library in the first place.
  ///
  /// @see mpi_communicator::initialize_environment()
  //////////////////////////////////////////////////////////////////////
  static void environment_finalize(void) noexcept
  {
    if (sm_mpi_initialized)
      MPI_Finalize();
  }

private:
  //////////////////////////////////////////////////////////////////////
  /// @brief Duplicates the given communicator.
  //////////////////////////////////////////////////////////////////////
  static MPI_Comm create_duplicate(MPI_Comm comm) noexcept
  {
    MPI_Comm newcomm = MPI_COMM_NULL;
    MPI_Comm_dup(comm, &newcomm);
    if (newcomm==MPI_COMM_NULL)
      STAPL_RUNTIME_ERROR("Could not duplicate communicator.");
    return newcomm;
  }

  //////////////////////////////////////////////////////////////////////
  /// @brief Creates a Cartesian communicator from @p comm and the given
  ///        dimensions.
  //////////////////////////////////////////////////////////////////////
  static MPI_Comm create_cartesian(MPI_Comm comm, std::vector<int>& dims)
  {
    int comm_size = MPI_PROC_NULL;
    MPI_Comm_size(comm, &comm_size);
    if (comm_size<=0)
      STAPL_RUNTIME_ERROR("Parent communicator is invalid.");
    if (comm_size!=
          std::accumulate(dims.begin(), dims.end(), 1, std::multiplies<int>()))
      STAPL_RUNTIME_ERROR("Cartesian grid is not the same size as the parent "
                          "communicator.");
    std::vector<int> periods(dims.size(), 1);
    MPI_Comm newcomm = MPI_COMM_NULL;
    MPI_Cart_create(comm, dims.size(), &(dims[0]), &(periods[0]), 1, &newcomm);
    return newcomm;
  }

private:
  enum Tag
  {
    /// Tag for default message channel.
    DEFAULT_TAG = 0,
    /// Tag for long message channel.
    LONG_TAG = 1
  };

  using send_container_type    =
    boost::unordered_map<int, message_raw_ptr_slist>;
  using request_container_type = std::vector<MPI_Request>;
  using task_queue_type        = task_queue<void(mpi_communicator&)>;

  MPI_Comm              m_comm;
  int                   m_size;
  int                   m_rank;
  /// Number of ranks per node.
  unsigned int          m_nppn;

  /// Pending sent messages.
  send_container_type   m_send_msg;
  /// Number of pending sent messages.
  size_type             m_pending_send;
  /// Queue of pending forwarded messages.
  message_raw_ptr_slist m_fwd_msg;
  /// Queue of pending to be received messages.
  message_raw_ptr_slist m_recv_msg;
  /// @c true if there are too many messages pending.
  bool                  m_overloaded;
  /// Queue of functions that were not called because @c *this was locked.
  task_queue_type       m_q;
  mutable std::mutex    m_mtx;

  void check_overloaded(void) noexcept
  {
    if (m_overloaded) {
      if (m_pending_send<=sm_send_max) {
        m_overloaded = false;
        runqueue::set_overloaded(false);
      }
    }
    else {
      if (m_pending_send>sm_send_max) {
        m_overloaded = true;
        runqueue::set_overloaded(true);
      }
    }
  }

public:
  mpi_communicator(void)
  : m_comm(MPI_COMM_NULL),
    m_size(MPI_PROC_NULL),
    m_rank(MPI_PROC_NULL),
    m_nppn(0),
    m_pending_send(0),
    m_overloaded(false)
  { }

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

  ////////////////////////////////////////////////////////////////////
  /// @brief Initializes this @ref mpi_communicator object.
  ///
  /// This function can receive options through the @p opts object. The user can
  /// define the MPI commmunicator to use by setting it accordingly with the
  /// @c MPI_Comm tag in @p opts, as well a Cartesian topology through the tag
  /// @c MPI_Cart.
  ///
  /// @param opts @ref option object to initialize this @ref mpi_communicator.
  ////////////////////////////////////////////////////////////////////
  void initialize(option const& opts)
  {
    std::lock_guard<std::mutex> lock{m_mtx};

    // get the user-specified communicator if any
    MPI_Comm comm = MPI_COMM_WORLD;
    opts.try_get_noenv("MPI_Comm", comm);

    // create the communicator
    std::string cart_topo;
    opts.try_get("MPI_Cart", cart_topo);
    if (!cart_topo.empty()) {
      // cartesian topology requested
      std::vector<int> dims = split_string_to_vector<int>(cart_topo, " ,");
      if (dims.empty())
        STAPL_RUNTIME_ERROR("MPI_Cart is only allowed to have integers "
                            "separated by spaces or commas.");
      m_comm = create_cartesian(comm, dims);
    }
    else {
      // no topology requested
      m_comm = create_duplicate(comm);
    }

    // set-up communicator
    char name[] = "STAPL_RTS_COMM";
    MPI_Comm_set_name(m_comm, name);
    MPI_Comm_size(m_comm, &m_size);
    MPI_Comm_rank(m_comm, &m_rank);

    // find number of proceses/node and also implicit barrier for all processes
    // to complete initialization
    m_nppn = get_processes_per_node(m_comm);
  }

  ////////////////////////////////////////////////////////////////////
  /// @brief Finalizes this @ref mpi_communicator object.
  ///
  /// All pending messages will be canceled. An implicit barrier is part of the
  /// cleanup to ensure correctness.
  ////////////////////////////////////////////////////////////////////
  void finalize(void)
  {
    std::lock_guard<std::mutex> lock{m_mtx};
    MPI_Comm_free(&m_comm);
    m_size = MPI_PROC_NULL;
    m_rank = MPI_PROC_NULL;
    m_nppn = 0;
  }

  ////////////////////////////////////////////////////////////////////
  /// @brief Starts this @ref mpi_communicator object.
  ///
  /// New messages will be allocated to waiting for incoming communication. An
  /// implicit barrier is part of the setup to ensure that no process will start
  /// communication before other processes had the opportunity to finish their
  /// setup.
  ////////////////////////////////////////////////////////////////////
  void start(void)
  {
    std::lock_guard<std::mutex> lock{m_mtx};
    create_receive_message(sm_recv_min);
    MPI_Barrier(m_comm); // all processes should complete setup
  }

  ////////////////////////////////////////////////////////////////////
  /// @brief Stops this @ref mpi_communicator object.
  ///
  /// All pending messages will be canceled. An implicit barrier is part of the
  /// cleanup to ensure correctness.
  ////////////////////////////////////////////////////////////////////
  void stop(void)
  {
    std::lock_guard<std::mutex> lock{m_mtx};
    cancel_receive_messages();
    wait_sent_messages();
    MPI_Barrier(m_comm); // all processes should complete cleanup
  }

  bool initialized(void) const noexcept
  { return (m_comm!=MPI_COMM_NULL); }

  int get_id(void) const noexcept
  { return m_rank; }

  int size(void) const noexcept
  { return m_size; }

  int get_num_procs_per_node(void) const noexcept
  { return m_nppn; }

  void exit(int exit_code) const
  {
    std::lock_guard<std::mutex> lock{m_mtx};
    MPI_Abort((initialized() ? m_comm : MPI_COMM_WORLD), exit_code);
  }

  ////////////////////////////////////////////////////////////////////
  /// @brief Sets the default communication message size.
  ///
  /// @warning This is a collective operation and is supposed to be called by
  ///          one thread on each process only.
  ///
  /// @param size Size of the @ref message objects.
  ///
  /// @see message
  ////////////////////////////////////////////////////////////////////
  void set_default_message_size(const std::size_t size)
  {
    std::lock_guard<std::mutex> lock{m_mtx};

    // clear out messages from queues
    cancel_receive_messages();
    wait_sent_messages();

    // set new default size and post the receives
    message::set_default_body_capacity(size);
    create_receive_message(sm_recv_min);

    // check if value is the same across all processes; implicit barrier
    unsigned long sz = size;
    MPI_Bcast(&sz, 1, MPI_UNSIGNED_LONG, 0, m_comm);
    if (sz!=size)
      STAPL_RUNTIME_ERROR("Default message size has to be the same in all "
                          "processes.");
    if (sz==0)
      STAPL_RUNTIME_ERROR("Default message size cannot be 0.");
  }

  void lock(void)
  { m_mtx.lock(); }

  void unlock(void)
  { m_mtx.unlock(); }

  ////////////////////////////////////////////////////////////////////
  /// @brief Returns an @c MPI_Request object associated with @p m.
  ////////////////////////////////////////////////////////////////////
  MPI_Request& request_get(message& m)
  {
    return m.handle().mpi_request();
  }

  ////////////////////////////////////////////////////////////////////
  /// @brief Returns @p n @c MPI_Request objects associated with @p m.
  ////////////////////////////////////////////////////////////////////
  request_container_type& request_get(message& m, const size_type n)
  {
    return m.handle().mpi_requests(n);
  }

  ////////////////////////////////////////////////////////////////////
  /// @brief Returns all the n @c MPI_Request objects associated with @p m.
  ////////////////////////////////////////////////////////////////////
  request_container_type& request_get_all(message& m)
  {
    return m.handle().mpi_requests();
  }

  //////////////////////////////////////////////////////////////////////
  /// @brief Posts an @c MPI_Irecv() with the given message.
  ///
  /// @param m Message to post for reception.
  //////////////////////////////////////////////////////////////////////
  void post_receive_message(message* m)
  {
    STAPL_RUNTIME_ASSERT(m->capacity()==message::default_capacity());
    MPI_Request& req = request_get(*m);
    STAPL_RUNTIME_ASSERT(req==MPI_REQUEST_NULL);
    MPI_Irecv(m->data(), m->capacity(), MPI_BYTE,
              MPI_ANY_SOURCE, DEFAULT_TAG, m_comm, &req);
    m_recv_msg.push_back(*m);
  }

  //////////////////////////////////////////////////////////////////////
  /// @brief Creates a number of @c MPI_Irecv(), waiting for messages to be
  ///        received.
  ///
  /// @param n Number of messages to pre-fire for receiving.
  ///
  /// @todo Use a @ref message::construct() that returns multiple messages.
  //////////////////////////////////////////////////////////////////////
  void create_receive_message(const size_type n = 1)
  {
    for (size_type i=0; i<n; ++i) {
      message* const m = message::construct();
      post_receive_message(m);
    }
  }

  //////////////////////////////////////////////////////////////////////
  /// @brief Cancels all pending @c MPI_Irecv().
  //////////////////////////////////////////////////////////////////////
  void cancel_receive_messages(void)
  {
    while (!m_recv_msg.empty()) {
      message& m = m_recv_msg.front();
      m_recv_msg.pop_front();
      MPI_Request& req = m.handle().mpi_request();
      STAPL_RUNTIME_ASSERT(req!=MPI_REQUEST_NULL);
      MPI_Cancel(&req);
      MPI_Wait(&req, MPI_STATUS_IGNORE);
      message::destroy(&m);
    }
  }

  ////////////////////////////////////////////////////////////////////
  /// @brief Tests @p m if it was received.
  ///
  /// @return A @c std::pair with the sender process id and the size of the
  ///         message if it was succesfully received, otherwise a @c std::pair
  ///         of @c MPI_PROC_NULL and 0.
  ////////////////////////////////////////////////////////////////////
  static std::pair<int, std::size_t> test_receive(message& m) noexcept
  {
    MPI_Request& req = m.handle().mpi_request();
    STAPL_RUNTIME_ASSERT(req!=MPI_REQUEST_NULL);
    int flag = 0;
    MPI_Status status;
    MPI_Test(&req, &flag, &status);
    if (flag==0) {
      return std::make_pair(MPI_PROC_NULL, 0);
    }

    const int proc = status.MPI_SOURCE;
    int size = MPI_UNDEFINED;
    MPI_Get_count(&status, MPI_BYTE, &size);
    STAPL_RUNTIME_CHECK( (size!=MPI_UNDEFINED) && (proc!=MPI_PROC_NULL),
                         "Problem receiving message" );

    return std::make_pair(proc, std::size_t(size));
  }

  ////////////////////////////////////////////////////////////////////
  /// @brief Waits for @p m to be received.
  ////////////////////////////////////////////////////////////////////
  static std::pair<int, std::size_t> wait_receive(message& m) noexcept
  {
    MPI_Request& req = m.handle().mpi_request();
    STAPL_RUNTIME_ASSERT(req!=MPI_REQUEST_NULL);
    MPI_Status status;
    MPI_Wait(&req, &status);

    const int proc = status.MPI_SOURCE;
    int size = MPI_UNDEFINED;
    MPI_Get_count(&status, MPI_BYTE, &size);
    STAPL_RUNTIME_CHECK( (size!=MPI_UNDEFINED) && (proc!=MPI_PROC_NULL),
                         "Problem receiving message" );

    return std::make_pair(proc, std::size_t(size));
  }

  ////////////////////////////////////////////////////////////////////
  /// @brief Tries to receive a long message from process @p source of size
  ///        @c s.
  ///
  /// @return A pointer to the message if it was received, otherwise @c nullptr.
  ////////////////////////////////////////////////////////////////////
  message* try_receive_long(int source, const std::size_t s)
  {
    message* const m = message::construct(s, true);

    MPI_Request& req = request_get(*m);
    STAPL_RUNTIME_ASSERT(req==MPI_REQUEST_NULL);
    MPI_Irecv(m->data(), m->capacity(), MPI_BYTE,
              source, LONG_TAG, m_comm, &req);
    int flag = 0;
    MPI_Status status;
    MPI_Test(&req, &flag, &status);
    if (flag==0) {
      // not received yet; push to the front to prevent breaking ordering
      m_recv_msg.push_front(*m);
      return 0;
    }

    const int proc = status.MPI_SOURCE;
    int size = MPI_UNDEFINED;
    MPI_Get_count(&status, MPI_BYTE, &size);
    STAPL_RUNTIME_CHECK( (size!=MPI_UNDEFINED) && (proc==source),
                         "Problem receiving message" );
    STAPL_RUNTIME_ASSERT(size==int(m->size()));

    return m;
  }

  ////////////////////////////////////////////////////////////////////
  /// @brief Waits to receive a long message from process @p source of size
  ///        @c s.
  ////////////////////////////////////////////////////////////////////
  message* wait_receive_long(int source, const std::size_t s)
  {
    message* const m = message::construct(s, true);

    MPI_Status status;
    MPI_Recv(m->data(), m->capacity(), MPI_BYTE,
             source, LONG_TAG, m_comm, &status);

    const int proc = status.MPI_SOURCE;
    int size = MPI_UNDEFINED;
    MPI_Get_count(&status, MPI_BYTE, &size);
    STAPL_RUNTIME_CHECK( (size!=MPI_UNDEFINED) && (proc==source),
                         "Problem receiving message" );
    STAPL_RUNTIME_ASSERT(size==int(m->size()));

    return m;
  }

  ////////////////////////////////////////////////////////////////////
  /// @brief Returns @c true if @p m was successfully sent.
  ////////////////////////////////////////////////////////////////////
  static bool test_sent_message(message& m) noexcept
  {
    request_container_type& reqs = m.handle().mpi_requests();
    STAPL_RUNTIME_ASSERT(reqs.size()>0);
    int flag = 0;
    MPI_Testall(reqs.size(), &(reqs[0]), &flag, MPI_STATUSES_IGNORE);
    return (flag!=0);
  }

  ////////////////////////////////////////////////////////////////////
  /// @brief Waits for @p m to be sent.
  ////////////////////////////////////////////////////////////////////
  static void wait_sent_message(message& m) noexcept
  {
    request_container_type& reqs = m.handle().mpi_requests();
    STAPL_RUNTIME_ASSERT(reqs.size()>0);
    MPI_Waitall(reqs.size(), &(reqs[0]), MPI_STATUSES_IGNORE);
  }

  ////////////////////////////////////////////////////////////////////
  /// @brief Notifies that @p m has been sent to @p dest.
  ///
  /// If @p m was not successfully sent yet, it will be added to a queue to be
  /// checked later.
  ////////////////////////////////////////////////////////////////////
  void notify_sent_message(int dest, message& m)
  {
    if (!test_sent_message(m)) {
      m_send_msg[dest].push_back(m);
      ++m_pending_send;
    }
    else {
      message::destroy(&m);
    }
  }

  ////////////////////////////////////////////////////////////////////
  /// @brief Notifies that @p m has been sent to multiple destinations.
  ///
  /// If @p m was not successfully sent yet, it will be added to a queue to be
  /// checked later.
  ////////////////////////////////////////////////////////////////////
  void notify_sent_message(message& m)
  {
    if (!test_sent_message(m)) {
      m_send_msg[size()].push_back(m);
      ++m_pending_send;
    }
    else {
      message::destroy(&m);
    }
  }

  ////////////////////////////////////////////////////////////////////
  /// @brief Removes all the successfully sent messages from the pending queues.
  ////////////////////////////////////////////////////////////////////
  void test_sent_messages(void)
  {
    // test all sent messages
    for (auto it = m_send_msg.begin(); it != m_send_msg.end(); ) {
      auto& q = it->second;
      STAPL_RUNTIME_ASSERT(!q.empty());
      do {
        message& m = q.front();
        if (!test_sent_message(m))
          break;
        q.pop_front();
        --m_pending_send;
        message::destroy(&m);
      } while (!q.empty());
      if (q.empty()) {
        // remove empty queues
        it = m_send_msg.erase(it);
      }
      else {
        ++it;
      }
    }
    STAPL_RUNTIME_STATISTICS("mpi_communicator send queue size",
                             m_pending_send);
  }

  ////////////////////////////////////////////////////////////////////
  /// @brief Waits for all the messages in the pending and forwarded queues to
  ///        be sent.
  ////////////////////////////////////////////////////////////////////
  void wait_sent_messages(void)
  {
    // wait for all sent messages
    for (auto it = m_send_msg.begin(); it != m_send_msg.end(); ++it) {
      auto& q = it->second;
      STAPL_RUNTIME_ASSERT(!q.empty());
      const size_type queue_size = q.size();
      do {
        message& m = q.front();
        wait_sent_message(m);
        q.pop_front();
        message::destroy(&m);
      } while (!q.empty());
      m_pending_send -= queue_size;
    }
    m_send_msg.clear();

    // wait for forwarded messages
    while (!m_fwd_msg.empty()) {
      message& m = m_fwd_msg.front();
      if (m.handle().mpi_requests().size()>0)
        wait_sent_message(m);
      m_fwd_msg.pop_front();
      message::destroy(&m);
    }
  }

  ////////////////////////////////////////////////////////////////////
  /// @brief Notifies that @p m has been forwarded.
  ////////////////////////////////////////////////////////////////////
  void notify_fwd_message(message& m)
  {
    m_fwd_msg.push_back(m);
  }

  ////////////////////////////////////////////////////////////////////
  /// @brief Removes all the successfully forwarded messages from the pending
  ///        queue and pushes them back in @p c.
  ////////////////////////////////////////////////////////////////////
  template<typename Container>
  void test_fwd_messages(Container& c)
  {
    while (!m_fwd_msg.empty()) {
      message& m = m_fwd_msg.front();
      if (m.handle().mpi_requests().size()>0 && !test_sent_message(m)) {
        break;
      }
      m_fwd_msg.pop_front();
      c.push_back(&m);
    }
  }

  ////////////////////////////////////////////////////////////////////
  /// @brief Sends @p m to @p dest.
  ////////////////////////////////////////////////////////////////////
  void send_impl(const int dest, message& m)
  {
    MPI_Request& req = request_get(m);
    STAPL_RUNTIME_ASSERT(req==MPI_REQUEST_NULL);
    MPI_Isend(m.data(), m.size(), MPI_BYTE, dest, DEFAULT_TAG, m_comm, &req);
    notify_sent_message(dest, m);
  }

  ////////////////////////////////////////////////////////////////////
  /// @brief Sends @p m, which is a long message, to @p dest.
  ///
  /// This function sends the size of the @p m to the regular message channel
  /// and the actual message to the long message channel.
  ////////////////////////////////////////////////////////////////////
  void send_long_impl(const int dest, message& m)
  {
    auto& reqs = request_get_all(m);
    STAPL_RUNTIME_ASSERT(reqs.size()>1             &&
                         reqs[0]==MPI_REQUEST_NULL &&
                         reqs[1]==MPI_REQUEST_NULL);
    MPI_Isend(m.data(), sizeof(std::size_t), MPI_BYTE,
              dest, DEFAULT_TAG, m_comm, &(reqs[0]));
    MPI_Isend(m.data(), m.size(), MPI_BYTE,
              dest, LONG_TAG, m_comm, &(reqs[1]));
    notify_sent_message(dest, m);
  }

  ////////////////////////////////////////////////////////////////////
  /// @brief Sends @p m to processes in @p r.
  ///
  /// @param r    Processes to send @p m to.
  /// @param m    Message to send.
  /// @param keep @c true if the current process should keep a copy of @p m.
  ////////////////////////////////////////////////////////////////////
  template<typename ForwardRange>
  void send_impl(ForwardRange const& r, message& m, const bool keep)
  {
    auto& reqs = request_get_all(m);
    message_handle::size_type i = 0;
    for (const int dest : r) {
      STAPL_RUNTIME_ASSERT((dest!=get_id()) &&
                           (i<reqs.size())  &&
                           (reqs[i]==MPI_REQUEST_NULL));
      MPI_Isend(m.data(), m.size(), MPI_BYTE,
                dest, DEFAULT_TAG, m_comm, &(reqs[i]));
      ++i;
    }

    // if the message is required in this process, then declare it forwarded,
    // otherwise declare it as sent
    if (keep)
      notify_fwd_message(m);
    else
      notify_sent_message(m);
  }

  ////////////////////////////////////////////////////////////////////
  /// @brief Sends @p m, which is a long message, to processes in @p r.
  ///
  /// @param r    Processes to send @p m to.
  /// @param m    Message to send.
  /// @param keep @c true if the current process should keep a copy of @p m.
  ////////////////////////////////////////////////////////////////////
  template<typename ForwardRange>
  void send_long_impl(ForwardRange&& r, message& m, const bool keep)
  {
    auto& reqs = request_get_all(m);
    message_handle::size_type i = 0;
    for (const int dest : r) {
      STAPL_RUNTIME_ASSERT((dest!=get_id())            &&
                           ((i+1)<reqs.size())         &&
                           (reqs[i]==MPI_REQUEST_NULL) &&
                           (reqs[i+1]==MPI_REQUEST_NULL));
      MPI_Isend(m.data(), sizeof(std::size_t), MPI_BYTE,
                dest, DEFAULT_TAG, m_comm, &(reqs[i]));
      MPI_Isend(m.data(), m.size(), MPI_BYTE,
                dest, LONG_TAG, m_comm, &(reqs[i+1]));
      i += 2;
    }

    // if the message is required in this process, then declare it forwarded,
    // otherwise declare it as sent
    if (keep)
      notify_fwd_message(m);
    else
      notify_sent_message(m);
  }

public:
  ////////////////////////////////////////////////////////////////////
  /// @brief Sends the message to the given destination.
  ///
  /// @param dest Destination of the message
  /// @param p    Message to be sent.
  ////////////////////////////////////////////////////////////////////
  void send(const int dest, message_ptr p)
  {
    message& m = *(p.release());
    STAPL_RUNTIME_ASSERT(!m.body_empty() && dest!=get_id());
    const bool long_msg = m.is_long();
    if (long_msg)
      request_get(m, 2);

    std::unique_lock<std::mutex> lock{m_mtx, std::try_to_lock};
    if (lock.owns_lock()) {
      // drain the queue and sent the message
      test_sent_messages();
      m_q.drain(*this);
      if (!long_msg)
        send_impl(dest, m);
      else
        send_long_impl(dest, m);
      check_overloaded();
    }
    else {
      // enqueue the operation
      if (!long_msg)
        m_q.add([dest, &m](mpi_communicator& c) { c.send_impl(dest, m); });
      else
        m_q.add([dest, &m](mpi_communicator& c) { c.send_long_impl(dest, m); });
    }
  }

  ////////////////////////////////////////////////////////////////////
  /// @brief Sends the message to multiple destinations.
  ///
  /// @param r    Range of destinations.
  /// @param p    Message to be sent.
  /// @param keep @c true if the current process should keep a copy of @p m.
  ////////////////////////////////////////////////////////////////////
  template<typename ForwardRange>
  void send(ForwardRange&& r, message_ptr p, const bool keep)
  {
    message& m   = *(p.release());
    const auto n = boost::size(r);
    STAPL_RUNTIME_ASSERT(!m.body_empty() && ((n!=0) || keep));
    const bool long_msg = m.is_long();
    if (long_msg)
      request_get(m, (2*n));
    else
      request_get(m, n);

    std::unique_lock<std::mutex> lock{m_mtx, std::try_to_lock};
    if (lock.owns_lock()) {
      // drain the queue and sent the message
      test_sent_messages();
      m_q.drain(*this);
      if (!long_msg)
        send_impl(r, m, keep);
      else
        send_long_impl(r, m, keep);
      check_overloaded();
    }
    else {
      // enqueue the operation
      using range_type = typename std::decay<ForwardRange>::type;
      if (!long_msg) {
        m_q.add(std::bind([&m, keep](mpi_communicator& c, range_type const& r)
                          {
                            c.send_impl(r, m, keep);
                          },
                          std::placeholders::_1,
                          std::forward<ForwardRange>(r)));
      }
      else {
        m_q.add(std::bind([&m, keep](mpi_communicator& c, range_type const& r)
                          {
                            c.send_long_impl(r, m, keep);
                          },
                          std::placeholders::_1,
                          std::forward<ForwardRange>(r)));
      }
    }
  }

  ////////////////////////////////////////////////////////////////////
  /// @brief Receives all messages that can be received and puts them in the
  ///        given list.
  ///
  /// Tests the buffers initialized for reception, then removes, sorts and
  /// replaces the ones that have already completed. The call can be specified
  /// either blocking or non-blocking and only tests one more buffer than the
  /// number of received messages. It can receive more messages than the length
  /// of the receiving queue.
  ///
  /// @param wait @c true if the call should be blocking, @c false if not.
  ///
  /// @return The number of received messages.
  ///
  /// @bug The receiving queue can grow but it never shrinks.
  /// @todo The condition for waiting should include forwarded messages as well.
  ///       Right now, it just ignores waiting if there are forwarded messages.
  ////////////////////////////////////////////////////////////////////
  message_slist receive(const bool wait)
  {
    message_slist msg_list;

    std::lock_guard<std::mutex> lock{m_mtx};
    m_q.drain(*this);

    // We count the number of messages a single call to try_receive() allows to
    // receive. In the case where this number exceeds the number we anticipated,
    // we increase this number and the size of the queue.
    // Semantically, the intensity of the communication on this node is
    // increasing.
    // TODO Reversely if after a certain number of checks we did not use a
    // significant amount of the pre-fired receiving messages, we shrink the
    // size.
    const size_type queue_size = m_recv_msg.size();
    const size_type max_recv   = std::max(2 * queue_size, sm_recv_max);
    size_type recv_counter     = 0;

    // check if everything has been sent
    test_sent_messages();

    // wait for a message
    if (wait && m_fwd_msg.empty()) {
      // no forwarded messages, so we can afford to wait

      // receive a message
      STAPL_RUNTIME_ASSERT(!m_recv_msg.empty());
      message* m = &(m_recv_msg.front());
      const std::pair<int, std::size_t> p = wait_receive(*m);
      m_recv_msg.pop_front();

      if (p.second==sizeof(std::size_t)) {
        // long message incoming; prepare to receive it
        const std::size_t size = m->size();
        m->reset();
        post_receive_message(m);
        m = wait_receive_long(p.first, size);
      }
      else if (p.second<=message::default_capacity()) {
        // regular message received
        create_receive_message();
      }

      msg_list.push_back(m);
      ++recv_counter;
    }
    else {
      // add to the queue all completed forwarded messages
      test_fwd_messages(msg_list);
    }

    check_overloaded();

    // message receiving loop
    for (; recv_counter<max_recv; ++recv_counter) {
      // receive a message
      STAPL_RUNTIME_ASSERT(!m_recv_msg.empty());
      message* m = &(m_recv_msg.front());
      const std::pair<int, std::size_t> p = test_receive(*m);
      if (p.first==MPI_PROC_NULL)
        break;
      m_recv_msg.pop_front();

      if (p.second==sizeof(std::size_t)) {
        // long message incoming; prepare to receive it
        const std::size_t size = m->size();
        m->reset();
        post_receive_message(m);
        m = try_receive_long(p.first, size);
        if (m==0)
          break;
      }
      else if (p.second<=message::default_capacity()) {
        // regular message received
        create_receive_message();
      }

      msg_list.push_back(m);
    }
    STAPL_RUNTIME_ASSERT(sm_recv_min<=m_recv_msg.size());

    // increase the receiving queue if more than the posted were received and
    // the queue did not exit maximum size
    if (recv_counter>queue_size && queue_size<m_recv_msg.size()) {
      const size_type nsize = std::min(queue_size, (sm_recv_max - queue_size));
      create_receive_message(nsize);
    }

    STAPL_RUNTIME_STATISTICS("mpi_communicator receives succeeded",
                             recv_counter);
    STAPL_RUNTIME_STATISTICS("mpi_communicator receive queue size",
                             m_recv_msg.size());

    return msg_list;
  }
};
mpi_communicator::size_type mpi_communicator::sm_recv_min        = 0;
mpi_communicator::size_type mpi_communicator::sm_recv_max        = 0;
mpi_communicator::size_type mpi_communicator::sm_send_max        = 0;
bool                        mpi_communicator::sm_mpi_initialized = false;

} // namespace runtime

} // namespace stapl

#endif


text:
//==================================================================================================
/*!
  @file

    @copyright 2016 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#ifndef BOOST_SIMD_FUNCTION_FPCLASSIFY_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_FPCLASSIFY_HPP_INCLUDED

#if defined(DOXYGEN_ONLY)
namespace boost { namespace simd
{

  /*!
    @ingroup group-ieee
    This function object categorizes floating point value into the following categories:
    zero, subnormal, normal, infinite, nan, or implementation-defined.

    @par Header <boost/simd/function/fpclassify.hpp>

    @par Notes

    - fpclassify returns a value of integral type that matches one of the classification
    macro constants, depending on the value of @c x :
    value description:
      - @c FP_INFINITE Positive or negative infinity
      - @c FP_NAN  Not-A-Number
      - @c FP_ZERO Value of zero
      - @c FP_SUBNORMAL  Sub-normal value
      - @c FP_NORMAL Normal value (none of the above)

      These macro constants of type int are defined in header @c cmath

    - Note that each value pertains to a single category: for fpclassify, zero is not a
    normal value.

    - the return type is not @c int : it is the integral signed type
       associated to the floating entry type.

    @par Decorators

      - std_ for floating entries call std::fpclassify and returns @c int

    @see is_eqz, is_denormal, is_normal, is_inf, is_nan

    @par Example:

      @snippet fpclassify.cpp fpclassify

    @par Possible output:

      @snippet fpclassify.txt fpclassify

  **/
  as_integer_t<IEEEValue> fpclassify(IEEEValue const& x);
} }
#endif

#include <boost/simd/function/scalar/fpclassify.hpp>
#include <boost/simd/function/simd/fpclassify.hpp>

#endif

max_stars_repo_name: SylvainCorlay/pythran

max_issues_repo_name: SylvainCorlay/pythran

max_forks_repo_name: SylvainCorlay/pythran


text:
/**
 * @file
 * @author  Mamadou Babaei <info@babaei.net>
 * @version 0.1.0
 *
 * @section LICENSE
 *
 * (The MIT License)
 *
 * Copyright (c) 2016 - 2021 Mamadou Babaei
 *
 * 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.
 *
 * @section DESCRIPTION
 *
 * Contains necessary functions to uncompress a file.
 */

#include <algorithm>
#include <fstream>
#include <iterator>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <boost/filesystem.hpp>
#include <boost/format.hpp>
#include <archive.h>
#include <archive_entry.h>
#include <zip.h>
#include "Archiver.hpp"
#include "Compression.hpp"
#include "FileSystem.hpp"
#include "System.hpp"

using namespace std;
using namespace boost;
using namespace CoreLib;

static int UnTarCopyData(archive *ar, archive *aw)
{
    int r;
    const void *buffer;

    size_t size;

#if ARCHIVE_VERSION_NUMBER >= 3000000
    int64_t offset;
#else
    off_t offset;
#endif

    for (;;) {
        r = archive_read_data_block(ar, &buffer, &size, &offset);

        if (r == ARCHIVE_EOF) {
            return (ARCHIVE_OK);
        }

        if (r != ARCHIVE_OK) {
            return r;
        }

        r = static_cast<int>(
                    archive_write_data_block(aw, buffer, size, offset));

        if (r != ARCHIVE_OK) {
            /// archive_write_data_block() failed!
            //archive_error_string(aw));
            return r;
        }
    }
}

bool Archiver::UnGzip(const std::string &archive, const std::string &extractedFile)
{
    string error;
    return UnGzip(archive, extractedFile, error);
}

bool Archiver::UnGzip(const std::string &archive, const std::string &extractedFile,
                      std::string &out_error)
{
    out_error.clear();

    ifstream ifs(archive, ios::binary);
    if (!ifs.is_open()) {
        out_error.assign((format("Archiver::UnGzip: Could not extract '%1%' as %2%!")
                          % archive % extractedFile).str());
        return false;
    }
    Compression::Buffer compressedContents((std::istreambuf_iterator<char>(ifs)),
                                           std::istreambuf_iterator<char>());
    ifs.close();

    Compression::Buffer uncompressedContents;
    Compression::Decompress(compressedContents, uncompressedContents,
                            Compression::Algorithm::Gzip);

    ofstream ofs(extractedFile, ios::binary);
    if (!ofs.is_open()) {
        out_error.assign((format("Archiver::UnGzip: Could not extract '%1%' as %2%!")
                          % archive % extractedFile).str());
        return false;
    }
    copy(uncompressedContents.begin(), uncompressedContents.end(),
         ostreambuf_iterator<char>(ofs));
    ofs.flush();
    ofs.close();

    return true;
}

bool Archiver::UnTar(const std::string &archivePath, const std::string &extractDirectory)
{
    string error;
    return UnTar(archivePath, extractDirectory, error);
}

bool Archiver::UnTar(const std::string &archivePath, const std::string &extractDirectory,
                     std::string &out_error)
{
    out_error.clear();
    bool success = false;

    int flags = ARCHIVE_EXTRACT_TIME;
    //    flags |= ARCHIVE_EXTRACT_PERM;
    //    flags |= ARCHIVE_EXTRACT_ACL;
    //    flags |= ARCHIVE_EXTRACT_FFLAGS;

    archive *a = archive_read_new();
    archive *ext = archive_write_disk_new();

    archive_write_disk_set_options(ext, flags);
    archive_read_support_format_tar(a);

    int r;
    if ((r = archive_read_open_filename(a, archivePath.c_str(), 10240))) {
        out_error.assign(
                    (format("Archiver::UnTar: archive_read_open_filename() failed: %1%; %2")
                     % r % archive_error_string(a)).str());
    } else {
        archive_entry *entry;

        for (;;) {
            r = archive_read_next_header(a, &entry);

            if (r == ARCHIVE_EOF) {
                success = true;
                break;
            }

            if (r != ARCHIVE_OK) {
                out_error.assign(
                            (format("Archiver::UnTar: archive_read_next_header() failed: %1%; %2")
                             % 1 % archive_error_string(a)).str());
            } else {
                const char *file = archive_entry_pathname(entry);
                const std::string filePath =
                        (boost::filesystem::path(extractDirectory)
                        / boost::filesystem::path(file)).string();
                archive_entry_set_pathname(entry, filePath.c_str());

                r = archive_write_header(ext, entry);

                if (r != ARCHIVE_OK) {
                    out_error +=
                            (format("Archiver::UnTar: archive_write_header() failed: %1%; %2\n")
                             % archive_error_string(ext)).str();
                } else {
                    (void)UnTarCopyData(a, ext);

                    r = archive_write_finish_entry(ext);

                    if (r != ARCHIVE_OK) {
                        out_error +=
                                (format("Archiver::UnTar: archive_write_finish_entry() failed: %1%; %2\n")
                                 % 1 % archive_error_string(ext)).str();
                    }
                }
            }
        }
    }

    archive_read_close(a);
    archive_read_free(a);

    archive_write_close(ext);
    archive_write_free(ext);

    return success;
}

bool Archiver::UnZip(const std::string &archive, const std::string &extractionPath)
{
    string error;
    return UnZip(archive, extractionPath, error);
}

bool Archiver::UnZip(const std::string &archive, const std::string &extractionPath,
                     std::string &out_error)
{
    out_error.clear();

    struct zip *za;
    char buf[100];
    int err;

    if ((za = zip_open(archive.c_str(), 0, &err)) == NULL) {
        zip_error_to_str(buf, sizeof(buf), err, errno);
        out_error.assign((format("Archiver::UnZip: Can't open zip archive `%1%': %2%!")
                          % archive % buf).str());
        return false;
    }

    struct zip_file *zf;
    struct zip_stat sb;
    zip_int64_t len;
    int fd;
    zip_uint64_t sum;

    for (zip_int64_t i = 0; i < zip_get_num_entries(za, 0); ++i) {
        if (zip_stat_index(za, static_cast<zip_uint64_t>(i), 0, &sb) != 0) {
            out_error.assign((format("Archiver::UnZip: Corrupted zip archive `%1%'!")
                              % archive).str());
            return false;
        }

        len = static_cast<zip_int64_t>(strlen(sb.name));
        if (sb.name[len - 1] == '/') {
            string dir((boost::filesystem::path(extractionPath)
                        / sb.name).string());
            if (!FileSystem::CreateDir(dir, true)) {
                out_error.assign((format("Archiver::UnZip: Failed to create directory `%1%'!")
                                  % dir).str());
                return false;
            }
            continue;
        }

        boost::filesystem::path p(sb.name);
        if (p.parent_path().string() != "") {
            string dir((boost::filesystem::path(extractionPath)
                        / p.parent_path()).string());
            if (!FileSystem::CreateDir(dir, true)) {
                out_error.assign((format("Archiver::UnZip: Failed to create directory `%1%'!")
                                  % dir).str());
                return false;
            }
        }

        zf = zip_fopen_index(za, static_cast<zip_uint64_t>(i), 0);
        if (!zf) {
            out_error.assign((format("Archiver::UnZip: Corrupted zip archive `%1%'!")
                              % archive).str());
            return false;
        }

#if ! defined ( _WIN32 )
        fd = open((boost::filesystem::path(extractionPath)
                   / boost::filesystem::path(sb.name)).string().c_str(),
                  O_RDWR | O_TRUNC | O_CREAT, 0644);
#else
        fd = open((boost::filesystem::path(extractionPath)
                   / boost::filesystem::path(sb.name)).string().c_str(),
                  O_RDWR | O_TRUNC | O_CREAT | O_BINARY, 0644);
#endif  // ! defined ( _WIN32 )

        if (fd < 0) {
            out_error.assign((format("Archiver::UnZip: Cannot open file `%1%' for writing!")
                              % sb.name).str());
            return false;
        }

        sum = 0;
        while (sum != sb.size) {
            len = zip_fread(zf, buf, 100);
            if (len < 0) {
                out_error.assign((format("Archiver::UnZip: Corrupted zip archive `%1%'!")
                                  % archive).str());
                return false;
            }
            write(fd, buf, static_cast<size_t>(len));
            sum += static_cast<zip_uint64_t>(len);
        }
        close(fd);
        zip_fclose(zf);
    }

    if (zip_close(za) == -1) {
        out_error.assign((format("Archiver::UnZip: Can't close zip archive `%1%'!")
                          % archive).str());
        return false;
    }

    return true;
}


text:
//---------------------------------------------------------------------------//
// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com>
//
// 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
//
// See http://boostorg.github.com/compute for more information.
//---------------------------------------------------------------------------//

#ifndef BOOST_COMPUTE_ALGORITHM_COPY_N_HPP
#define BOOST_COMPUTE_ALGORITHM_COPY_N_HPP

#include <boost/compute/system.hpp>
#include <boost/compute/command_queue.hpp>
#include <boost/compute/algorithm/copy.hpp>

namespace boost {
namespace compute {

/// Copies \p count elements from \p first to \p result.
///
/// For example, to copy four values from the host to the device:
/// \code
/// // values on the host and vector on the device
/// float values[4] = { 1.f, 2.f, 3.f, 4.f };
/// boost::compute::vector<float> vec(4, context);
///
/// // copy from the host to the device
/// boost::compute::copy_n(values, 4, vec.begin(), queue);
/// \endcode
///
/// \see copy()
template<class InputIterator, class Size, class OutputIterator>
inline OutputIterator copy_n(InputIterator first,
                             Size count,
                             OutputIterator result,
                             command_queue &queue = system::default_queue())
{
    typedef typename std::iterator_traits<InputIterator>::difference_type difference_type;

    return ::boost::compute::copy(first,
                                  first + static_cast<difference_type>(count),
                                  result,
                                  queue);
}

} // end compute namespace
} // end boost namespace

#endif // BOOST_COMPUTE_ALGORITHM_COPY_N_HPP

max_stars_repo_name: rudylee/expo

max_issues_repo_name: rudylee/expo

max_forks_repo_name: rudylee/expo