<commit_before>#include "follow_me_impl.h"
#include "system.h"
#include "global_include.h"
#include "px4_custom_mode.h"

namespace dronecode_sdk {

using namespace std::placeholders; // for `_1`

FollowMeImpl::FollowMeImpl(System &system) : PluginImplBase(system)
{
    // (Lat, Lon, Alt) => double, (vx, vy, vz) => float
    _last_location = _target_location =
        FollowMe::TargetLocation{double(NAN), double(NAN), double(NAN), NAN, NAN, NAN};
    _parent->register_plugin(this);
}

FollowMeImpl::~FollowMeImpl()
{
    _parent->unregister_plugin(this);
}

void FollowMeImpl::init()
{
    _parent->register_mavlink_message_handler(MAVLINK_MSG_ID_HEARTBEAT,
                                              std::bind(&FollowMeImpl::process_heartbeat, this, _1),
                                              static_cast<void *>(this));
}

void FollowMeImpl::deinit()
{
    _parent->unregister_all_mavlink_message_handlers(this);
}

void FollowMeImpl::enable()
{
    _parent->get_param_float_async("NAV_MIN_FT_HT", [this](bool success, float value) {
        if (success) {
            _config.min_height_m = value;
        }
    });
    _parent->get_param_float_async("NAV_FT_DST", [this](bool success, float value) {
        if (success) {
            _config.follow_distance_m = value;
        }
    });
    _parent->get_param_int_async("NAV_FT_FS", [this](bool success, int32_t value) {
        if (success) {
            _config.follow_direction = static_cast<FollowMe::Config::FollowDirection>(value);
        }
    });
    _parent->get_param_float_async("NAV_FT_RS", [this](bool success, float value) {
        if (success) {
            _config.responsiveness = value;
        }
    });
}

void FollowMeImpl::disable()
{
    stop_sending_target_location();
}

const FollowMe::Config &FollowMeImpl::get_config() const
{
    return _config;
}

FollowMe::Result FollowMeImpl::set_config(const FollowMe::Config &config)
{
    // Valdidate configuration
    if (!is_config_ok(config)) {
        LogErr() << debug_str << "set_config() failed. Last configuration is preserved.";
        return FollowMe::Result::SET_CONFIG_FAILED;
    }

    auto height = config.min_height_m;
    auto distance = config.follow_distance_m;
    int32_t direction = static_cast<int32_t>(config.follow_direction);
    auto responsiveness = config.responsiveness;

    LogDebug() << "Waiting for the system confirmation of the new configuration..";

    bool success = true;

    // Send configuration to Vehicle
    if (_config.min_height_m != height) {
        if (_parent->set_param_float("NAV_MIN_FT_HT", height)) {
            _config.min_height_m = height;
        } else {
            success = false;
        }
    }
    if (_config.follow_distance_m != distance) {
        if (_parent->set_param_float("NAV_FT_DST", distance)) {
            _config.follow_distance_m = distance;
        } else {
            success = false;
        }
    }
    if (_config.follow_direction != config.follow_direction) {
        if (_parent->set_param_int("NAV_FT_FS", direction)) {
            _config.follow_direction = static_cast<FollowMe::Config::FollowDirection>(direction);

        } else {
            success = false;
        }
    }
    if (_config.responsiveness != responsiveness) {
        if (_parent->set_param_float("NAV_FT_RS", responsiveness)) {
            _config.responsiveness = responsiveness;
        } else {
            success = false;
        }
    }

    return (success ? FollowMe::Result::SUCCESS : FollowMe::Result::SET_CONFIG_FAILED);
}

void FollowMeImpl::set_target_location(const FollowMe::TargetLocation &location)
{
    _mutex.lock();
    _target_location = location;
    // We're interested only in lat, long.
    _estimatation_capabilities |= (1 << static_cast<int>(EstimationCapabilites::POS));

    if (_mode != Mode::ACTIVE) {
        _mutex.unlock();
        return;
    }
    // If set already, reschedule it.
    if (_target_location_cookie) {
        _parent->reset_call_every(_target_location_cookie);
        _target_location_cookie = nullptr;
    } else {
        // Regiter now for sending in the next cycle.
        _parent->add_call_every(
            [this]() { send_target_location(); }, SENDER_RATE, &_target_location_cookie);
    }
    _mutex.unlock();

    // Send it immediately for now.
    send_target_location();
}

const FollowMe::TargetLocation &FollowMeImpl::get_last_location() const
{
    std::lock_guard<std::mutex> lock(_mutex);
    return _last_location;
}

bool FollowMeImpl::is_active() const
{
    std::lock_guard<std::mutex> lock(_mutex);
    return _mode == Mode::ACTIVE;
}

FollowMe::Result FollowMeImpl::start()
{
    FollowMe::Result result =
        to_follow_me_result(_parent->set_flight_mode(SystemImpl::FlightMode::FOLLOW_ME));

    if (result == FollowMe::Result::SUCCESS) {
        // If location was set before, lets send it to vehicle
        std::lock_guard<std::mutex> lock(
            _mutex); // locking is not necessary here but lets do it for integrity
        if (is_target_location_set()) {
            _parent->add_call_every(
                [this]() { send_target_location(); }, SENDER_RATE, &_target_location_cookie);
        }
    }
    return result;
}

FollowMe::Result FollowMeImpl::stop()
{
    {
        std::lock_guard<std::mutex> lock(_mutex);
        if (_mode == Mode::ACTIVE) {
            stop_sending_target_location();
        }
    }
    return to_follow_me_result(_parent->set_flight_mode(SystemImpl::FlightMode::HOLD));
}

bool FollowMeImpl::is_config_ok(const FollowMe::Config &config) const
{
    auto config_ok = false;

    if (config.min_height_m < FollowMe::Config::MIN_HEIGHT_M) {
        LogErr() << debug_str << "Err: Min height must be atleast 8.0 meters";
    } else if (config.follow_distance_m < FollowMe::Config::MIN_FOLLOW_DIST_M) {
        LogErr() << debug_str << "Err: Min Follow distance must be atleast 1.0 meter";
    } else if (config.follow_direction < FollowMe::Config::FollowDirection::FRONT_RIGHT ||
               config.follow_direction > FollowMe::Config::FollowDirection::NONE) {
        LogErr() << debug_str << "Err: Invalid Follow direction";
    } else if (config.responsiveness < FollowMe::Config::MIN_RESPONSIVENESS ||
               config.responsiveness > FollowMe::Config::MAX_RESPONSIVENESS) {
        LogErr() << debug_str << "Err: Responsiveness must be in range (0.0 to 1.0)";
    } else { // Config is OK
        config_ok = true;
    }

    return config_ok;
}

FollowMe::Result FollowMeImpl::to_follow_me_result(MAVLinkCommands::Result result) const
{
    switch (result) {
        case MAVLinkCommands::Result::SUCCESS:
            return FollowMe::Result::SUCCESS;
        case MAVLinkCommands::Result::NO_SYSTEM:
            return FollowMe::Result::NO_SYSTEM;
        case MAVLinkCommands::Result::CONNECTION_ERROR:
            return FollowMe::Result::CONNECTION_ERROR;
        case MAVLinkCommands::Result::BUSY:
            return FollowMe::Result::BUSY;
        case MAVLinkCommands::Result::COMMAND_DENIED:
            return FollowMe::Result::COMMAND_DENIED;
        case MAVLinkCommands::Result::TIMEOUT:
            return FollowMe::Result::TIMEOUT;
        default:
            return FollowMe::Result::UNKNOWN;
    }
}

bool FollowMeImpl::is_target_location_set() const
{
    // If the target's latitude is NAN, we assume that location is not set.
    // We assume that mutex was acquired by the caller
    return std::isfinite(_target_location.latitude_deg);
}

void FollowMeImpl::send_target_location()
{
    // Don't send if we're not in FollowMe mode.
    if (!is_active()) {
        return;
    }

    dl_time_t now = _time.steady_time();
    // needed by http://mavlink.org/messages/common#FOLLOW_TARGET
    uint64_t elapsed_msec =
        static_cast<uint64_t>(_time.elapsed_since_s(now) * 1000); // milliseconds

    _mutex.lock();
    //   LogDebug() << debug_str <<  "Lat: " << _target_location.latitude_deg << " Lon: " <<
    //   _target_location.longitude_deg <<
    //	" Alt: " << _target_location.absolute_altitude_m;
    const int32_t lat_int = static_cast<int32_t>(_target_location.latitude_deg * 1e7);
    const int32_t lon_int = static_cast<int32_t>(_target_location.longitude_deg * 1e7);
    const float alt = static_cast<float>(_target_location.absolute_altitude_m);
    _mutex.unlock();

    const float pos_std_dev[] = {NAN, NAN, NAN};
    const float vel[] = {NAN, NAN, NAN};
    const float accel_unknown[] = {NAN, NAN, NAN};
    const float attitude_q_unknown[] = {1.f, NAN, NAN, NAN};
    const float rates_unknown[] = {NAN, NAN, NAN};
    uint64_t custom_state = 0;

    mavlink_message_t msg{};
    mavlink_msg_follow_target_pack(GCSClient::system_id,
                                   GCSClient::component_id,
                                   &msg,
                                   elapsed_msec,
                                   _estimatation_capabilities,
                                   lat_int,
                                   lon_int,
                                   alt,
                                   vel,
                                   accel_unknown,
                                   attitude_q_unknown,
                                   rates_unknown,
                                   pos_std_dev,
                                   custom_state);

    if (!_parent->send_message(msg)) {
        LogErr() << debug_str << "send_target_location() failed..";
    } else {
        std::lock_guard<std::mutex> lock(_mutex);
        _last_location = _target_location;
    }
}

void FollowMeImpl::stop_sending_target_location()
{
    // We assume that mutex was acquired by the caller
    if (_target_location_cookie) {
        _parent->remove_call_every(_target_location_cookie);
        _target_location_cookie = nullptr;
    }
    _mode = Mode::NOT_ACTIVE;
}

void FollowMeImpl::process_heartbeat(const mavlink_message_t &message)
{
    mavlink_heartbeat_t heartbeat;
    mavlink_msg_heartbeat_decode(&message, &heartbeat);

    bool follow_me_active = false; // tells whether we're in FollowMe mode right now
    if (heartbeat.base_mode & MAV_MODE_FLAG_CUSTOM_MODE_ENABLED) {
        px4::px4_custom_mode px4_custom_mode;
        px4_custom_mode.data = heartbeat.custom_mode;

        if (px4_custom_mode.main_mode == px4::PX4_CUSTOM_MAIN_MODE_AUTO &&
            px4_custom_mode.sub_mode == px4::PX4_CUSTOM_SUB_MODE_AUTO_FOLLOW_TARGET) {
            follow_me_active = true; // we're in FollowMe mode
        }
    }

    {
        std::lock_guard<std::mutex> lock(_mutex);
        if (!follow_me_active && _mode == Mode::ACTIVE) {
            // We're NOT in FollowMe mode anymore.
            // Lets stop sending target location updates
            stop_sending_target_location();
        } else if (follow_me_active && _mode == Mode::NOT_ACTIVE) {
            // We're in FollowMe mode now
            _mode = Mode::ACTIVE;
            _mutex.unlock(); // we must unlock to avoid deadlock in send_target_location()
            return;
        }
    }
}

} // namespace dronecode_sdk
<commit_msg>follow_me: small improvement<commit_after>#include "follow_me_impl.h"
#include "system.h"
#include "global_include.h"
#include "px4_custom_mode.h"

