<commit_before>// This file is distributed under the MIT license.
// See the LICENSE file for details.

#include <visionaray/math/math.h>

#include <gtest/gtest.h>

using namespace visionaray;

//-------------------------------------------------------------------------------------------------
// Test routines for simd::gather()
//
// Those tests should also be performed in AVX compilation mode (not AVX2)!
// simd::gather() can make use of dedicated AVX2 intrinsics in certain cases.
//
//
//-------------------------------------------------------------------------------------------------

//-------------------------------------------------------------------------------------------------
// Template to test gather with unorm<N> array
//

template <unsigned Bits>
static void test_gather_unorm()
{

    // init memory

    VSNRAY_ALIGN(32) unorm<Bits> arr[16];

    for (int i = 0; i < 16; ++i)
    {
        arr[i] = i;
    }

    // test float4

    simd::int4 index4(0, 2, 4, 6);
    simd::float4 res4 = gather(arr, index4);

    EXPECT_TRUE( simd::get<0>(res4) == static_cast<float>(unorm<Bits>( 0)) );
    EXPECT_TRUE( simd::get<1>(res4) == static_cast<float>(unorm<Bits>( 2)) );
    EXPECT_TRUE( simd::get<2>(res4) == static_cast<float>(unorm<Bits>( 4)) );
    EXPECT_TRUE( simd::get<3>(res4) == static_cast<float>(unorm<Bits>( 6)) );

#if VSNRAY_SIMD_ISA >= VSNRAY_SIMD_ISA_AVX

    // test float8

    simd::int8 index8(0, 2, 4, 6, 8, 10, 12, 14);
    simd::float8 res8 = gather(arr, index8);

    EXPECT_TRUE( simd::get<0>(res8) == static_cast<float>(unorm<Bits>( 0)) );
    EXPECT_TRUE( simd::get<1>(res8) == static_cast<float>(unorm<Bits>( 2)) );
    EXPECT_TRUE( simd::get<2>(res8) == static_cast<float>(unorm<Bits>( 4)) );
    EXPECT_TRUE( simd::get<3>(res8) == static_cast<float>(unorm<Bits>( 6)) );
    EXPECT_TRUE( simd::get<4>(res8) == static_cast<float>(unorm<Bits>( 8)) );
    EXPECT_TRUE( simd::get<5>(res8) == static_cast<float>(unorm<Bits>(10)) );
    EXPECT_TRUE( simd::get<6>(res8) == static_cast<float>(unorm<Bits>(12)) );
    EXPECT_TRUE( simd::get<7>(res8) == static_cast<float>(unorm<Bits>(14)) );

#endif

}

//-------------------------------------------------------------------------------------------------
// Test gather() with 8-bit, 16-bit, and 32-bit unorms
//

TEST(SIMD, GatherUnorm)
{
    test_gather_unorm< 8>();
    test_gather_unorm<16>();
    test_gather_unorm<32>();
}

//-------------------------------------------------------------------------------------------------
// Test gather() with floats
//

TEST(SIMD, GatherFloat)
{

    // init memory

    VSNRAY_ALIGN(32) float arr[16];

    for (int i = 0; i < 16; ++i)
    {
        arr[i] = static_cast<float>(i);
    }

    // test float4

    simd::int4 index4(0, 2, 4, 6);
    simd::float4 res4 = gather(arr, index4);

    EXPECT_FLOAT_EQ(simd::get<0>(res4),  0.0f);
    EXPECT_FLOAT_EQ(simd::get<1>(res4),  2.0f);
    EXPECT_FLOAT_EQ(simd::get<2>(res4),  4.0f);
    EXPECT_FLOAT_EQ(simd::get<3>(res4),  6.0f);

#if VSNRAY_SIMD_ISA >= VSNRAY_SIMD_ISA_AVX

    // test float8

    simd::int8 index8(0, 2, 4, 6, 8, 10, 12, 14);
    simd::float8 res8 = gather(arr, index8);

    EXPECT_FLOAT_EQ(simd::get<0>(res8),  0.0f);
    EXPECT_FLOAT_EQ(simd::get<1>(res8),  2.0f);
    EXPECT_FLOAT_EQ(simd::get<2>(res8),  4.0f);
    EXPECT_FLOAT_EQ(simd::get<3>(res8),  6.0f);
    EXPECT_FLOAT_EQ(simd::get<4>(res8),  8.0f);
    EXPECT_FLOAT_EQ(simd::get<5>(res8), 10.0f);
    EXPECT_FLOAT_EQ(simd::get<6>(res8), 12.0f);
    EXPECT_FLOAT_EQ(simd::get<7>(res8), 14.0f);

#endif

}

//-------------------------------------------------------------------------------------------------
// Test gather() with integers
//

TEST(SIMD, GatherInt)
{

    // init memory

    VSNRAY_ALIGN(32) int arr[16];

    for (int i = 0; i < 16; ++i)
    {
        arr[i] = i;
    }

    // test int4

    simd::int4 index4(0, 2, 4, 6);
    simd::int4 res4 = gather(arr, index4);

    EXPECT_TRUE(simd::get<0>(res4) ==  0);
    EXPECT_TRUE(simd::get<1>(res4) ==  2);
    EXPECT_TRUE(simd::get<2>(res4) ==  4);
    EXPECT_TRUE(simd::get<3>(res4) ==  6);

#if VSNRAY_SIMD_ISA >= VSNRAY_SIMD_ISA_AVX

    // test int8

    simd::int8 index8(0, 2, 4, 6, 8, 10, 12, 14);
    simd::int8 res8 = gather(arr, index8);

    EXPECT_TRUE(simd::get<0>(res8) ==  0);
    EXPECT_TRUE(simd::get<1>(res8) ==  2);
    EXPECT_TRUE(simd::get<2>(res8) ==  4);
    EXPECT_TRUE(simd::get<3>(res8) ==  6);
    EXPECT_TRUE(simd::get<4>(res8) ==  8);
    EXPECT_TRUE(simd::get<5>(res8) == 10);
    EXPECT_TRUE(simd::get<6>(res8) == 12);
    EXPECT_TRUE(simd::get<7>(res8) == 14);

#endif

}

//-------------------------------------------------------------------------------------------------
// Test gather() with vec4's
//

TEST(SIMD, GatherVec4)
{

    // init memory

    VSNRAY_ALIGN(32) vec4 arr[16];

    for (int i = 0; i < 16; ++i)
    {
        arr[i] = vec4(
            static_cast<float>(i * 4),
            static_cast<float>(i * 4 + 1),
            static_cast<float>(i * 4 + 2),
            static_cast<float>(i * 4 + 3)
            );

    }

    // test vector<4, float4>

    simd::int4 index4(0, 2, 4, 6);
    vector<4, simd::float4> res4 = gather(arr, index4);

    EXPECT_FLOAT_EQ(simd::get<0>(res4.x),  0.0f);
    EXPECT_FLOAT_EQ(simd::get<0>(res4.y),  1.0f);
    EXPECT_FLOAT_EQ(simd::get<0>(res4.z),  2.0f);
    EXPECT_FLOAT_EQ(simd::get<0>(res4.w),  3.0f);

    EXPECT_FLOAT_EQ(simd::get<1>(res4.x),  8.0f);
    EXPECT_FLOAT_EQ(simd::get<1>(res4.y),  9.0f);
    EXPECT_FLOAT_EQ(simd::get<1>(res4.z), 10.0f);
    EXPECT_FLOAT_EQ(simd::get<1>(res4.w), 11.0f);

    EXPECT_FLOAT_EQ(simd::get<2>(res4.x), 16.0f);
    EXPECT_FLOAT_EQ(simd::get<2>(res4.y), 17.0f);
    EXPECT_FLOAT_EQ(simd::get<2>(res4.z), 18.0f);
    EXPECT_FLOAT_EQ(simd::get<2>(res4.w), 19.0f);

    EXPECT_FLOAT_EQ(simd::get<3>(res4.x), 24.0f);
    EXPECT_FLOAT_EQ(simd::get<3>(res4.y), 25.0f);
    EXPECT_FLOAT_EQ(simd::get<3>(res4.z), 26.0f);
    EXPECT_FLOAT_EQ(simd::get<3>(res4.w), 27.0f);

#if VSNRAY_SIMD_ISA >= VSNRAY_SIMD_ISA_AVX

    // test vector<4, float8>

    simd::int8 index8(0, 2, 4, 6, 8, 10, 12, 14);
    vector<4, simd::float8> res8 = gather(arr, index8);

    EXPECT_FLOAT_EQ(simd::get<0>(res8.x),  0.0f);
    EXPECT_FLOAT_EQ(simd::get<0>(res8.y),  1.0f);
    EXPECT_FLOAT_EQ(simd::get<0>(res8.z),  2.0f);
    EXPECT_FLOAT_EQ(simd::get<0>(res8.w),  3.0f);

    EXPECT_FLOAT_EQ(simd::get<1>(res8.x),  8.0f);
    EXPECT_FLOAT_EQ(simd::get<1>(res8.y),  9.0f);
    EXPECT_FLOAT_EQ(simd::get<1>(res8.z), 10.0f);
    EXPECT_FLOAT_EQ(simd::get<1>(res8.w), 11.0f);

    EXPECT_FLOAT_EQ(simd::get<2>(res8.x), 16.0f);
    EXPECT_FLOAT_EQ(simd::get<2>(res8.y), 17.0f);
    EXPECT_FLOAT_EQ(simd::get<2>(res8.z), 18.0f);
    EXPECT_FLOAT_EQ(simd::get<2>(res8.w), 19.0f);

    EXPECT_FLOAT_EQ(simd::get<3>(res8.x), 24.0f);
    EXPECT_FLOAT_EQ(simd::get<3>(res8.y), 25.0f);
    EXPECT_FLOAT_EQ(simd::get<3>(res8.z), 26.0f);
    EXPECT_FLOAT_EQ(simd::get<3>(res8.w), 27.0f);

    EXPECT_FLOAT_EQ(simd::get<4>(res8.x), 32.0f);
    EXPECT_FLOAT_EQ(simd::get<4>(res8.y), 33.0f);
    EXPECT_FLOAT_EQ(simd::get<4>(res8.z), 34.0f);
    EXPECT_FLOAT_EQ(simd::get<4>(res8.w), 35.0f);

    EXPECT_FLOAT_EQ(simd::get<5>(res8.x), 40.0f);
    EXPECT_FLOAT_EQ(simd::get<5>(res8.y), 41.0f);
    EXPECT_FLOAT_EQ(simd::get<5>(res8.z), 42.0f);
    EXPECT_FLOAT_EQ(simd::get<5>(res8.w), 43.0f);

    EXPECT_FLOAT_EQ(simd::get<6>(res8.x), 48.0f);
    EXPECT_FLOAT_EQ(simd::get<6>(res8.y), 49.0f);
    EXPECT_FLOAT_EQ(simd::get<6>(res8.z), 50.0f);
    EXPECT_FLOAT_EQ(simd::get<6>(res8.w), 51.0f);

    EXPECT_FLOAT_EQ(simd::get<7>(res8.x), 56.0f);
    EXPECT_FLOAT_EQ(simd::get<7>(res8.y), 57.0f);
    EXPECT_FLOAT_EQ(simd::get<7>(res8.z), 58.0f);
    EXPECT_FLOAT_EQ(simd::get<7>(res8.w), 59.0f);

#endif

}
<commit_msg>More unit tests for simd::gather()<commit_after>// This file is distributed under the MIT license.
// See the LICENSE file for details.

#include <visionaray/math/math.h>

#include <gtest/gtest.h>

using namespace visionaray;

//-------------------------------------------------------------------------------------------------
// Test routines for simd::gather()
//
// Those tests should also be performed in AVX compilation mode (not AVX2)!
// simd::gather() can make use of dedicated AVX2 intrinsics in certain cases.
//
//
//-------------------------------------------------------------------------------------------------

//-------------------------------------------------------------------------------------------------
// Template to test gather with unorm<N> array
//

template <unsigned Bits>
static void test_gather_unorm()
{

    // init memory

    VSNRAY_ALIGN(32) unorm<Bits> arr[16];

    for (int i = 0; i < 16; ++i)
    {
        arr[i] = i;
    }

    // test float4

    simd::int4 index4(0, 2, 4, 6);
    simd::float4 res4 = gather(arr, index4);

    EXPECT_TRUE( simd::get<0>(res4) == static_cast<float>(unorm<Bits>( 0)) );
    EXPECT_TRUE( simd::get<1>(res4) == static_cast<float>(unorm<Bits>( 2)) );
    EXPECT_TRUE( simd::get<2>(res4) == static_cast<float>(unorm<Bits>( 4)) );
    EXPECT_TRUE( simd::get<3>(res4) == static_cast<float>(unorm<Bits>( 6)) );

#if VSNRAY_SIMD_ISA >= VSNRAY_SIMD_ISA_AVX

    // test float8

    simd::int8 index8(0, 2, 4, 6, 8, 10, 12, 14);
    simd::float8 res8 = gather(arr, index8);

    EXPECT_TRUE( simd::get<0>(res8) == static_cast<float>(unorm<Bits>( 0)) );
    EXPECT_TRUE( simd::get<1>(res8) == static_cast<float>(unorm<Bits>( 2)) );
    EXPECT_TRUE( simd::get<2>(res8) == static_cast<float>(unorm<Bits>( 4)) );
    EXPECT_TRUE( simd::get<3>(res8) == static_cast<float>(unorm<Bits>( 6)) );
    EXPECT_TRUE( simd::get<4>(res8) == static_cast<float>(unorm<Bits>( 8)) );
    EXPECT_TRUE( simd::get<5>(res8) == static_cast<float>(unorm<Bits>(10)) );
    EXPECT_TRUE( simd::get<6>(res8) == static_cast<float>(unorm<Bits>(12)) );
    EXPECT_TRUE( simd::get<7>(res8) == static_cast<float>(unorm<Bits>(14)) );

#endif

}

