<commit_before>#include "stretch.h"
#include <algorithm>

// NOTE: This is everything but beautyful code. Unfortunately, I can't come up with a better way
//       to solve this problem. If you know a more elegant solution, please contact me.
//       Even tough I tried my best to comment and explain as much as possible, I wouldn't recommend
//       spending more time in here than necessary.

namespace ncurses
{
    Resize_data::Resize_data (
            const std::vector < std::shared_ptr < Element > >* elements,
            const std::shared_ptr < Window >& window,
            const std::shared_ptr < Orientation >& orientation
            ):
        window ( window ),
        elements ( elements ),
        already_used_length ( 0 )
    {
        // Create prefered_length_sum
        prefered_length_sum = 0;
        std::for_each ( elements->begin (), elements->end (),
                [ & ] ( std::shared_ptr < Element > element )
                    { prefered_length_sum += orientation->get_prefered_length ( element ); } );

        // Create no_preference_element_count
        no_preference_element_count = std::count_if ( elements->begin (), elements->end (),
                [ & ] ( std::shared_ptr < Element > element )
                    { return orientation->get_prefered_length ( element ) == 0; } );
    }

    void Stretch_layout::update_elements (
            const std::vector < std::shared_ptr < Element > >& elements,
            char key,
            const std::shared_ptr < Window >& window
            )
    {
        // We need an orientation for this to work
        if ( orientation.get () != nullptr )
        {
            // Only resize if we have to ( speeds it up a lot )
            if ( has_input_changed ( elements, window ) )
                resize ( elements, window );

            // This is something Stretch_layout::compress_window_dummies does
            // Look at if for more details
            if ( windows.size () != 0 )
            {
                // Indexes in elements correspond to indexes in windows
                for ( int i = 0; i < elements.size (); i++ )
                {
                    elements.at ( i )->update ( key, windows.at ( i ) );
                }
            }
        }
        else
        {
            window->draw_string ( "Missing Orientation!" );
            window->refresh ();
        }
    }

    void Stretch_layout::set_orientation ( const std::shared_ptr < Orientation >& orientation )
    {
        this->orientation = orientation;
    }

    bool Stretch_layout::has_input_changed (
            const std::vector < std::shared_ptr < Element > >& elements,
            const std::shared_ptr < Window >& window
            )
    {
        // elements or something about the window has changed
        return (
                elements                != last_elements    ||
                window->get_x ()        != last_window.x    ||
                window->get_y ()        != last_window.y    ||
                window->get_width ()    != last_window.width||
                window->get_height ()   != last_window.height
                );
    }

    void Stretch_layout::resize (
            const std::vector < std::shared_ptr < Element > >& elements,
            const std::shared_ptr < Window >& window
            )
    {
        // Remove all old windows
        windows.clear ();
        Resize_data resize_data ( &elements, window, orientation );

        // Generate window_dummies
        std::vector < std::shared_ptr < Window_dummy > > window_dummies = generate_window_dummies ( resize_data );
        // Turn window_dummies into actual windows and put them into windows
        for ( auto it = window_dummies.begin (); it != window_dummies.end (); it++ )
        {
            std::shared_ptr < Window > element_window = std::make_shared < Window > (
                    ( *it )->x,
                    ( *it )->y,
                    ( *it )->width,
                    ( *it )->height
                    );
            windows.push_back ( element_window );
        }
    }

    std::vector < std::shared_ptr < Window_dummy > > Stretch_layout::generate_window_dummies ( Resize_data& resize_data )
    {
        // Generate basic window_dummies, they might be longer than the available length
        std::vector < std::shared_ptr < Window_dummy > > window_dummies = generate_basic_window_dummies ( resize_data );
        // Now scale them down, if they are longer
        compress_window_dummies ( resize_data, window_dummies );
        // And distribut remaining length ( created by integer division errors )
        distribute_remaining_length ( resize_data, window_dummies );

        return window_dummies;
    }

    int Stretch_layout::generate_no_preference_length ( Resize_data& resize_data )
    {
        // If prefered_lengths are already longer than provided length, return average of prefered_lengths
        if ( resize_data.prefered_length_sum > orientation->get_primary_length ( resize_data.window ) )
            return resize_data.prefered_length_sum / ( resize_data.elements->size () - resize_data.no_preference_element_count );
        else
            // Return remaining length divided by no_preference_element_count
            return ( orientation->get_primary_length ( resize_data.window ) - resize_data.prefered_length_sum )
                / resize_data.no_preference_element_count;
    }

    std::vector < std::shared_ptr < Window_dummy > > Stretch_layout::generate_basic_window_dummies ( Resize_data& resize_data )
    {
        std::vector < std::shared_ptr < Window_dummy > > basic_dummies;
        int no_preference_length = generate_no_preference_length ( resize_data );

        for ( int i = 0; i < resize_data.elements->size (); i++ )
        {
            std::shared_ptr < Window_dummy > next_window_dummy = std::make_shared < Window_dummy > ();

            // Set secondary coordinate and length to the same as window's
            orientation->set_secondary_length ( next_window_dummy, orientation->get_secondary_length ( resize_data.window ) );
            orientation->set_secondary_coordinate ( next_window_dummy, orientation->get_secondary_coordinate ( resize_data.window ) );

            // Set primary coordinate to window's plus the already used length
            orientation->set_primary_coordinate ( next_window_dummy,
                    orientation->get_primary_coordinate ( resize_data.window ) + resize_data.already_used_length );

            // If element has a preference, use it
            if ( orientation->get_prefered_length ( resize_data.elements->at ( i ) ) > 0 )
                orientation->set_primary_length ( next_window_dummy, orientation->get_prefered_length ( resize_data.elements->at ( i ) ) );
            else
                // Use the generated no_preference_length
                orientation->set_primary_length ( next_window_dummy, no_preference_length );

            // Add window_dummy's primary_length to already used length
            resize_data.already_used_length += orientation->get_primary_length ( next_window_dummy );
            basic_dummies.push_back ( next_window_dummy );
        }

        return basic_dummies;
    }

    void Stretch_layout::compress_window_dummies (
            Resize_data& resize_data,
            std::vector < std::shared_ptr < Window_dummy > >& window_dummies
            )
    {
        // If we need to compress the window_dummies
        if ( resize_data.already_used_length > orientation->get_primary_length ( resize_data.window ) )
        {
            // If there isn't evene enough space to show every single element, delete the window_dummies
            if ( orientation->get_primary_length( resize_data.window ) < resize_data.elements->size () )
                window_dummies.clear ();

            for ( auto it = window_dummies.begin (); it != window_dummies.end (); it++ )
            {
                // Set primary length to available length * percentage of already used length used by window_dummy
                orientation->set_primary_length ( *it,
                        orientation->get_primary_length ( resize_data.window ) *
                        ( ( float ) orientation->get_primary_length ( *it ) / resize_data.already_used_length ) );

                // Add new length to already used length
                resize_data.already_used_length += orientation->get_primary_length ( *it );
            }

            // Move the window_dummies to prevent overlap or free space
            for ( auto it = window_dummies.begin () + 1; it != window_dummies.end (); it++ )
            {
                orientation->set_primary_coordinate ( *it,
                        orientation->get_primary_coordinate ( *( it - 1 ) ) +
                        orientation->get_primary_length ( *( it - 1 ) )
                        );
            }

            // Update already used length
            resize_data.already_used_length =
                orientation->get_primary_length ( window_dummies.back () ) +
                orientation->get_primary_coordinate ( window_dummies.back () ) -
                orientation->get_primary_coordinate ( window_dummies.front () );
        }
    }

    void Stretch_layout::distribute_remaining_length (
            Resize_data& resize_data,
            std::vector < std::shared_ptr < Window_dummy > >& window_dummies
            )
    {
        if ( !window_dummies.empty () )
        {
            int index = 0;
            // While there still is length to distribute
            while ( resize_data.already_used_length < orientation->get_primary_length ( resize_data.window ) )
            {
                if (
                        // No prefered size
                        orientation->get_prefered_length ( resize_data.elements->at ( index ) ) == 0 ||
                        // No elements without preference
                        resize_data.no_preference_element_count == 0 ||
                        // Window is compressed
                        orientation->get_primary_length ( window_dummies.at ( index ) ) <
                        orientation->get_prefered_length ( resize_data.elements->at ( index ) )
                   )
                {
                    // Add one to primary_length
                    orientation->set_primary_length ( window_dummies.at ( index ),
                            orientation->get_primary_length ( window_dummies.at ( index ) ) + 1 );

                    resize_data.already_used_length++;

                    // Shift all windows after this one by one
                    for ( int i = index + 1; i < window_dummies.size (); i++ )
                    {
                        orientation->set_primary_coordinate ( window_dummies.at ( i ),
                            orientation->get_primary_coordinate ( window_dummies.at ( i ) ) + 1 );
                    }
                }

                index++;
                if ( index == window_dummies.size () )
                    index = 0;
            }
        }
    }
}
<commit_msg>Fix compiler warnings in ncurses::Stretch<commit_after>#include "stretch.h"
#include <algorithm>

// NOTE: This is everything but beautyful code. Unfortunately, I can't come up with a better way
//       to solve this problem. If you know a more elegant solution, please contact me.
//       Even tough I tried my best to comment and explain as much as possible, I wouldn't recommend
//       spending more time in here than necessary.

namespace ncurses
{
    Resize_data::Resize_data (
            const std::vector < std::shared_ptr < Element > >* elements,
            const std::shared_ptr < Window >& window,
            const std::shared_ptr < Orientation >& orientation
            ):
        window ( window ),
        elements ( elements ),
        already_used_length ( 0 )
    {
        // Create prefered_length_sum
        prefered_length_sum = 0;
        std::for_each ( elements->begin (), elements->end (),
                [ & ] ( std::shared_ptr < Element > element )
                    { prefered_length_sum += orientation->get_prefered_length ( element ); } );

        // Create no_preference_element_count
        no_preference_element_count = std::count_if ( elements->begin (), elements->end (),
                [ & ] ( std::shared_ptr < Element > element )
                    { return orientation->get_prefered_length ( element ) == 0; } );
    }

    void Stretch_layout::update_elements (
            const std::vector < std::shared_ptr < Element > >& elements,
            char key,
            const std::shared_ptr < Window >& window
            )
    {
        // We need an orientation for this to work
        if ( orientation.get () != nullptr )
        {
            // Only resize if we have to ( speeds it up a lot )
            if ( has_input_changed ( elements, window ) )
                resize ( elements, window );

            // This is something Stretch_layout::compress_window_dummies does
            // Look at if for more details
            if ( windows.size () != 0 )
            {
                // Indexes in elements correspond to indexes in windows
                for ( size_t i = 0; i < elements.size (); i++ )
                {
                    elements.at ( i )->update ( key, windows.at ( i ) );
                }
            }
        }
        else
        {
            window->draw_string ( "Missing Orientation!" );
            window->refresh ();
        }
    }

    void Stretch_layout::set_orientation ( const std::shared_ptr < Orientation >& orientation )
    {
        this->orientation = orientation;
    }

    bool Stretch_layout::has_input_changed (
            const std::vector < std::shared_ptr < Element > >& elements,
            const std::shared_ptr < Window >& window
            )
    {
        // elements or something about the window has changed
        return (
                elements                != last_elements    ||
                window->get_x ()        != last_window.x    ||
                window->get_y ()        != last_window.y    ||
                window->get_width ()    != last_window.width||
                window->get_height ()   != last_window.height
                );
    }