namespace dronecode_sdk {

FollowMeImpl::FollowMeImpl(System &system) : PluginImplBase(system)
{
    // (Lat, Lon, Alt) => double, (vx, vy, vz) => float
    _last_location = _target_location =
        FollowMe::TargetLocation{double(NAN), double(NAN), double(NAN), NAN, NAN, NAN};
    _parent->register_plugin(this);
}

FollowMeImpl::~FollowMeImpl()
{
    _parent->unregister_plugin(this);
}

void FollowMeImpl::init()
{
    _parent->register_mavlink_message_handler(
        MAVLINK_MSG_ID_HEARTBEAT,
        std::bind(&FollowMeImpl::process_heartbeat, this, std::placeholders::_1),
        static_cast<void *>(this));
}

void FollowMeImpl::deinit()
{
    _parent->unregister_all_mavlink_message_handlers(this);
}

void FollowMeImpl::enable()
{
    _parent->get_param_float_async("NAV_MIN_FT_HT", [this](bool success, float value) {
        if (success) {
            _config.min_height_m = value;
        }
    });
    _parent->get_param_float_async("NAV_FT_DST", [this](bool success, float value) {
        if (success) {
            _config.follow_distance_m = value;
        }
    });
    _parent->get_param_int_async("NAV_FT_FS", [this](bool success, int32_t value) {
        if (success) {
            _config.follow_direction = static_cast<FollowMe::Config::FollowDirection>(value);
        }
    });
    _parent->get_param_float_async("NAV_FT_RS", [this](bool success, float value) {
        if (success) {
            _config.responsiveness = value;
        }
    });
}

void FollowMeImpl::disable()
{
    stop_sending_target_location();
}

const FollowMe::Config &FollowMeImpl::get_config() const
{
    return _config;
}

FollowMe::Result FollowMeImpl::set_config(const FollowMe::Config &config)
{
    // Valdidate configuration
    if (!is_config_ok(config)) {
        LogErr() << debug_str << "set_config() failed. Last configuration is preserved.";
        return FollowMe::Result::SET_CONFIG_FAILED;
    }

    auto height = config.min_height_m;
    auto distance = config.follow_distance_m;
    int32_t direction = static_cast<int32_t>(config.follow_direction);
    auto responsiveness = config.responsiveness;

    LogDebug() << "Waiting for the system confirmation of the new configuration..";

    bool success = true;

    // Send configuration to Vehicle
    if (_config.min_height_m != height) {
        if (_parent->set_param_float("NAV_MIN_FT_HT", height)) {
            _config.min_height_m = height;
        } else {
            success = false;
        }
    }
    if (_config.follow_distance_m != distance) {
        if (_parent->set_param_float("NAV_FT_DST", distance)) {
            _config.follow_distance_m = distance;
        } else {
            success = false;
        }
    }
    if (_config.follow_direction != config.follow_direction) {
        if (_parent->set_param_int("NAV_FT_FS", direction)) {
            _config.follow_direction = static_cast<FollowMe::Config::FollowDirection>(direction);

        } else {
            success = false;
        }
    }
    if (_config.responsiveness != responsiveness) {
        if (_parent->set_param_float("NAV_FT_RS", responsiveness)) {
            _config.responsiveness = responsiveness;
        } else {
            success = false;
        }
    }

    return (success ? FollowMe::Result::SUCCESS : FollowMe::Result::SET_CONFIG_FAILED);
}

void FollowMeImpl::set_target_location(const FollowMe::TargetLocation &location)
{
    _mutex.lock();
    _target_location = location;
    // We're interested only in lat, long.
    _estimatation_capabilities |= (1 << static_cast<int>(EstimationCapabilites::POS));

    if (_mode != Mode::ACTIVE) {
        _mutex.unlock();
        return;
    }
    // If set already, reschedule it.
    if (_target_location_cookie) {
        _parent->reset_call_every(_target_location_cookie);
        _target_location_cookie = nullptr;
    } else {
        // Regiter now for sending in the next cycle.
        _parent->add_call_every(
            [this]() { send_target_location(); }, SENDER_RATE, &_target_location_cookie);
    }
    _mutex.unlock();

    // Send it immediately for now.
    send_target_location();
}

const FollowMe::TargetLocation &FollowMeImpl::get_last_location() const
{
    std::lock_guard<std::mutex> lock(_mutex);
    return _last_location;
}

bool FollowMeImpl::is_active() const
{
    std::lock_guard<std::mutex> lock(_mutex);
    return _mode == Mode::ACTIVE;
}

FollowMe::Result FollowMeImpl::start()
{
    FollowMe::Result result =
        to_follow_me_result(_parent->set_flight_mode(SystemImpl::FlightMode::FOLLOW_ME));

    if (result == FollowMe::Result::SUCCESS) {
        // If location was set before, lets send it to vehicle
        std::lock_guard<std::mutex> lock(
            _mutex); // locking is not necessary here but lets do it for integrity
        if (is_target_location_set()) {
            _parent->add_call_every(
                [this]() { send_target_location(); }, SENDER_RATE, &_target_location_cookie);
        }
    }
    return result;
}

FollowMe::Result FollowMeImpl::stop()
{
    {
        std::lock_guard<std::mutex> lock(_mutex);
        if (_mode == Mode::ACTIVE) {
            stop_sending_target_location();
        }
    }
    return to_follow_me_result(_parent->set_flight_mode(SystemImpl::FlightMode::HOLD));
}

bool FollowMeImpl::is_config_ok(const FollowMe::Config &config) const
{
    auto config_ok = false;

    if (config.min_height_m < FollowMe::Config::MIN_HEIGHT_M) {
        LogErr() << debug_str << "Err: Min height must be atleast 8.0 meters";
    } else if (config.follow_distance_m < FollowMe::Config::MIN_FOLLOW_DIST_M) {
        LogErr() << debug_str << "Err: Min Follow distance must be atleast 1.0 meter";
    } else if (config.follow_direction < FollowMe::Config::FollowDirection::FRONT_RIGHT ||
               config.follow_direction > FollowMe::Config::FollowDirection::NONE) {
        LogErr() << debug_str << "Err: Invalid Follow direction";
    } else if (config.responsiveness < FollowMe::Config::MIN_RESPONSIVENESS ||
               config.responsiveness > FollowMe::Config::MAX_RESPONSIVENESS) {
        LogErr() << debug_str << "Err: Responsiveness must be in range (0.0 to 1.0)";
    } else { // Config is OK
        config_ok = true;
    }

    return config_ok;
}

FollowMe::Result FollowMeImpl::to_follow_me_result(MAVLinkCommands::Result result) const
{
    switch (result) {
        case MAVLinkCommands::Result::SUCCESS:
            return FollowMe::Result::SUCCESS;
        case MAVLinkCommands::Result::NO_SYSTEM:
            return FollowMe::Result::NO_SYSTEM;
        case MAVLinkCommands::Result::CONNECTION_ERROR:
            return FollowMe::Result::CONNECTION_ERROR;
        case MAVLinkCommands::Result::BUSY:
            return FollowMe::Result::BUSY;
        case MAVLinkCommands::Result::COMMAND_DENIED:
            return FollowMe::Result::COMMAND_DENIED;
        case MAVLinkCommands::Result::TIMEOUT:
            return FollowMe::Result::TIMEOUT;
        default:
            return FollowMe::Result::UNKNOWN;
    }
}

bool FollowMeImpl::is_target_location_set() const
{
    // If the target's latitude is NAN, we assume that location is not set.
    // We assume that mutex was acquired by the caller
    return std::isfinite(_target_location.latitude_deg);
}

void FollowMeImpl::send_target_location()
{
    // Don't send if we're not in FollowMe mode.
    if (!is_active()) {
        return;
    }

    dl_time_t now = _time.steady_time();
    // needed by http://mavlink.org/messages/common#FOLLOW_TARGET
    uint64_t elapsed_msec =
        static_cast<uint64_t>(_time.elapsed_since_s(now) * 1000); // milliseconds

    _mutex.lock();
    //   LogDebug() << debug_str <<  "Lat: " << _target_location.latitude_deg << " Lon: " <<
    //   _target_location.longitude_deg <<
    //	" Alt: " << _target_location.absolute_altitude_m;
    const int32_t lat_int = static_cast<int32_t>(_target_location.latitude_deg * 1e7);
    const int32_t lon_int = static_cast<int32_t>(_target_location.longitude_deg * 1e7);
    const float alt = static_cast<float>(_target_location.absolute_altitude_m);
    _mutex.unlock();

    const float pos_std_dev[] = {NAN, NAN, NAN};
    const float vel[] = {NAN, NAN, NAN};
    const float accel_unknown[] = {NAN, NAN, NAN};
    const float attitude_q_unknown[] = {1.f, NAN, NAN, NAN};
    const float rates_unknown[] = {NAN, NAN, NAN};
    uint64_t custom_state = 0;

    mavlink_message_t msg{};
    mavlink_msg_follow_target_pack(GCSClient::system_id,
                                   GCSClient::component_id,
                                   &msg,
                                   elapsed_msec,
                                   _estimatation_capabilities,
                                   lat_int,
                                   lon_int,
                                   alt,
                                   vel,
                                   accel_unknown,
                                   attitude_q_unknown,
                                   rates_unknown,
                                   pos_std_dev,
                                   custom_state);

    if (!_parent->send_message(msg)) {
        LogErr() << debug_str << "send_target_location() failed..";
    } else {
        std::lock_guard<std::mutex> lock(_mutex);
        _last_location = _target_location;
    }
}

void FollowMeImpl::stop_sending_target_location()
{
    // We assume that mutex was acquired by the caller
    if (_target_location_cookie) {
        _parent->remove_call_every(_target_location_cookie);
        _target_location_cookie = nullptr;
    }
    _mode = Mode::NOT_ACTIVE;
}

void FollowMeImpl::process_heartbeat(const mavlink_message_t &message)
{
    mavlink_heartbeat_t heartbeat;
    mavlink_msg_heartbeat_decode(&message, &heartbeat);

    bool follow_me_active = false; // tells whether we're in FollowMe mode right now
    if (heartbeat.base_mode & MAV_MODE_FLAG_CUSTOM_MODE_ENABLED) {
        px4::px4_custom_mode px4_custom_mode;
        px4_custom_mode.data = heartbeat.custom_mode;

        if (px4_custom_mode.main_mode == px4::PX4_CUSTOM_MAIN_MODE_AUTO &&
            px4_custom_mode.sub_mode == px4::PX4_CUSTOM_SUB_MODE_AUTO_FOLLOW_TARGET) {
            follow_me_active = true; // we're in FollowMe mode
        }
    }

    {
        std::lock_guard<std::mutex> lock(_mutex);
        if (!follow_me_active && _mode == Mode::ACTIVE) {
            // We're NOT in FollowMe mode anymore.
            // Lets stop sending target location updates
            stop_sending_target_location();
        } else if (follow_me_active && _mode == Mode::NOT_ACTIVE) {
            // We're in FollowMe mode now
            _mode = Mode::ACTIVE;
            _mutex.unlock(); // we must unlock to avoid deadlock in send_target_location()
            return;
        }
    }
}

} // namespace dronecode_sdk
<|endoftext|>