template <size_t Dim, unsigned Bits>
static void test_gather_vector_unorm()
{

    // init memory

    VSNRAY_ALIGN(32) vector<Dim, unorm<Bits>> arr[16];

    for (int i = 0; i < 16; ++i)
    {
        for (size_t d = 0; d < Dim; ++d)
        {
            arr[i][d] = (i * Dim + d) / static_cast<float>(Dim * 16);
        }
    }

    // test vector<Dim, float4>

    simd::int4 index4(0, 2, 4, 6);
    vector<Dim, simd::float4> res4 = gather(arr, index4);

    for (size_t d = 0; d < Dim; ++d)
    {
        simd::float4 f = res4[d];

        unorm<Bits> u0( ( 0 * Dim + d) / static_cast<float>(Dim * 16) );
        unorm<Bits> u1( ( 2 * Dim + d) / static_cast<float>(Dim * 16) );
        unorm<Bits> u2( ( 4 * Dim + d) / static_cast<float>(Dim * 16) );
        unorm<Bits> u3( ( 6 * Dim + d) / static_cast<float>(Dim * 16) );

        EXPECT_FLOAT_EQ( simd::get<0>(f), static_cast<float>(u0) );
        EXPECT_FLOAT_EQ( simd::get<1>(f), static_cast<float>(u1) );
        EXPECT_FLOAT_EQ( simd::get<2>(f), static_cast<float>(u2) );
        EXPECT_FLOAT_EQ( simd::get<3>(f), static_cast<float>(u3) );
    }

#if VSNRAY_SIMD_ISA >= VSNRAY_SIMD_ISA_AVX

    // test vector<Dim, float8>

    simd::int8 index8(0, 2, 4, 6, 8, 10, 12, 14);
    vector<Dim, simd::float8> res8 = gather(arr, index8);

    for (size_t d = 0; d < Dim; ++d)
    {
        simd::float8 f = res8[d];

        unorm<Bits> u0( ( 0 * Dim + d) / static_cast<float>(Dim * 16) );
        unorm<Bits> u1( ( 2 * Dim + d) / static_cast<float>(Dim * 16) );
        unorm<Bits> u2( ( 4 * Dim + d) / static_cast<float>(Dim * 16) );
        unorm<Bits> u3( ( 6 * Dim + d) / static_cast<float>(Dim * 16) );
        unorm<Bits> u4( ( 8 * Dim + d) / static_cast<float>(Dim * 16) );
        unorm<Bits> u5( (10 * Dim + d) / static_cast<float>(Dim * 16) );
        unorm<Bits> u6( (12 * Dim + d) / static_cast<float>(Dim * 16) );
        unorm<Bits> u7( (14 * Dim + d) / static_cast<float>(Dim * 16) );

        EXPECT_FLOAT_EQ( simd::get<0>(f), static_cast<float>(u0) );
        EXPECT_FLOAT_EQ( simd::get<1>(f), static_cast<float>(u1) );
        EXPECT_FLOAT_EQ( simd::get<2>(f), static_cast<float>(u2) );
        EXPECT_FLOAT_EQ( simd::get<3>(f), static_cast<float>(u3) );
        EXPECT_FLOAT_EQ( simd::get<4>(f), static_cast<float>(u4) );
        EXPECT_FLOAT_EQ( simd::get<5>(f), static_cast<float>(u5) );
        EXPECT_FLOAT_EQ( simd::get<6>(f), static_cast<float>(u6) );
        EXPECT_FLOAT_EQ( simd::get<7>(f), static_cast<float>(u7) );
    }

#endif

}

//-------------------------------------------------------------------------------------------------
// Test gather() with 8-bit, 16-bit, and 32-bit unorms
//

TEST(SIMD, GatherUnorm)
{
    test_gather_unorm< 8>();
    test_gather_unorm<16>();
    test_gather_unorm<32>();
}

//-------------------------------------------------------------------------------------------------
// Test gather() with floats
//

TEST(SIMD, GatherFloat)
{

    // init memory

    VSNRAY_ALIGN(32) float arr[16];

    for (int i = 0; i < 16; ++i)
    {
        arr[i] = static_cast<float>(i);
    }

    // test float4

    simd::int4 index4(0, 2, 4, 6);
    simd::float4 res4 = gather(arr, index4);

    EXPECT_FLOAT_EQ(simd::get<0>(res4),  0.0f);
    EXPECT_FLOAT_EQ(simd::get<1>(res4),  2.0f);
    EXPECT_FLOAT_EQ(simd::get<2>(res4),  4.0f);
    EXPECT_FLOAT_EQ(simd::get<3>(res4),  6.0f);

#if VSNRAY_SIMD_ISA >= VSNRAY_SIMD_ISA_AVX

    // test float8

    simd::int8 index8(0, 2, 4, 6, 8, 10, 12, 14);
    simd::float8 res8 = gather(arr, index8);

    EXPECT_FLOAT_EQ(simd::get<0>(res8),  0.0f);
    EXPECT_FLOAT_EQ(simd::get<1>(res8),  2.0f);
    EXPECT_FLOAT_EQ(simd::get<2>(res8),  4.0f);
    EXPECT_FLOAT_EQ(simd::get<3>(res8),  6.0f);
    EXPECT_FLOAT_EQ(simd::get<4>(res8),  8.0f);
    EXPECT_FLOAT_EQ(simd::get<5>(res8), 10.0f);
    EXPECT_FLOAT_EQ(simd::get<6>(res8), 12.0f);
    EXPECT_FLOAT_EQ(simd::get<7>(res8), 14.0f);

#endif

}

//-------------------------------------------------------------------------------------------------
// Test gather() with integers
//

TEST(SIMD, GatherInt)
{

    // init memory

    VSNRAY_ALIGN(32) int arr[16];

    for (int i = 0; i < 16; ++i)
    {
        arr[i] = i;
    }

    // test int4

    simd::int4 index4(0, 2, 4, 6);
    simd::int4 res4 = gather(arr, index4);

    EXPECT_TRUE(simd::get<0>(res4) ==  0);
    EXPECT_TRUE(simd::get<1>(res4) ==  2);
    EXPECT_TRUE(simd::get<2>(res4) ==  4);
    EXPECT_TRUE(simd::get<3>(res4) ==  6);

#if VSNRAY_SIMD_ISA >= VSNRAY_SIMD_ISA_AVX

    // test int8

    simd::int8 index8(0, 2, 4, 6, 8, 10, 12, 14);
    simd::int8 res8 = gather(arr, index8);

    EXPECT_TRUE(simd::get<0>(res8) ==  0);
    EXPECT_TRUE(simd::get<1>(res8) ==  2);
    EXPECT_TRUE(simd::get<2>(res8) ==  4);
    EXPECT_TRUE(simd::get<3>(res8) ==  6);
    EXPECT_TRUE(simd::get<4>(res8) ==  8);
    EXPECT_TRUE(simd::get<5>(res8) == 10);
    EXPECT_TRUE(simd::get<6>(res8) == 12);
    EXPECT_TRUE(simd::get<7>(res8) == 14);

#endif

}

//-------------------------------------------------------------------------------------------------
// Test gather() with unorm vectors
//

TEST(SIMD, GatherVecNUnorm)
{
    test_gather_vector_unorm<2,  8>();
    test_gather_vector_unorm<3,  8>();
    test_gather_vector_unorm<4,  8>();

    test_gather_vector_unorm<2, 16>();
    test_gather_vector_unorm<3, 16>();
    test_gather_vector_unorm<4, 16>();

    test_gather_vector_unorm<2, 32>();
    test_gather_vector_unorm<3, 32>();
    test_gather_vector_unorm<4, 32>();
}

//-------------------------------------------------------------------------------------------------
// Test gather() with vec4's
//

TEST(SIMD, GatherVec4)
{

    // init memory

    VSNRAY_ALIGN(32) vec4 arr[16];

    for (int i = 0; i < 16; ++i)
    {
        arr[i] = vec4(
            static_cast<float>(i * 4),
            static_cast<float>(i * 4 + 1),
            static_cast<float>(i * 4 + 2),
            static_cast<float>(i * 4 + 3)
            );

    }

    // test vector<4, float4>

    simd::int4 index4(0, 2, 4, 6);
    vector<4, simd::float4> res4 = gather(arr, index4);

    EXPECT_FLOAT_EQ(simd::get<0>(res4.x),  0.0f);
    EXPECT_FLOAT_EQ(simd::get<0>(res4.y),  1.0f);
    EXPECT_FLOAT_EQ(simd::get<0>(res4.z),  2.0f);
    EXPECT_FLOAT_EQ(simd::get<0>(res4.w),  3.0f);

    EXPECT_FLOAT_EQ(simd::get<1>(res4.x),  8.0f);
    EXPECT_FLOAT_EQ(simd::get<1>(res4.y),  9.0f);
    EXPECT_FLOAT_EQ(simd::get<1>(res4.z), 10.0f);
    EXPECT_FLOAT_EQ(simd::get<1>(res4.w), 11.0f);

    EXPECT_FLOAT_EQ(simd::get<2>(res4.x), 16.0f);
    EXPECT_FLOAT_EQ(simd::get<2>(res4.y), 17.0f);
    EXPECT_FLOAT_EQ(simd::get<2>(res4.z), 18.0f);
    EXPECT_FLOAT_EQ(simd::get<2>(res4.w), 19.0f);

    EXPECT_FLOAT_EQ(simd::get<3>(res4.x), 24.0f);
    EXPECT_FLOAT_EQ(simd::get<3>(res4.y), 25.0f);
    EXPECT_FLOAT_EQ(simd::get<3>(res4.z), 26.0f);
    EXPECT_FLOAT_EQ(simd::get<3>(res4.w), 27.0f);

#if VSNRAY_SIMD_ISA >= VSNRAY_SIMD_ISA_AVX

    // test vector<4, float8>

    simd::int8 index8(0, 2, 4, 6, 8, 10, 12, 14);
    vector<4, simd::float8> res8 = gather(arr, index8);

    EXPECT_FLOAT_EQ(simd::get<0>(res8.x),  0.0f);
    EXPECT_FLOAT_EQ(simd::get<0>(res8.y),  1.0f);
    EXPECT_FLOAT_EQ(simd::get<0>(res8.z),  2.0f);
    EXPECT_FLOAT_EQ(simd::get<0>(res8.w),  3.0f);

    EXPECT_FLOAT_EQ(simd::get<1>(res8.x),  8.0f);
    EXPECT_FLOAT_EQ(simd::get<1>(res8.y),  9.0f);
    EXPECT_FLOAT_EQ(simd::get<1>(res8.z), 10.0f);
    EXPECT_FLOAT_EQ(simd::get<1>(res8.w), 11.0f);

    EXPECT_FLOAT_EQ(simd::get<2>(res8.x), 16.0f);
    EXPECT_FLOAT_EQ(simd::get<2>(res8.y), 17.0f);
    EXPECT_FLOAT_EQ(simd::get<2>(res8.z), 18.0f);
    EXPECT_FLOAT_EQ(simd::get<2>(res8.w), 19.0f);

    EXPECT_FLOAT_EQ(simd::get<3>(res8.x), 24.0f);
    EXPECT_FLOAT_EQ(simd::get<3>(res8.y), 25.0f);
    EXPECT_FLOAT_EQ(simd::get<3>(res8.z), 26.0f);
    EXPECT_FLOAT_EQ(simd::get<3>(res8.w), 27.0f);

    EXPECT_FLOAT_EQ(simd::get<4>(res8.x), 32.0f);
    EXPECT_FLOAT_EQ(simd::get<4>(res8.y), 33.0f);
    EXPECT_FLOAT_EQ(simd::get<4>(res8.z), 34.0f);
    EXPECT_FLOAT_EQ(simd::get<4>(res8.w), 35.0f);

    EXPECT_FLOAT_EQ(simd::get<5>(res8.x), 40.0f);
    EXPECT_FLOAT_EQ(simd::get<5>(res8.y), 41.0f);
    EXPECT_FLOAT_EQ(simd::get<5>(res8.z), 42.0f);
    EXPECT_FLOAT_EQ(simd::get<5>(res8.w), 43.0f);

    EXPECT_FLOAT_EQ(simd::get<6>(res8.x), 48.0f);
    EXPECT_FLOAT_EQ(simd::get<6>(res8.y), 49.0f);
    EXPECT_FLOAT_EQ(simd::get<6>(res8.z), 50.0f);
    EXPECT_FLOAT_EQ(simd::get<6>(res8.w), 51.0f);

    EXPECT_FLOAT_EQ(simd::get<7>(res8.x), 56.0f);
    EXPECT_FLOAT_EQ(simd::get<7>(res8.y), 57.0f);
    EXPECT_FLOAT_EQ(simd::get<7>(res8.z), 58.0f);
    EXPECT_FLOAT_EQ(simd::get<7>(res8.w), 59.0f);

#endif

}
<|endoftext|>


<commit_before>// Copyright (c) 2013, Matthew Harvey. All rights reserved.

#ifndef GUARD_debug_log_hpp
#define GUARD_debug_log_hpp

/** @file debug_log.hpp
 *
 * @brief Provides macro for printing to std::clog in debug builds.
 *
 * From someone called "snstrnd" on Stack Overflow.
 */

#include <iostream>

/**Macros to print to std::clog iff DEBUG is defined.
 *
 * If DEBUG is defined, JEWEL_DEBUG_LOG acts like std::clog
 * (but prints "  LOG: " before the rest of the output),
 * but if DEBUG is not defined, JEWEL_DEBUG_LOG, and the rest
 * of the line, is effectively compiled away to nothing.
 *
 * If DEBUG is defined JEWEL_DEBUG_LOG_LOCATION prints the
 * file and line number to std::clog; otherwise, it is
 * effectively compiled away to nothing.
 *
 * Note a semicolon must still be included by client code
 * at the end of a statement using either of these macros.
 *
 * No particular exception safety guarantee is offered by
 * these macros. They are not intended for use in release builds.
 * But note that all it does is write to std::clog; so unless
 * exceptions have been enabled on std::clog, the only part of this
 * function that could throw is in initialization of the string being
 * written to std::clog. This might throw under conditions of
 * memory shortage; but it is extremely unlikely.
 */