    void Stretch_layout::resize (
            const std::vector < std::shared_ptr < Element > >& elements,
            const std::shared_ptr < Window >& window
            )
    {
        // Remove all old windows
        windows.clear ();
        Resize_data resize_data ( &elements, window, orientation );

        // Generate window_dummies
        std::vector < std::shared_ptr < Window_dummy > > window_dummies = generate_window_dummies ( resize_data );
        // Turn window_dummies into actual windows and put them into windows
        for ( auto it = window_dummies.begin (); it != window_dummies.end (); it++ )
        {
            std::shared_ptr < Window > element_window = std::make_shared < Window > (
                    ( *it )->x,
                    ( *it )->y,
                    ( *it )->width,
                    ( *it )->height
                    );
            windows.push_back ( element_window );
        }
    }

    std::vector < std::shared_ptr < Window_dummy > > Stretch_layout::generate_window_dummies ( Resize_data& resize_data )
    {
        // Generate basic window_dummies, they might be longer than the available length
        std::vector < std::shared_ptr < Window_dummy > > window_dummies = generate_basic_window_dummies ( resize_data );
        // Now scale them down, if they are longer
        compress_window_dummies ( resize_data, window_dummies );
        // And distribut remaining length ( created by integer division errors )
        distribute_remaining_length ( resize_data, window_dummies );

        return window_dummies;
    }

    int Stretch_layout::generate_no_preference_length ( Resize_data& resize_data )
    {
        // If prefered_lengths are already longer than provided length, return average of prefered_lengths
        if ( resize_data.prefered_length_sum > orientation->get_primary_length ( resize_data.window ) )
            return resize_data.prefered_length_sum / ( resize_data.elements->size () - resize_data.no_preference_element_count );
        else
            // Return remaining length divided by no_preference_element_count
            return ( orientation->get_primary_length ( resize_data.window ) - resize_data.prefered_length_sum )
                / resize_data.no_preference_element_count;
    }

    std::vector < std::shared_ptr < Window_dummy > > Stretch_layout::generate_basic_window_dummies ( Resize_data& resize_data )
    {
        std::vector < std::shared_ptr < Window_dummy > > basic_dummies;
        int no_preference_length = generate_no_preference_length ( resize_data );

        for ( size_t i = 0; i < resize_data.elements->size (); i++ )
        {
            std::shared_ptr < Window_dummy > next_window_dummy = std::make_shared < Window_dummy > ();

            // Set secondary coordinate and length to the same as window's
            orientation->set_secondary_length ( next_window_dummy, orientation->get_secondary_length ( resize_data.window ) );
            orientation->set_secondary_coordinate ( next_window_dummy, orientation->get_secondary_coordinate ( resize_data.window ) );

            // Set primary coordinate to window's plus the already used length
            orientation->set_primary_coordinate ( next_window_dummy,
                    orientation->get_primary_coordinate ( resize_data.window ) + resize_data.already_used_length );

            // If element has a preference, use it
            if ( orientation->get_prefered_length ( resize_data.elements->at ( i ) ) > 0 )
                orientation->set_primary_length ( next_window_dummy, orientation->get_prefered_length ( resize_data.elements->at ( i ) ) );
            else
                // Use the generated no_preference_length
                orientation->set_primary_length ( next_window_dummy, no_preference_length );

            // Add window_dummy's primary_length to already used length
            resize_data.already_used_length += orientation->get_primary_length ( next_window_dummy );
            basic_dummies.push_back ( next_window_dummy );
        }

        return basic_dummies;
    }

    void Stretch_layout::compress_window_dummies (
            Resize_data& resize_data,
            std::vector < std::shared_ptr < Window_dummy > >& window_dummies
            )
    {
        // If we need to compress the window_dummies
        if ( resize_data.already_used_length > orientation->get_primary_length ( resize_data.window ) )
        {
            // If there isn't evene enough space to show every single element, delete the window_dummies
            if ( static_cast < size_t > ( orientation->get_primary_length( resize_data.window ) ) < resize_data.elements->size () )
                window_dummies.clear ();

            for ( auto it = window_dummies.begin (); it != window_dummies.end (); it++ )
            {
                // Set primary length to available length * percentage of already used length used by window_dummy
                orientation->set_primary_length ( *it,
                        orientation->get_primary_length ( resize_data.window ) *
                        ( ( float ) orientation->get_primary_length ( *it ) / resize_data.already_used_length ) );

                // Add new length to already used length
                resize_data.already_used_length += orientation->get_primary_length ( *it );
            }

            // Move the window_dummies to prevent overlap or free space
            for ( auto it = window_dummies.begin () + 1; it != window_dummies.end (); it++ )
            {
                orientation->set_primary_coordinate ( *it,
                        orientation->get_primary_coordinate ( *( it - 1 ) ) +
                        orientation->get_primary_length ( *( it - 1 ) )
                        );
            }

            // Update already used length
            resize_data.already_used_length =
                orientation->get_primary_length ( window_dummies.back () ) +
                orientation->get_primary_coordinate ( window_dummies.back () ) -
                orientation->get_primary_coordinate ( window_dummies.front () );
        }
    }

    void Stretch_layout::distribute_remaining_length (
            Resize_data& resize_data,
            std::vector < std::shared_ptr < Window_dummy > >& window_dummies
            )
    {
        if ( !window_dummies.empty () )
        {
            size_t index = 0;
            // While there still is length to distribute
            while ( resize_data.already_used_length < orientation->get_primary_length ( resize_data.window ) )
            {
                if (
                        // No prefered size
                        orientation->get_prefered_length ( resize_data.elements->at ( index ) ) == 0 ||
                        // No elements without preference
                        resize_data.no_preference_element_count == 0 ||
                        // Window is compressed
                        orientation->get_primary_length ( window_dummies.at ( index ) ) <
                        orientation->get_prefered_length ( resize_data.elements->at ( index ) )
                   )
                {
                    // Add one to primary_length
                    orientation->set_primary_length ( window_dummies.at ( index ),
                            orientation->get_primary_length ( window_dummies.at ( index ) ) + 1 );

                    resize_data.already_used_length++;

                    // Shift all windows after this one by one
                    for ( size_t i = index + 1; i < window_dummies.size (); i++ )
                    {
                        orientation->set_primary_coordinate ( window_dummies.at ( i ),
                            orientation->get_primary_coordinate ( window_dummies.at ( i ) ) + 1 );
                    }
                }

                index++;
                if ( index == window_dummies.size () )
                    index = 0;
            }
        }
    }
}
<|endoftext|>


<commit_before>/**
 * These codes are licensed under the Unlicense.
 * http://unlicense.org
 */

#include <sstream>
#include <tuple>

#include <gtest/gtest.h>

#include <furfurylic/commata/primitive_parser.hpp>
#include <furfurylic/commata/record_extractor.hpp>

#include "BaseTest.hpp"

using namespace furfurylic::commata;

struct TestRecordExtractor :
    furfurylic::test::BaseTestWithParam<std::size_t>
{};

TEST_P(TestRecordExtractor, LeftmostKey)
{
    const wchar_t* s = L"key_a,key_b,value_a,value_b\n"
                       L"\"ka1\",kb1,va1,vb1\r\n"
                       L"ka2,kb2,va2,vb2\n"
                       L"ka1,kb3,vb3,\"vb3\"\r";
    std::wstringbuf in(s);
    std::wstringbuf out;
    parse(&in, make_record_extractor(&out, L"key_a", L"ka1"), GetParam());
    ASSERT_EQ(L"key_a,key_b,value_a,value_b\n"
              L"\"ka1\",kb1,va1,vb1\n"
              L"ka1,kb3,vb3,\"vb3\"\n",
              out.str());
}

TEST_P(TestRecordExtractor, InnerKey)
{
    const char* s = "\r\n\n"
                    "key_a,key_b,value_a,value_b\n"
                    "ka1,kb01,va1,vb1\n"
                    "ka2,kb12,va2,vb2\n"
                    "ka1,kb13,\"vb\n3\",vb3";
    std::stringbuf in(s);
    std::ostringstream out;
    parse(&in, make_record_extractor(out, "key_b",
        [](const char* first ,const char* last) {
            return std::string(first, last).substr(0, 3) == "kb1";
        }), GetParam());
    ASSERT_EQ("key_a,key_b,value_a,value_b\n"
              "ka2,kb12,va2,vb2\n"
              "ka1,kb13,\"vb\n3\",vb3\n",
              out.str());
}

TEST_P(TestRecordExtractor, NoSuchKey)
{
    const char* s = "key_a,key_b,value_a,value_b\n"
                    "ka1,kb01,va1,vb1\n"
                    "ka2,kb12,va2,vb2\n";
    std::stringbuf in(s);
    std::stringbuf out;
    try {
        parse(&in, make_record_extractor(&out, "key_c", "kc1"), GetParam());
        FAIL();
    } catch (const record_extraction_error& e) {
        ASSERT_NE(e.get_physical_position(), nullptr);
        ASSERT_EQ(0U, e.get_physical_position()->first);
        std::string message(e.what());
        ASSERT_TRUE(message.find("key_c") != std::string::npos);
    }
}

TEST_P(TestRecordExtractor, NoSuchField)
{
    const char* s = "key_a,key_b\r"
                    "k1\r"
                    "k0,k1,k2\r";
    std::stringbuf in(s);
    std::stringbuf out;
    ASSERT_TRUE(parse(&in,
        make_record_extractor(&out, "key_b", "k1"), GetParam()));
    ASSERT_EQ("key_a,key_b\n"
              "k0,k1,k2\n",
              out.str());
}

INSTANTIATE_TEST_CASE_P(, TestRecordExtractor, testing::Values(1, 10, 1024));

struct TestRecordExtractorLimit :
    testing::TestWithParam<std::tuple<bool, std::size_t>>
{};

TEST_P(TestRecordExtractorLimit, Basics)
{
    const auto includes_header = std::get<0>(GetParam());
    const auto max_record_num = std::get<1>(GetParam());
    const char* s = "key_a,key_b,value_a,value_b\n"
                    "ka1,kb1,va1,vb1\r"
                    "ka2,kb2,va2,vb2\n"
                    "ka1,kb3,vb3,vb3\n";
    std::stringbuf in(s);
    std::stringbuf out;
    const auto result = parse(&in, make_record_extractor(
        &out, "key_a", "ka1", includes_header, max_record_num), 2);
    ASSERT_EQ(max_record_num > 1, result);
    std::string expected;
    if (includes_header) {
        expected += "key_a,key_b,value_a,value_b\n";
    }
    expected += "ka1,kb1,va1,vb1\n";
    if (max_record_num > 1) {
        expected += "ka1,kb3,vb3,vb3\n";
    }
    ASSERT_EQ(expected, out.str());
}

INSTANTIATE_TEST_CASE_P(, TestRecordExtractorLimit,
    testing::Combine(
        testing::Bool(),
        testing::Values(1, std::numeric_limits<std::size_t>::max())));

struct TestRecordExtractorLimit0 : furfurylic::test::BaseTest
{};

TEST_F(TestRecordExtractorLimit0, IncludeHeader)
{
    const char* s = "key_a,key_b,value_a,value_b\r"
                    "ka1,kb1,va1,\"vb1\r";  // Ill-formed row, but not parsed
    std::stringbuf in(s);
    std::stringbuf out;
    const auto result = parse(&in,
        make_record_extractor(&out, "key_a", "ka1", true, 0), 64);
    ASSERT_FALSE(result);
    std::string expected;
    ASSERT_EQ("key_a,key_b,value_a,value_b\n", out.str());
}