<commit_before>#include "point_series_xy.h"
#include <cmath>
#include <cstdlib>

PointSeriesXY::PointSeriesXY(const PlotData *y_axis, const PlotData *x_axis):
    DataSeriesBase( &_cached_curve ),
    _x_axis(x_axis),
    _y_axis(y_axis),
    _cached_curve("")
{
    updateCache();
}

PlotData::RangeTimeOpt PointSeriesXY::getVisualizationRangeX()
{
    if( this->size() < 2 )
        return  PlotData::RangeTimeOpt();
    else{
        return PlotData::RangeTimeOpt( { _bounding_box.left() ,
                                         _bounding_box.right()} );
    }
}

nonstd::optional<QPointF> PointSeriesXY::sampleFromTime(double t)
{
    if( _cached_curve.size() == 0 )
    {
        return {};
    }

    int index = _y_axis->getIndexFromX(t);
    if(index <0)
    {
        return {};
    }
    const auto& p = _cached_curve.at( size_t(index) );
    return QPointF(p.x, p.y);
}

PlotData::RangeValueOpt PointSeriesXY::getVisualizationRangeY(PlotData::RangeTime range_X)
{
    //TODO: improve?
    return PlotData::RangeValueOpt( { _bounding_box.bottom(),
                                      _bounding_box.top() } );
}

bool PointSeriesXY::updateCache()
{
    if( _x_axis == nullptr )
    {
        throw std::runtime_error("the X axis is null");
    }

    const size_t data_size =  _x_axis->size();

    if( data_size != _y_axis->size() )
    {
        _bounding_box = QRectF();
        _cached_curve.clear();
        throw std::runtime_error("X and Y axis don't share the same time axis");
    }

    if(data_size == 0)
    {
        _bounding_box = QRectF();
        _cached_curve.clear();
        return true;
    }

    double min_y =( std::numeric_limits<double>::max() );
    double max_y =(-std::numeric_limits<double>::max() );
    double min_x =( std::numeric_limits<double>::max() );
    double max_x =(-std::numeric_limits<double>::max() );

    _cached_curve.resize( data_size );

    const double EPS = std::numeric_limits<double>::epsilon();

    for (size_t i=0; i<data_size; i++ )
    {
        if( Abs( _x_axis->at(i).x  - _y_axis->at(i).x ) >  EPS)
        {
            _bounding_box = QRectF();
            _cached_curve.clear();
            throw std::runtime_error("X and Y axis don't share the same time axis");
        }

        const QPointF p(_x_axis->at(i).y,
                        _y_axis->at(i).y );

        _cached_curve.at(i) = { p.x(), p.y() };

        min_x = std::min( min_x, p.x() );
        max_x = std::max( max_x, p.x() );
        min_y = std::min( min_y, p.y() );
        max_y = std::max( max_y, p.y() );
    }

    _bounding_box.setLeft(  min_x );
    _bounding_box.setRight( max_x );
    _bounding_box.setBottom( min_y );
    _bounding_box.setTop( max_y );

    return true;
}
<commit_msg>relax the XY consitions as suggested in #177<commit_after>#include "point_series_xy.h"
#include <cmath>
#include <cstdlib>

PointSeriesXY::PointSeriesXY(const PlotData *y_axis, const PlotData *x_axis):
    DataSeriesBase( &_cached_curve ),
    _x_axis(x_axis),
    _y_axis(y_axis),
    _cached_curve("")
{
    updateCache();
}

PlotData::RangeTimeOpt PointSeriesXY::getVisualizationRangeX()
{
    if( this->size() < 2 )
        return  PlotData::RangeTimeOpt();
    else{
        return PlotData::RangeTimeOpt( { _bounding_box.left() ,
                                         _bounding_box.right()} );
    }
}

nonstd::optional<QPointF> PointSeriesXY::sampleFromTime(double t)
{
    if( _cached_curve.size() == 0 )
    {
        return {};
    }

    int index = _y_axis->getIndexFromX(t);
    if(index <0)
    {
        return {};
    }
    const auto& p = _cached_curve.at( size_t(index) );
    return QPointF(p.x, p.y);
}

PlotData::RangeValueOpt PointSeriesXY::getVisualizationRangeY(PlotData::RangeTime range_X)
{
    //TODO: improve?
    return PlotData::RangeValueOpt( { _bounding_box.bottom(),
                                      _bounding_box.top() } );
}

bool PointSeriesXY::updateCache()
{
    if( _x_axis == nullptr )
    {
        throw std::runtime_error("the X axis is null");
    }

    const size_t data_size =  std::min(_x_axis->size(), _y_axis->size());

    if(data_size == 0)
    {
        _bounding_box = QRectF();
        _cached_curve.clear();
        return true;
    }

    double min_y =( std::numeric_limits<double>::max() );
    double max_y =(-std::numeric_limits<double>::max() );
    double min_x =( std::numeric_limits<double>::max() );
    double max_x =(-std::numeric_limits<double>::max() );

    _cached_curve.resize( data_size );

    const double EPS = std::numeric_limits<double>::epsilon();

    for (size_t i=0; i<data_size; i++ )
    {
        if( Abs( _x_axis->at(i).x  - _y_axis->at(i).x ) >  EPS)
        {
            _bounding_box = QRectF();
            _cached_curve.clear();
            throw std::runtime_error("X and Y axis don't share the same time axis");
        }

        const QPointF p(_x_axis->at(i).y,
                        _y_axis->at(i).y );

        _cached_curve.at(i) = { p.x(), p.y() };

        min_x = std::min( min_x, p.x() );
        max_x = std::max( max_x, p.x() );
        min_y = std::min( min_y, p.y() );
        max_y = std::max( max_y, p.y() );
    }

    _bounding_box.setLeft(  min_x );
    _bounding_box.setRight( max_x );
    _bounding_box.setBottom( min_y );
    _bounding_box.setTop( max_y );

    return true;
}
<|endoftext|>