#ifdef DEBUG
	#define JEWEL_DEBUG_LOG std::clog << "  LOG: "
	#define JEWEL_DEBUG_LOG_LOCATION std::clog << __FILE__ << ": " << __LINE__ << std::endl;
#else
	#define JEWEL_DEBUG_LOG 0 && std::clog
	#define JEWEL_DEBUG_LOG_LOCATION 0
#endif

#endif  // GUARD_debug_log_hpp
<commit_msg>Created JEWEL_DEBUG_LOG_VALUE(x) macro to facilitate logging an expression, and its value, to std::clog when debugging.<commit_after>// Copyright (c) 2013, Matthew Harvey. All rights reserved.

#ifndef GUARD_debug_log_hpp
#define GUARD_debug_log_hpp

/** @file debug_log.hpp
 *
 * @brief Provides macro for printing to std::clog in debug builds.
 *
 * From someone called "snstrnd" on Stack Overflow.
 */

#include <iostream>

/**Macros to print to std::clog if DEBUG is defined, or else to compile
 * away to nothing if DEBUG is not defined.
 *
 * If DEBUG is defined, JEWEL_DEBUG_LOG acts like std::clog
 * (but prints "LOG: " before the rest of the output),
 * but if DEBUG is not defined, JEWEL_DEBUG_LOG, and the rest
 * of the line, is effectively compiled away to nothing.
 *
 * If DEBUG is defined JEWEL_DEBUG_LOG_LOCATION prints the
 * file and line number to std::clog; otherwise, it is
 * effectively compiled away to nothing.
 *
 * If DEBUG is defined JEWEL_DEBUG_LOG_VALUE(x) prints a string
 * of the form "LOG: x: [value of x]". E.g. if x == 3, then
 * JEWEL_DEBUG_LOG_VALUE(x) will print "LOG: x: 3".
 *
 * Note a semicolon must still be included by client code
 * at the end of a statement using either of these macros.
 *
 * No particular exception safety guarantee is offered by
 * these macros. They are not intended for use in release builds.
 * But note that all it does is write to std::clog; so unless
 * exceptions have been enabled on std::clog, the only part of this
 * function that could throw is in initialization of the string being
 * written to std::clog. This might throw under conditions of
 * memory shortage; but it is extremely unlikely.
 */

#ifdef DEBUG
	#define JEWEL_DEBUG_LOG std::clog << "LOG: "
	#define JEWEL_DEBUG_LOG_LOCATION std::clog << __FILE__ << ": " << __LINE__ << std::endl;
	#define JEWEL_DEBUG_LOG_VALUE(x) std::clog << "LOG: " #x ": " << x << std::endl;
#else
	#define JEWEL_DEBUG_LOG 0 && std::clog
	#define JEWEL_DEBUG_LOG_LOCATION 0
	#define JEWEL_DEBUG_LOG_VALUE(X) 0
#endif

#endif  // GUARD_debug_log_hpp
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
// taskwarrior - a command line task list manager.
//
// Copyright 2006 - 2013, Paul Beckingham, Federico Hernandez.
//
// 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.
//
// http://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////

#include <cmake.h>

#ifdef HAVE_LIBGNUTLS

#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <TLSClient.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/errno.h>
#include <sys/types.h>
#include <netdb.h>
#include <i18n.h>

#define MAX_BUF 16384

////////////////////////////////////////////////////////////////////////////////
static void gnutls_log_function (int level, const char* message)
{
  std::cout << "c: " << level << " " << message;
}

////////////////////////////////////////////////////////////////////////////////
TLSClient::TLSClient ()
: _ca ("")
, _socket (0)
, _limit (0)
, _debug (false)
{
}

////////////////////////////////////////////////////////////////////////////////
TLSClient::~TLSClient ()
{
  gnutls_deinit (_session);
  gnutls_certificate_free_credentials (_credentials);
  gnutls_global_deinit ();

  if (_socket)
  {
    shutdown (_socket, SHUT_RDWR);
    close (_socket);
  }
}

////////////////////////////////////////////////////////////////////////////////
void TLSClient::limit (int max)
{
  _limit = max;
}

////////////////////////////////////////////////////////////////////////////////
// Calling this method results in all subsequent socket traffic being sent to
// std::cout, labelled with 'c: ...'.
void TLSClient::debug (int level)
{
  if (level)
    _debug = true;

  gnutls_global_set_log_function (gnutls_log_function);
  gnutls_global_set_log_level (level);
}

////////////////////////////////////////////////////////////////////////////////
void TLSClient::init (const std::string& ca)
{
  _ca = ca;

  gnutls_global_init ();
  gnutls_certificate_allocate_credentials (&_credentials);
  gnutls_certificate_set_x509_trust_file (_credentials, _ca.c_str (), GNUTLS_X509_FMT_PEM);
  gnutls_init (&_session, GNUTLS_CLIENT);

  // Use default priorities.
  const char *err;
  int ret = gnutls_priority_set_direct (_session, "NORMAL", &err);
  if (ret < 0)
  {
    if (_debug && ret == GNUTLS_E_INVALID_REQUEST)
      std::cout << "c: ERROR Priority error at: " << err << "\n";

    throw std::string (STRING_TLS_INIT_FAIL);
  }

  // Apply the x509 credentials to the current session.
  gnutls_credentials_set (_session, GNUTLS_CRD_CERTIFICATE, _credentials);
}