TEST_F(TestRecordExtractorLimit0, ExcludeHeaderNoSuchKey)
{
    const char* s = "key_a,key_b,value_a,value_b\r"
                    "ka1,kb1,va1,vb1\r";
    std::stringbuf in(s);
    std::stringbuf out;
    try {
        parse(&in, make_record_extractor(&out, "key_A", "ka1", false, 0), 64);
        FAIL();
    } catch (const record_extraction_error& e) {
        ASSERT_NE(e.get_physical_position(), nullptr);
        ASSERT_EQ(0U, e.get_physical_position()->first);
    }
}

struct TestRecordExtractorIndexed : furfurylic::test::BaseTest
{};

TEST_F(TestRecordExtractorIndexed, Basics)
{
    const char* s = "\r\n\n"
                    "key_a,key_b,value_a,value_b\n"
                    "ka1,kb01,va1,vb1\n"
                    "ka2,kb12,va2,vb2\n"
                    "ka1,kb13,\"vb\n3\",vb3";
    std::stringbuf in(s);
    std::ostringstream out;
    parse(&in, make_record_extractor(out, 1,
        [](const char* first ,const char* last) {
            return std::string(first, last).substr(0, 3) == "kb1";
        }), 1024);
    ASSERT_EQ("key_a,key_b,value_a,value_b\n"
              "ka2,kb12,va2,vb2\n"
              "ka1,kb13,\"vb\n3\",vb3\n",
              out.str());
}

struct FinalPredicateForValue final
{
    bool operator()(const char* first ,const char* last) const
    {
        return std::string(first, last).substr(0, 3) == "kb1";
    }
};

struct TestRecordExtractorFinalPredicateForValue : furfurylic::test::BaseTest
{};

TEST_F(TestRecordExtractorFinalPredicateForValue, Basics)
{
    const char* s = "\r\n\n"
                    "key_a,key_b,value_a,value_b\n"
                    "ka1,kb01,va1,vb1\n"
                    "ka2,kb12,va2,vb2\n"
                    "ka1,kb13,\"vb\n3\",vb3";
    std::stringbuf in(s);
    std::stringbuf out;
    parse(&in, make_record_extractor(&out, 1, FinalPredicateForValue()), 1024);
    ASSERT_EQ("key_a,key_b,value_a,value_b\n"
              "ka2,kb12,va2,vb2\n"
              "ka1,kb13,\"vb\n3\",vb3\n",
              out.str());
}
<commit_msg>Add a test that ensures record_extractor can handle wrapped-reference predicates<commit_after>/**
 * These codes are licensed under the Unlicense.
 * http://unlicense.org
 */

#include <sstream>
#include <tuple>

#include <gtest/gtest.h>

#include <furfurylic/commata/primitive_parser.hpp>
#include <furfurylic/commata/record_extractor.hpp>

#include "BaseTest.hpp"

using namespace furfurylic::commata;

struct TestRecordExtractor :
    furfurylic::test::BaseTestWithParam<std::size_t>
{};

TEST_P(TestRecordExtractor, LeftmostKey)
{
    const wchar_t* s = L"key_a,key_b,value_a,value_b\n"
                       L"\"ka1\",kb1,va1,vb1\r\n"
                       L"ka2,kb2,va2,vb2\n"
                       L"ka1,kb3,vb3,\"vb3\"\r";
    std::wstringbuf in(s);
    std::wstringbuf out;
    parse(&in, make_record_extractor(&out, L"key_a", L"ka1"), GetParam());
    ASSERT_EQ(L"key_a,key_b,value_a,value_b\n"
              L"\"ka1\",kb1,va1,vb1\n"
              L"ka1,kb3,vb3,\"vb3\"\n",
              out.str());
}

TEST_P(TestRecordExtractor, InnerKey)
{
    const char* s = "\r\n\n"
                    "key_a,key_b,value_a,value_b\n"
                    "ka1,kb01,va1,vb1\n"
                    "ka2,kb12,va2,vb2\n"
                    "ka1,kb13,\"vb\n3\",vb3";
    std::stringbuf in(s);
    std::ostringstream out;
    parse(&in, make_record_extractor(out, "key_b",
        [](const char* first ,const char* last) {
            return std::string(first, last).substr(0, 3) == "kb1";
        }), GetParam());
    ASSERT_EQ("key_a,key_b,value_a,value_b\n"
              "ka2,kb12,va2,vb2\n"
              "ka1,kb13,\"vb\n3\",vb3\n",
              out.str());
}

TEST_P(TestRecordExtractor, NoSuchKey)
{
    const char* s = "key_a,key_b,value_a,value_b\n"
                    "ka1,kb01,va1,vb1\n"
                    "ka2,kb12,va2,vb2\n";
    std::stringbuf in(s);
    std::stringbuf out;
    try {
        parse(&in, make_record_extractor(&out, "key_c", "kc1"), GetParam());
        FAIL();
    } catch (const record_extraction_error& e) {
        ASSERT_NE(e.get_physical_position(), nullptr);
        ASSERT_EQ(0U, e.get_physical_position()->first);
        std::string message(e.what());
        ASSERT_TRUE(message.find("key_c") != std::string::npos);
    }
}

TEST_P(TestRecordExtractor, NoSuchField)
{
    const char* s = "key_a,key_b\r"
                    "k1\r"
                    "k0,k1,k2\r";
    std::stringbuf in(s);
    std::stringbuf out;
    ASSERT_TRUE(parse(&in,
        make_record_extractor(&out, "key_b", "k1"), GetParam()));
    ASSERT_EQ("key_a,key_b\n"
              "k0,k1,k2\n",
              out.str());
}

INSTANTIATE_TEST_CASE_P(, TestRecordExtractor, testing::Values(1, 10, 1024));

struct TestRecordExtractorLimit :
    testing::TestWithParam<std::tuple<bool, std::size_t>>
{};

TEST_P(TestRecordExtractorLimit, Basics)
{
    const auto includes_header = std::get<0>(GetParam());
    const auto max_record_num = std::get<1>(GetParam());
    const char* s = "key_a,key_b,value_a,value_b\n"
                    "ka1,kb1,va1,vb1\r"
                    "ka2,kb2,va2,vb2\n"
                    "ka1,kb3,vb3,vb3\n";
    std::stringbuf in(s);
    std::stringbuf out;
    const auto result = parse(&in, make_record_extractor(
        &out, "key_a", "ka1", includes_header, max_record_num), 2);
    ASSERT_EQ(max_record_num > 1, result);
    std::string expected;
    if (includes_header) {
        expected += "key_a,key_b,value_a,value_b\n";
    }
    expected += "ka1,kb1,va1,vb1\n";
    if (max_record_num > 1) {
        expected += "ka1,kb3,vb3,vb3\n";
    }
    ASSERT_EQ(expected, out.str());
}

INSTANTIATE_TEST_CASE_P(, TestRecordExtractorLimit,
    testing::Combine(
        testing::Bool(),
        testing::Values(1, std::numeric_limits<std::size_t>::max())));

struct TestRecordExtractorLimit0 : furfurylic::test::BaseTest
{};

TEST_F(TestRecordExtractorLimit0, IncludeHeader)
{
    const char* s = "key_a,key_b,value_a,value_b\r"
                    "ka1,kb1,va1,\"vb1\r";  // Ill-formed row, but not parsed
    std::stringbuf in(s);
    std::stringbuf out;
    const auto result = parse(&in,
        make_record_extractor(&out, "key_a", "ka1", true, 0), 64);
    ASSERT_FALSE(result);
    std::string expected;
    ASSERT_EQ("key_a,key_b,value_a,value_b\n", out.str());
}

TEST_F(TestRecordExtractorLimit0, ExcludeHeaderNoSuchKey)
{
    const char* s = "key_a,key_b,value_a,value_b\r"
                    "ka1,kb1,va1,vb1\r";
    std::stringbuf in(s);
    std::stringbuf out;
    try {
        parse(&in, make_record_extractor(&out, "key_A", "ka1", false, 0), 64);
        FAIL();
    } catch (const record_extraction_error& e) {
        ASSERT_NE(e.get_physical_position(), nullptr);
        ASSERT_EQ(0U, e.get_physical_position()->first);
    }
}

struct TestRecordExtractorIndexed : furfurylic::test::BaseTest
{};

TEST_F(TestRecordExtractorIndexed, Basics)
{
    const char* s = "\r\n\n"
                    "key_a,key_b,value_a,value_b\n"
                    "ka1,kb01,va1,vb1\n"
                    "ka2,kb12,va2,vb2\n"
                    "ka1,kb13,\"vb\n3\",vb3";
    std::stringbuf in(s);
    std::ostringstream out;
    parse(&in, make_record_extractor(out, 1,
        [](const char* first ,const char* last) {
            return std::string(first, last).substr(0, 3) == "kb1";
        }), 1024);
    ASSERT_EQ("key_a,key_b,value_a,value_b\n"
              "ka2,kb12,va2,vb2\n"
              "ka1,kb13,\"vb\n3\",vb3\n",
              out.str());
}

struct FinalPredicateForValue final
{
    bool operator()(const char* first ,const char* last) const
    {
        return std::string(first, last).substr(0, 3) == "kb1";
    }
};

struct TestRecordExtractorFinalPredicateForValue : furfurylic::test::BaseTest
{};

TEST_F(TestRecordExtractorFinalPredicateForValue, Basics)
{
    const char* s = "\r\n\n"
                    "key_a,key_b,value_a,value_b\n"
                    "ka1,kb01,va1,vb1\n"
                    "ka2,kb12,va2,vb2\n"
                    "ka1,kb13,\"vb\n3\",vb3";
    std::stringbuf in(s);
    std::stringbuf out;
    parse(&in, make_record_extractor(&out, 1, FinalPredicateForValue()), 1024);
    ASSERT_EQ("key_a,key_b,value_a,value_b\n"
              "ka2,kb12,va2,vb2\n"
              "ka1,kb13,\"vb\n3\",vb3\n",
              out.str());
}

struct TestRecordExtractorReference : furfurylic::test::BaseTest
{};

TEST_F(TestRecordExtractorReference, Basics)
{
    const char* s = "instrument,type\n"
                    "viola,string\n"
                    "tuba,brass\n"
                    "clarinet,woodwind\n"
                    "koto,string";
    std::stringbuf in(s);
    std::stringbuf out;

    const auto key_pred = [](auto begin, auto end) {
        return ((end - begin) >= 3) && (std::strncmp(begin, "typ", 3) == 0);
    };
    const auto value_pred = [](auto begin, auto end) {
        const std::string value(begin, end);
        return (value == "brass") || (value == "woodwind");
    };

    // Freaking VS2015 picks up parse's overload for reference_wrappers
    // and complain about ambiguity, so we squelch it by force with explicit
    // template arguments
    auto ex = make_record_extractor(
        &out, std::ref(key_pred), std::ref(value_pred));
    parse<std::char_traits<char>, decltype(ex)>(&in, std::move(ex));
    ASSERT_EQ("instrument,type\n"
              "tuba,brass\n"
              "clarinet,woodwind\n",
              out.str());
}
<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_META_REF_TYPE_HPP
#define STAN_MATH_PRIM_META_REF_TYPE_HPP

#include <stan/math/prim/meta/is_eigen.hpp>
#include <stan/math/prim/meta/is_arena_matrix.hpp>
#include <stan/math/prim/meta/is_vector.hpp>
#include <stan/math/prim/meta/plain_type.hpp>
#include <stan/math/prim/fun/Eigen.hpp>

#include <type_traits>