<commit_before>/******************************************************************************
 * This file is part of the MULA project
 * Copyright (c) 2011 Laszlo Papp <lpapp@kde.org>
 *
 * 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.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License aLong with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "dictionary.h"

#include "dictionaryzip.h"
#include "stardictdictionaryinfo.h"
#include "indexfile.h"
#include "offsetcachefile.h"

#include <QtCore/QScopedPointer>
#include <QtCore/QFile>
#include <QtCore/QDebug>

using namespace MulaPluginStarDict;

class Dictionary::Private
{
    public:
        Private()
            : wordCount(0)
            , indexFileSize(0)
        {
        }

        ~Private()
        {
        }

        QString ifoFilePath;
        long wordCount;
        QString bookName;

        QScopedPointer<AbstractIndexFile> indexFile;
        int indexFileSize;
};

Dictionary::Dictionary()
    : d(new Private)
{
}

Dictionary::~Dictionary()
{
}

int
Dictionary::articleCount() const
{
    return d->wordCount;
}

const QString
Dictionary::dictionaryName() const
{
    return d->bookName;
}

const QString
Dictionary::ifoFilePath() const
{
    return d->ifoFilePath;
}

const QString
Dictionary::key(long index) const
{
    if (d->indexFile.isNull())
        return QString();

    return d->indexFile->key(index);
}

QString
Dictionary::data(long index)
{
    Q_UNUSED(index);
    if (d->indexFile.isNull())
        return QString();

    return AbstractDictionary::wordData(d->indexFile->wordEntryOffset(), d->indexFile->wordEntrySize());
}

const WordEntry
Dictionary::wordEntry(long index)
{
    if (d->indexFile.isNull())
        return WordEntry();

    WordEntry wordEntry;
    wordEntry.setData(d->indexFile->key(index));
    wordEntry.setDataOffset(d->indexFile->wordEntryOffset());
    wordEntry.setDataSize(d->indexFile->wordEntrySize());

    return wordEntry;
}

bool
Dictionary::lookup(const QString word, int &index)
{
    if (d->indexFile.isNull())
        return false;

    return d->indexFile->lookup(word.toUtf8(), index);
}

bool
Dictionary::load(const QString& ifoFilePath)
{
    if (!loadIfoFile(ifoFilePath))
        return false;

    QString completeFilePath = ifoFilePath;
    completeFilePath.replace(completeFilePath.length() - sizeof("ifo") + 1, sizeof("ifo") - 1, "dict.dz");

    if (QFile(completeFilePath).exists())
    {
        DictionaryZip *dictionaryZip = compressedDictionaryFile();
        if (!dictionaryZip)
        {
            delete dictionaryZip;
            dictionaryZip = 0;
        }

        dictionaryZip = new DictionaryZip();
        if (!dictionaryZip->open(completeFilePath, 0))
        {
            qDebug() << "Failed to open file:" << completeFilePath;
            return false;
        }
    }
    else
    {
        completeFilePath.chop(sizeof(".dz"));

        QFile *uncompressedDictionaryFile = dictionaryFile();
        if (uncompressedDictionaryFile)
        {
            delete uncompressedDictionaryFile;
            uncompressedDictionaryFile = 0;
        }

        uncompressedDictionaryFile = new QFile(completeFilePath);
        if( uncompressedDictionaryFile->open( QIODevice::ReadOnly ) )
        {
            qDebug() << "Failed to open file:" << completeFilePath;
            return -1;
        }
    }

    completeFilePath = ifoFilePath;
    completeFilePath.replace(completeFilePath.length() - sizeof("ifo") + 1, sizeof("ifo") - 1, "idx.gz");

    if (QFile(completeFilePath).exists())
    {
        d->indexFile.reset(new IndexFile);
    }
    else
    {
        completeFilePath.chop(sizeof(".gz"));
        d->indexFile.reset(new OffsetCacheFile);
    }

    if (!d->indexFile->load(completeFilePath, d->wordCount, d->indexFileSize))
        return false;

    return true;
}

bool
Dictionary::loadIfoFile(const QString& ifoFilePath)
{
    StarDictDictionaryInfo dictionaryInfo;
    if (!dictionaryInfo.loadFromIfoFile(ifoFilePath))
        return false;

    if (dictionaryInfo.wordCount() == 0)
        return false;

    d->ifoFilePath = dictionaryInfo.ifoFilePath();
    d->wordCount = dictionaryInfo.wordCount();
    d->bookName = dictionaryInfo.bookName();

    d->indexFileSize = dictionaryInfo.indexFileSize();

    setSameTypeSequence(dictionaryInfo.sameTypeSequence());

    return true;
}

bool
Dictionary::lookupWithRule(const QString& pattern, long *aIndex, int iBuffLen)
{
    int indexCount = 0;
    bool found = false;

    QRegExp rx(pattern);
    rx.setPatternSyntax(QRegExp::Wildcard);

    for (int i = 0; i < articleCount() && indexCount < iBuffLen - 1; ++i)
    {
        if (rx.exactMatch(key(i)))
        {
            aIndex[indexCount++] = i;
            found = true;
        }
    }

    aIndex[indexCount] = -1; // -1 is the end.

    return found;
}

<commit_msg>Use one dictionaryInfo member in the private class instead of various members<commit_after>/******************************************************************************
 * This file is part of the MULA project
 * Copyright (c) 2011 Laszlo Papp <lpapp@kde.org>
 *
 * 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.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License aLong with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "dictionary.h"

#include "dictionaryzip.h"
#include "stardictdictionaryinfo.h"
#include "indexfile.h"
#include "offsetcachefile.h"

#include <QtCore/QScopedPointer>
#include <QtCore/QFile>
#include <QtCore/QDebug>

using namespace MulaPluginStarDict;

class Dictionary::Private
{
    public:
        Private()
        {
        }

        ~Private()
        {
        }

        StarDictDictionaryInfo dictionaryInfo;
        QScopedPointer<AbstractIndexFile> indexFile;
};

Dictionary::Dictionary()
    : d(new Private)
{
}

Dictionary::~Dictionary()
{
}

int
Dictionary::articleCount() const
{
    return d->dictionaryInfo.wordCount();
}

const QString
Dictionary::dictionaryName() const
{
    return d->dictionaryInfo.bookName();
}

const QString
Dictionary::ifoFilePath() const
{
    return d->dictionaryInfo.ifoFilePath();
}

const QString
Dictionary::key(long index) const
{
    if (d->indexFile.isNull())
        return QString();

    return d->indexFile->key(index);
}

QString
Dictionary::data(long index)
{
    Q_UNUSED(index);
    if (d->indexFile.isNull())
        return QString();

    return AbstractDictionary::wordData(d->indexFile->wordEntryOffset(), d->indexFile->wordEntrySize());
}

const WordEntry
Dictionary::wordEntry(long index)
{
    if (d->indexFile.isNull())
        return WordEntry();

    WordEntry wordEntry;
    wordEntry.setData(d->indexFile->key(index));
    wordEntry.setDataOffset(d->indexFile->wordEntryOffset());
    wordEntry.setDataSize(d->indexFile->wordEntrySize());

    return wordEntry;
}

bool
Dictionary::lookup(const QString word, int &index)
{
    if (d->indexFile.isNull())
        return false;

    return d->indexFile->lookup(word.toUtf8(), index);
}

bool
Dictionary::load(const QString& ifoFilePath)
{
    if (!loadIfoFile(ifoFilePath))
        return false;

    QString completeFilePath = ifoFilePath;
    completeFilePath.replace(completeFilePath.length() - sizeof("ifo") + 1, sizeof("ifo") - 1, "dict.dz");

    if (QFile(completeFilePath).exists())
    {
        DictionaryZip *dictionaryZip = compressedDictionaryFile();
        if (!dictionaryZip)
        {
            delete dictionaryZip;
            dictionaryZip = 0;
        }

        dictionaryZip = new DictionaryZip();
        if (!dictionaryZip->open(completeFilePath, 0))
        {
            qDebug() << "Failed to open file:" << completeFilePath;
            return false;
        }
    }
    else
    {
        completeFilePath.chop(sizeof(".dz"));

        QFile *uncompressedDictionaryFile = dictionaryFile();
        if (uncompressedDictionaryFile)
        {
            delete uncompressedDictionaryFile;
            uncompressedDictionaryFile = 0;
        }

        uncompressedDictionaryFile = new QFile(completeFilePath);
        if( uncompressedDictionaryFile->open( QIODevice::ReadOnly ) )
        {
            qDebug() << "Failed to open file:" << completeFilePath;
            return -1;
        }
    }

    completeFilePath = ifoFilePath;
    completeFilePath.replace(completeFilePath.length() - sizeof("ifo") + 1, sizeof("ifo") - 1, "idx.gz");

    if (QFile(completeFilePath).exists())
    {
        d->indexFile.reset(new IndexFile);
    }
    else
    {
        completeFilePath.chop(sizeof(".gz"));
        d->indexFile.reset(new OffsetCacheFile);
    }

    if (!d->indexFile->load(completeFilePath, d->dictionaryInfo.wordCount(), d->dictionaryInfo.indexFileSize()))
        return false;

    return true;
}

bool
Dictionary::loadIfoFile(const QString& ifoFilePath)
{
    if (!d->dictionaryInfo.loadFromIfoFile(ifoFilePath))
        return false;

    if (d->dictionaryInfo.wordCount() == 0)
        return false;

    setSameTypeSequence(d->dictionaryInfo.sameTypeSequence());

    return true;
}

bool
Dictionary::lookupWithRule(const QString& pattern, long *aIndex, int iBuffLen)
{
    int indexCount = 0;
    bool found = false;

    QRegExp rx(pattern);
    rx.setPatternSyntax(QRegExp::Wildcard);

    for (int i = 0; i < articleCount() && indexCount < iBuffLen - 1; ++i)
    {
        if (rx.exactMatch(key(i)))
        {
            aIndex[indexCount++] = i;
            found = true;
        }
    }

    aIndex[indexCount] = -1; // -1 is the end.

    return found;
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: osl_Module_DLL.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 15:30:48 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <stdio.h>
#include <sal/types.h>
#include <cppunit/simpleheader.hxx>

extern "C" sal_Bool SAL_CALL firstfunc( sal_Bool bRes )
{
   return ( bRes = sal_True );
}
extern "C" void SAL_CALL secondfunc()
{
   printf("second func called.\n");
}

<commit_msg>INTEGRATION: CWS pchfix02 (1.4.140); FILE MERGED 2006/09/01 17:34:04 kaib 1.4.140.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: osl_Module_DLL.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 08:50:21 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sal.hxx"

#include <stdio.h>
#include <sal/types.h>
#include <cppunit/simpleheader.hxx>

extern "C" sal_Bool SAL_CALL firstfunc( sal_Bool bRes )
{
   return ( bRes = sal_True );
}
extern "C" void SAL_CALL secondfunc()
{
   printf("second func called.\n");
}

<|endoftext|>


<commit_before>#include <system/Display.h>

namespace lime {

	int Display::GetNumDevices() {

		return SDL_GetNumVideoDisplays();

	}

	static const char* GetDisplayName (int displayIndex) {

		return SDL_GetDisplayName(displayIndex);

	}

}<commit_msg>add name<commit_after>#include <system/Display.h>

namespace lime {

	int Display::GetNumDevices() {

		return SDL_GetNumVideoDisplays();

	}

	const char* Display::GetDisplayName (int displayIndex) {

		return SDL_GetDisplayName(displayIndex);

	}

}<|endoftext|>


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

extern "C" {
#include "main/macros.h"
#include "program/register_allocate.h"
} /* extern "C" */

#include "brw_vec4.h"
#include "brw_vs.h"

using namespace brw;