////////////////////////////////////////////////////////////////////////////////
void TLSClient::connect (const std::string& host, const std::string& port)
{
  // use IPv4 or IPv6, does not matter.
  struct addrinfo hints = {0};
  hints.ai_family   = AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags    = AI_PASSIVE; // use my IP

  struct addrinfo* res;
  if (::getaddrinfo (host.c_str (), port.c_str (), &hints, &res) != 0)
    throw "ERROR: " + std::string (::gai_strerror (errno));

  // Try them all, stop on success.
  struct addrinfo* p;
  for (p = res; p != NULL; p = p->ai_next)
  {
    if ((_socket = ::socket (p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
      continue;

    // When a socket is closed, it remains unavailable for a while (netstat -an).
    // Setting SO_REUSEADDR allows this program to assume control of a closed,
    // but unavailable socket.
    int on = 1;
    if (::setsockopt (_socket,
                      SOL_SOCKET,
                      SO_REUSEADDR,
                      (const void*) &on,
                      sizeof (on)) == -1)
      throw "ERROR: " + std::string (::strerror (errno));

    if (::connect (_socket, p->ai_addr, p->ai_addrlen) == -1)
      continue;

    break;
  }

  free (res);

  if (p == NULL)
    throw "ERROR: Could not connect to " + host + " " + port;

  gnutls_transport_set_ptr (_session, (gnutls_transport_ptr_t) (long) _socket);

  // Perform the TLS handshake
  int ret = gnutls_handshake (_session);
  if (ret < 0)
  {
    if (_debug)
      std::cout << "c: ERROR Handshake failed\n";
    gnutls_perror (ret);
  }
  else
  {
    if (_debug)
      std::cout << "c: INFO Handshake was completed\n";
  }
}

////////////////////////////////////////////////////////////////////////////////
void TLSClient::bye ()
{
  gnutls_bye (_session, GNUTLS_SHUT_RDWR);
}

////////////////////////////////////////////////////////////////////////////////
void TLSClient::send (const std::string& data)
{
  std::string packet = "XXXX" + data;

  // Encode the length.
  unsigned long l = packet.length ();
  packet[0] = l >>24;
  packet[1] = l >>16;
  packet[2] = l >>8;
  packet[3] = l;

  int total = 0;
  int remaining = packet.length ();

  while (total < packet.length ())
  {
    int status;
    do
    {
      status = gnutls_record_send (_session, packet.c_str () + total, remaining);
    }
    while (errno == GNUTLS_E_INTERRUPTED ||
           errno == GNUTLS_E_AGAIN);

    if (status == -1)
      break;

    total     += status;
    remaining -= status;
  }

  if (_debug)
    std::cout << "c: INFO Sending 'XXXX"
              << data.c_str ()
              << "' (" << total << " bytes)"
              << std::endl;
}

////////////////////////////////////////////////////////////////////////////////
void TLSClient::recv (std::string& data)
{
  data = "";          // No appending of data.
  int received = 0;

  // Get the encoded length.
  unsigned char header[4] = {0};
  do
  {
    received = gnutls_record_recv (_session, header, 4);
  }
  while (received > 0 &&
         (errno == GNUTLS_E_INTERRUPTED ||
          errno == GNUTLS_E_AGAIN));

  int total = received;

  // Decode the length.
  unsigned long expected = (header[0]<<24) |
                           (header[1]<<16) |
                           (header[2]<<8) |
                            header[3];
  if (_debug)
    std::cout << "c: INFO expecting " << expected << " bytes.\n";

  // TODO This would be a good place to assert 'expected < _limit'.

  // Arbitrary buffer size.
  char buffer[MAX_BUF];

  // Keep reading until no more data.  Concatenate chunks of data if a) the
  // read was interrupted by a signal, and b) if there is more data than
  // fits in the buffer.
  do
  {
    do
    {
      received = gnutls_record_recv (_session, buffer, MAX_BUF - 1);
    }
    while (received > 0 &&
           (errno == GNUTLS_E_INTERRUPTED ||
            errno == GNUTLS_E_AGAIN));

    // Other end closed the connection.
    if (received == 0)
    {
      if (_debug)
        std::cout << "c: INFO Peer has closed the TLS connection\n";
      break;
    }

    // Something happened.
    if (received < 0)
      throw "ERROR: " + std::string (gnutls_strerror (received));

    buffer [received] = '\0';
    data += buffer;
    total += received;

    // Stop at defined limit.
    if (_limit && total > _limit)
      break;
  }
  while (received > 0 && total < (int) expected);

  if (_debug)
    std::cout << "c: INFO Receiving 'XXXX"
              << data.c_str ()
              << "' (" << total << " bytes)"
              << std::endl;
}

////////////////////////////////////////////////////////////////////////////////
#endif
<commit_msg>Build<commit_after>////////////////////////////////////////////////////////////////////////////////
// taskwarrior - a command line task list manager.
//
// Copyright 2006 - 2013, Paul Beckingham, Federico Hernandez.
//
// 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.
//
// http://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////

#include <cmake.h>

#ifdef HAVE_LIBGNUTLS

#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <TLSClient.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/errno.h>
#include <sys/types.h>
#include <netdb.h>
#include <i18n.h>

#define MAX_BUF 16384

////////////////////////////////////////////////////////////////////////////////
static void gnutls_log_function (int level, const char* message)
{
  std::cout << "c: " << level << " " << message;
}

////////////////////////////////////////////////////////////////////////////////
TLSClient::TLSClient ()
: _ca ("")
, _socket (0)
, _limit (0)
, _debug (false)
{
}

////////////////////////////////////////////////////////////////////////////////
TLSClient::~TLSClient ()
{
  gnutls_deinit (_session);
  gnutls_certificate_free_credentials (_credentials);
  gnutls_global_deinit ();

  if (_socket)
  {
    shutdown (_socket, SHUT_RDWR);
    close (_socket);
  }
}

////////////////////////////////////////////////////////////////////////////////
void TLSClient::limit (int max)
{
  _limit = max;
}

////////////////////////////////////////////////////////////////////////////////
// Calling this method results in all subsequent socket traffic being sent to
// std::cout, labelled with 'c: ...'.
void TLSClient::debug (int level)
{
  if (level)
    _debug = true;

  gnutls_global_set_log_function (gnutls_log_function);
  gnutls_global_set_log_level (level);
}

////////////////////////////////////////////////////////////////////////////////
void TLSClient::init (const std::string& ca)
{
  _ca = ca;

  gnutls_global_init ();
  gnutls_certificate_allocate_credentials (&_credentials);
  gnutls_certificate_set_x509_trust_file (_credentials, _ca.c_str (), GNUTLS_X509_FMT_PEM);
  gnutls_init (&_session, GNUTLS_CLIENT);

  // Use default priorities.
  const char *err;
  int ret = gnutls_priority_set_direct (_session, "NORMAL", &err);
  if (ret < 0)
  {
    if (_debug && ret == GNUTLS_E_INVALID_REQUEST)
      std::cout << "c: ERROR Priority error at: " << err << "\n";

    throw std::string (STRING_TLS_INIT_FAIL);
  }

  // Apply the x509 credentials to the current session.
  gnutls_credentials_set (_session, GNUTLS_CRD_CERTIFICATE, _credentials);
}

////////////////////////////////////////////////////////////////////////////////
void TLSClient::connect (const std::string& host, const std::string& port)
{
  // use IPv4 or IPv6, does not matter.
  struct addrinfo hints = {0};
  hints.ai_family   = AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags    = AI_PASSIVE; // use my IP

  struct addrinfo* res;
  if (::getaddrinfo (host.c_str (), port.c_str (), &hints, &res) != 0)
    throw "ERROR: " + std::string (::gai_strerror (errno));

  // Try them all, stop on success.
  struct addrinfo* p;
  for (p = res; p != NULL; p = p->ai_next)
  {
    if ((_socket = ::socket (p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
      continue;

    // When a socket is closed, it remains unavailable for a while (netstat -an).
    // Setting SO_REUSEADDR allows this program to assume control of a closed,
    // but unavailable socket.
    int on = 1;
    if (::setsockopt (_socket,
                      SOL_SOCKET,
                      SO_REUSEADDR,
                      (const void*) &on,
                      sizeof (on)) == -1)
      throw "ERROR: " + std::string (::strerror (errno));

    if (::connect (_socket, p->ai_addr, p->ai_addrlen) == -1)
      continue;

    break;
  }

  free (res);

  if (p == NULL)
    throw "ERROR: Could not connect to " + host + " " + port;

  gnutls_transport_set_ptr (_session, (gnutls_transport_ptr_t) (long) _socket);

  // Perform the TLS handshake
  int ret = gnutls_handshake (_session);
  if (ret < 0)
  {
    if (_debug)
      std::cout << "c: ERROR Handshake failed\n";
    gnutls_perror (ret);
  }
  else
  {
    if (_debug)
      std::cout << "c: INFO Handshake was completed\n";
  }
}

////////////////////////////////////////////////////////////////////////////////
void TLSClient::bye ()
{
  gnutls_bye (_session, GNUTLS_SHUT_RDWR);
}

////////////////////////////////////////////////////////////////////////////////
void TLSClient::send (const std::string& data)
{
  std::string packet = "XXXX" + data;

  // Encode the length.
  unsigned long l = packet.length ();
  packet[0] = l >>24;
  packet[1] = l >>16;
  packet[2] = l >>8;
  packet[3] = l;

  unsigned int total = 0;
  unsigned int remaining = packet.length ();

  while (total < packet.length ())
  {
    int status;
    do
    {
      status = gnutls_record_send (_session, packet.c_str () + total, remaining);
    }
    while (errno == GNUTLS_E_INTERRUPTED ||
           errno == GNUTLS_E_AGAIN);

    if (status == -1)
      break;

    total     += (unsigned int) status;
    remaining -= (unsigned int) status;
  }

  if (_debug)
    std::cout << "c: INFO Sending 'XXXX"
              << data.c_str ()
              << "' (" << total << " bytes)"
              << std::endl;
}

////////////////////////////////////////////////////////////////////////////////
void TLSClient::recv (std::string& data)
{
  data = "";          // No appending of data.
  int received = 0;

  // Get the encoded length.
  unsigned char header[4] = {0};
  do
  {
    received = gnutls_record_recv (_session, header, 4);
  }
  while (received > 0 &&
         (errno == GNUTLS_E_INTERRUPTED ||
          errno == GNUTLS_E_AGAIN));

  int total = received;

  // Decode the length.
  unsigned long expected = (header[0]<<24) |
                           (header[1]<<16) |
                           (header[2]<<8) |
                            header[3];
  if (_debug)
    std::cout << "c: INFO expecting " << expected << " bytes.\n";

  // TODO This would be a good place to assert 'expected < _limit'.

  // Arbitrary buffer size.
  char buffer[MAX_BUF];

  // Keep reading until no more data.  Concatenate chunks of data if a) the
  // read was interrupted by a signal, and b) if there is more data than
  // fits in the buffer.
  do
  {
    do
    {
      received = gnutls_record_recv (_session, buffer, MAX_BUF - 1);
    }
    while (received > 0 &&
           (errno == GNUTLS_E_INTERRUPTED ||
            errno == GNUTLS_E_AGAIN));

    // Other end closed the connection.
    if (received == 0)
    {
      if (_debug)
        std::cout << "c: INFO Peer has closed the TLS connection\n";
      break;
    }

    // Something happened.
    if (received < 0)
      throw "ERROR: " + std::string (gnutls_strerror (received));

    buffer [received] = '\0';
    data += buffer;
    total += received;

    // Stop at defined limit.
    if (_limit && total > _limit)
      break;
  }
  while (received > 0 && total < (int) expected);

  if (_debug)
    std::cout << "c: INFO Receiving 'XXXX"
              << data.c_str ()
              << "' (" << total << " bytes)"
              << std::endl;
}

////////////////////////////////////////////////////////////////////////////////
#endif
<|endoftext|>


<commit_before>// ------------------------------------------------------------------------
// Pion is a development platform for building Reactors that process Events
// ------------------------------------------------------------------------
// Copyright (C) 2007-2008 Atomic Labs, Inc.  (http://www.atomiclabs.com)
//
// Pion is free software: you can redistribute it and/or modify it under the
// terms of the GNU Affero General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// Pion is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for
// more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Pion.  If not, see <http://www.gnu.org/licenses/>.
//

#include <boost/filesystem/operations.hpp>
#include <pion/platform/ConfigManager.hpp>
#include <pion/platform/DatabaseManager.hpp>
#include "SQLiteDatabase.hpp"

using namespace pion::platform;

namespace pion {		// begin namespace pion
namespace plugins {		// begin namespace plugins

// static members of SQLiteDatabase

const std::string			SQLiteDatabase::BACKUP_FILE_EXTENSION = ".bak";
const std::string			SQLiteDatabase::FILENAME_ELEMENT_NAME = "Filename";

// SQLiteDatabase member functions

void SQLiteDatabase::setConfig(const Vocabulary& v, const xmlNodePtr config_ptr)
{
	Database::setConfig(v, config_ptr);

	readConfig(config_ptr, "SQLite");

	// get the Filename of the database
	if (! ConfigManager::getConfigOption(FILENAME_ELEMENT_NAME, m_database_name, config_ptr))
		throw EmptyFilenameException(getId());

	// resolve paths relative to the platform DataDirectory
	boost::filesystem::path path_to_file(boost::filesystem::system_complete(getDatabaseManager().getDataDirectory()));
	path_to_file /= m_database_name;
	path_to_file.normalize();
	m_database_name = path_to_file.file_string();
}

DatabasePtr SQLiteDatabase::clone(void) const
{
	SQLiteDatabase *db_ptr(new SQLiteDatabase());
	db_ptr->copyDatabase(*this);
	db_ptr->m_database_name = m_database_name;
	return DatabasePtr(db_ptr);
}

void SQLiteDatabase::open(unsigned partition)
{
	// create a backup copy of the database before opening it
	const bool is_new_database = ! boost::filesystem::exists(m_database_name);
/* "no backups no more" since it's not supported by Enterprise database either...
	if (! is_new_database && create_backup) {
		const std::string backup_filename(m_database_name + BACKUP_FILE_EXTENSION);
		if (boost::filesystem::exists(backup_filename))
			boost::filesystem::remove(backup_filename);
		boost::filesystem::copy_file(m_database_name, backup_filename);
	}
*/
	// If Partitioning: Change "name.db" into "name_001.db" or, "name" into "name_001.db"
	if (partition) {
		char buff[10];
		sprintf(buff, "_%03u.db", partition);
		std::string::size_type i = 0;
		if ((i = m_database_name.find(".db", i)) != std::string::npos)
			m_database_name.replace(i, strlen(".db"), buff);
		else
			m_database_name += buff;
	}

	// open up the database
//	if (sqlite3_open_v2(m_database_name.c_str(), &m_sqlite_db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, NULL) != SQLITE_OK) {
	if (sqlite3_open_v2(m_database_name.c_str(), &m_sqlite_db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX, NULL) != SQLITE_OK) {
		// prevent memory leak (sqlite3 assigns handle even if error)
		if (m_sqlite_db != NULL) {
			sqlite3_close(m_sqlite_db);
			m_sqlite_db = NULL;
		}
		throw OpenDatabaseException(m_database_name);
	}

	// set a 10s busy timeout to deal with db locking
	sqlite3_busy_timeout(m_sqlite_db, 10000);

	// execute all PreSQL (if any)
	for (unsigned i = 0; i < m_pre_sql.size(); i++)
		if (sqlite3_exec(m_sqlite_db, m_pre_sql[i].c_str(), NULL, NULL, &m_error_ptr) != SQLITE_OK)
			throw SQLiteAPIException(getSQLiteError());
}

void SQLiteDatabase::close(void)
{
	if (m_sqlite_db != NULL)
		sqlite3_close(m_sqlite_db);
	m_sqlite_db = NULL;
}

void SQLiteDatabase::runQuery(const std::string& sql_query)
{
	// sanity checks
	PION_ASSERT(is_open());
	PION_ASSERT(! sql_query.empty());

	// execute the query
	if (sqlite3_exec(m_sqlite_db, sql_query.c_str(), NULL, NULL, &m_error_ptr) != SQLITE_OK)
		throw SQLiteAPIException(getSQLiteError());
}

QueryPtr SQLiteDatabase::addQuery(QueryID query_id,
								  const std::string& sql_query)
{
	// sanity checks
	PION_ASSERT(is_open());
	PION_ASSERT(! query_id.empty());
	PION_ASSERT(! sql_query.empty());

	// generate a new database query object
	QueryPtr query_ptr(new SQLiteQuery(sql_query, m_sqlite_db));

	// add the query to our query map
	m_query_map.insert(std::make_pair(query_id, query_ptr));

	// return the new database query object
	return query_ptr;
}

void SQLiteDatabase::createTable(const Query::FieldMap& field_map,
								std::string& table_name,
								const Query::IndexMap& index_map,
								unsigned partition)
{
	PION_ASSERT(is_open());

	// If partition is defined, change table_name
	if (partition) {
		char buff[10];
		sprintf(buff, "_%03u", partition);
		table_name += buff;
	}

	// build a SQL query to create the output table if it doesn't yet exist
	std::string create_table_sql = m_create_log;
	stringSubstitutes(create_table_sql, field_map, table_name);

	// run the SQL query to create the table
	runQuery(create_table_sql);

	// CREATE [UNIQUE] INDEX [IF NOT EXISTS] [dbname.] indexname ON tablename ( indexcolumn [, indexcolumn] )
	//		indexcolumn:  indexcolumn [COLLATE collatename] [ ASC | DESC]
	// DROP INDEX [IF EXISTS] [dbname.] indexname
	for (unsigned i = 0; i < index_map.size(); i++) {
		std::string Sql;
		const std::string idxname = table_name + "_" + field_map[i].first + "_idx";
		if (index_map[i] == "false" || index_map[i].empty())
			Sql = "DROP INDEX IF EXISTS " + idxname;
		else if (index_map[i] == "true")
			Sql = "CREATE INDEX IF NOT EXISTS " + idxname + " ON " + table_name + " ( " + field_map[i].first + " )";
		else if (index_map[i] == "unique")
			Sql = "CREATE UNIQUE INDEX IF NOT EXISTS " + idxname + " ON " + table_name + " ( " + field_map[i].first + " )";
		else
			Sql = "CREATE INDEX IF NOT EXISTS " + idxname + " ON " + table_name + " ( " + index_map[i] + " )";

		if (sqlite3_exec(m_sqlite_db, Sql.c_str(), NULL, NULL, &m_error_ptr) != SQLITE_OK)
			throw SQLiteAPIException(getSQLiteError());
	}
}

void SQLiteDatabase::dropTable(std::string& table_name, unsigned partition)
{
	if (m_sqlite_db) {
//		throw DBStillOpen(m_database_name);
		close();
		unlink(m_database_name.c_str());
		open();			// NOTE: don't id partition, it doubles up...
	} else {
		if (partition) {
			char buff[10];
			sprintf(buff, "_%03u.db", partition);
			std::string::size_type i = 0;
			if ((i = table_name.find(".db", i)) != std::string::npos)
				table_name.replace(i, strlen(".db"), buff);
			else
				table_name += buff;
		}
		unlink(table_name.c_str());
	}
}

QueryPtr SQLiteDatabase::prepareInsertQuery(const Query::FieldMap& field_map,
											const std::string& table_name)
{
	PION_ASSERT(is_open());

	// exit early if it already exists
	QueryMap::const_iterator query_it = m_query_map.find(INSERT_QUERY_ID);
	if (query_it != m_query_map.end())
		return query_it->second;

	// build a SQL query that can be used to insert a new record
	std::string insert_sql = m_insert_log;
	stringSubstitutes(insert_sql, field_map, table_name);

	// compile the SQL query into a prepared statement
	return addQuery(Database::INSERT_QUERY_ID, insert_sql);
}

QueryPtr SQLiteDatabase::getBeginTransactionQuery(void)
{
	PION_ASSERT(is_open());
	QueryMap::const_iterator i = m_query_map.find(BEGIN_QUERY_ID);
	if (i == m_query_map.end())
		return addQuery(BEGIN_QUERY_ID, m_begin_insert);
	return i->second;
}

QueryPtr SQLiteDatabase::getCommitTransactionQuery(void)
{
	PION_ASSERT(is_open());
	QueryMap::const_iterator i = m_query_map.find(COMMIT_QUERY_ID);
	if (i == m_query_map.end())
		return addQuery(COMMIT_QUERY_ID, m_commit_insert);
	return i->second;
}

QueryPtr SQLiteDatabase::prepareFullQuery(const std::string& query)
{
	PION_ASSERT(is_open());

	QueryPtr query_ptr(new SQLiteQuery(query, m_sqlite_db));
	return query_ptr;
}

bool SQLiteDatabase::SQLiteQuery::runFullQuery(const pion::platform::Query::FieldMap& ins, const pion::platform::EventPtr& src,
	const pion::platform::Query::FieldMap& outs, pion::platform::EventPtr& dest, unsigned int limit)
{
	bool changes = false;
	sqlite3_reset(m_sqlite_stmt);
	bindEvent(ins, *src);
	while (sqlite3_step(m_sqlite_stmt) == SQLITE_ROW) {
		fetchEvent(outs, dest);
		changes = true;
		if (!--limit) return changes;
	}
	return changes;
}

bool SQLiteDatabase::SQLiteQuery::runFullGetMore(const pion::platform::Query::FieldMap& outs, pion::platform::EventPtr& dest,
	unsigned int limit)
{
	bool changes = false;
	while (sqlite3_step(m_sqlite_stmt) == SQLITE_ROW) {
		fetchEvent(outs, dest);
		changes = true;
		if (!--limit) return changes;
	}
	return changes;
}

// SQLiteDatabase::SQLiteQuery member functions

SQLiteDatabase::SQLiteQuery::SQLiteQuery(const std::string& sql_query, sqlite3 *db_ptr)
	: Query(sql_query), m_sqlite_db(db_ptr), m_sqlite_stmt(NULL)
{
	PION_ASSERT(db_ptr != NULL);
	if (sqlite3_prepare_v2(m_sqlite_db, sql_query.c_str(), sql_query.size(),
						&m_sqlite_stmt, NULL) != SQLITE_OK)
		SQLiteDatabase::throwAPIException(m_sqlite_db);
	PION_ASSERT(m_sqlite_stmt != NULL);
}

bool SQLiteDatabase::SQLiteQuery::run(void)
{
	// step forward to the next row in the query (if there are any)
	bool row_available = false;
	switch (sqlite3_step(m_sqlite_stmt)) {
		case SQLITE_BUSY:
			throw SQLiteDatabase::DatabaseBusyException();
			break;
		case SQLITE_ROW:
			// a new result row is available
			row_available = true;
			break;
		case SQLITE_DONE:
			// query is finished; no more rows to return
			row_available = false;
			break;
		default:
			SQLiteDatabase::throwAPIException(m_sqlite_db);
			break;
	}
	return row_available;
}

bool SQLiteDatabase::SQLiteQuery::fetchRow(const FieldMap& field_map, EventPtr e)
{
	bool row_available = false;
	switch (sqlite3_step(m_sqlite_stmt)) {
		case SQLITE_BUSY:
			throw SQLiteDatabase::DatabaseBusyException();
			break;
		case SQLITE_ROW:
			// a new result row is available
			fetchEvent(field_map, e);
			row_available = true;
			break;
		case SQLITE_DONE:
			// query is finished; no more rows to return
//			row_available = false;
			break;
		default:
			SQLiteDatabase::throwAPIException(m_sqlite_db);
			break;
	}
	return row_available;
}

}	// end namespace plugins
}	// end namespace pion

/// creates new SQLiteDatabase objects
extern "C" PION_PLUGIN_API pion::platform::Database *pion_create_SQLiteDatabase(void) {
	return new pion::plugins::SQLiteDatabase();
}

/// destroys SQLiteDatabase objects
extern "C" PION_PLUGIN_API void pion_destroy_SQLiteDatabase(pion::plugins::SQLiteDatabase *database_ptr) {
	delete database_ptr;
}
<commit_msg>SQLite<commit_after>// ------------------------------------------------------------------------
// Pion is a development platform for building Reactors that process Events
// ------------------------------------------------------------------------
// Copyright (C) 2007-2008 Atomic Labs, Inc.  (http://www.atomiclabs.com)
//
// Pion is free software: you can redistribute it and/or modify it under the
// terms of the GNU Affero General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// Pion is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for
// more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Pion.  If not, see <http://www.gnu.org/licenses/>.
//

#include <boost/filesystem/operations.hpp>
#include <pion/platform/ConfigManager.hpp>
#include <pion/platform/DatabaseManager.hpp>
#include "SQLiteDatabase.hpp"

using namespace pion::platform;

namespace pion {		// begin namespace pion
namespace plugins {		// begin namespace plugins

// static members of SQLiteDatabase

const std::string			SQLiteDatabase::BACKUP_FILE_EXTENSION = ".bak";
const std::string			SQLiteDatabase::FILENAME_ELEMENT_NAME = "Filename";

// SQLiteDatabase member functions

void SQLiteDatabase::setConfig(const Vocabulary& v, const xmlNodePtr config_ptr)
{
	Database::setConfig(v, config_ptr);

	readConfig(config_ptr, "SQLite");

	// get the Filename of the database
	if (! ConfigManager::getConfigOption(FILENAME_ELEMENT_NAME, m_database_name, config_ptr))
		throw EmptyFilenameException(getId());

	// resolve paths relative to the platform DataDirectory
	boost::filesystem::path path_to_file(boost::filesystem::system_complete(getDatabaseManager().getDataDirectory()));
	path_to_file /= m_database_name;
	path_to_file.normalize();
	m_database_name = path_to_file.file_string();
}

DatabasePtr SQLiteDatabase::clone(void) const
{
	SQLiteDatabase *db_ptr(new SQLiteDatabase());
	db_ptr->copyDatabase(*this);
	db_ptr->m_database_name = m_database_name;
	return DatabasePtr(db_ptr);
}

std::string dbPartition(std::string name, unsigned partition)
{
	if (partition) {
		char buff[10];
		sprintf(buff, "_%03u.db", partition);
		std::string::size_type i = 0;
		if ((i = name.find(".db", i)) != std::string::npos)
			name.replace(i, strlen(".db"), buff);
		else
			name += buff;
	}
	return name;
}

void SQLiteDatabase::open(unsigned partition)
{
	// create a backup copy of the database before opening it
	const bool is_new_database = ! boost::filesystem::exists(m_database_name);
/* "no backups no more" since it's not supported by Enterprise database either...
	if (! is_new_database && create_backup) {
		const std::string backup_filename(m_database_name + BACKUP_FILE_EXTENSION);
		if (boost::filesystem::exists(backup_filename))
			boost::filesystem::remove(backup_filename);
		boost::filesystem::copy_file(m_database_name, backup_filename);
	}
*/
	// If Partitioning: Change "name.db" into "name_001.db" or, "name" into "name_001.db"
	std::string dbname = dbPartition(m_database_name, partition);

	// open up the database
//	if (sqlite3_open_v2(m_database_name.c_str(), &m_sqlite_db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, NULL) != SQLITE_OK) {
	if (sqlite3_open_v2(dbname.c_str(), &m_sqlite_db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX, NULL) != SQLITE_OK) {
		// prevent memory leak (sqlite3 assigns handle even if error)
		if (m_sqlite_db != NULL) {
			sqlite3_close(m_sqlite_db);
			m_sqlite_db = NULL;
		}
		throw OpenDatabaseException(dbname);
	}

	// set a 10s busy timeout to deal with db locking
	sqlite3_busy_timeout(m_sqlite_db, 10000);

	// execute all PreSQL (if any)
	for (unsigned i = 0; i < m_pre_sql.size(); i++)
		if (sqlite3_exec(m_sqlite_db, m_pre_sql[i].c_str(), NULL, NULL, &m_error_ptr) != SQLITE_OK)
			throw SQLiteAPIException(getSQLiteError());
}

void SQLiteDatabase::close(void)
{
	if (m_sqlite_db != NULL)
		sqlite3_close(m_sqlite_db);
	m_sqlite_db = NULL;
}

void SQLiteDatabase::runQuery(const std::string& sql_query)
{
	// sanity checks
	PION_ASSERT(is_open());
	PION_ASSERT(! sql_query.empty());

	// execute the query
	if (sqlite3_exec(m_sqlite_db, sql_query.c_str(), NULL, NULL, &m_error_ptr) != SQLITE_OK)
		throw SQLiteAPIException(getSQLiteError());
}

QueryPtr SQLiteDatabase::addQuery(QueryID query_id,
								  const std::string& sql_query)
{
	// sanity checks
	PION_ASSERT(is_open());
	PION_ASSERT(! query_id.empty());
	PION_ASSERT(! sql_query.empty());

	// generate a new database query object
	QueryPtr query_ptr(new SQLiteQuery(sql_query, m_sqlite_db));

	// add the query to our query map
	m_query_map.insert(std::make_pair(query_id, query_ptr));

	// return the new database query object
	return query_ptr;
}

void SQLiteDatabase::createTable(const Query::FieldMap& field_map,
								std::string& table_name,
								const Query::IndexMap& index_map,
								unsigned partition)
{
	PION_ASSERT(is_open());

	// If partition is defined, change table_name
	if (partition) {
		char buff[10];
		sprintf(buff, "_%03u", partition);
		table_name += buff;
	}

	// build a SQL query to create the output table if it doesn't yet exist
	std::string create_table_sql = m_create_log;
	stringSubstitutes(create_table_sql, field_map, table_name);

	// run the SQL query to create the table
	runQuery(create_table_sql);

	// CREATE [UNIQUE] INDEX [IF NOT EXISTS] [dbname.] indexname ON tablename ( indexcolumn [, indexcolumn] )
	//		indexcolumn:  indexcolumn [COLLATE collatename] [ ASC | DESC]
	// DROP INDEX [IF EXISTS] [dbname.] indexname
	for (unsigned i = 0; i < index_map.size(); i++) {
		std::string Sql;
		const std::string idxname = table_name + "_" + field_map[i].first + "_idx";
		if (index_map[i] == "false" || index_map[i].empty())
			Sql = "DROP INDEX IF EXISTS " + idxname;
		else if (index_map[i] == "true")
			Sql = "CREATE INDEX IF NOT EXISTS " + idxname + " ON " + table_name + " ( " + field_map[i].first + " )";
		else if (index_map[i] == "unique")
			Sql = "CREATE UNIQUE INDEX IF NOT EXISTS " + idxname + " ON " + table_name + " ( " + field_map[i].first + " )";
		else
			Sql = "CREATE INDEX IF NOT EXISTS " + idxname + " ON " + table_name + " ( " + index_map[i] + " )";

		if (sqlite3_exec(m_sqlite_db, Sql.c_str(), NULL, NULL, &m_error_ptr) != SQLITE_OK)
			throw SQLiteAPIException(getSQLiteError());
	}
}

void SQLiteDatabase::dropTable(std::string& table_name, unsigned partition)
{
	if (m_sqlite_db) {
		close();
		unlink(dbPartition(table_name).c_str());
		open(partition);
	} else {
		unlink(dbPartition(table_name).c_str());
	}
}

QueryPtr SQLiteDatabase::prepareInsertQuery(const Query::FieldMap& field_map,
											const std::string& table_name)
{
	PION_ASSERT(is_open());

	// exit early if it already exists
	QueryMap::const_iterator query_it = m_query_map.find(INSERT_QUERY_ID);
	if (query_it != m_query_map.end())
		return query_it->second;

	// build a SQL query that can be used to insert a new record
	std::string insert_sql = m_insert_log;
	stringSubstitutes(insert_sql, field_map, table_name);

	// compile the SQL query into a prepared statement
	return addQuery(Database::INSERT_QUERY_ID, insert_sql);
}

QueryPtr SQLiteDatabase::getBeginTransactionQuery(void)
{
	PION_ASSERT(is_open());
	QueryMap::const_iterator i = m_query_map.find(BEGIN_QUERY_ID);
	if (i == m_query_map.end())
		return addQuery(BEGIN_QUERY_ID, m_begin_insert);
	return i->second;
}

QueryPtr SQLiteDatabase::getCommitTransactionQuery(void)
{
	PION_ASSERT(is_open());
	QueryMap::const_iterator i = m_query_map.find(COMMIT_QUERY_ID);
	if (i == m_query_map.end())
		return addQuery(COMMIT_QUERY_ID, m_commit_insert);
	return i->second;
}

QueryPtr SQLiteDatabase::prepareFullQuery(const std::string& query)
{
	PION_ASSERT(is_open());

	QueryPtr query_ptr(new SQLiteQuery(query, m_sqlite_db));
	return query_ptr;
}

bool SQLiteDatabase::SQLiteQuery::runFullQuery(const pion::platform::Query::FieldMap& ins, const pion::platform::EventPtr& src,
	const pion::platform::Query::FieldMap& outs, pion::platform::EventPtr& dest, unsigned int limit)
{
	bool changes = false;
	sqlite3_reset(m_sqlite_stmt);
	bindEvent(ins, *src);
	while (sqlite3_step(m_sqlite_stmt) == SQLITE_ROW) {
		fetchEvent(outs, dest);
		changes = true;
		if (!--limit) return changes;
	}
	return changes;
}

bool SQLiteDatabase::SQLiteQuery::runFullGetMore(const pion::platform::Query::FieldMap& outs, pion::platform::EventPtr& dest,
	unsigned int limit)
{
	bool changes = false;
	while (sqlite3_step(m_sqlite_stmt) == SQLITE_ROW) {
		fetchEvent(outs, dest);
		changes = true;
		if (!--limit) return changes;
	}
	return changes;
}

// SQLiteDatabase::SQLiteQuery member functions

SQLiteDatabase::SQLiteQuery::SQLiteQuery(const std::string& sql_query, sqlite3 *db_ptr)
	: Query(sql_query), m_sqlite_db(db_ptr), m_sqlite_stmt(NULL)
{
	PION_ASSERT(db_ptr != NULL);
	if (sqlite3_prepare_v2(m_sqlite_db, sql_query.c_str(), sql_query.size(),
						&m_sqlite_stmt, NULL) != SQLITE_OK)
		SQLiteDatabase::throwAPIException(m_sqlite_db);
	PION_ASSERT(m_sqlite_stmt != NULL);
}

bool SQLiteDatabase::SQLiteQuery::run(void)
{
	// step forward to the next row in the query (if there are any)
	bool row_available = false;
	switch (sqlite3_step(m_sqlite_stmt)) {
		case SQLITE_BUSY:
			throw SQLiteDatabase::DatabaseBusyException();
			break;
		case SQLITE_ROW:
			// a new result row is available
			row_available = true;
			break;
		case SQLITE_DONE:
			// query is finished; no more rows to return
			row_available = false;
			break;
		default:
			SQLiteDatabase::throwAPIException(m_sqlite_db);
			break;
	}
	return row_available;
}

bool SQLiteDatabase::SQLiteQuery::fetchRow(const FieldMap& field_map, EventPtr e)
{
	bool row_available = false;
	switch (sqlite3_step(m_sqlite_stmt)) {
		case SQLITE_BUSY:
			throw SQLiteDatabase::DatabaseBusyException();
			break;
		case SQLITE_ROW:
			// a new result row is available
			fetchEvent(field_map, e);
			row_available = true;
			break;
		case SQLITE_DONE:
			// query is finished; no more rows to return
//			row_available = false;
			break;
		default:
			SQLiteDatabase::throwAPIException(m_sqlite_db);
			break;
	}
	return row_available;
}

}	// end namespace plugins
}	// end namespace pion

/// creates new SQLiteDatabase objects
extern "C" PION_PLUGIN_API pion::platform::Database *pion_create_SQLiteDatabase(void) {
	return new pion::plugins::SQLiteDatabase();
}

/// destroys SQLiteDatabase objects
extern "C" PION_PLUGIN_API void pion_destroy_SQLiteDatabase(pion::plugins::SQLiteDatabase *database_ptr) {
	delete database_ptr;
}
<|endoftext|>


<commit_before>
#ifndef GDT_COLLISION_DETECTION_HPP
#define GDT_COLLISION_DETECTION_HPP

namespace GDT
{
    /// Returns true if the point (x,y) is within a convex polygon.
    /**
        The shape of the polygon defined by arrayOfPairs must be convex.
        Otherwise, behavior is undefined.
        arrayOfPairs must be an array of at least size 3 of an array size 2.
        size must be the number of size-2-arrays within arrayOfPairs.
        Thus if arrayOfPairs is defined as \code{.cpp} float arrayOfPairs[4][2]
        \endcode , then size must be 4.
    */
    bool isWithinPolygon(float (*arrayOfPairs)[2], unsigned int size, float x, float y);

    /// Returns true if the point (x,y) is within a convex polygon.
    /**
        The shape of the polygon defined by arrayOfPairs must be convex.
        Otherwise, behavior is undefined.
        arrayOfPairs must be an array of at least size 6 and even.
        arraySize must be the size of arrayOfPairs.
        Thus if arrayOfPairs is defined as float arrayOfPairs[8], then
        arraySize must be 8.
        If the size of arrayOfPairs is not even, then behavior is undefined.
    */
    bool isWithinPolygon(float* arrayOfPairs, unsigned int arraySize, float x, float y);
}

#endif

<commit_msg>Fixed documentation of CollisionDetection.hpp<commit_after>
#ifndef GDT_COLLISION_DETECTION_HPP
#define GDT_COLLISION_DETECTION_HPP

namespace GDT
{
    /// Returns true if the point (x,y) is within a convex polygon.
    /**
        The shape of the polygon defined by arrayOfPairs must be convex.
        Otherwise, behavior is undefined.
        arrayOfPairs must be an array of at least size 3 of an array size 2.
        size must be the number of size-2-arrays within arrayOfPairs.
        Thus if arrayOfPairs is defined as float arrayOfPairs[4][2], then size
        must be 4.
    */
    bool isWithinPolygon(float (*arrayOfPairs)[2], unsigned int size, float x, float y);

    /// Returns true if the point (x,y) is within a convex polygon.
    /**
        The shape of the polygon defined by arrayOfPairs must be convex.
        Otherwise, behavior is undefined.
        arrayOfPairs must be an array of at least size 6 and even.
        arraySize must be the size of arrayOfPairs.
        Thus if arrayOfPairs is defined as float arrayOfPairs[8], then
        arraySize must be 8.
        If the size of arrayOfPairs is not even, then behavior is undefined.
    */
    bool isWithinPolygon(float* arrayOfPairs, unsigned int arraySize, float x, float y);
}

#endif

<|endoftext|>


<commit_before>#include "VerticalImageList.h"
#include "ListItem.h"

#include "dataset/Bitmap.h"
#include "widgets/DragTargetNull.h"

namespace d2d
{

VerticalImageList::VerticalImageList(wxWindow* parent, const wxString& name/* = wxEmptyString*/,
									 bool draggable /*= true*/)
	: wxVListBox(parent)
	, m_name(name)
{
	SetBackgroundColour(wxColour(229, 229, 229));

	Connect(GetId(), wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler(VerticalImageList::onListSelected));
	Connect(GetId(), wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, wxCommandEventHandler(VerticalImageList::onListDoubleClicked));

	if (draggable)
	{
		SetDropTarget(new DragTargetNull);
		Connect(GetId(), wxEVT_MOTION, wxMouseEventHandler(VerticalImageList::onDragInit));
	}
}

VerticalImageList::~VerticalImageList()
{
	clear();
}

void VerticalImageList::traverse(IVisitor& visitor) const
{
	std::vector<ListItem*>::const_iterator itr = m_items.begin();
	for ( ; itr != m_items.end(); ++itr)
	{
		bool hasNext;
		visitor.visit(*itr, hasNext);
		if (!hasNext) break;
	}
}

void VerticalImageList::clear()
{
	for (int i = 0, n = m_items.size(); i < n; ++i) {
		m_items[i]->release();
	}
	m_items.clear();
	SetItemCount(0);
	Refresh();
}

void VerticalImageList::insert(ListItem* item)
{
	item->retain();
	m_items.push_back(item);
	SetItemCount(m_items.size());
	SetSelection(m_items.size() - 1);
	Refresh();
}

void VerticalImageList::insertFront(ListItem* item)
{
	item->retain();
	m_items.insert(m_items.begin(), item);
	SetItemCount(m_items.size());
	SetSelection(0);
	Refresh();
}

void VerticalImageList::remove()
{
	remove(GetSelection());
}

void VerticalImageList::remove(int index)
{
	if (index < 0 || index >= m_items.size())
		return;

	m_items[index]->release();
	m_items.erase(m_items.begin() + index);
 	SetItemCount(m_items.size());
	Refresh();
}

void VerticalImageList::swap(int i0, int i1)
{
	if (i0 < 0 || i0 >= m_items.size() ||
		i1 < 0 || i1 >= m_items.size())
		return;

	ListItem* tmp = m_items[i0];
	m_items[i0] = m_items[i1];
	m_items[i1] = tmp;

	Refresh();
}

void VerticalImageList::OnDrawItem(wxDC& dc, const wxRect& rect, size_t n) const
{
	int y = rect.y + SPACE_UP;

	const Bitmap* bmp = m_items[n]->getBitmap();
	if (bmp)
	{
		// bmp
		const wxBitmap* wxBmp = bmp->getBitmap();
		int x = wxBmp->GetWidth() > rect.width ? 0 : (rect.width - wxBmp->GetWidth()) * 0.5f;
		dc.DrawBitmap(*wxBmp, x, y);

		// info
		wxString info = m_items[n]->getInfo();
		dc.SetFont(wxFont(18, wxDEFAULT, wxNORMAL, wxNORMAL));
		//dc.SetTextForeground(wxColour(0xFF, 0x20, 0xFF));
		wxSize size = dc.GetTextExtent(info);
		//dc.DrawText(info, rect.x/* + rect.width * 0.5f - size.GetWidth() * 0.5f*/, y);
		dc.DrawText(info, rect.x + SPACE_UP, y);

		y += wxBmp->GetHeight();
	}

	// name
	wxString name = m_items[n]->getName();
	dc.SetFont(wxFont(10, wxDEFAULT, wxNORMAL, wxNORMAL));
	wxSize size = dc.GetTextExtent(name);
	dc.DrawText(name, rect.x + rect.width * 0.5f - size.GetWidth() * 0.5f, y + SPACE_UP);
}

// void VerticalImageList::OnDrawBackground(wxDC& dc, const wxRect& rect, size_t n) const
// {
//   	dc.SetPen(*wxRED_PEN);
//   	dc.DrawRectangle(rect);
// }

void VerticalImageList::OnDrawSeparator(wxDC& dc, wxRect& rect, size_t n) const
{
	dc.SetPen(wxPen(wxColour(0, 0, 0), 3));
	dc.DrawLine(rect.GetLeftBottom(), rect.GetRightBottom());
}

wxCoord VerticalImageList::OnMeasureItem(size_t n) const
{
	const Bitmap* bmp = m_items[n]->getBitmap();
	if (bmp)
		return bmp->getBitmap()->GetHeight() + SPACE_UP + SPACE_DOWN;
	else
		return SPACE_UP + SPACE_DOWN;
}

void VerticalImageList::onDragInit(wxMouseEvent& event)
{
	if (event.Dragging())
	{
		wxTextDataObject tdo(m_name + "," + wxString::FromDouble(GetSelection()));
		wxDropSource ds(tdo);
		ds.DoDragDrop(wxDrag_CopyOnly);
	}
}
} // d2d<commit_msg>[FIXED] 缩略图某些机器加载bmp会失败<commit_after>#include "VerticalImageList.h"
#include "ListItem.h"

#include "dataset/Bitmap.h"
#include "widgets/DragTargetNull.h"

namespace d2d
{

VerticalImageList::VerticalImageList(wxWindow* parent, const wxString& name/* = wxEmptyString*/,
									 bool draggable /*= true*/)
	: wxVListBox(parent)
	, m_name(name)
{
	SetBackgroundColour(wxColour(229, 229, 229));

	Connect(GetId(), wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler(VerticalImageList::onListSelected));
	Connect(GetId(), wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, wxCommandEventHandler(VerticalImageList::onListDoubleClicked));

	if (draggable)
	{
		SetDropTarget(new DragTargetNull);
		Connect(GetId(), wxEVT_MOTION, wxMouseEventHandler(VerticalImageList::onDragInit));
	}
}

VerticalImageList::~VerticalImageList()
{
	clear();
}

void VerticalImageList::traverse(IVisitor& visitor) const
{
	std::vector<ListItem*>::const_iterator itr = m_items.begin();
	for ( ; itr != m_items.end(); ++itr)
	{
		bool hasNext;
		visitor.visit(*itr, hasNext);
		if (!hasNext) break;
	}
}

void VerticalImageList::clear()
{
	for (int i = 0, n = m_items.size(); i < n; ++i) {
		m_items[i]->release();
	}
	m_items.clear();
	SetItemCount(0);
	Refresh();
}

void VerticalImageList::insert(ListItem* item)
{
	item->retain();
	m_items.push_back(item);
	SetItemCount(m_items.size());
	SetSelection(m_items.size() - 1);
	Refresh();
}

void VerticalImageList::insertFront(ListItem* item)
{
	item->retain();
	m_items.insert(m_items.begin(), item);
	SetItemCount(m_items.size());
	SetSelection(0);
	Refresh();
}

void VerticalImageList::remove()
{
	remove(GetSelection());
}

void VerticalImageList::remove(int index)
{
	if (index < 0 || index >= m_items.size())
		return;

	m_items[index]->release();
	m_items.erase(m_items.begin() + index);
 	SetItemCount(m_items.size());
	Refresh();
}

void VerticalImageList::swap(int i0, int i1)
{
	if (i0 < 0 || i0 >= m_items.size() ||
		i1 < 0 || i1 >= m_items.size())
		return;

	ListItem* tmp = m_items[i0];
	m_items[i0] = m_items[i1];
	m_items[i1] = tmp;

	Refresh();
}

void VerticalImageList::OnDrawItem(wxDC& dc, const wxRect& rect, size_t n) const
{
	int y = rect.y + SPACE_UP;

	const Bitmap* bmp = m_items[n]->getBitmap();
	if (bmp)
	{
		const wxBitmap* wxBmp = bmp->getBitmap();
		if (wxBmp)
		{
			// bmp
			int x = wxBmp->GetWidth() > rect.width ? 0 : (rect.width - wxBmp->GetWidth()) * 0.5f;
			dc.DrawBitmap(*wxBmp, x, y);

			// info
			wxString info = m_items[n]->getInfo();
			dc.SetFont(wxFont(18, wxDEFAULT, wxNORMAL, wxNORMAL));
			//dc.SetTextForeground(wxColour(0xFF, 0x20, 0xFF));
			wxSize size = dc.GetTextExtent(info);
			//dc.DrawText(info, rect.x/* + rect.width * 0.5f - size.GetWidth() * 0.5f*/, y);
			dc.DrawText(info, rect.x + SPACE_UP, y);

			y += wxBmp->GetHeight();
		}
	}

	// name
	wxString name = m_items[n]->getName();
	dc.SetFont(wxFont(10, wxDEFAULT, wxNORMAL, wxNORMAL));
	wxSize size = dc.GetTextExtent(name);
	dc.DrawText(name, rect.x + rect.width * 0.5f - size.GetWidth() * 0.5f, y + SPACE_UP);
}

// void VerticalImageList::OnDrawBackground(wxDC& dc, const wxRect& rect, size_t n) const
// {
//   	dc.SetPen(*wxRED_PEN);
//   	dc.DrawRectangle(rect);
// }

void VerticalImageList::OnDrawSeparator(wxDC& dc, wxRect& rect, size_t n) const
{
	dc.SetPen(wxPen(wxColour(0, 0, 0), 3));
	dc.DrawLine(rect.GetLeftBottom(), rect.GetRightBottom());
}

wxCoord VerticalImageList::OnMeasureItem(size_t n) const
{
	int size = SPACE_UP + SPACE_DOWN;
	const Bitmap* bmp = m_items[n]->getBitmap();
	if (bmp) {
		const wxBitmap* wxBmp = bmp->getBitmap();
		if (wxBmp) {
			size = wxBmp->GetHeight() + SPACE_UP + SPACE_DOWN;
		}
	}
	return size;
}

void VerticalImageList::onDragInit(wxMouseEvent& event)
{
	if (event.Dragging())
	{
		wxTextDataObject tdo(m_name + "," + wxString::FromDouble(GetSelection()));
		wxDropSource ds(tdo);
		ds.DoDragDrop(wxDrag_CopyOnly);
	}
}
} // d2d<|endoftext|>


<commit_before>/*
    Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>

    This file is part of Magnum.

    Magnum is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License version 3
    only, as published by the Free Software Foundation.

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

#include "Font.h"

#include <ft2build.h>
#include FT_FREETYPE_H
#include <hb-ft.h>

#include "Extensions.h"
#include "Image.h"
#include "TextureTools/Atlas.h"

namespace Magnum { namespace Text {

Font::Font(FontRenderer& renderer, const std::string& fontFile, GLfloat size): _size(size) {
    #ifndef MAGNUM_TARGET_GLES
    MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::texture_rg);
    #else
    MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::EXT::texture_rg);
    #endif

    /* Create FreeType font */
    CORRADE_INTERNAL_ASSERT(FT_New_Face(renderer.library(), fontFile.c_str(), 0, &_ftFont) == 0);
    CORRADE_INTERNAL_ASSERT(FT_Set_Char_Size(_ftFont, 0, _size*64, 100, 100) == 0);

    /* Create Harfbuzz font */
    _hbFont = hb_ft_font_create(_ftFont, nullptr);

    /* Set up the texture */
    _texture.setWrapping(Texture2D::Wrapping::ClampToEdge)
        ->setMinificationFilter(Texture2D::Filter::LinearInterpolation)
        ->setMagnificationFilter(Texture2D::Filter::LinearInterpolation);
}

void Font::prerender(const std::string& characters, const Vector2i& atlasSize) {
    glyphs.clear();

    /** @bug Crash when atlas is too small */
    /** @todo Get rid of duplicate characters */

    /* Get character codes from string */
    /** @todo proper UTF-8 decoding */
    std::vector<std::uint32_t> charCodes(characters.begin(), characters.end());

    /* Get character indices */
    std::vector<FT_UInt> charIndices;
    charIndices.push_back(0);
    for(std::uint32_t charCode: charCodes)
        charIndices.push_back(FT_Get_Char_Index(_ftFont, charCode));

    /* Sizes of all characters */
    std::vector<Vector2i> charSizes;
    charSizes.reserve(charIndices.size());
    for(FT_UInt c: charIndices) {
        CORRADE_INTERNAL_ASSERT(FT_Load_Glyph(_ftFont, c, FT_LOAD_DEFAULT) == 0);
        charSizes.push_back((Vector2i(_ftFont->glyph->metrics.width, _ftFont->glyph->metrics.height))/64);
    }

    /* Create texture atlas */
    std::vector<Rectanglei> charPositions = TextureTools::atlas(atlasSize, charSizes);

    /* Render all characters to the atlas and create character map */
    glyphs.reserve(charPositions.size());
    unsigned char* pixmap = new unsigned char[atlasSize.product()]();
    Image2D image(atlasSize, Image2D::Format::Red, Image2D::Type::UnsignedByte, pixmap);
    for(std::size_t i = 0; i != charPositions.size(); ++i) {
        /* Load and render glyph */
        /** @todo B&W only */
        FT_GlyphSlot glyph = _ftFont->glyph;
        CORRADE_INTERNAL_ASSERT(FT_Load_Glyph(_ftFont, charIndices[i], FT_LOAD_DEFAULT) == 0);
        CORRADE_INTERNAL_ASSERT(FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL) == 0);

        /* Copy rendered bitmap to texture image */
        const FT_Bitmap& bitmap = glyph->bitmap;
        CORRADE_INTERNAL_ASSERT(std::abs(bitmap.width-charPositions[i].width()) <= 2);
        CORRADE_INTERNAL_ASSERT(std::abs(bitmap.rows-charPositions[i].height()) <= 2);
        for(std::int32_t yin = 0, yout = charPositions[i].bottom(), ymax = bitmap.rows; yin != ymax; ++yin, ++yout)
            for(std::int32_t xin = 0, xout = charPositions[i].left(), xmax = bitmap.width; xin != xmax; ++xin, ++xout)
                pixmap[yout*atlasSize.x() + xout] = bitmap.buffer[(bitmap.rows-yin-1)*bitmap.width + xin];

        /* Save character texture position and texture coordinates for given character index */
        glyphs.insert({charIndices[i], std::make_tuple(
            Rectangle::fromSize(Vector2(glyph->bitmap_left, glyph->bitmap_top-charPositions[i].height())/_size,
                                Vector2(charPositions[i].size())/_size),
            Rectangle(Vector2(charPositions[i].bottomLeft())/atlasSize,
                      Vector2(charPositions[i].topRight())/atlasSize)
        )});
    }

    /* Set texture data */
    #ifndef MAGNUM_TARGET_GLES
    _texture.setImage(0, Texture2D::InternalFormat::R8, &image);
    #else
    _texture.setImage(0, Texture2D::InternalFormat::Red, &image);
    #endif
}

void Font::destroy() {
    if(!_ftFont) return;

    hb_font_destroy(_hbFont);
    FT_Done_Face(_ftFont);
}

void Font::move() {
    _hbFont = nullptr;
    _ftFont = nullptr;
}

Font::~Font() { destroy(); }

Font::Font(Font&& other): glyphs(std::move(other.glyphs)), _texture(std::move(other._texture)), _ftFont(other._ftFont), _hbFont(other._hbFont), _size(other._size) {
    other.move();
}

Font& Font::operator=(Font&& other) {
    destroy();

    glyphs = std::move(other.glyphs);
    _texture = std::move(other._texture);
    _ftFont = other._ftFont;
    _hbFont = other._hbFont;
    _size = other._size;

    other.move();
    return *this;
}

const std::tuple<Rectangle, Rectangle>& Font::operator[](std::uint32_t character) const {
    auto it = glyphs.find(character);

    if(it == glyphs.end())
        return glyphs.at(0);
    return it->second;
}

}}
<commit_msg>Text: removing duplicate glyphs in Font::prerender().<commit_after>/*
    Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>

    This file is part of Magnum.

    Magnum is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License version 3
    only, as published by the Free Software Foundation.

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

#include "Font.h"

#include <algorithm>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <hb-ft.h>

#include "Extensions.h"
#include "Image.h"
#include "TextureTools/Atlas.h"

namespace Magnum { namespace Text {

Font::Font(FontRenderer& renderer, const std::string& fontFile, GLfloat size): _size(size) {
    #ifndef MAGNUM_TARGET_GLES
    MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::texture_rg);
    #else
    MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::EXT::texture_rg);
    #endif

    /* Create FreeType font */
    CORRADE_INTERNAL_ASSERT(FT_New_Face(renderer.library(), fontFile.c_str(), 0, &_ftFont) == 0);
    CORRADE_INTERNAL_ASSERT(FT_Set_Char_Size(_ftFont, 0, _size*64, 100, 100) == 0);

    /* Create Harfbuzz font */
    _hbFont = hb_ft_font_create(_ftFont, nullptr);

    /* Set up the texture */
    _texture.setWrapping(Texture2D::Wrapping::ClampToEdge)
        ->setMinificationFilter(Texture2D::Filter::LinearInterpolation)
        ->setMagnificationFilter(Texture2D::Filter::LinearInterpolation);
}

void Font::prerender(const std::string& characters, const Vector2i& atlasSize) {
    glyphs.clear();

    /** @bug Crash when atlas is too small */

    /* Get character codes from string */
    /** @todo proper UTF-8 decoding */
    std::vector<std::uint32_t> charCodes(characters.begin(), characters.end());

    /* Get character indices */
    std::vector<FT_UInt> charIndices;
    charIndices.push_back(0);
    for(std::uint32_t charCode: charCodes)
        charIndices.push_back(FT_Get_Char_Index(_ftFont, charCode));

    /* Remove duplicates (e.g. uppercase and lowercase mapped to same glyph) */
    std::sort(charIndices.begin(), charIndices.end());
    charIndices.erase(std::unique(charIndices.begin(), charIndices.end()), charIndices.end());

    /* Sizes of all characters */
    std::vector<Vector2i> charSizes;
    charSizes.reserve(charIndices.size());
    for(FT_UInt c: charIndices) {
        CORRADE_INTERNAL_ASSERT(FT_Load_Glyph(_ftFont, c, FT_LOAD_DEFAULT) == 0);
        charSizes.push_back((Vector2i(_ftFont->glyph->metrics.width, _ftFont->glyph->metrics.height))/64);
    }

    /* Create texture atlas */
    std::vector<Rectanglei> charPositions = TextureTools::atlas(atlasSize, charSizes);

    /* Render all characters to the atlas and create character map */
    glyphs.reserve(charPositions.size());
    unsigned char* pixmap = new unsigned char[atlasSize.product()]();
    Image2D image(atlasSize, Image2D::Format::Red, Image2D::Type::UnsignedByte, pixmap);
    for(std::size_t i = 0; i != charPositions.size(); ++i) {
        /* Load and render glyph */
        /** @todo B&W only */
        FT_GlyphSlot glyph = _ftFont->glyph;
        CORRADE_INTERNAL_ASSERT(FT_Load_Glyph(_ftFont, charIndices[i], FT_LOAD_DEFAULT) == 0);
        CORRADE_INTERNAL_ASSERT(FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL) == 0);

        /* Copy rendered bitmap to texture image */
        const FT_Bitmap& bitmap = glyph->bitmap;
        CORRADE_INTERNAL_ASSERT(std::abs(bitmap.width-charPositions[i].width()) <= 2);
        CORRADE_INTERNAL_ASSERT(std::abs(bitmap.rows-charPositions[i].height()) <= 2);
        for(std::int32_t yin = 0, yout = charPositions[i].bottom(), ymax = bitmap.rows; yin != ymax; ++yin, ++yout)
            for(std::int32_t xin = 0, xout = charPositions[i].left(), xmax = bitmap.width; xin != xmax; ++xin, ++xout)
                pixmap[yout*atlasSize.x() + xout] = bitmap.buffer[(bitmap.rows-yin-1)*bitmap.width + xin];

        /* Save character texture position and texture coordinates for given character index */
        glyphs.insert({charIndices[i], std::make_tuple(
            Rectangle::fromSize(Vector2(glyph->bitmap_left, glyph->bitmap_top-charPositions[i].height())/_size,
                                Vector2(charPositions[i].size())/_size),
            Rectangle(Vector2(charPositions[i].bottomLeft())/atlasSize,
                      Vector2(charPositions[i].topRight())/atlasSize)
        )});
    }

    /* Set texture data */
    #ifndef MAGNUM_TARGET_GLES
    _texture.setImage(0, Texture2D::InternalFormat::R8, &image);
    #else
    _texture.setImage(0, Texture2D::InternalFormat::Red, &image);
    #endif
}