namespace stan {

/**
 * If the condition is true determines appropriate type for assigning expression
 * of given type to, to evaluate expensive expressions, but not make a copy if T
 * involves no calculations. This works similarly as `Eigen::Ref`. It also
 * handles rvalue references, so it can be used with perfect forwarding. If the
 * condition is false the expression will never be evaluated.
 *
 * Warning: if a variable of this type could be assigned a rvalue, make sure
 * template parameter `T` is of correct reference type (rvalue).
 * @tparam T type to determine reference for
 */
template <bool Condition, typename T, typename = void>
struct ref_type_if {
  using T_plain = plain_type_t<T>;
  using T_optionally_ref
      = std::conditional_t<std::is_rvalue_reference<T>::value,
                           std::remove_reference_t<T>, const T&>;
  using type = std::conditional_t<
      Eigen::internal::traits<Eigen::Ref<std::decay_t<T_plain>>>::
              template match<std::decay_t<T>>::MatchAtCompileTime
          || !Condition,
      T_optionally_ref, T_plain>;
};

template <bool Condition, typename T>
struct ref_type_if<Condition, T,
                   require_t<bool_constant<!is_eigen<T>::value
                                           || is_arena_matrix<T>::value>>> {
  using type = std::conditional_t<std::is_rvalue_reference<T>::value,
                                  std::remove_reference_t<T>, const T&>;
};

template <typename T>
using ref_type_t = typename ref_type_if<true, T>::type;

template <bool Condition, typename T>
using ref_type_if_t = typename ref_type_if<Condition, T>::type;

/**
 * Determines appropriate type for assigning expression of given type to, so
 * that the resulting type has directly accessible contiguous colum-major data,
 * which is needed to copy to OpenCL device for construction of matrix_cl.
 *
 * THis is similar to `ref_type` except this also copies expressions, which do
 * not have contiguous data (in both dimensions) or have row major storage
 * order.
 *
 * Warning: if a variable of this type could be assigned a rvalue, make sure
 * template parameter `T` is of correct reference type (rvalue).
 * @tparam T type to determine reference for
 */
template <typename T, typename = void>
struct ref_type_for_opencl {
  using T_val = std::remove_reference_t<T>;
  using T_plain_col_major = std::conditional_t<
      std::is_same<typename Eigen::internal::traits<T_val>::XprKind,
                   Eigen::MatrixXpr>::value,
      Eigen::Matrix<value_type_t<T>, T_val::RowsAtCompileTime,
                    T_val::ColsAtCompileTime>,
      Eigen::Array<value_type_t<T>, T_val::RowsAtCompileTime,
                   T_val::ColsAtCompileTime>>;
  using T_optionally_ref
      = std::conditional_t<std::is_rvalue_reference<T>::value, T_val, const T&>;
  // Setting Outer stride of Ref to 0 (default) won't actually check that
  // expression has contiguous outer stride. Instead we need to check that
  // evaluator flags contain LinearAccessBit and PacketAccessBit.
  using type = std::conditional_t<
      Eigen::internal::traits<Eigen::Ref<std::decay_t<T_plain_col_major>>>::
              template match<T_val>::MatchAtCompileTime
          && (Eigen::internal::evaluator<T_val>::Flags & Eigen::LinearAccessBit)
          && (Eigen::internal::evaluator<T_val>::Flags
              & Eigen::PacketAccessBit),
      T_optionally_ref, T_plain_col_major>;
};

template <typename T>
struct ref_type_for_opencl<T, require_not_eigen_t<T>> {
  using type = std::conditional_t<std::is_rvalue_reference<T>::value,
                                  std::remove_reference_t<T>, const T&>;
};

template <typename T>
using ref_type_for_opencl_t = typename ref_type_for_opencl<T>::type;

}  // namespace stan

#endif
<commit_msg>fix ref_type_for_opencl to also use non-eigen version for arena_matrix<commit_after>#ifndef STAN_MATH_PRIM_META_REF_TYPE_HPP
#define STAN_MATH_PRIM_META_REF_TYPE_HPP

#include <stan/math/prim/meta/is_eigen.hpp>
#include <stan/math/prim/meta/is_arena_matrix.hpp>
#include <stan/math/prim/meta/is_vector.hpp>
#include <stan/math/prim/meta/plain_type.hpp>
#include <stan/math/prim/fun/Eigen.hpp>

#include <type_traits>

namespace stan {

/**
 * If the condition is true determines appropriate type for assigning expression
 * of given type to, to evaluate expensive expressions, but not make a copy if T
 * involves no calculations. This works similarly as `Eigen::Ref`. It also
 * handles rvalue references, so it can be used with perfect forwarding. If the
 * condition is false the expression will never be evaluated.
 *
 * Warning: if a variable of this type could be assigned a rvalue, make sure
 * template parameter `T` is of correct reference type (rvalue).
 * @tparam T type to determine reference for
 */
template <bool Condition, typename T, typename = void>
struct ref_type_if {
  using T_plain = plain_type_t<T>;
  using T_optionally_ref
      = std::conditional_t<std::is_rvalue_reference<T>::value,
                           std::remove_reference_t<T>, const T&>;
  using type = std::conditional_t<
      Eigen::internal::traits<Eigen::Ref<std::decay_t<T_plain>>>::
              template match<std::decay_t<T>>::MatchAtCompileTime
          || !Condition,
      T_optionally_ref, T_plain>;
};

template <bool Condition, typename T>
struct ref_type_if<Condition, T,
                   require_t<bool_constant<!is_eigen<T>::value
                                           || is_arena_matrix<T>::value>>> {
  using type = std::conditional_t<std::is_rvalue_reference<T>::value,
                                  std::remove_reference_t<T>, const T&>;
};

template <typename T>
using ref_type_t = typename ref_type_if<true, T>::type;

template <bool Condition, typename T>
using ref_type_if_t = typename ref_type_if<Condition, T>::type;

/**
 * Determines appropriate type for assigning expression of given type to, so
 * that the resulting type has directly accessible contiguous colum-major data,
 * which is needed to copy to OpenCL device for construction of matrix_cl.
 *
 * THis is similar to `ref_type` except this also copies expressions, which do
 * not have contiguous data (in both dimensions) or have row major storage
 * order.
 *
 * Warning: if a variable of this type could be assigned a rvalue, make sure
 * template parameter `T` is of correct reference type (rvalue).
 * @tparam T type to determine reference for
 */
template <typename T, typename = void>
struct ref_type_for_opencl {
  using T_val = std::remove_reference_t<T>;
  using T_plain_col_major = std::conditional_t<
      std::is_same<typename Eigen::internal::traits<T_val>::XprKind,
                   Eigen::MatrixXpr>::value,
      Eigen::Matrix<value_type_t<T>, T_val::RowsAtCompileTime,
                    T_val::ColsAtCompileTime>,
      Eigen::Array<value_type_t<T>, T_val::RowsAtCompileTime,
                   T_val::ColsAtCompileTime>>;
  using T_optionally_ref
      = std::conditional_t<std::is_rvalue_reference<T>::value, T_val, const T&>;
  // Setting Outer stride of Ref to 0 (default) won't actually check that
  // expression has contiguous outer stride. Instead we need to check that
  // evaluator flags contain LinearAccessBit and PacketAccessBit.
  using type = std::conditional_t<
      Eigen::internal::traits<Eigen::Ref<std::decay_t<T_plain_col_major>>>::
              template match<T_val>::MatchAtCompileTime
          && (Eigen::internal::evaluator<T_val>::Flags & Eigen::LinearAccessBit)
          && (Eigen::internal::evaluator<T_val>::Flags
              & Eigen::PacketAccessBit),
      T_optionally_ref, T_plain_col_major>;
};

template <typename T>
struct ref_type_for_opencl<T, require_t<bool_constant<!is_eigen<T>::value
                        || is_arena_matrix<T>::value>>> {
  using type = std::conditional_t<std::is_rvalue_reference<T>::value,
                                  std::remove_reference_t<T>, const T&>;
};

template <typename T>
using ref_type_for_opencl_t = typename ref_type_for_opencl<T>::type;

}  // namespace stan

#endif
<|endoftext|>


<commit_before>/*
** Copyright 2017 Centreon
**
** 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.
**
** For more information : contact@centreon.com
*/

#include <arpa/inet.h>
#include <limits>
#include <memory>
#include <sstream>
#include "com/centreon/broker/exceptions/msg.hh"
#include "com/centreon/broker/file/cfile.hh"
#include "com/centreon/broker/file/qt_fs_browser.hh"
#include "com/centreon/broker/file/splitter.hh"
#include "com/centreon/broker/io/exceptions/shutdown.hh"
#include "com/centreon/broker/logging/logging.hh"

using namespace com::centreon::broker;
using namespace com::centreon::broker::file;

/**
 *  Build a new splitter.
 *
 *  @param[in] path           Base path to file.
 *  @param[in] mode           Ignored. Files will always be open
 *                            read/write.
 *  @param[in] file_factory   fs_file_factory to work with single files.
 *  @param[in] fs             fs_browser object to manipulate file
 *                            system.
 *  @param[in] max_file_size  Maximum single file size.
 *  @param[in] auto_delete    True to delete file parts as they are
 *                            read.
 */
splitter::splitter(
            std::string const& path,
            fs_file::open_mode mode,
            fs_file_factory* file_factory,
            fs_browser* fs,
            long max_file_size,
            bool auto_delete)
  : _auto_delete(auto_delete),
    _base_path(path),
    _file_factory(file_factory),
    _fs(fs),
    _max_file_size(max_file_size) {
  (void)mode;

  // Set max file size.
  static long min_file_size(10000000);
  if (!_max_file_size) {
    _max_file_size = std::numeric_limits<long>::max();
  }
  else if (_max_file_size < min_file_size)
    _max_file_size = min_file_size;

  // Get IDs of already existing file parts.
  // XXX
}

/**
 *  Destructor.
 */
splitter::~splitter() {}

/**
 *  Read data.
 *
 *  @param[out] buffer    Output buffer.
 *  @param[in]  max_size  Maximum number of bytes that can be read.
 *
 *  @return Number of bytes read.
 */
long splitter::read(void* buffer, long max_size) {
  // Check if we should read.
  if (!_rfile.data()) {
    // If read-ID equals write-ID, then we're finished.
    if (_rid >= _wid) {
      _wfile.clear();
      throw (io::exceptions::shutdown(true, true)
             << "end of file");
    }
    // Otherwise open next ID.
    _open_next_read();
  }

  // Seek to position.
  _rfile->seek(_roffset);

  // Read data.
  long rb;
  try {
    rb = _rfile->read(buffer, max_size);
  }
  catch (io::exceptions::shutdown const& e) {
    (void)e;
    if (_wid == _rid) {
      _rfile.clear();
      _wfile.clear();
      std::string file_path(_file_path(_rid));
      if (_auto_delete) {
        logging::info(logging::high) << "file: end of last file '"
          << file_path.c_str() << "' reached, closing and erasing file";
        ::remove(file_path.c_str());
      }
      else {
        logging::info(logging::high) << "file: end of last file '"
          << file_path.c_str() << "' reached, closing but NOT erasing file";
      }
      throw ;
    }
    _open_next_read();
    rb = _rfile->read(buffer, max_size);
  }

  // Process data.
  logging::debug(logging::low) << "file: read " << rb << " bytes from '"
    << _file_path(_rid).c_str() << "'";
  _roffset += rb;
  return (rb);
}

/**
 *  Throw an exception.
 *
 *  @param[in] offset  Unused.
 *  @param[in] whence  Unused.
 */
void splitter::seek(long offset, fs_file::seek_whence whence) {
  (void)offset;
  (void)whence;
  throw (exceptions::msg() << "cannot seek within a splitted file");
}