namespace brw {

static void
assign(unsigned int *reg_hw_locations, reg *reg)
{
   if (reg->file == GRF) {
      reg->reg = reg_hw_locations[reg->reg];
   }
}

bool
vec4_visitor::reg_allocate_trivial()
{
   unsigned int hw_reg_mapping[this->virtual_grf_count];
   bool virtual_grf_used[this->virtual_grf_count];
   int i;
   int next;

   /* Calculate which virtual GRFs are actually in use after whatever
    * optimization passes have occurred.
    */
   for (int i = 0; i < this->virtual_grf_count; i++) {
      virtual_grf_used[i] = false;
   }

   foreach_iter(exec_list_iterator, iter, this->instructions) {
      vec4_instruction *inst = (vec4_instruction *)iter.get();

      if (inst->dst.file == GRF)
	 virtual_grf_used[inst->dst.reg] = true;

      for (int i = 0; i < 3; i++) {
	 if (inst->src[i].file == GRF)
	    virtual_grf_used[inst->src[i].reg] = true;
      }
   }

   hw_reg_mapping[0] = this->first_non_payload_grf;
   next = hw_reg_mapping[0] + this->virtual_grf_sizes[0];
   for (i = 1; i < this->virtual_grf_count; i++) {
      if (virtual_grf_used[i]) {
	 hw_reg_mapping[i] = next;
	 next += this->virtual_grf_sizes[i];
      }
   }
   prog_data->total_grf = next;

   foreach_iter(exec_list_iterator, iter, this->instructions) {
      vec4_instruction *inst = (vec4_instruction *)iter.get();

      assign(hw_reg_mapping, &inst->dst);
      assign(hw_reg_mapping, &inst->src[0]);
      assign(hw_reg_mapping, &inst->src[1]);
      assign(hw_reg_mapping, &inst->src[2]);
   }

   if (prog_data->total_grf > max_grf) {
      fail("Ran out of regs on trivial allocator (%d/%d)\n",
	   prog_data->total_grf, max_grf);
      return false;
   }

   return true;
}

static void
brw_alloc_reg_set_for_classes(struct brw_context *brw,
			      int *class_sizes,
			      int class_count,
			      int base_reg_count)
{
   /* Compute the total number of registers across all classes. */
   int ra_reg_count = 0;
   for (int i = 0; i < class_count; i++) {
      ra_reg_count += base_reg_count - (class_sizes[i] - 1);
   }

   ralloc_free(brw->vs.ra_reg_to_grf);
   brw->vs.ra_reg_to_grf = ralloc_array(brw, uint8_t, ra_reg_count);
   ralloc_free(brw->vs.regs);
   brw->vs.regs = ra_alloc_reg_set(brw, ra_reg_count);
   if (brw->gen >= 6)
      ra_set_allocate_round_robin(brw->vs.regs);
   ralloc_free(brw->vs.classes);
   brw->vs.classes = ralloc_array(brw, int, class_count + 1);

   /* Now, add the registers to their classes, and add the conflicts
    * between them and the base GRF registers (and also each other).
    */
   int reg = 0;
   for (int i = 0; i < class_count; i++) {
      int class_reg_count = base_reg_count - (class_sizes[i] - 1);
      brw->vs.classes[i] = ra_alloc_reg_class(brw->vs.regs);

      for (int j = 0; j < class_reg_count; j++) {
	 ra_class_add_reg(brw->vs.regs, brw->vs.classes[i], reg);

	 brw->vs.ra_reg_to_grf[reg] = j;

	 for (int base_reg = j;
	      base_reg < j + class_sizes[i];
	      base_reg++) {
	    ra_add_transitive_reg_conflict(brw->vs.regs, base_reg, reg);
	 }

	 reg++;
      }
   }
   assert(reg == ra_reg_count);

   ra_set_finalize(brw->vs.regs, NULL);
}

bool
vec4_visitor::reg_allocate()
{
   unsigned int hw_reg_mapping[virtual_grf_count];
   int first_assigned_grf = this->first_non_payload_grf;
   int base_reg_count = max_grf - first_assigned_grf;
   int class_sizes[base_reg_count];
   int class_count = 0;

   /* Using the trivial allocator can be useful in debugging undefined
    * register access as a result of broken optimization passes.
    */
   if (0)
      return reg_allocate_trivial();

   calculate_live_intervals();

   /* Set up the register classes.
    *
    * The base registers store a vec4.  However, we'll need larger
    * storage for arrays, structures, and matrices, which will be sets
    * of contiguous registers.
    */
   class_sizes[class_count++] = 1;

   for (int r = 0; r < virtual_grf_count; r++) {
      int i;

      for (i = 0; i < class_count; i++) {
	 if (class_sizes[i] == this->virtual_grf_sizes[r])
	    break;
      }
      if (i == class_count) {
	 if (this->virtual_grf_sizes[r] >= base_reg_count) {
	    fail("Object too large to register allocate.\n");
	 }

	 class_sizes[class_count++] = this->virtual_grf_sizes[r];
      }
   }

   brw_alloc_reg_set_for_classes(brw, class_sizes, class_count, base_reg_count);

   struct ra_graph *g = ra_alloc_interference_graph(brw->vs.regs,
						    virtual_grf_count);

   for (int i = 0; i < virtual_grf_count; i++) {
      for (int c = 0; c < class_count; c++) {
	 if (class_sizes[c] == this->virtual_grf_sizes[i]) {
	    ra_set_node_class(g, i, brw->vs.classes[c]);
	    break;
	 }
      }

      for (int j = 0; j < i; j++) {
	 if (virtual_grf_interferes(i, j)) {
	    ra_add_node_interference(g, i, j);
	 }
      }
   }

   if (!ra_allocate_no_spills(g)) {
      /* Failed to allocate registers.  Spill a reg, and the caller will
       * loop back into here to try again.
       */
      int reg = choose_spill_reg(g);
      if (reg == -1) {
         fail("no register to spill\n");
      } else {
         spill_reg(reg);
      }
      ralloc_free(g);
      return false;
   }

   /* Get the chosen virtual registers for each node, and map virtual
    * regs in the register classes back down to real hardware reg
    * numbers.
    */
   prog_data->total_grf = first_assigned_grf;
   for (int i = 0; i < virtual_grf_count; i++) {
      int reg = ra_get_node_reg(g, i);

      hw_reg_mapping[i] = first_assigned_grf + brw->vs.ra_reg_to_grf[reg];
      prog_data->total_grf = MAX2(prog_data->total_grf,
				  hw_reg_mapping[i] + virtual_grf_sizes[i]);
   }

   foreach_list(node, &this->instructions) {
      vec4_instruction *inst = (vec4_instruction *)node;

      assign(hw_reg_mapping, &inst->dst);
      assign(hw_reg_mapping, &inst->src[0]);
      assign(hw_reg_mapping, &inst->src[1]);
      assign(hw_reg_mapping, &inst->src[2]);
   }

   ralloc_free(g);

   return true;
}

void
vec4_visitor::evaluate_spill_costs(float *spill_costs, bool *no_spill)
{
   float loop_scale = 1.0;

   for (int i = 0; i < this->virtual_grf_count; i++) {
      spill_costs[i] = 0.0;
      no_spill[i] = virtual_grf_sizes[i] != 1;
   }

   /* Calculate costs for spilling nodes.  Call it a cost of 1 per
    * spill/unspill we'll have to do, and guess that the insides of
    * loops run 10 times.
    */
   foreach_list(node, &this->instructions) {
      vec4_instruction *inst = (vec4_instruction *) node;

      for (unsigned int i = 0; i < 3; i++) {
	 if (inst->src[i].file == GRF) {
	    spill_costs[inst->src[i].reg] += loop_scale;
            if (inst->src[i].reladdr)
               no_spill[inst->src[i].reg] = true;
	 }
      }

      if (inst->dst.file == GRF) {
	 spill_costs[inst->dst.reg] += loop_scale;
         if (inst->dst.reladdr)
            no_spill[inst->dst.reg] = true;
      }

      switch (inst->opcode) {

      case BRW_OPCODE_DO:
	 loop_scale *= 10;
	 break;

      case BRW_OPCODE_WHILE:
	 loop_scale /= 10;
	 break;

      case VS_OPCODE_SCRATCH_READ:
      case VS_OPCODE_SCRATCH_WRITE:
         for (int i = 0; i < 3; i++) {
            if (inst->src[i].file == GRF)
               no_spill[inst->src[i].reg] = true;
         }
	 if (inst->dst.file == GRF)
	    no_spill[inst->dst.reg] = true;
	 break;

      default:
	 break;
      }
   }
}

int
vec4_visitor::choose_spill_reg(struct ra_graph *g)
{
   float spill_costs[this->virtual_grf_count];
   bool no_spill[this->virtual_grf_count];

   evaluate_spill_costs(spill_costs, no_spill);

   for (int i = 0; i < this->virtual_grf_count; i++) {
      if (!no_spill[i])
         ra_set_node_spill_cost(g, i, spill_costs[i]);
   }

   return ra_get_best_spill_node(g);
}

void
vec4_visitor::spill_reg(int spill_reg_nr)
{
   assert(virtual_grf_sizes[spill_reg_nr] == 1);
   unsigned int spill_offset = c->last_scratch++;

   /* Generate spill/unspill instructions for the objects being spilled. */
   foreach_list(node, &this->instructions) {
      vec4_instruction *inst = (vec4_instruction *) node;

      for (unsigned int i = 0; i < 3; i++) {
         if (inst->src[i].file == GRF && inst->src[i].reg == spill_reg_nr) {
            src_reg spill_reg = inst->src[i];
            inst->src[i].reg = virtual_grf_alloc(1);
            dst_reg temp = dst_reg(inst->src[i]);

            /* Only read the necessary channels, to avoid overwriting the rest
             * with data that may not have been written to scratch.
             */
            temp.writemask = 0;
            for (int c = 0; c < 4; c++)
               temp.writemask |= (1 << BRW_GET_SWZ(inst->src[i].swizzle, c));
            assert(temp.writemask != 0);

            emit_scratch_read(inst, temp, spill_reg, spill_offset);
         }
      }

      if (inst->dst.file == GRF && inst->dst.reg == spill_reg_nr) {
         emit_scratch_write(inst, spill_offset);
      }
   }

   this->live_intervals_valid = false;
}

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

extern "C" {
#include "main/macros.h"
#include "program/register_allocate.h"
} /* extern "C" */

#include "brw_vec4.h"
#include "brw_vs.h"

using namespace brw;

namespace brw {

static void
assign(unsigned int *reg_hw_locations, reg *reg)
{
   if (reg->file == GRF) {
      reg->reg = reg_hw_locations[reg->reg];
   }
}

bool
vec4_visitor::reg_allocate_trivial()
{
   unsigned int hw_reg_mapping[this->virtual_grf_count];
   bool virtual_grf_used[this->virtual_grf_count];
   int i;
   int next;

   /* Calculate which virtual GRFs are actually in use after whatever
    * optimization passes have occurred.
    */
   for (int i = 0; i < this->virtual_grf_count; i++) {
      virtual_grf_used[i] = false;
   }

   foreach_iter(exec_list_iterator, iter, this->instructions) {
      vec4_instruction *inst = (vec4_instruction *)iter.get();

      if (inst->dst.file == GRF)
	 virtual_grf_used[inst->dst.reg] = true;

      for (int i = 0; i < 3; i++) {
	 if (inst->src[i].file == GRF)
	    virtual_grf_used[inst->src[i].reg] = true;
      }
   }

   hw_reg_mapping[0] = this->first_non_payload_grf;
   next = hw_reg_mapping[0] + this->virtual_grf_sizes[0];
   for (i = 1; i < this->virtual_grf_count; i++) {
      if (virtual_grf_used[i]) {
	 hw_reg_mapping[i] = next;
	 next += this->virtual_grf_sizes[i];
      }
   }
   prog_data->total_grf = next;

   foreach_iter(exec_list_iterator, iter, this->instructions) {
      vec4_instruction *inst = (vec4_instruction *)iter.get();

      assign(hw_reg_mapping, &inst->dst);
      assign(hw_reg_mapping, &inst->src[0]);
      assign(hw_reg_mapping, &inst->src[1]);
      assign(hw_reg_mapping, &inst->src[2]);
   }

   if (prog_data->total_grf > max_grf) {
      fail("Ran out of regs on trivial allocator (%d/%d)\n",
	   prog_data->total_grf, max_grf);
      return false;
   }

   return true;
}

static void
brw_alloc_reg_set(struct brw_context *brw, int base_reg_count)
{
   /* After running split_virtual_grfs(), almost all VGRFs will be of size 1.
    * SEND-from-GRF sources cannot be split, so we also need classes for each
    * potential message length.
    */
   const int class_count = 2;
   const int class_sizes[class_count] = {1, 2};

   /* Compute the total number of registers across all classes. */
   int ra_reg_count = 0;
   for (int i = 0; i < class_count; i++) {
      ra_reg_count += base_reg_count - (class_sizes[i] - 1);
   }

   ralloc_free(brw->vs.ra_reg_to_grf);
   brw->vs.ra_reg_to_grf = ralloc_array(brw, uint8_t, ra_reg_count);
   ralloc_free(brw->vs.regs);
   brw->vs.regs = ra_alloc_reg_set(brw, ra_reg_count);
   if (brw->gen >= 6)
      ra_set_allocate_round_robin(brw->vs.regs);
   ralloc_free(brw->vs.classes);
   brw->vs.classes = ralloc_array(brw, int, class_count + 1);

   /* Now, add the registers to their classes, and add the conflicts
    * between them and the base GRF registers (and also each other).
    */
   int reg = 0;
   for (int i = 0; i < class_count; i++) {
      int class_reg_count = base_reg_count - (class_sizes[i] - 1);
      brw->vs.classes[i] = ra_alloc_reg_class(brw->vs.regs);

      for (int j = 0; j < class_reg_count; j++) {
	 ra_class_add_reg(brw->vs.regs, brw->vs.classes[i], reg);

	 brw->vs.ra_reg_to_grf[reg] = j;

	 for (int base_reg = j;
	      base_reg < j + class_sizes[i];
	      base_reg++) {
	    ra_add_transitive_reg_conflict(brw->vs.regs, base_reg, reg);
	 }

	 reg++;
      }
   }
   assert(reg == ra_reg_count);

   ra_set_finalize(brw->vs.regs, NULL);
}

bool
vec4_visitor::reg_allocate()
{
   unsigned int hw_reg_mapping[virtual_grf_count];
   int first_assigned_grf = this->first_non_payload_grf;
   int base_reg_count = max_grf - first_assigned_grf;

   /* Using the trivial allocator can be useful in debugging undefined
    * register access as a result of broken optimization passes.
    */
   if (0)
      return reg_allocate_trivial();

   calculate_live_intervals();

   brw_alloc_reg_set(brw, base_reg_count);

   struct ra_graph *g = ra_alloc_interference_graph(brw->vs.regs,
						    virtual_grf_count);

   for (int i = 0; i < virtual_grf_count; i++) {
      int size = this->virtual_grf_sizes[i];
      assert(size >= 1 && size <= 2 &&
             "Register allocation relies on split_virtual_grfs().");
      ra_set_node_class(g, i, brw->vs.classes[size - 1]);

      for (int j = 0; j < i; j++) {
	 if (virtual_grf_interferes(i, j)) {
	    ra_add_node_interference(g, i, j);
	 }
      }
   }

   if (!ra_allocate_no_spills(g)) {
      /* Failed to allocate registers.  Spill a reg, and the caller will
       * loop back into here to try again.
       */
      int reg = choose_spill_reg(g);
      if (reg == -1) {
         fail("no register to spill\n");
      } else {
         spill_reg(reg);
      }
      ralloc_free(g);
      return false;
   }

   /* Get the chosen virtual registers for each node, and map virtual
    * regs in the register classes back down to real hardware reg
    * numbers.
    */
   prog_data->total_grf = first_assigned_grf;
   for (int i = 0; i < virtual_grf_count; i++) {
      int reg = ra_get_node_reg(g, i);

      hw_reg_mapping[i] = first_assigned_grf + brw->vs.ra_reg_to_grf[reg];
      prog_data->total_grf = MAX2(prog_data->total_grf,
				  hw_reg_mapping[i] + virtual_grf_sizes[i]);
   }

   foreach_list(node, &this->instructions) {
      vec4_instruction *inst = (vec4_instruction *)node;

      assign(hw_reg_mapping, &inst->dst);
      assign(hw_reg_mapping, &inst->src[0]);
      assign(hw_reg_mapping, &inst->src[1]);
      assign(hw_reg_mapping, &inst->src[2]);
   }

   ralloc_free(g);

   return true;
}

void
vec4_visitor::evaluate_spill_costs(float *spill_costs, bool *no_spill)
{
   float loop_scale = 1.0;

   for (int i = 0; i < this->virtual_grf_count; i++) {
      spill_costs[i] = 0.0;
      no_spill[i] = virtual_grf_sizes[i] != 1;
   }

   /* Calculate costs for spilling nodes.  Call it a cost of 1 per
    * spill/unspill we'll have to do, and guess that the insides of
    * loops run 10 times.
    */
   foreach_list(node, &this->instructions) {
      vec4_instruction *inst = (vec4_instruction *) node;

      for (unsigned int i = 0; i < 3; i++) {
	 if (inst->src[i].file == GRF) {
	    spill_costs[inst->src[i].reg] += loop_scale;
            if (inst->src[i].reladdr)
               no_spill[inst->src[i].reg] = true;
	 }
      }

      if (inst->dst.file == GRF) {
	 spill_costs[inst->dst.reg] += loop_scale;
         if (inst->dst.reladdr)
            no_spill[inst->dst.reg] = true;
      }

      switch (inst->opcode) {

      case BRW_OPCODE_DO:
	 loop_scale *= 10;
	 break;

      case BRW_OPCODE_WHILE:
	 loop_scale /= 10;
	 break;

      case VS_OPCODE_SCRATCH_READ:
      case VS_OPCODE_SCRATCH_WRITE:
         for (int i = 0; i < 3; i++) {
            if (inst->src[i].file == GRF)
               no_spill[inst->src[i].reg] = true;
         }
	 if (inst->dst.file == GRF)
	    no_spill[inst->dst.reg] = true;
	 break;

      default:
	 break;
      }
   }
}

int
vec4_visitor::choose_spill_reg(struct ra_graph *g)
{
   float spill_costs[this->virtual_grf_count];
   bool no_spill[this->virtual_grf_count];

   evaluate_spill_costs(spill_costs, no_spill);

   for (int i = 0; i < this->virtual_grf_count; i++) {
      if (!no_spill[i])
         ra_set_node_spill_cost(g, i, spill_costs[i]);
   }

   return ra_get_best_spill_node(g);
}

void
vec4_visitor::spill_reg(int spill_reg_nr)
{
   assert(virtual_grf_sizes[spill_reg_nr] == 1);
   unsigned int spill_offset = c->last_scratch++;

   /* Generate spill/unspill instructions for the objects being spilled. */
   foreach_list(node, &this->instructions) {
      vec4_instruction *inst = (vec4_instruction *) node;

      for (unsigned int i = 0; i < 3; i++) {
         if (inst->src[i].file == GRF && inst->src[i].reg == spill_reg_nr) {
            src_reg spill_reg = inst->src[i];
            inst->src[i].reg = virtual_grf_alloc(1);
            dst_reg temp = dst_reg(inst->src[i]);

            /* Only read the necessary channels, to avoid overwriting the rest
             * with data that may not have been written to scratch.
             */
            temp.writemask = 0;
            for (int c = 0; c < 4; c++)
               temp.writemask |= (1 << BRW_GET_SWZ(inst->src[i].swizzle, c));
            assert(temp.writemask != 0);

            emit_scratch_read(inst, temp, spill_reg, spill_offset);
         }
      }

      if (inst->dst.file == GRF && inst->dst.reg == spill_reg_nr) {
         emit_scratch_write(inst, spill_offset);
      }
   }

   this->live_intervals_valid = false;
}

} /* namespace brw */
<|endoftext|>


<commit_before>// 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

#ifdef __WINDOWS__
#include <stout/windows.hpp>
#else
#include <netinet/tcp.h>
#endif // __WINDOWS__

#include <process/io.hpp>
#include <process/network.hpp>
#include <process/socket.hpp>

#include <stout/os/sendfile.hpp>
#include <stout/os/strerror.hpp>
#include <stout/os.hpp>

#include "config.hpp"
#include "poll_socket.hpp"

using std::string;

namespace process {
namespace network {

Try<std::shared_ptr<Socket::Impl>> PollSocketImpl::create(int s)
{
  return std::make_shared<PollSocketImpl>(s);
}

Try<Nothing> PollSocketImpl::listen(int backlog)
{
  if (::listen(get(), backlog) < 0) {
    return ErrnoError();
  }
  return Nothing();
}

namespace internal {

Future<Socket> accept(int fd)
{
  Try<int> accepted = network::accept(fd);
  if (accepted.isError()) {
    return Failure(accepted.error());
  }

  int s = accepted.get();
  Try<Nothing> nonblock = os::nonblock(s);
  if (nonblock.isError()) {
    LOG_IF(INFO, VLOG_IS_ON(1)) << "Failed to accept, nonblock: "
                                << nonblock.error();
    os::close(s);
    return Failure("Failed to accept, nonblock: " + nonblock.error());
  }

  Try<Nothing> cloexec = os::cloexec(s);
  if (cloexec.isError()) {
    LOG_IF(INFO, VLOG_IS_ON(1)) << "Failed to accept, cloexec: "
                                << cloexec.error();
    os::close(s);
    return Failure("Failed to accept, cloexec: " + cloexec.error());
  }

  // Turn off Nagle (TCP_NODELAY) so pipelined requests don't wait.
  // NOTE: We cast to `char*` here because the function prototypes on Windows
  // use `char*` instead of `void*`.
  int on = 1;
  if (::setsockopt(
          s,
          SOL_TCP,
          TCP_NODELAY,
          reinterpret_cast<const char*>(&on),
          sizeof(on)) < 0) {
    const string error = os::strerror(errno);
    VLOG(1) << "Failed to turn off the Nagle algorithm: " << error;
    os::close(s);
    return Failure(
      "Failed to turn off the Nagle algorithm: " + stringify(error));
  }

  Try<Socket> socket = Socket::create(Socket::DEFAULT_KIND(), s);
  if (socket.isError()) {
    os::close(s);
    return Failure("Failed to accept, create socket: " + socket.error());
  }
  return socket.get();
}

} // namespace internal {

Future<Socket> PollSocketImpl::accept()
{
  return io::poll(get(), io::READ)
    .then(lambda::bind(&internal::accept, get()));
}

namespace internal {

Future<Nothing> connect(const Socket& socket)
{
  // Now check that a successful connection was made.
  int opt;
  socklen_t optlen = sizeof(opt);
  int s = socket.get();

  // NOTE: We cast to `char*` here because the function prototypes on Windows
  // use `char*` instead of `void*`.
  if (::getsockopt(
          s,
          SOL_SOCKET,
          SO_ERROR,
          reinterpret_cast<char*>(&opt),
          &optlen) < 0 ||
      opt != 0) {
    // Connect failure.
    VLOG(1) << "Socket error while connecting";
    return Failure("Socket error while connecting");
  }

  return Nothing();
}

} // namespace internal {

Future<Nothing> PollSocketImpl::connect(const Address& address)
{
  Try<int, SocketError> connect = network::connect(get(), address);
  if (connect.isError()) {
    if (net::is_inprogress_error(connect.error().code)) {
      return io::poll(get(), io::WRITE)
        .then(lambda::bind(&internal::connect, socket()));
    }

    return Failure(connect.error());
  }

  return Nothing();
}

Future<size_t> PollSocketImpl::recv(char* data, size_t size)
{
  return io::read(get(), data, size);
}

namespace internal {

Future<size_t> socket_send_data(int s, const char* data, size_t size)
{
  CHECK(size > 0);

  while (true) {
    ssize_t length = send(s, data, size, MSG_NOSIGNAL);

#ifdef __WINDOWS__
    int error = WSAGetLastError();
#else
    int error = errno;
#endif // __WINDOWS__

    if (length < 0 && net::is_restartable_error(error)) {
      // Interrupted, try again now.
      continue;
    } else if (length < 0 && net::is_retryable_error(error)) {
      // Might block, try again later.
      return io::poll(s, io::WRITE)
        .then(lambda::bind(&internal::socket_send_data, s, data, size));
    } else if (length <= 0) {
      // Socket error or closed.
      if (length < 0) {
        const string error = os::strerror(errno);
        VLOG(1) << "Socket error while sending: " << error;
      } else {
        VLOG(1) << "Socket closed while sending";
      }
      if (length == 0) {
        return length;
      } else {
        return Failure(ErrnoError("Socket send failed"));
      }
    } else {
      CHECK(length > 0);

      return length;
    }
  }
}

Future<size_t> socket_send_file(int s, int fd, off_t offset, size_t size)
{
  CHECK(size > 0);

  while (true) {
    ssize_t length = os::sendfile(s, fd, offset, size);

    if (length < 0 && (errno == EINTR)) {
      // Interrupted, try again now.
      continue;
    } else if (length < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
      // Might block, try again later.
      return io::poll(s, io::WRITE)
        .then(lambda::bind(&internal::socket_send_file, s, fd, offset, size));
    } else if (length <= 0) {
      // Socket error or closed.
      if (length < 0) {
        const string error = os::strerror(errno);
        VLOG(1) << "Socket error while sending: " << error;
      } else {
        VLOG(1) << "Socket closed while sending";
      }
      if (length == 0) {
        return length;
      } else {
        return Failure(ErrnoError("Socket sendfile failed"));
      }
    } else {
      CHECK(length > 0);

      return length;
    }
  }
}

} // namespace internal {

Future<size_t> PollSocketImpl::send(const char* data, size_t size)
{
  return io::poll(get(), io::WRITE)
    .then(lambda::bind(&internal::socket_send_data, get(), data, size));
}

Future<size_t> PollSocketImpl::sendfile(int fd, off_t offset, size_t size)
{
  return io::poll(get(), io::WRITE)
    .then(lambda::bind(&internal::socket_send_file, get(), fd, offset, size));
}

} // namespace network {
} // namespace process {
<commit_msg>Windows: Used `sendfile` with the typed error state of `Try`.<commit_after>// 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

#ifdef __WINDOWS__
#include <stout/windows.hpp>
#else
#include <netinet/tcp.h>
#endif // __WINDOWS__

#include <process/io.hpp>
#include <process/network.hpp>
#include <process/socket.hpp>

#include <stout/os/sendfile.hpp>
#include <stout/os/strerror.hpp>
#include <stout/os.hpp>

#include "config.hpp"
#include "poll_socket.hpp"

using std::string;

namespace process {
namespace network {

Try<std::shared_ptr<Socket::Impl>> PollSocketImpl::create(int s)
{
  return std::make_shared<PollSocketImpl>(s);
}

Try<Nothing> PollSocketImpl::listen(int backlog)
{
  if (::listen(get(), backlog) < 0) {
    return ErrnoError();
  }
  return Nothing();
}

namespace internal {

Future<Socket> accept(int fd)
{
  Try<int> accepted = network::accept(fd);
  if (accepted.isError()) {
    return Failure(accepted.error());
  }

  int s = accepted.get();
  Try<Nothing> nonblock = os::nonblock(s);
  if (nonblock.isError()) {
    LOG_IF(INFO, VLOG_IS_ON(1)) << "Failed to accept, nonblock: "
                                << nonblock.error();
    os::close(s);
    return Failure("Failed to accept, nonblock: " + nonblock.error());
  }

  Try<Nothing> cloexec = os::cloexec(s);
  if (cloexec.isError()) {
    LOG_IF(INFO, VLOG_IS_ON(1)) << "Failed to accept, cloexec: "
                                << cloexec.error();
    os::close(s);
    return Failure("Failed to accept, cloexec: " + cloexec.error());
  }

  // Turn off Nagle (TCP_NODELAY) so pipelined requests don't wait.
  // NOTE: We cast to `char*` here because the function prototypes on Windows
  // use `char*` instead of `void*`.
  int on = 1;
  if (::setsockopt(
          s,
          SOL_TCP,
          TCP_NODELAY,
          reinterpret_cast<const char*>(&on),
          sizeof(on)) < 0) {
    const string error = os::strerror(errno);
    VLOG(1) << "Failed to turn off the Nagle algorithm: " << error;
    os::close(s);
    return Failure(
      "Failed to turn off the Nagle algorithm: " + stringify(error));
  }

  Try<Socket> socket = Socket::create(Socket::DEFAULT_KIND(), s);
  if (socket.isError()) {
    os::close(s);
    return Failure("Failed to accept, create socket: " + socket.error());
  }
  return socket.get();
}

} // namespace internal {

Future<Socket> PollSocketImpl::accept()
{
  return io::poll(get(), io::READ)
    .then(lambda::bind(&internal::accept, get()));
}

namespace internal {

Future<Nothing> connect(const Socket& socket)
{
  // Now check that a successful connection was made.
  int opt;
  socklen_t optlen = sizeof(opt);
  int s = socket.get();

  // NOTE: We cast to `char*` here because the function prototypes on Windows
  // use `char*` instead of `void*`.
  if (::getsockopt(
          s,
          SOL_SOCKET,
          SO_ERROR,
          reinterpret_cast<char*>(&opt),
          &optlen) < 0 ||
      opt != 0) {
    // Connect failure.
    VLOG(1) << "Socket error while connecting";
    return Failure("Socket error while connecting");
  }

  return Nothing();
}

} // namespace internal {

Future<Nothing> PollSocketImpl::connect(const Address& address)
{
  Try<int, SocketError> connect = network::connect(get(), address);
  if (connect.isError()) {
    if (net::is_inprogress_error(connect.error().code)) {
      return io::poll(get(), io::WRITE)
        .then(lambda::bind(&internal::connect, socket()));
    }

    return Failure(connect.error());
  }

  return Nothing();
}

Future<size_t> PollSocketImpl::recv(char* data, size_t size)
{
  return io::read(get(), data, size);
}

namespace internal {

Future<size_t> socket_send_data(int s, const char* data, size_t size)
{
  CHECK(size > 0);

  while (true) {
    ssize_t length = send(s, data, size, MSG_NOSIGNAL);

#ifdef __WINDOWS__
    int error = WSAGetLastError();
#else
    int error = errno;
#endif // __WINDOWS__

    if (length < 0 && net::is_restartable_error(error)) {
      // Interrupted, try again now.
      continue;
    } else if (length < 0 && net::is_retryable_error(error)) {
      // Might block, try again later.
      return io::poll(s, io::WRITE)
        .then(lambda::bind(&internal::socket_send_data, s, data, size));
    } else if (length <= 0) {
      // Socket error or closed.
      if (length < 0) {
        const string error = os::strerror(errno);
        VLOG(1) << "Socket error while sending: " << error;
      } else {
        VLOG(1) << "Socket closed while sending";
      }
      if (length == 0) {
        return length;
      } else {
        return Failure(ErrnoError("Socket send failed"));
      }
    } else {
      CHECK(length > 0);

      return length;
    }
  }
}

Future<size_t> socket_send_file(int s, int fd, off_t offset, size_t size)
{
  CHECK(size > 0);

  while (true) {
    Try<ssize_t, SocketError> length = os::sendfile(s, fd, offset, size);

    if (length.isSome()) {
      CHECK(length.get() >= 0);
      if (length.get() == 0) {
        // Socket closed.
        VLOG(1) << "Socket closed while sending";
      }
      return length.get();
    }

    if (net::is_restartable_error(length.error().code)) {
      // Interrupted, try again now.
      continue;
    } else if (net::is_retryable_error(length.error().code)) {
      // Might block, try again later.
      return io::poll(s, io::WRITE)
        .then(lambda::bind(&internal::socket_send_file, s, fd, offset, size));
    } else {
      // Socket error or closed.
      VLOG(1) << length.error().message;
      return Failure(length.error());
    };
  }
}

} // namespace internal {

Future<size_t> PollSocketImpl::send(const char* data, size_t size)
{
  return io::poll(get(), io::WRITE)
    .then(lambda::bind(&internal::socket_send_data, get(), data, size));
}

Future<size_t> PollSocketImpl::sendfile(int fd, off_t offset, size_t size)
{
  return io::poll(get(), io::WRITE)
    .then(lambda::bind(&internal::socket_send_file, get(), fd, offset, size));
}

} // namespace network {
} // namespace process {
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "compileoutputwindow.h"
#include "buildmanager.h"
#include "showoutputtaskhandler.h"
#include "task.h"
#include "projectexplorerconstants.h"
#include "projectexplorer.h"
#include "projectexplorersettings.h"
#include "taskhub.h"

#include <coreplugin/icontext.h>
#include <find/basetextfind.h>
#include <aggregation/aggregate.h>
#include <extensionsystem/pluginmanager.h>
#include <texteditor/texteditorsettings.h>
#include <texteditor/fontsettings.h>

#include <QKeyEvent>
#include <QIcon>
#include <QTextCharFormat>
#include <QTextBlock>
#include <QTextCursor>
#include <QTextEdit>
#include <QScrollBar>
#include <QPlainTextEdit>
#include <QToolButton>

using namespace ProjectExplorer;
using namespace ProjectExplorer::Internal;

namespace {
const int MAX_LINECOUNT = 50000;
}

namespace ProjectExplorer {
namespace Internal {

class CompileOutputTextEdit : public Core::OutputWindow
{
    Q_OBJECT
public:
    CompileOutputTextEdit(const Core::Context &context) : Core::OutputWindow(context)
    {
        fontSettingsChanged();
        connect(TextEditor::TextEditorSettings::instance(), SIGNAL(fontSettingsChanged(TextEditor::FontSettings)),
                this, SLOT(fontSettingsChanged()));
    }