void Font::destroy() {
    if(!_ftFont) return;

    hb_font_destroy(_hbFont);
    FT_Done_Face(_ftFont);
}

void Font::move() {
    _hbFont = nullptr;
    _ftFont = nullptr;
}

Font::~Font() { destroy(); }

Font::Font(Font&& other): glyphs(std::move(other.glyphs)), _texture(std::move(other._texture)), _ftFont(other._ftFont), _hbFont(other._hbFont), _size(other._size) {
    other.move();
}

Font& Font::operator=(Font&& other) {
    destroy();

    glyphs = std::move(other.glyphs);
    _texture = std::move(other._texture);
    _ftFont = other._ftFont;
    _hbFont = other._hbFont;
    _size = other._size;

    other.move();
    return *this;
}

const std::tuple<Rectangle, Rectangle>& Font::operator[](std::uint32_t character) const {
    auto it = glyphs.find(character);

    if(it == glyphs.end())
        return glyphs.at(0);
    return it->second;
}

}}
<|endoftext|>


<commit_before>// -*- coding: us-ascii-unix -*-
// Copyright 2014 Lukas Kemmer
//
// Licensed under the Apache License, Version 2.0 (the "License"); you
// may not use this file except in compliance with the License. You
// may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.

#ifndef FAINT_MEASURE_HH
#define FAINT_MEASURE_HH
#include <vector>
#include "geo/geo-fwd.hh"
#include "geo/primitive.hh"