/**
 *  Get current position.
 *
 *  @return Current position in file.
 */
long splitter::tell() {
  return (_roffset);
}

/**
 *  Write data.
 *
 *  @param[in] buffer  Data.
 *  @param[in] size    Number of bytes in buffer.
 *
 *  @return Number of bytes written.
 */
long splitter::write(void const* buffer, long size) {
  // Check that file should still be written to.
  if (_wfile.isNull())
    throw (io::exceptions::shutdown(true, true)
           << "end of file");

  // Seek to end of file if necessary.
  _wfile->seek(_woffset);

  // Debug message.
  logging::debug(logging::low) << "file: write request of "
    << size << " bytes for '" << _file_path(_wid).c_str() << "'";

  // Open new file if necessary.
  if ((_woffset + size) > _max_file_size)
    _open_next_write();

  // Write data.
  while (size > 0) {
    unsigned long wb(_wfile->write(buffer, size));
    size -= wb;
    _woffset += wb;
    buffer = static_cast<char const*>(buffer) + wb;
  }

  return (size);
}

/**
 *  Get the file path matching the ID.
 *
 *  @param[in] id Current ID.
 */
std::string splitter::_file_path(int id) const {
  if (id) {
    std::ostringstream oss;
    oss << _base_path << id;
    return (oss.str());
  }
  else
    return (_base_path);
}

/**
 *  Open the next readable file.
 */
void splitter::_open_next_read() {
  // Did we reached the write file ?
  _rfile.clear();
  ++_rid;
  if (_rid == _wid)
    _rfile = _wfile;
  else {
    // Open next file.
    std::string file_path(_file_path(_rid));
    {
      misc::shared_ptr<fs_file>
        new_file(_file_factory->new_fs_file(
                                  file_path,
                                  fs_file::open_read_write_no_create));
      _rfile = new_file;
    }
  }
  _roffset = 0;

  // Remove previous file.
  std::string file_path(_file_path(_rid - 1));
  if (_auto_delete) {
    logging::info(logging::high) << "file: end of file '"
      << file_path.c_str() << "' reached, erasing file";
    ::remove(file_path.c_str());
  }
  else {
    logging::info(logging::high) << "file: end of file '"
      << file_path.c_str() << "' reached, NOT erasing file";
  }

  return ;
}

/**
 *  Open the next writable file.
 */
void splitter::_open_next_write() {
  // Open file.
  _wfile.clear();
  ++_wid;
  std::string file_path(_file_path(_wid));
  logging::info(logging::high) << "file: opening new file '"
    << file_path.c_str() << "'";
  {
    try {
      _wfile = _file_factory->new_fs_file(
                                file_path,
                                fs_file::open_read_write_no_create);
    }
    catch (exceptions::msg const& e) {
      _wfile = _file_factory->new_fs_file(
                                file_path,
                                fs_file::open_read_write_truncate);
    }
  }

  // Position.
  _wfile->seek(0, fs_file::seek_end);
  _woffset = _wfile->tell();

  if (_woffset < static_cast<long>(2 * sizeof(uint32_t))) {
    // Rewind to file beginning.
    _wfile->seek(0);

    // Write read offset.
    union {
      char     bytes[2 * sizeof(uint32_t)];
      uint32_t integers[2];
    } header;
    header.integers[0] = 0;
    header.integers[1] = htonl(2 * sizeof(uint32_t));
    unsigned int size(0);
    while (size < sizeof(header))
      size += _wfile->write(header.bytes + size, sizeof(header) - size);

    // Set current offset.
    _woffset = 2 * sizeof(uint32_t);
  }

  return ;
}

/**
 *  Build a new default splitter.
 *
 *  @param[in] path  Path to file.
 *  @param[in] mode  Open mode (ignored).
 *
 *  @return A new default splitter.
 */
fs_file* splitter_factory::new_fs_file(
                             std::string const& path,
                             fs_file::open_mode mode) {
  return (new_cfile_splitter(path, mode));
}

/**
 *  Build a new cfile splitter.
 *
 *  @param[in] path           Path to file.
 *  @param[in] mode           Open mode (ignored).
 *  @param[in] max_file_size  Max single file size.
 *  @param[in] auto_delete    True to delete file parts as they are
 *                            read.
 *
 *  @return A new cfile splitter.
 */
splitter* splitter_factory::new_cfile_splitter(
                              std::string const& path,
                              fs_file::open_mode mode,
                              long max_file_size,
                              bool auto_delete) {
  std::auto_ptr<fs_file_factory> f(new cfile_factory());
  std::auto_ptr<fs_browser> b(new qt_fs_browser());
  splitter* s(new splitter(
                    path,
                    mode,
                    f.get(),
                    b.get(),
                    max_file_size,
                    auto_delete));
  f.release();
  b.release();
  return (s);
}
<commit_msg>core: find current read and write file IDs in file::splitter.<commit_after>/*
** Copyright 2017 Centreon
**
** 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.
**
** For more information : contact@centreon.com
*/

#include <arpa/inet.h>
#include <limits>
#include <memory>
#include <sstream>
#include "com/centreon/broker/exceptions/msg.hh"
#include "com/centreon/broker/file/cfile.hh"
#include "com/centreon/broker/file/qt_fs_browser.hh"
#include "com/centreon/broker/file/splitter.hh"
#include "com/centreon/broker/io/exceptions/shutdown.hh"
#include "com/centreon/broker/logging/logging.hh"

using namespace com::centreon::broker;
using namespace com::centreon::broker::file;

/**
 *  Build a new splitter.
 *
 *  @param[in] path           Base path to file.
 *  @param[in] mode           Ignored. Files will always be open
 *                            read/write.
 *  @param[in] file_factory   fs_file_factory to work with single files.
 *  @param[in] fs             fs_browser object to manipulate file
 *                            system.
 *  @param[in] max_file_size  Maximum single file size.
 *  @param[in] auto_delete    True to delete file parts as they are
 *                            read.
 */
splitter::splitter(
            std::string const& path,
            fs_file::open_mode mode,
            fs_file_factory* file_factory,
            fs_browser* fs,
            long max_file_size,
            bool auto_delete)
  : _auto_delete(auto_delete),
    _base_path(path),
    _file_factory(file_factory),
    _fs(fs),
    _max_file_size(max_file_size),
    _rid(0),
    _roffset(0),
    _wid(0),
    _woffset(0) {
  (void)mode;

  // Set max file size.
  static long min_file_size(10000000);
  if (!_max_file_size) {
    _max_file_size = std::numeric_limits<long>::max();
  }
  else if (_max_file_size < min_file_size)
    _max_file_size = min_file_size;

  // Get IDs of already existing file parts. File parts are suffixed
  // with their order number. A file named /var/lib/foo would have
  // parts named /var/lib/foo, /var/lib/foo1, /var/lib/foo2, ...
  // in this order.
  std::string base_dir;
  std::string base_name;
  {
    size_t last_slash(_base_path.find_last_of('/'));
    if (last_slash == std::string::npos) {
      base_dir = ".";
      base_name = _base_path;
    }
    else {
      base_dir = _base_path.substr(0, last_slash).c_str();
      base_name = _base_path.substr(last_slash + 1).c_str();
    }
  }
  base_name.append("*");
  fs_browser::entry_list parts(_fs->read_directory(
                                      base_dir,
                                      base_name));
  _rid = std::numeric_limits<int>::max();
  _wid = 0;
  for (fs_browser::entry_list::iterator
         it(parts.begin()),
         end(parts.end());
       it != end;
       ++it) {
    char const* ptr(it->c_str() + base_name.size());
    int val(0);
    if (*ptr) { // Not, empty, conversion needed.
      char* endptr(NULL);
      val = strtol(ptr, &endptr, 10);
      if (ptr && *ptr) // Invalid conversion.
        continue ;
    }

    if (val < _rid)
      _rid = val;
    if (val > _wid)
      _wid = val;
  }
  if (_rid == std::numeric_limits<int>::max())
    _rid = 0;

  // File IDs will be incremented when opening next files.
  --_rid;
  --_wid;
}

/**
 *  Destructor.
 */
splitter::~splitter() {}

/**
 *  Read data.
 *
 *  @param[out] buffer    Output buffer.
 *  @param[in]  max_size  Maximum number of bytes that can be read.
 *
 *  @return Number of bytes read.
 */
long splitter::read(void* buffer, long max_size) {
  // Check if we should read.
  if (!_rfile.data()) {
    // If read-ID equals write-ID, then we're finished.
    if (_rid >= _wid) {
      _wfile.clear();
      throw (io::exceptions::shutdown(true, true)
             << "end of file");
    }
    // Otherwise open next ID.
    _open_next_read();
  }

  // Seek to position.
  _rfile->seek(_roffset);

  // Read data.
  long rb;
  try {
    rb = _rfile->read(buffer, max_size);
  }
  catch (io::exceptions::shutdown const& e) {
    (void)e;
    if (_wid == _rid) {
      _rfile.clear();
      _wfile.clear();
      std::string file_path(_file_path(_rid));
      if (_auto_delete) {
        logging::info(logging::high) << "file: end of last file '"
          << file_path.c_str() << "' reached, closing and erasing file";
        ::remove(file_path.c_str());
      }
      else {
        logging::info(logging::high) << "file: end of last file '"
          << file_path.c_str() << "' reached, closing but NOT erasing file";
      }
      throw ;
    }
    _open_next_read();
    rb = _rfile->read(buffer, max_size);
  }

  // Process data.
  logging::debug(logging::low) << "file: read " << rb << " bytes from '"
    << _file_path(_rid).c_str() << "'";
  _roffset += rb;
  return (rb);
}

/**
 *  Throw an exception.
 *
 *  @param[in] offset  Unused.
 *  @param[in] whence  Unused.
 */
void splitter::seek(long offset, fs_file::seek_whence whence) {
  (void)offset;
  (void)whence;
  throw (exceptions::msg() << "cannot seek within a splitted file");
}

/**
 *  Get current position.
 *
 *  @return Current position in file.
 */
long splitter::tell() {
  return (_roffset);
}

/**
 *  Write data.
 *
 *  @param[in] buffer  Data.
 *  @param[in] size    Number of bytes in buffer.
 *
 *  @return Number of bytes written.
 */
long splitter::write(void const* buffer, long size) {
  // Check that file should still be written to.
  if (_wfile.isNull())
    throw (io::exceptions::shutdown(true, true)
           << "end of file");

  // Seek to end of file if necessary.
  _wfile->seek(_woffset);

  // Debug message.
  logging::debug(logging::low) << "file: write request of "
    << size << " bytes for '" << _file_path(_wid).c_str() << "'";

  // Open new file if necessary.
  if ((_woffset + size) > _max_file_size)
    _open_next_write();

  // Write data.
  while (size > 0) {
    unsigned long wb(_wfile->write(buffer, size));
    size -= wb;
    _woffset += wb;
    buffer = static_cast<char const*>(buffer) + wb;
  }

  return (size);
}

/**
 *  Get the file path matching the ID.
 *
 *  @param[in] id Current ID.
 */
std::string splitter::_file_path(int id) const {
  if (id) {
    std::ostringstream oss;
    oss << _base_path << id;
    return (oss.str());
  }
  else
    return (_base_path);
}

/**
 *  Open the next readable file.
 */