    void addTask(const Task &task, int blocknumber)
    {
        m_taskids.insert(blocknumber, task.taskId);
    }

    void clearTasks()
    {
        m_taskids.clear();
    }
private slots:
    void fontSettingsChanged()
    {
        setFont(TextEditor::TextEditorSettings::instance()->fontSettings().font());
    }

protected:
    void mouseDoubleClickEvent(QMouseEvent *ev)
    {
        int line = cursorForPosition(ev->pos()).block().blockNumber();
        if (unsigned taskid = m_taskids.value(line, 0)) {
            TaskHub *hub = ExtensionSystem::PluginManager::getObject<TaskHub>();
            hub->showTaskInEditor(taskid);
        } else {
            QPlainTextEdit::mouseDoubleClickEvent(ev);
        }
    }

private:
    QHash<int, unsigned int> m_taskids;   //Map blocknumber to taskId
};

} // namespace Internal
} // namespace ProjectExplorer

CompileOutputWindow::CompileOutputWindow(BuildManager * /*bm*/, QAction *cancelBuildAction) :
    m_cancelBuildButton(new QToolButton)
{
    Core::Context context(Constants::C_COMPILE_OUTPUT);
    m_outputWindow = new CompileOutputTextEdit(context);
    m_outputWindow->setWindowTitle(tr("Compile Output"));
    m_outputWindow->setWindowIcon(QIcon(QLatin1String(Constants::ICON_WINDOW)));
    m_outputWindow->setReadOnly(true);
    m_outputWindow->setUndoRedoEnabled(false);
    m_outputWindow->setMaxLineCount(MAX_LINECOUNT);

    m_cancelBuildButton->setDefaultAction(cancelBuildAction);

    Aggregation::Aggregate *agg = new Aggregation::Aggregate;
    agg->add(m_outputWindow);
    agg->add(new Find::BaseTextFind(m_outputWindow));

    qRegisterMetaType<QTextCharFormat>("QTextCharFormat");

    m_handler = new ShowOutputTaskHandler(this);
    ExtensionSystem::PluginManager::addObject(m_handler);
    connect(ProjectExplorerPlugin::instance(), SIGNAL(settingsChanged()),
            this, SLOT(updateWordWrapMode()));
    updateWordWrapMode();
}

CompileOutputWindow::~CompileOutputWindow()
{
    ExtensionSystem::PluginManager::removeObject(m_handler);
    delete m_handler;
    delete m_cancelBuildButton;
}

void CompileOutputWindow::updateWordWrapMode()
{
    m_outputWindow->setWordWrapEnabled(ProjectExplorerPlugin::instance()->projectExplorerSettings().wrapAppOutput);
}

bool CompileOutputWindow::hasFocus() const
{
    return m_outputWindow->hasFocus();
}

bool CompileOutputWindow::canFocus() const
{
    return true;
}

void CompileOutputWindow::setFocus()
{
    m_outputWindow->setFocus();
}

QWidget *CompileOutputWindow::outputWidget(QWidget *)
{
    return m_outputWindow;
}

QList<QWidget *> CompileOutputWindow::toolBarWidgets() const
{
     return QList<QWidget *>() << m_cancelBuildButton;
}

static QColor mix_colors(QColor a, QColor b)
{
    return QColor((a.red() + 2 * b.red()) / 3, (a.green() + 2 * b.green()) / 3,
                  (a.blue() + 2* b.blue()) / 3, (a.alpha() + 2 * b.alpha()) / 3);
}

void CompileOutputWindow::appendText(const QString &text, ProjectExplorer::BuildStep::OutputFormat format)
{
    QPalette p = m_outputWindow->palette();
    QTextCharFormat textFormat;
    switch (format) {
    case BuildStep::NormalOutput:
        textFormat.setForeground(p.color(QPalette::Text));
        textFormat.setFontWeight(QFont::Normal);
        break;
    case BuildStep::ErrorOutput:
        textFormat.setForeground(mix_colors(p.color(QPalette::Text), QColor(Qt::red)));
        textFormat.setFontWeight(QFont::Normal);
        break;
    case BuildStep::MessageOutput:
        textFormat.setForeground(mix_colors(p.color(QPalette::Text), QColor(Qt::blue)));
        break;
    case BuildStep::ErrorMessageOutput:
        textFormat.setForeground(mix_colors(p.color(QPalette::Text), QColor(Qt::red)));
        textFormat.setFontWeight(QFont::Bold);
        break;

    }

    m_outputWindow->appendText(text, textFormat);
}

void CompileOutputWindow::clearContents()
{
    m_outputWindow->clear();
    m_outputWindow->clearTasks();
    m_taskPositions.clear();
}

void CompileOutputWindow::visibilityChanged(bool)
{

}

int CompileOutputWindow::priorityInStatusBar() const
{
    return 50;
}

bool CompileOutputWindow::canNext() const
{
    return false;
}

bool CompileOutputWindow::canPrevious() const
{
    return false;
}

void CompileOutputWindow::goToNext()
{

}

void CompileOutputWindow::goToPrev()
{

}

bool CompileOutputWindow::canNavigate() const
{
    return false;
}

void CompileOutputWindow::registerPositionOf(const Task &task)
{
    int blocknumber = m_outputWindow->blockCount();
    if (blocknumber > MAX_LINECOUNT)
        return;

    m_taskPositions.insert(task.taskId, blocknumber);
    m_outputWindow->addTask(task, blocknumber);
}

bool CompileOutputWindow::knowsPositionOf(const Task &task)
{
    return (m_taskPositions.contains(task.taskId));
}

void CompileOutputWindow::showPositionOf(const Task &task)
{
    int position = m_taskPositions.value(task.taskId);
    QTextCursor newCursor(m_outputWindow->document()->findBlockByNumber(position));
    newCursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
    m_outputWindow->setTextCursor(newCursor);
}

#include "compileoutputwindow.moc"
<commit_msg>CompileOutputWindow: Allow for 100k lines<commit_after>/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "compileoutputwindow.h"
#include "buildmanager.h"
#include "showoutputtaskhandler.h"
#include "task.h"
#include "projectexplorerconstants.h"
#include "projectexplorer.h"
#include "projectexplorersettings.h"
#include "taskhub.h"

#include <coreplugin/icontext.h>
#include <find/basetextfind.h>
#include <aggregation/aggregate.h>
#include <extensionsystem/pluginmanager.h>
#include <texteditor/texteditorsettings.h>
#include <texteditor/fontsettings.h>

#include <QKeyEvent>
#include <QIcon>
#include <QTextCharFormat>
#include <QTextBlock>
#include <QTextCursor>
#include <QTextEdit>
#include <QScrollBar>
#include <QPlainTextEdit>
#include <QToolButton>

using namespace ProjectExplorer;
using namespace ProjectExplorer::Internal;

namespace {
const int MAX_LINECOUNT = 100000;
}

namespace ProjectExplorer {
namespace Internal {

class CompileOutputTextEdit : public Core::OutputWindow
{
    Q_OBJECT
public:
    CompileOutputTextEdit(const Core::Context &context) : Core::OutputWindow(context)
    {
        fontSettingsChanged();
        connect(TextEditor::TextEditorSettings::instance(), SIGNAL(fontSettingsChanged(TextEditor::FontSettings)),
                this, SLOT(fontSettingsChanged()));
    }