namespace faint{

// Returns the angle of the line in the interval [0, 2pi],
// with angles increasing counter-clockwise.
// <../doc/angle360_ccw.png>
Angle angle360_ccw(const LineSegment&);

// Note: returns an 1x1 rectangle with TopLeft IntPoint,
// This is required by the variadic bounding_rect implementation.
IntRect bounding_rect(const IntPoint&);

IntRect bounding_rect(const IntPoint&, const IntPoint&);
IntRect bounding_rect(const IntLineSegment&);
IntRect bounding_rect(const IntRect&, const IntRect&);

// Note: Returns a 1x1 rectangle situated at Point.
// This is required by the variadic bounding_rect implementation.
Rect bounding_rect(const Point&);

Rect bounding_rect(const Point&, const Point&);
Rect bounding_rect(const Rect&);
Rect bounding_rect(const Rect&, const Rect&);
Rect bounding_rect(const LineSegment&);

template<class A, class ...B>
auto bounding_rect(const A& head, const B&... tail)
  -> decltype(bounding_rect(head))
{
  return bounding_rect(bounding_rect(head), bounding_rect(tail...));
}

// Returns the positive distance between the points. Insensitive to
// ordering.
coord distance(const IntPoint&, const IntPoint&);
coord distance(const Point&, const Point&);

// Approximates the length of the Bezier curve from start, using the
// line distance for the specified number of subdivisions. A higher
// number of subdivisions gives a better approximation, but is more
// time consuming.
coord distance(const Point& start, const CubicBezier&, int subdivisions);

// a and b are diameters
coord ellipse_perimeter(coord a, coord b);
coord ellipse_perimeter(const Radii&);

// Returns the angle between the positive x-axis and the line in the
// interval (-pi, pi], with positive angles on the lower semi-circle
// (Pretty much the same as atan2!)
// <../doc/line_angle_cw.png>
Angle line_angle_cw(const LineSegment&);

Point mid_point(const LineSegment&);
Point mid_point(const Point&, const Point&);

// Returns the mid_point between all points in the vector. The
// returned vector will contain one point less than source vector,
// or no points if the source was empty.
std::vector<Point> mid_points(const std::vector<Point>&);

// Returns the points with the mid-points between adjacent points
// interspersed.
// For {p1, p2, p3}, returns {p1, m(p1, p2), p2, m(p2, p3), p3}
std::vector<Point> with_mid_points(const std::vector<Point>&);

// Returns the points with the mid-points between adjacent points
// interspersed, including the mid-point between the last and first
// points (as implied by cyclic).
// For {p1, p2, p3}, returns {m(p3, p1), p1, m(p2, p1), p2, m(p2, p3), p3}
std::vector<Point> with_mid_points_cyclic(const std::vector<Point>&);

coord perimeter(const std::vector<PathPt>&);

} // namespace