void splitter::_open_next_read() {
  // Did we reached the write file ?
  _rfile.clear();
  ++_rid;
  if (_rid == _wid)
    _rfile = _wfile;
  else {
    // Open next file.
    std::string file_path(_file_path(_rid));
    {
      misc::shared_ptr<fs_file>
        new_file(_file_factory->new_fs_file(
                                  file_path,
                                  fs_file::open_read_write_no_create));
      _rfile = new_file;
    }
  }
  _roffset = 0;

  // Remove previous file.
  std::string file_path(_file_path(_rid - 1));
  if (_auto_delete) {
    logging::info(logging::high) << "file: end of file '"
      << file_path.c_str() << "' reached, erasing file";
    ::remove(file_path.c_str());
  }
  else {
    logging::info(logging::high) << "file: end of file '"
      << file_path.c_str() << "' reached, NOT erasing file";
  }

  return ;
}

/**
 *  Open the next writable file.
 */
void splitter::_open_next_write() {
  // Open file.
  _wfile.clear();
  ++_wid;
  std::string file_path(_file_path(_wid));
  logging::info(logging::high) << "file: opening new file '"
    << file_path.c_str() << "'";
  {
    try {
      _wfile = _file_factory->new_fs_file(
                                file_path,
                                fs_file::open_read_write_no_create);
    }
    catch (exceptions::msg const& e) {
      _wfile = _file_factory->new_fs_file(
                                file_path,
                                fs_file::open_read_write_truncate);
    }
  }

  // Position.
  _wfile->seek(0, fs_file::seek_end);
  _woffset = _wfile->tell();

  if (_woffset < static_cast<long>(2 * sizeof(uint32_t))) {
    // Rewind to file beginning.
    _wfile->seek(0);

    // Write read offset.
    union {
      char     bytes[2 * sizeof(uint32_t)];
      uint32_t integers[2];
    } header;
    header.integers[0] = 0;
    header.integers[1] = htonl(2 * sizeof(uint32_t));
    unsigned int size(0);
    while (size < sizeof(header))
      size += _wfile->write(header.bytes + size, sizeof(header) - size);

    // Set current offset.
    _woffset = 2 * sizeof(uint32_t);
  }

  return ;
}

/**
 *  Build a new default splitter.
 *
 *  @param[in] path  Path to file.
 *  @param[in] mode  Open mode (ignored).
 *
 *  @return A new default splitter.
 */
fs_file* splitter_factory::new_fs_file(
                             std::string const& path,
                             fs_file::open_mode mode) {
  return (new_cfile_splitter(path, mode));
}

/**
 *  Build a new cfile splitter.
 *
 *  @param[in] path           Path to file.
 *  @param[in] mode           Open mode (ignored).
 *  @param[in] max_file_size  Max single file size.
 *  @param[in] auto_delete    True to delete file parts as they are
 *                            read.
 *
 *  @return A new cfile splitter.
 */
splitter* splitter_factory::new_cfile_splitter(
                              std::string const& path,
                              fs_file::open_mode mode,
                              long max_file_size,
                              bool auto_delete) {
  std::auto_ptr<fs_file_factory> f(new cfile_factory());
  std::auto_ptr<fs_browser> b(new qt_fs_browser());
  splitter* s(new splitter(
                    path,
                    mode,
                    f.get(),
                    b.get(),
                    max_file_size,
                    auto_delete));
  f.release();
  b.release();
  return (s);
}
<|endoftext|>


<commit_before>#include "label.h"

#include "util/geom.h"
#include "glm/gtx/rotate_vector.hpp"
#include "tangram.h"

namespace Tangram {

Label::Label(Label::Transform _transform, glm::vec2 _size, Type _type, Options _options, LabelProperty::Anchor _anchor)
    : m_type(_type),
      m_transform(_transform),
      m_dim(_size),
      m_options(_options),
      m_anchorType(_anchor) {

    if (!m_options.collide || m_type == Type::debug){
        enterState(State::visible, 1.0);
    } else {
        m_state = State::wait_occ;
        m_transform.state.alpha = 0.0;
    }

    m_occludedLastFrame = false;
    m_occluded = false;
    m_parent = nullptr;
}

Label::~Label() {}

bool Label::updateScreenTransform(const glm::mat4& _mvp, const glm::vec2& _screenSize, bool _testVisibility) {

    glm::vec2 screenPosition;
    glm::vec2 rotation = {1, 0};
    bool clipped = false;

    switch (m_type) {
        case Type::debug:
        case Type::point:
        {
            screenPosition = worldToScreenSpace(_mvp, glm::vec4(m_transform.modelPosition1, 0.0, 1.0),
                                                _screenSize, clipped);

            if (_testVisibility && clipped) {
                return false;
            }

            screenPosition += m_anchor;

            break;
        }
        case Type::line:
        {
            // project label position from mercator world space to screen
            // coordinates
            glm::vec2 ap1 = worldToScreenSpace(_mvp, glm::vec4(m_transform.modelPosition1, 0.0, 1.0),
                                               _screenSize, clipped);
            glm::vec2 ap2 = worldToScreenSpace(_mvp, glm::vec4(m_transform.modelPosition2, 0.0, 1.0),
                                               _screenSize, clipped);

            // check whether the label is behind the camera using the
            // perspective division factor
            if (_testVisibility && clipped) {
                return false;
            }

            float length = glm::length(ap2 - ap1);

            float exceedHeuristic = 0.3; // default heuristic : 30%

            if (_testVisibility && (m_dim.x > length)) {
                float exceed = 1 - (length / m_dim.x);
                if (exceed > exceedHeuristic) {
                    return false;
                }
            }

            screenPosition = (ap1 + ap2) * 0.5f;

            rotation = (ap1.x <= ap2.x ? ap2 - ap1 : ap1 - ap2) / length;

            break;
        }
    }

    glm::vec2 offset = rotateBy(m_options.offset, rotation);

    m_transform.state.screenPos = screenPosition + offset;
    m_transform.state.rotation = rotation;

    return true;
}

void Label::setParent(const Label& _parent, bool _definePriority) {
    m_parent = &_parent;

    glm::vec2 anchorDir = LabelProperty::anchorDirection(_parent.anchorType());
    glm::vec2 anchorOrigin = anchorDir * _parent.dimension() * 0.5f;
    applyAnchor(m_dim + _parent.dimension(), anchorOrigin, m_anchorType);

    if (_definePriority) {
        m_options.priority = _parent.options().priority + 0.5f;
    }

    m_options.offset += _parent.options().offset;
}

bool Label::offViewport(const glm::vec2& _screenSize) {
    const auto& quad = m_obb.getQuad();

    for (int i = 0; i < 4; ++i) {
        const auto& p = quad[i];
        if (p.x < _screenSize.x && p.y < _screenSize.y && p.x > 0 && p.y > 0) {
            return false;
        }
    }

    return true;
}

bool Label::canOcclude() {
    if (!m_options.collide) {
        return false;
    }

    int occludeFlags = (State::visible |
                        State::wait_occ |
                        State::skip_transition |
                        State::fading_in |
                        State::sleep |
                        State::out_of_screen |
                        State::dead);

    return (occludeFlags & m_state) && !(m_type == Type::debug);
}

bool Label::visibleState() const {
    int visibleFlags = (State::visible |
                        State::fading_in |
                        State::fading_out |
                        State::skip_transition);

    return (visibleFlags & m_state);
}

void Label::skipTransitions() {
    enterState(State::skip_transition, 0.0);
}

glm::vec2 Label::center() const {
    return m_obb.getCentroid();
}

void Label::enterState(const State& _state, float _alpha) {
    if (m_state == State::dead) { return; }

    m_state = _state;
    setAlpha(_alpha);
}

void Label::setAlpha(float _alpha) {
    m_transform.state.alpha = CLAMP(_alpha, 0.0, 1.0);
}

void Label::resetState() {
    if (m_state == State::dead) { return; }

    m_occludedLastFrame = false;
    m_occluded = false;
    enterState(State::wait_occ, 0.0);
}

bool Label::update(const glm::mat4& _mvp, const glm::vec2& _screenSize, float _zoomFract, bool _allLabels) {

    m_occludedLastFrame = m_occluded;
    m_occluded = false;

    if (m_state == State::dead) {
        if (!_allLabels) {
            return false;
        } else {
            m_occluded = true;
        }
    }

    bool ruleSatisfied = updateScreenTransform(_mvp, _screenSize, !_allLabels);

    // one of the label rules has not been satisfied
    if (!ruleSatisfied) {
        enterState(State::sleep, 0.0);
        return false;
    }

    // update the view-space bouding box
    updateBBoxes(_zoomFract);

    // checks whether the label is out of the viewport
    if (offViewport(_screenSize)) {
        enterState(State::out_of_screen, 0.0);
        if (m_occludedLastFrame) {
            m_occluded = true;
            return false;
        }
    } else if (m_state == State::out_of_screen) {
        if (m_occludedLastFrame) {
            enterState(State::sleep, 0.0);
        } else {
            enterState(State::visible, 1.0);
        }
    }

    return true;
}

bool Label::evalState(const glm::vec2& _screenSize, float _dt) {

    // if (Tangram::getDebugFlag(DebugFlags::all_labels)) {
    //     enterState(State::visible, 1.0);
    //     return false;
    // }

    bool animate = false;

    switch (m_state) {
        case State::visible:
            if (m_occluded) {
                m_fade = FadeEffect(false, m_options.hideTransition.ease,
                                    m_options.hideTransition.time);
                enterState(State::fading_out, 1.0);
                animate = true;
            }
            break;
        case State::fading_in:
            if (m_occluded) {
                enterState(State::sleep, 0.0);
                // enterState(State::fading_out, m_transform.state.alpha);
                // animate = true;
                break;
            }
            setAlpha(m_fade.update(_dt));
            animate = true;
            if (m_fade.isFinished()) {
                enterState(State::visible, 1.0);
            }
            break;
        case State::fading_out:
            if (!m_occluded) {
                enterState(State::fading_in, m_transform.state.alpha);
                animate = true;
                break;
            }
            setAlpha(m_fade.update(_dt));
            animate = true;
            if (m_fade.isFinished()) {
                enterState(State::sleep, 0.0);
            }
            break;
        case State::wait_occ:
            if (m_occluded) {
                enterState(State::sleep, 0.0);
            } else {
                m_fade = FadeEffect(true, m_options.showTransition.ease,
                                    m_options.showTransition.time);
                enterState(State::fading_in, 0.0);
                animate = true;
            }
            break;
        case State::skip_transition:
            if (m_occluded) {
                enterState(State::sleep, 0.0);
            } else {
                enterState(State::visible, 1.0);
            }
            break;
        case State::sleep:
            if (!m_occluded) {
                m_fade = FadeEffect(true, m_options.showTransition.ease,
                                    m_options.showTransition.time);
                enterState(State::fading_in, 0.0);
                animate = true;
            }
            break;
        case State::dead:
        case State::out_of_screen:
            break;
    }

    return animate;
}

}
<commit_msg>keep screen position center at world center (less sliding in tilted view)<commit_after>#include "label.h"

#include "util/geom.h"
#include "glm/gtx/rotate_vector.hpp"
#include "tangram.h"