    void addTask(const Task &task, int blocknumber)
    {
        m_taskids.insert(blocknumber, task.taskId);
    }

    void clearTasks()
    {
        m_taskids.clear();
    }
private slots:
    void fontSettingsChanged()
    {
        setFont(TextEditor::TextEditorSettings::instance()->fontSettings().font());
    }

protected:
    void mouseDoubleClickEvent(QMouseEvent *ev)
    {
        int line = cursorForPosition(ev->pos()).block().blockNumber();
        if (unsigned taskid = m_taskids.value(line, 0)) {
            TaskHub *hub = ExtensionSystem::PluginManager::getObject<TaskHub>();
            hub->showTaskInEditor(taskid);
        } else {
            QPlainTextEdit::mouseDoubleClickEvent(ev);
        }
    }

private:
    QHash<int, unsigned int> m_taskids;   //Map blocknumber to taskId
};

} // namespace Internal
} // namespace ProjectExplorer

CompileOutputWindow::CompileOutputWindow(BuildManager * /*bm*/, QAction *cancelBuildAction) :
    m_cancelBuildButton(new QToolButton)
{
    Core::Context context(Constants::C_COMPILE_OUTPUT);
    m_outputWindow = new CompileOutputTextEdit(context);
    m_outputWindow->setWindowTitle(tr("Compile Output"));
    m_outputWindow->setWindowIcon(QIcon(QLatin1String(Constants::ICON_WINDOW)));
    m_outputWindow->setReadOnly(true);
    m_outputWindow->setUndoRedoEnabled(false);
    m_outputWindow->setMaxLineCount(MAX_LINECOUNT);

    m_cancelBuildButton->setDefaultAction(cancelBuildAction);

    Aggregation::Aggregate *agg = new Aggregation::Aggregate;
    agg->add(m_outputWindow);
    agg->add(new Find::BaseTextFind(m_outputWindow));

    qRegisterMetaType<QTextCharFormat>("QTextCharFormat");

    m_handler = new ShowOutputTaskHandler(this);
    ExtensionSystem::PluginManager::addObject(m_handler);
    connect(ProjectExplorerPlugin::instance(), SIGNAL(settingsChanged()),
            this, SLOT(updateWordWrapMode()));
    updateWordWrapMode();
}

CompileOutputWindow::~CompileOutputWindow()
{
    ExtensionSystem::PluginManager::removeObject(m_handler);
    delete m_handler;
    delete m_cancelBuildButton;
}

void CompileOutputWindow::updateWordWrapMode()
{
    m_outputWindow->setWordWrapEnabled(ProjectExplorerPlugin::instance()->projectExplorerSettings().wrapAppOutput);
}

bool CompileOutputWindow::hasFocus() const
{
    return m_outputWindow->hasFocus();
}

bool CompileOutputWindow::canFocus() const
{
    return true;
}

void CompileOutputWindow::setFocus()
{
    m_outputWindow->setFocus();
}

QWidget *CompileOutputWindow::outputWidget(QWidget *)
{
    return m_outputWindow;
}

QList<QWidget *> CompileOutputWindow::toolBarWidgets() const
{
     return QList<QWidget *>() << m_cancelBuildButton;
}

static QColor mix_colors(QColor a, QColor b)
{
    return QColor((a.red() + 2 * b.red()) / 3, (a.green() + 2 * b.green()) / 3,
                  (a.blue() + 2* b.blue()) / 3, (a.alpha() + 2 * b.alpha()) / 3);
}

void CompileOutputWindow::appendText(const QString &text, ProjectExplorer::BuildStep::OutputFormat format)
{
    QPalette p = m_outputWindow->palette();
    QTextCharFormat textFormat;
    switch (format) {
    case BuildStep::NormalOutput:
        textFormat.setForeground(p.color(QPalette::Text));
        textFormat.setFontWeight(QFont::Normal);
        break;
    case BuildStep::ErrorOutput:
        textFormat.setForeground(mix_colors(p.color(QPalette::Text), QColor(Qt::red)));
        textFormat.setFontWeight(QFont::Normal);
        break;
    case BuildStep::MessageOutput:
        textFormat.setForeground(mix_colors(p.color(QPalette::Text), QColor(Qt::blue)));
        break;
    case BuildStep::ErrorMessageOutput:
        textFormat.setForeground(mix_colors(p.color(QPalette::Text), QColor(Qt::red)));
        textFormat.setFontWeight(QFont::Bold);
        break;

    }

    m_outputWindow->appendText(text, textFormat);
}

void CompileOutputWindow::clearContents()
{
    m_outputWindow->clear();
    m_outputWindow->clearTasks();
    m_taskPositions.clear();
}

void CompileOutputWindow::visibilityChanged(bool)
{

}

int CompileOutputWindow::priorityInStatusBar() const
{
    return 50;
}

bool CompileOutputWindow::canNext() const
{
    return false;
}

bool CompileOutputWindow::canPrevious() const
{
    return false;
}

void CompileOutputWindow::goToNext()
{

}

void CompileOutputWindow::goToPrev()
{

}

bool CompileOutputWindow::canNavigate() const
{
    return false;
}

void CompileOutputWindow::registerPositionOf(const Task &task)
{
    int blocknumber = m_outputWindow->blockCount();
    if (blocknumber > MAX_LINECOUNT)
        return;

    m_taskPositions.insert(task.taskId, blocknumber);
    m_outputWindow->addTask(task, blocknumber);
}

bool CompileOutputWindow::knowsPositionOf(const Task &task)
{
    return (m_taskPositions.contains(task.taskId));
}

void CompileOutputWindow::showPositionOf(const Task &task)
{
    int position = m_taskPositions.value(task.taskId);
    QTextCursor newCursor(m_outputWindow->document()->findBlockByNumber(position));
    newCursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
    m_outputWindow->setTextCursor(newCursor);
}

#include "compileoutputwindow.moc"
<|endoftext|>