#endif
<commit_msg>Whitespace.<commit_after>// -*- coding: us-ascii-unix -*-
// Copyright 2014 Lukas Kemmer
//
// Licensed under the Apache License, Version 2.0 (the "License"); you
// may not use this file except in compliance with the License. You
// may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.

#ifndef FAINT_MEASURE_HH
#define FAINT_MEASURE_HH
#include <vector>
#include "geo/geo-fwd.hh"
#include "geo/primitive.hh"

namespace faint{

// Returns the angle of the line in the interval [0, 2pi],
// with angles increasing counter-clockwise.
// <../doc/angle360_ccw.png>
Angle angle360_ccw(const LineSegment&);

// Note: returns an 1x1 rectangle with TopLeft IntPoint,
// This is required by the variadic bounding_rect implementation.
IntRect bounding_rect(const IntPoint&);

IntRect bounding_rect(const IntPoint&, const IntPoint&);
IntRect bounding_rect(const IntLineSegment&);
IntRect bounding_rect(const IntRect&, const IntRect&);

// Note: Returns a 1x1 rectangle situated at Point.
// This is required by the variadic bounding_rect implementation.
Rect bounding_rect(const Point&);

Rect bounding_rect(const Point&, const Point&);
Rect bounding_rect(const Rect&);
Rect bounding_rect(const Rect&, const Rect&);
Rect bounding_rect(const LineSegment&);

template<class A, class ...B>
auto bounding_rect(const A& head, const B&... tail)
  -> decltype(bounding_rect(head))
{
  return bounding_rect(bounding_rect(head), bounding_rect(tail...));
}

// Returns the positive distance between the points. Insensitive to
// ordering.
coord distance(const IntPoint&, const IntPoint&);
coord distance(const Point&, const Point&);

// Approximates the length of the Bezier curve from start, using the
// line distance for the specified number of subdivisions. A higher
// number of subdivisions gives a better approximation, but is more
// time consuming.
coord distance(const Point& start, const CubicBezier&, int subdivisions);

// a and b are diameters
coord ellipse_perimeter(coord a, coord b);
coord ellipse_perimeter(const Radii&);

// Returns the angle between the positive x-axis and the line in the
// interval (-pi, pi], with positive angles on the lower semi-circle
// (Pretty much the same as atan2!)
// <../doc/line_angle_cw.png>
Angle line_angle_cw(const LineSegment&);

Point mid_point(const LineSegment&);
Point mid_point(const Point&, const Point&);

// Returns the mid_point between all points in the vector. The
// returned vector will contain one point less than source vector,
// or no points if the source was empty.
std::vector<Point> mid_points(const std::vector<Point>&);

// Returns the points with the mid-points between adjacent points
// interspersed.
// For {p1, p2, p3}, returns {p1, m(p1, p2), p2, m(p2, p3), p3}
std::vector<Point> with_mid_points(const std::vector<Point>&);

// Returns the points with the mid-points between adjacent points
// interspersed, including the mid-point between the last and first
// points (as implied by cyclic).
// For {p1, p2, p3}, returns {m(p3, p1), p1, m(p2, p1), p2, m(p2, p3), p3}
std::vector<Point> with_mid_points_cyclic(const std::vector<Point>&);

coord perimeter(const std::vector<PathPt>&);

} // namespace