namespace Tangram {

Label::Label(Label::Transform _transform, glm::vec2 _size, Type _type, Options _options, LabelProperty::Anchor _anchor)
    : m_type(_type),
      m_transform(_transform),
      m_dim(_size),
      m_options(_options),
      m_anchorType(_anchor) {

    if (!m_options.collide || m_type == Type::debug){
        enterState(State::visible, 1.0);
    } else {
        m_state = State::wait_occ;
        m_transform.state.alpha = 0.0;
    }

    m_occludedLastFrame = false;
    m_occluded = false;
    m_parent = nullptr;
}

Label::~Label() {}

bool Label::updateScreenTransform(const glm::mat4& _mvp, const glm::vec2& _screenSize, bool _testVisibility) {

    glm::vec2 screenPosition;
    glm::vec2 rotation = {1, 0};
    bool clipped = false;

    switch (m_type) {
        case Type::debug:
        case Type::point:
        {
            glm::vec2 p0 = m_transform.modelPosition1;

            screenPosition = worldToScreenSpace(_mvp, glm::vec4(p0, 0.0, 1.0),
                                                _screenSize, clipped);

            if (_testVisibility && clipped) {
                return false;
            }

            screenPosition += m_anchor;

            break;
        }
        case Type::line:
        {
            // project label position from mercator world space to screen
            // coordinates
            glm::vec2 p0 = m_transform.modelPosition1;
            glm::vec2 p2 = m_transform.modelPosition2;

            glm::vec2 ap0 = worldToScreenSpace(_mvp, glm::vec4(p0, 0.0, 1.0),
                                               _screenSize, clipped);
            glm::vec2 ap2 = worldToScreenSpace(_mvp, glm::vec4(p2, 0.0, 1.0),
                                               _screenSize, clipped);

            // check whether the label is behind the camera using the
            // perspective division factor
            if (_testVisibility && clipped) {
                return false;
            }

            float length = glm::length(ap2 - ap0);

            // default heuristic : allow label to be 30% wider than segment
            float minLength = m_dim.x * 0.7;

            if (_testVisibility && length < minLength) {
                return false;
            }

            glm::vec2 p1 = glm::vec2(p2 + p0) * 0.5f;

            glm::vec2 ap1 = worldToScreenSpace(_mvp, glm::vec4(p1, 0.0, 1.0),
                                               _screenSize, clipped);

            // Keep screen position center at world center (less sliding in tilted view)
            screenPosition = ap1;

            rotation = (ap0.x <= ap2.x ? ap2 - ap0 : ap0 - ap2) / length;

            break;
        }
    }

    glm::vec2 offset = rotateBy(m_options.offset, rotation);

    m_transform.state.screenPos = screenPosition + offset;
    m_transform.state.rotation = rotation;

    return true;
}

void Label::setParent(const Label& _parent, bool _definePriority) {
    m_parent = &_parent;

    glm::vec2 anchorDir = LabelProperty::anchorDirection(_parent.anchorType());
    glm::vec2 anchorOrigin = anchorDir * _parent.dimension() * 0.5f;
    applyAnchor(m_dim + _parent.dimension(), anchorOrigin, m_anchorType);

    if (_definePriority) {
        m_options.priority = _parent.options().priority + 0.5f;
    }

    m_options.offset += _parent.options().offset;
}

bool Label::offViewport(const glm::vec2& _screenSize) {
    const auto& quad = m_obb.getQuad();

    for (int i = 0; i < 4; ++i) {
        const auto& p = quad[i];
        if (p.x < _screenSize.x && p.y < _screenSize.y && p.x > 0 && p.y > 0) {
            return false;
        }
    }

    return true;
}

bool Label::canOcclude() {
    if (!m_options.collide) {
        return false;
    }

    int occludeFlags = (State::visible |
                        State::wait_occ |
                        State::skip_transition |
                        State::fading_in |
                        State::sleep |
                        State::out_of_screen |
                        State::dead);

    return (occludeFlags & m_state) && !(m_type == Type::debug);
}

bool Label::visibleState() const {
    int visibleFlags = (State::visible |
                        State::fading_in |
                        State::fading_out |
                        State::skip_transition);

    return (visibleFlags & m_state);
}

void Label::skipTransitions() {
    enterState(State::skip_transition, 0.0);
}

glm::vec2 Label::center() const {
    return m_obb.getCentroid();
}

void Label::enterState(const State& _state, float _alpha) {
    if (m_state == State::dead) { return; }

    m_state = _state;
    setAlpha(_alpha);
}

void Label::setAlpha(float _alpha) {
    m_transform.state.alpha = CLAMP(_alpha, 0.0, 1.0);
}

void Label::resetState() {
    if (m_state == State::dead) { return; }

    m_occludedLastFrame = false;
    m_occluded = false;
    enterState(State::wait_occ, 0.0);
}

bool Label::update(const glm::mat4& _mvp, const glm::vec2& _screenSize, float _zoomFract, bool _allLabels) {

    m_occludedLastFrame = m_occluded;
    m_occluded = false;

    if (m_state == State::dead) {
        if (!_allLabels) {
            return false;
        } else {
            m_occluded = true;
        }
    }

    bool ruleSatisfied = updateScreenTransform(_mvp, _screenSize, !_allLabels);

    // one of the label rules has not been satisfied
    if (!ruleSatisfied) {
        enterState(State::sleep, 0.0);
        return false;
    }

    // update the view-space bouding box
    updateBBoxes(_zoomFract);

    // checks whether the label is out of the viewport
    if (offViewport(_screenSize)) {
        enterState(State::out_of_screen, 0.0);
        if (m_occludedLastFrame) {
            m_occluded = true;
            return false;
        }
    } else if (m_state == State::out_of_screen) {
        if (m_occludedLastFrame) {
            enterState(State::sleep, 0.0);
        } else {
            enterState(State::visible, 1.0);
        }
    }

    return true;
}

bool Label::evalState(const glm::vec2& _screenSize, float _dt) {

    // if (Tangram::getDebugFlag(DebugFlags::all_labels)) {
    //     enterState(State::visible, 1.0);
    //     return false;
    // }

    bool animate = false;

    switch (m_state) {
        case State::visible:
            if (m_occluded) {
                m_fade = FadeEffect(false, m_options.hideTransition.ease,
                                    m_options.hideTransition.time);
                enterState(State::fading_out, 1.0);
                animate = true;
            }
            break;
        case State::fading_in:
            if (m_occluded) {
                enterState(State::sleep, 0.0);
                // enterState(State::fading_out, m_transform.state.alpha);
                // animate = true;
                break;
            }
            setAlpha(m_fade.update(_dt));
            animate = true;
            if (m_fade.isFinished()) {
                enterState(State::visible, 1.0);
            }
            break;
        case State::fading_out:
            if (!m_occluded) {
                enterState(State::fading_in, m_transform.state.alpha);
                animate = true;
                break;
            }
            setAlpha(m_fade.update(_dt));
            animate = true;
            if (m_fade.isFinished()) {
                enterState(State::sleep, 0.0);
            }
            break;
        case State::wait_occ:
            if (m_occluded) {
                enterState(State::sleep, 0.0);
            } else {
                m_fade = FadeEffect(true, m_options.showTransition.ease,
                                    m_options.showTransition.time);
                enterState(State::fading_in, 0.0);
                animate = true;
            }
            break;
        case State::skip_transition:
            if (m_occluded) {
                enterState(State::sleep, 0.0);
            } else {
                enterState(State::visible, 1.0);
            }
            break;
        case State::sleep:
            if (!m_occluded) {
                m_fade = FadeEffect(true, m_options.showTransition.ease,
                                    m_options.showTransition.time);
                enterState(State::fading_in, 0.0);
                animate = true;
            }
            break;
        case State::dead:
        case State::out_of_screen:
            break;
    }

    return animate;
}

}
<|endoftext|>


<commit_before>/**
 * @file Cosa/Power.cpp
 * @version 1.0
 *
 * @section License
 * Copyright (C) 2013-2015, Mikael Patel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * This file is part of the Arduino Che Cosa project.
 */

#include "Cosa/Power.hh"

// Software disable low voltage detect (23 uA at 5 V)
#define COSA_BOD_DISABLE

uint8_t Power::s_mode = SLEEP_MODE_IDLE;

void
Power::sleep(uint8_t mode)
{
  if (mode == POWER_SLEEP_MODE) mode = s_mode;
  set_sleep_mode(mode);
  sleep_enable();
#if defined(COSA_BOD_DISABLE) && defined(BODS)
  MCUCR = _BV(BODS) | _BV(BODSE);
  MCUCR = _BV(BODS);
#endif
  sleep_cpu();
  sleep_disable();
}

void
Power::clock_prescale(uint8_t factor)
{
  if (factor > 8) factor = 8;

  // Fix: RTC and other timer scaling
  synchronized {
    CLKPR = _BV(CLKPCE);
    CLKPR = factor;
  }
}
<commit_msg>Correct BOD setting for ATtinyX5.<commit_after>/**
 * @file Cosa/Power.cpp
 * @version 1.0
 *
 * @section License
 * Copyright (C) 2013-2015, Mikael Patel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * This file is part of the Arduino Che Cosa project.
 */

#include "Cosa/Power.hh"

// Software disable low voltage detect (23 uA at 5 V)
#define COSA_BOD_DISABLE

uint8_t Power::s_mode = SLEEP_MODE_IDLE;

void
Power::sleep(uint8_t mode)
{
  if (mode == POWER_SLEEP_MODE) mode = s_mode;
  set_sleep_mode(mode);
  sleep_enable();
#if defined(COSA_BOD_DISABLE) && defined(BODS)
  MCUCR |= _BV(BODS) | _BV(BODSE);
  MCUCR |= _BV(BODS);
#endif
  sleep_cpu();
  sleep_disable();
}

void
Power::clock_prescale(uint8_t factor)
{
  if (factor > 8) factor = 8;

  // Fix: RTC and other timer scaling
  synchronized {
    CLKPR = _BV(CLKPCE);
    CLKPR = factor;
  }
}
<|endoftext|>


<commit_before>/*
 * (C) Copyright 2014 Kurento (http://kurento.org/)
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser General Public License
 * (LGPL) version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl-2.1.html
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 */

#include <gst/gst.h>

#include "logging.hpp"

#include <boost/format.hpp>
#include <boost/log/sinks/text_file_backend.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/attributes.hpp>
#include <boost/log/sinks.hpp>
#include <boost/log/sources/channel_feature.hpp>
#include <boost/log/sources/channel_logger.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/utility/manipulators/add_value.hpp>

namespace logging = boost::log;
namespace attrs = boost::log::attributes;
namespace src = boost::log::sources;
namespace sinks = boost::log::sinks;
namespace expr = boost::log::expressions;
namespace keywords = boost::log::keywords;

typedef sinks::synchronous_sink< sinks::text_file_backend > sink_t;

namespace kurento
{

/* kurento logging sinks */
boost::shared_ptr< sink_t > system_sink;

static std::string
debug_object (GObject *object)
{
  if (object == NULL) {
    return "";
  }

  if (GST_IS_PAD (object) && GST_OBJECT_NAME (object) ) {
    boost::format fmt ("<%s:%s> ");
    fmt % (GST_OBJECT_PARENT (object) != NULL ? GST_OBJECT_NAME (GST_OBJECT_PARENT (
             object) ) : "''") % GST_OBJECT_NAME (object);
    return fmt.str();
  }

  if (GST_IS_OBJECT (object) && GST_OBJECT_NAME (object) ) {
    boost::format fmt ("<%s> ");
    fmt % GST_OBJECT_NAME (object);
    return fmt.str();
  }

  if (G_IS_OBJECT (object) ) {
    boost::format fmt ("<%s@%p> ");
    fmt %  G_OBJECT_TYPE_NAME (object) % object;
    return fmt.str();
  }

  boost::format fmt ("<%p> ");
  fmt % object;
  return fmt.str();
}

static std::string
expand_string (std::string str, int len)
{
  std::string ret = str;
  int sp = len - str.size ();

  for (int i = sp; i > 0; i--) {
    str.append (" ");
  }

  return str;
}

static severity_level
gst_debug_level_to_severity_level (GstDebugLevel level)
{
  switch (level) {
  case GST_LEVEL_ERROR:
    return error;

  case GST_LEVEL_WARNING:
    return warning;

  case GST_LEVEL_FIXME:
    return fixme;

  case GST_LEVEL_INFO:
    return info;

  case GST_LEVEL_DEBUG:
    return debug;

  case GST_LEVEL_LOG:
    return log;

  case GST_LEVEL_TRACE:
    return trace;

  default:
    return undefined;
  }
}

static void
kms_log_function (GstDebugCategory *category, GstDebugLevel level,
                  const gchar *file,
                  const gchar *function, gint line, GObject *object,
                  GstDebugMessage *message, gpointer user_data)
{
  if (level > gst_debug_category_get_threshold (category) ) {
    return;
  }

  severity_level severity = gst_debug_level_to_severity_level (level);

  if (severity == undefined) {
    return;
  }

  BOOST_LOG_SEV (system_logger::get(), severity) <<
      logging::add_value ("Category", expand_string (category->name, 25) ) <<
      logging::add_value ("FileName",
                          boost::filesystem::path (file).filename().string() ) <<
      logging::add_value ("Line", line) <<
      logging::add_value ("Function", function) <<
      logging::add_value ("GObject", debug_object (object) ) <<
      gst_debug_message_get (message);
}

void init_file_collecting (boost::shared_ptr< sink_t > sink,
                           const std::string &path)
{
  sink->locked_backend()->set_file_collector (sinks::file::make_collector (
        keywords::target = path,
        keywords::max_size = 16 * 1024 * 1024,
        keywords::min_free_space = 100 * 1024 * 1024
      ) );
}

/* The formatting logic for the severity level */
template< typename CharT, typename TraitsT >
inline std::basic_ostream< CharT, TraitsT > &operator<< (
  std::basic_ostream< CharT, TraitsT > &strm, severity_level lvl)
{
  static const char *const str[] = {
    "error",
    "warning",
    "fixme",
    "info",
    "debug",
    "log",
    "trace",
    "unknown"
  };

  if (static_cast< std::size_t > (lvl) < (sizeof (str) / sizeof (*str) ) ) {
    strm << str[lvl];
  } else {
    strm << static_cast< int > (lvl);
  }

  return strm;
}

static void
system_formatter (logging::record_view const &rec,
                  logging::formatting_ostream &strm)
{
  auto date_time_formatter = expr::stream
                             << expr::format_date_time< boost::posix_time::ptime > ("TimeStamp",
                                 "%Y-%m-%d %H:%M:%S,%f");
  date_time_formatter (rec, strm) << " ";
  strm << logging::extract< attrs::current_process_id::value_type > ("ProcessID",
       rec) << " ";
  strm << "[" <<
       logging::extract< attrs::current_thread_id::value_type > ("ThreadID",
           rec) << "] ";
  strm << logging::extract< severity_level > ("Severity", rec) << " ";
  strm << logging::extract< std::string > ("Category", rec) << " ";
  strm << logging::extract< std::string > ("FileName", rec) << ":";
  strm << logging::extract< int > ("Line", rec) << " ";
  strm << logging::extract< std::string > ("Function", rec) << "() ";
  strm << logging::extract< std::string > ("GObject", rec) << " ";
  strm << rec[expr::smessage];
}

bool
kms_init_logging (const std::string &path)
{
  gst_debug_remove_log_function_by_data (NULL);
  gst_debug_add_log_function (kms_log_function, NULL, NULL);

  boost::shared_ptr< logging::core > core = logging::core::get();

  boost::shared_ptr< sinks::text_file_backend > backend =
    boost::make_shared< sinks::text_file_backend > (
      keywords::file_name = path + "/" + "%Y%m%d_%H%M%S_%5N.log",
      keywords::rotation_size = 5 * 1024 * 1024,
      keywords::time_based_rotation = sinks::file::rotation_at_time_point (12, 0, 0)
    );

  /* Enable auto-flushing after each log record written */
  backend->auto_flush (true);

  /* Wrap it into the frontend and register in the core.   */
  /* The backend requires synchronization in the frontend. */
  system_sink = boost::shared_ptr< sink_t > (new sink_t (backend) );

  /*Set up filter to pass only records that have the necessary attributes */
  system_sink->set_filter (
    expr::has_attr< std::string > ("Channel") &&
    expr::attr< std::string > ("Channel") == "system"
  );

  /* Set up where the rotated files will be stored */
  init_file_collecting (system_sink, path + "/logs");

  /* Upon restart, scan the directory for files matching the file_name pattern */
  system_sink->locked_backend()->scan_for_files();

  core->add_sink (system_sink);

  system_sink->set_formatter (&system_formatter);

  return true;
}

}  /* kurento */
<commit_msg>logging.cpp: Fix severity indentation<commit_after>/*
 * (C) Copyright 2014 Kurento (http://kurento.org/)
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser General Public License
 * (LGPL) version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl-2.1.html
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 */

#include <gst/gst.h>

#include "logging.hpp"

#include <boost/format.hpp>
#include <boost/log/sinks/text_file_backend.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/attributes.hpp>
#include <boost/log/sinks.hpp>
#include <boost/log/sources/channel_feature.hpp>
#include <boost/log/sources/channel_logger.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/utility/manipulators/add_value.hpp>

namespace logging = boost::log;
namespace attrs = boost::log::attributes;
namespace src = boost::log::sources;
namespace sinks = boost::log::sinks;
namespace expr = boost::log::expressions;
namespace keywords = boost::log::keywords;

typedef sinks::synchronous_sink< sinks::text_file_backend > sink_t;

namespace kurento
{

/* kurento logging sinks */
boost::shared_ptr< sink_t > system_sink;

static std::string
debug_object (GObject *object)
{
  if (object == NULL) {
    return "";
  }

  if (GST_IS_PAD (object) && GST_OBJECT_NAME (object) ) {
    boost::format fmt ("<%s:%s> ");
    fmt % (GST_OBJECT_PARENT (object) != NULL ? GST_OBJECT_NAME (GST_OBJECT_PARENT (
             object) ) : "''") % GST_OBJECT_NAME (object);
    return fmt.str();
  }

  if (GST_IS_OBJECT (object) && GST_OBJECT_NAME (object) ) {
    boost::format fmt ("<%s> ");
    fmt % GST_OBJECT_NAME (object);
    return fmt.str();
  }

  if (G_IS_OBJECT (object) ) {
    boost::format fmt ("<%s@%p> ");
    fmt %  G_OBJECT_TYPE_NAME (object) % object;
    return fmt.str();
  }

  boost::format fmt ("<%p> ");
  fmt % object;
  return fmt.str();
}

static std::string
expand_string (std::string str, int len)
{
  std::string ret = str;
  int sp = len - str.size ();

  for (int i = sp; i > 0; i--) {
    str.append (" ");
  }

  return str;
}

static severity_level
gst_debug_level_to_severity_level (GstDebugLevel level)
{
  switch (level) {
  case GST_LEVEL_ERROR:
    return error;

  case GST_LEVEL_WARNING:
    return warning;

  case GST_LEVEL_FIXME:
    return fixme;

  case GST_LEVEL_INFO:
    return info;

  case GST_LEVEL_DEBUG:
    return debug;

  case GST_LEVEL_LOG:
    return log;

  case GST_LEVEL_TRACE:
    return trace;

  default:
    return undefined;
  }
}

static void
kms_log_function (GstDebugCategory *category, GstDebugLevel level,
                  const gchar *file,
                  const gchar *function, gint line, GObject *object,
                  GstDebugMessage *message, gpointer user_data)
{
  if (level > gst_debug_category_get_threshold (category) ) {
    return;
  }

  severity_level severity = gst_debug_level_to_severity_level (level);

  if (severity == undefined) {
    return;
  }

  BOOST_LOG_SEV (system_logger::get(), severity) <<
      logging::add_value ("Category", expand_string (category->name, 25) ) <<
      logging::add_value ("FileName",
                          boost::filesystem::path (file).filename().string() ) <<
      logging::add_value ("Line", line) <<
      logging::add_value ("Function", function) <<
      logging::add_value ("GObject", debug_object (object) ) <<
      gst_debug_message_get (message);
}

void init_file_collecting (boost::shared_ptr< sink_t > sink,
                           const std::string &path)
{
  sink->locked_backend()->set_file_collector (sinks::file::make_collector (
        keywords::target = path,
        keywords::max_size = 16 * 1024 * 1024,
        keywords::min_free_space = 100 * 1024 * 1024
      ) );
}

/* The formatting logic for the severity level */
template< typename CharT, typename TraitsT >
inline std::basic_ostream< CharT, TraitsT > &operator<< (
  std::basic_ostream< CharT, TraitsT > &strm, severity_level lvl)
{
  static const char *const str[] = {
    "  error",
    "warning",
    "  fixme",
    "   info",
    "  debug",
    "    log",
    "  trace",
    "unknown"
  };

  if (static_cast< std::size_t > (lvl) < (sizeof (str) / sizeof (*str) ) ) {
    strm << str[lvl];
  } else {
    strm << static_cast< int > (lvl);
  }

  return strm;
}

static void
system_formatter (logging::record_view const &rec,
                  logging::formatting_ostream &strm)
{
  auto date_time_formatter = expr::stream
                             << expr::format_date_time< boost::posix_time::ptime > ("TimeStamp",
                                 "%Y-%m-%d %H:%M:%S,%f");
  date_time_formatter (rec, strm) << " ";
  strm << logging::extract< attrs::current_process_id::value_type > ("ProcessID",
       rec) << " ";
  strm << "[" <<
       logging::extract< attrs::current_thread_id::value_type > ("ThreadID",
           rec) << "] ";
  strm << logging::extract< severity_level > ("Severity", rec) << " ";
  strm << logging::extract< std::string > ("Category", rec) << " ";
  strm << logging::extract< std::string > ("FileName", rec) << ":";
  strm << logging::extract< int > ("Line", rec) << " ";
  strm << logging::extract< std::string > ("Function", rec) << "() ";
  strm << logging::extract< std::string > ("GObject", rec) << " ";
  strm << rec[expr::smessage];
}

bool
kms_init_logging (const std::string &path)
{
  gst_debug_remove_log_function_by_data (NULL);
  gst_debug_add_log_function (kms_log_function, NULL, NULL);

  boost::shared_ptr< logging::core > core = logging::core::get();

  boost::shared_ptr< sinks::text_file_backend > backend =
    boost::make_shared< sinks::text_file_backend > (
      keywords::file_name = path + "/" + "%Y%m%d_%H%M%S_%5N.log",
      keywords::rotation_size = 5 * 1024 * 1024,
      keywords::time_based_rotation = sinks::file::rotation_at_time_point (12, 0, 0)
    );

  /* Enable auto-flushing after each log record written */
  backend->auto_flush (true);

  /* Wrap it into the frontend and register in the core.   */
  /* The backend requires synchronization in the frontend. */
  system_sink = boost::shared_ptr< sink_t > (new sink_t (backend) );

  /*Set up filter to pass only records that have the necessary attributes */
  system_sink->set_filter (
    expr::has_attr< std::string > ("Channel") &&
    expr::attr< std::string > ("Channel") == "system"
  );

  /* Set up where the rotated files will be stored */
  init_file_collecting (system_sink, path + "/logs");

  /* Upon restart, scan the directory for files matching the file_name pattern */
  system_sink->locked_backend()->scan_for_files();

  core->add_sink (system_sink);

  system_sink->set_formatter (&system_formatter);

  return true;
}

}  /* kurento */
<|endoftext|>