#endif
<|endoftext|>


<commit_before>#include "drake/systems/plants/RigidBodySystem.h"
#include "drake/util/testUtil.h"

using namespace std;
using namespace Drake;
using namespace Eigen;

Vector3d getAccelerometerOutput(shared_ptr<RigidBodySystem> const& sys, Vector3d const& rpy, Vector4d const& u) {
  VectorXd x0 = VectorXd::Zero(sys->getNumStates());
  auto const & tree = sys->getRigidBodyTree();
  x0.head(tree->num_positions) = tree->getZeroConfiguration();
  x0.segment(3, 4) = rpy2quat(rpy);
  auto const& output = sys->output(0, x0, u).tail<3>();
  return output;
}

int main(int argc, char* argv[]) {

  DrakeJoint::FloatingBaseType floating_base_type = DrakeJoint::QUATERNION;
  auto rigid_body_sys = make_shared<RigidBodySystem>();
  rigid_body_sys->addRobotFromFile(getDrakePath()+"/examples/Quadrotor/quadrotor.urdf", floating_base_type);
  auto const & tree = rigid_body_sys->getRigidBodyTree();
  auto sensor_frame = tree->frames[0]; //this is a propellor frame.  probably want a body frame for this
  auto accelerometer = make_shared<RigidBodyAccelerometer>(*rigid_body_sys, "accelerometer", sensor_frame);
  rigid_body_sys->addSensor(accelerometer);
  const double g = 9.81;
  const double tol = 1e-6;
  const Vector4d hoverThrust = 1.226250 * Vector4d::Ones();

  valuecheckMatrix(getAccelerometerOutput(rigid_body_sys, Vector3d::Zero(), Vector4d::Zero()),
                   Vector3d(0, 0, -g),
                   tol);

  valuecheckMatrix(getAccelerometerOutput(rigid_body_sys, Vector3d(M_PI, 0, 0), Vector4d::Zero()), //inverted
                   Vector3d(0, 0, g),
                   tol);

  valuecheckMatrix(getAccelerometerOutput(rigid_body_sys, Vector3d::Zero(), hoverThrust),
                   Vector3d(0, 0, 0),
                   tol);

  valuecheckMatrix(getAccelerometerOutput(rigid_body_sys, Vector3d(M_PI, 0, 0), hoverThrust), //inverted with thrust
                   Vector3d(0, 0, 2*g),
                   tol);

  valuecheckMatrix(getAccelerometerOutput(rigid_body_sys, Vector3d(M_PI/2, 0, 0), Vector4d::Zero()),
                   Vector3d(0, -g, 0),
                   tol);

  valuecheckMatrix(getAccelerometerOutput(rigid_body_sys, Vector3d(-M_PI/2, 0, 0), Vector4d::Zero()),
                   Vector3d(0, g, 0),
                   tol);

  valuecheckMatrix(getAccelerometerOutput(rigid_body_sys, Vector3d(0, M_PI/2, 0), Vector4d::Zero()),
                   Vector3d(g, 0, 0),
                   tol);

  valuecheckMatrix(getAccelerometerOutput(rigid_body_sys, Vector3d(0, -M_PI/2, 0), Vector4d::Zero()),
                   Vector3d(-g, 0, 0),
                   tol);

}
<commit_msg>fixed Eigen invalid memory read issue<commit_after>#include "drake/systems/plants/RigidBodySystem.h"
#include "drake/util/testUtil.h"

using namespace std;
using namespace Drake;
using namespace Eigen;

Vector3d getAccelerometerOutput(shared_ptr<RigidBodySystem> const& sys, Vector3d const& rpy, Vector4d const& u) {
  VectorXd x0 = VectorXd::Zero(sys->getNumStates());
  auto const & tree = sys->getRigidBodyTree();
  x0.head(tree->num_positions) = tree->getZeroConfiguration();
  x0.segment(3, 4) = rpy2quat(rpy);
  auto const& system_output = sys->output(0, x0, u);
  return system_output.tail<3>();
}

int main(int argc, char* argv[]) {

  DrakeJoint::FloatingBaseType floating_base_type = DrakeJoint::QUATERNION;
  auto rigid_body_sys = make_shared<RigidBodySystem>();
  rigid_body_sys->addRobotFromFile(getDrakePath()+"/examples/Quadrotor/quadrotor.urdf", floating_base_type);
  auto const & tree = rigid_body_sys->getRigidBodyTree();
  auto sensor_frame = tree->frames[0]; //this is a propellor frame.  probably want a body frame for this
  auto accelerometer = make_shared<RigidBodyAccelerometer>(*rigid_body_sys, "accelerometer", sensor_frame);
  rigid_body_sys->addSensor(accelerometer);
  const double g = 9.81;
  const double tol = 1e-6;
  const Vector4d hoverThrust = 1.226250 * Vector4d::Ones();

  valuecheckMatrix(getAccelerometerOutput(rigid_body_sys, Vector3d::Zero(), Vector4d::Zero()),
                   Vector3d(0, 0, -g),
                   tol);

  valuecheckMatrix(getAccelerometerOutput(rigid_body_sys, Vector3d(M_PI, 0, 0), Vector4d::Zero()), //inverted
                   Vector3d(0, 0, g),
                   tol);

  valuecheckMatrix(getAccelerometerOutput(rigid_body_sys, Vector3d::Zero(), hoverThrust),
                   Vector3d(0, 0, 0),
                   tol);

  valuecheckMatrix(getAccelerometerOutput(rigid_body_sys, Vector3d(M_PI, 0, 0), hoverThrust), //inverted with thrust
                   Vector3d(0, 0, 2*g),
                   tol);

  valuecheckMatrix(getAccelerometerOutput(rigid_body_sys, Vector3d(M_PI/2, 0, 0), Vector4d::Zero()),
                   Vector3d(0, -g, 0),
                   tol);

  valuecheckMatrix(getAccelerometerOutput(rigid_body_sys, Vector3d(-M_PI/2, 0, 0), Vector4d::Zero()),
                   Vector3d(0, g, 0),
                   tol);

  valuecheckMatrix(getAccelerometerOutput(rigid_body_sys, Vector3d(0, M_PI/2, 0), Vector4d::Zero()),
                   Vector3d(g, 0, 0),
                   tol);

  valuecheckMatrix(getAccelerometerOutput(rigid_body_sys, Vector3d(0, -M_PI/2, 0), Vector4d::Zero()),
                   Vector3d(-g, 0, 0),
                   tol);

}
<|endoftext|>


<commit_before>#include <string>
#include "nbind/api.h"
#include "control.h"
#include "ui.h"

class UiCheckbox : public UiControl {
	DEFINE_EVENT(onToggled)

  public:
	UiCheckbox(std::string text);
	UiCheckbox();
	DEFINE_CONTROL_METHODS()
	void setText(std::string text);
	std::string getText();
	void setChecked(bool checked);
	bool getChecked();
	~UiCheckbox();
	void onDestroy(uiControl *control) override;
};

void UiCheckbox::onDestroy(uiControl *control) {
	/*
		freeing event callbacks to allow JS to garbage collect this class
		when there are no references to it left in JS code.
	*/
	DISPOSE_EVENT(onToggled);
}

UiCheckbox::~UiCheckbox() {
	// printf("UiCheckbox %p destroyed with wrapper %p.\n", getHandle(), this);
}

IMPLEMENT_EVENT(UiCheckbox, uiCheckbox, onToggled, uiCheckboxOnToggled)

UiCheckbox::UiCheckbox(std::string text)
	: UiControl(uiControl(uiNewCheckbox(text.c_str()))) {}
UiCheckbox::UiCheckbox() : UiControl(uiControl(uiNewCheckbox(""))) {}

INHERITS_CONTROL_METHODS(UiCheckbox)

void UiCheckbox::setText(std::string text) {
	uiCheckboxSetText(uiCheckbox(getHandle()), text.c_str());
}

std::string UiCheckbox::getText() {
	char *char_ptr = uiCheckboxText(uiCheckbox(getHandle()));
	std::string s(char_ptr);
	uiFreeText(char_ptr);
	return s;
}

void UiCheckbox::setChecked(bool checked) {
	uiCheckboxSetChecked(uiCheckbox(getHandle()), checked);
	if (onToggledCallback != NULL) {
		(*onToggledCallback)();
	}
}

bool UiCheckbox::getChecked() {
	return uiCheckboxChecked(uiCheckbox(getHandle()));
}

NBIND_CLASS(UiCheckbox) {
	construct<std::string>();
	construct<>();
	DECLARE_CHILD_CONTROL_METHODS()
	getset(getChecked, setChecked);
	getset(getText, setText);
	method(getChecked);
	method(setChecked);
	method(getText);
	method(setText);
	method(onToggled);
}
<commit_msg>removed macro -> UiCheckbox<commit_after>#include <string>
#include "nbind/api.h"
#include "control.h"
#include "ui.h"

class UiCheckbox : public UiControl {
	DEFINE_EVENT(onToggled)

  public:
	UiCheckbox(std::string text);
	UiCheckbox();
	void setText(std::string text);
	std::string getText();
	void setChecked(bool checked);
	bool getChecked();
	~UiCheckbox();
	void onDestroy(uiControl *control) override;
};

void UiCheckbox::onDestroy(uiControl *control) {
	/*
		freeing event callbacks to allow JS to garbage collect this class
		when there are no references to it left in JS code.
	*/
	DISPOSE_EVENT(onToggled);
}

UiCheckbox::~UiCheckbox() {
	// printf("UiCheckbox %p destroyed with wrapper %p.\n", getHandle(), this);
}

IMPLEMENT_EVENT(UiCheckbox, uiCheckbox, onToggled, uiCheckboxOnToggled)

UiCheckbox::UiCheckbox(std::string text)
	: UiControl(uiControl(uiNewCheckbox(text.c_str()))) {}
UiCheckbox::UiCheckbox() : UiControl(uiControl(uiNewCheckbox(""))) {}

void UiCheckbox::setText(std::string text) {
	uiCheckboxSetText(uiCheckbox(getHandle()), text.c_str());
}

std::string UiCheckbox::getText() {
	char *char_ptr = uiCheckboxText(uiCheckbox(getHandle()));
	std::string s(char_ptr);
	uiFreeText(char_ptr);
	return s;
}

void UiCheckbox::setChecked(bool checked) {
	uiCheckboxSetChecked(uiCheckbox(getHandle()), checked);
	if (onToggledCallback != NULL) {
		(*onToggledCallback)();
	}
}

bool UiCheckbox::getChecked() {
	return uiCheckboxChecked(uiCheckbox(getHandle()));
}

NBIND_CLASS(UiCheckbox) {
	inherit(UiControl);
	construct<std::string>();
	construct<>();
	getset(getChecked, setChecked);
	getset(getText, setText);
	method(getChecked);
	method(setChecked);
	method(getText);
	method(setText);
	method(onToggled);
}
<|endoftext|>