<commit_before>#include "ffmpeg_video_target.h"
#include "except.h"

#ifdef GENERATE_PERFORMANCE_OUTPUT
#include <boost/timer/timer.hpp>
#endif

namespace gg
{

VideoTargetFFmpeg::VideoTargetFFmpeg(const std::string codec) :
    _codec(NULL),
    _codec_name(""),
    _frame(NULL),
    _first_frame(true),
    _framerate(-1),
    _sws_context(NULL),
    _format_context(NULL),
    _stream(NULL),
    _frame_index(0)
{
    if (codec != "H265")
    {
        std::string msg;
        msg.append("Codec ")
           .append(codec)
           .append(" not recognised");
        throw VideoTargetError(msg);
    }
#ifdef FFMPEG_HWACCEL
    _codec_name = "nvenc_hevc";
#else
    _codec_name = "libx265";
#endif

    av_register_all();
}

void VideoTargetFFmpeg::init(const std::string filepath, const float framerate)
{
    if (framerate <= 0)
        throw VideoTargetError("Negative fps does not make sense");
    if (framerate - (int) framerate > 0)
        throw VideoTargetError("Only integer framerates are supported");
    _framerate = (int) framerate;

    check_filetype_support(filepath, "mp4");

    _filepath = filepath;

    /* allocate the output media context */
    avformat_alloc_output_context2(&_format_context, NULL, NULL, _filepath.c_str());
    if (_format_context == NULL)
        // Use MP4 as default if context cannot be deduced from file extension
        avformat_alloc_output_context2(&_format_context, NULL, "mp4", NULL);
    if (_format_context == NULL)
        throw VideoTargetError("Could not allocate output media context");

    _codec = avcodec_find_encoder_by_name(_codec_name.c_str());
    if (not _codec)
        throw VideoTargetError("Codec not found");

    _stream = avformat_new_stream(_format_context, _codec);
    if (_stream == NULL)
        throw VideoTargetError("Could not allocate stream");
    _stream->id = _format_context->nb_streams-1; // TODO isn't this wrong?

    // allocate FFmpeg frame
    _frame = av_frame_alloc();
    if (not _frame)
        throw VideoTargetError("Could not allocate video frame");
    _first_frame = true;
}

void VideoTargetFFmpeg::append(const VideoFrame_BGRA & frame)
{
    ffmpeg_frame(frame.data(),
                 frame.data_length(),
                 frame.cols(), frame.rows(),
                 AV_PIX_FMT_BGRA, _frame);

    { // START auto_cpu_timer scope
#ifdef GENERATE_PERFORMANCE_OUTPUT
    boost::timer::auto_cpu_timer t(this_class_str + "1-encode_and_write" + timer_format_str);
#endif

    /* encode the image */
    int got_output;
    encode_and_write(_frame, got_output);

    } // END auto_cpu_timer scope
}

void VideoTargetFFmpeg::append(const VideoFrame_I420 & frame)
{
    // TODO
}

void VideoTargetFFmpeg::ffmpeg_frame(const unsigned char * data,
                                     const size_t data_length,
                                     const int width, const int height,
                                     const AVPixelFormat colour_space,
                                     AVFrame * frame)
{
    if (_framerate <= 0)
        throw VideoTargetError("Video target not initialised");

    // return value buffers
    int ret;

    // if first frame, initialise
    if (_first_frame)
    {
#ifdef GENERATE_PERFORMANCE_OUTPUT
#ifndef timer_format_str
#define timer_format_str \
        std::string(", %w, %u, %s, %t, %p" \
                    ", wall (s), user (s), system (s), user+system (s), CPU (\%)\n")
#endif
#ifndef this_class_str
#define this_class_str std::string("VideoTargetFFmpeg-")
#endif
        boost::timer::auto_cpu_timer t(this_class_str + "first-frame" + timer_format_str);
#endif
        // TODO - is _codec_context ever being modified after first frame?
        /* TODO: using default reduces filesize
         * but should we set it nonetheless?
         */
//        _stream->codec->bit_rate = 400000;
        _stream->codec->width = width;
        _stream->codec->height = height;
        _stream->time_base = (AVRational){ 1, _framerate };
        _stream->codec->time_base = _stream->time_base;
        _stream->codec->gop_size = 12;
        /* TODO emit one intra frame every twelve frames at most */
        _stream->codec->pix_fmt = AV_PIX_FMT_YUV420P;
        /* Some formats want stream headers to be separate. */
        if (_format_context->oformat->flags & AVFMT_GLOBALHEADER)
            _stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

        switch (_stream->codec->codec_id)
        {
        case AV_CODEC_ID_H264:
        case AV_CODEC_ID_HEVC:
#ifdef FFMPEG_HWACCEL
            // nop
            ret = 0;
#else
            /* TODO will this work in real-time with a framegrabber ?
             * "slow" produces 2x larger file compared to "ultrafast",
             * but with a substantial visual quality degradation
             * (judged using the coloured chessboard pattern)
             * "fast" is a trade-off: visual quality looks similar
             * while file size is reasonable
             */
            ret = av_opt_set(_stream->codec->priv_data, "preset", "fast", 0);
#endif
            if (ret != 0)
                throw VideoTargetError("Could not set codec-specific options");

            /* Resolution must be a multiple of two, as required
             * by H264 and H265. Introduce a one-pixel padding for
             * non-complying dimension(s).
             */
            _stream->codec->width +=
                    _stream->codec->width % 2 == 0 ? 0 : 1;
            _stream->codec->height +=
                    _stream->codec->height % 2 == 0 ? 0 : 1;
            break;
        default:
            // nop
            break;
        }

        /* open it */
        if (avcodec_open2(_stream->codec, _codec, NULL) < 0)
            throw VideoTargetError("Could not open codec");

        frame->format = _stream->codec->pix_fmt;
        frame->width  = _stream->codec->width;
        frame->height = _stream->codec->height;
        /* allocate the buffers for the frame data */
        // TODO #25 what influence does 32 have on performance?
        ret = av_frame_get_buffer(frame, 32);
        if (ret < 0)
            throw VideoTargetError("Could not allocate frame data");

        /* Now that all the parameters are set, we can open the audio and
         * video codecs and allocate the necessary encode buffers. */
        av_dump_format(_format_context, 0, _filepath.c_str(), 1);
        /* open the output file, if needed */
        if (!(_format_context->oformat->flags & AVFMT_NOFILE))
        {
            ret = avio_open(&_format_context->pb, _filepath.c_str(), AVIO_FLAG_WRITE);
            if (ret < 0)
            {
                std::string msg;
                msg.append("File ")
                   .append(_filepath)
                   .append(" could not be opened");
                throw VideoTargetError(msg);
            }
        }

        /* Write the stream header, if any. */
        ret = avformat_write_header(_format_context, NULL);
        if (ret < 0)
            throw VideoTargetError("Could not write header to file");

        /* TODO USE_COLOUR_SPACE_I420 also implicitly provides
         * this check, but selective code compilation might make
         * code faster, due to not having the conditional checks
         */
        if (colour_space == AV_PIX_FMT_BGRA)
        {
            /* Open context for converting BGRA pixels to YUV420p */
            _sws_context = sws_getContext(
                        width, height, AV_PIX_FMT_BGRA,
                        width, height, _stream->codec->pix_fmt,
                        0, NULL, NULL, NULL);
            if (_sws_context == NULL)
                throw VideoTargetError("Could not allocate Sws context");
        }
        else if (colour_space != AV_PIX_FMT_YUV420P)
            throw VideoTargetError("Colour space not supported");

        // To be incremented for each frame, used as pts
        _frame_index = 0;

        // Packet to be used when writing frames
        av_init_packet(&_packet);
        // TODO #25 data gets allocated each time?
        _packet.data = NULL;    // packet data will be allocated by the encoder
        _packet.size = 0;

        _bgra_stride[0] = 4*width;

        _first_frame = false;
    }

    if (not frame)
        throw VideoTargetError("FFmpeg frame not initialised");

    { // START auto_cpu_timer scope
#ifdef GENERATE_PERFORMANCE_OUTPUT
    boost::timer::auto_cpu_timer t(this_class_str + "1-av_frame_make_writable" + timer_format_str);
#endif

    /* when we pass a frame to the encoder, it may keep a reference to it
     * internally;
     * make sure we do not overwrite it here
     */
    // TODO #25 why not only once?
    ret = av_frame_make_writable(frame);
    if (ret < 0)
        throw VideoTargetError("Could not make frame writeable");

    } // END auto_cpu_timer scope

    { // START auto_cpu_timer scope
#ifdef GENERATE_PERFORMANCE_OUTPUT
    boost::timer::auto_cpu_timer t(this_class_str + "1-sws_scale" + timer_format_str);
#endif

    _src_data_ptr[0] = data;
    /* TODO USE_COLOUR_SPACE_I420 also implicitly provides
     * this check, but selective code compilation might make
     * code faster, due to not having the conditional checks
     */
    switch(colour_space)
    {
    case AV_PIX_FMT_BGRA:
        /* convert pixel format */
        sws_scale(_sws_context,
                  _src_data_ptr, _bgra_stride, // BGRA has one plane
                  0, height,
                  frame->data, frame->linesize
                  );
        break;
    case AV_PIX_FMT_YUV420P:
        // TODO, in first frame?
        break;
    default:
        throw VideoTargetError("Colour space not supported");
    }

    frame->pts = _frame_index++;

    } // END auto_cpu_timer scope
}

void VideoTargetFFmpeg::encode_and_write(AVFrame * frame, int & got_output)
{
    int ret;

    { // START auto_cpu_timer scope
#ifdef GENERATE_PERFORMANCE_OUTPUT
    boost::timer::auto_cpu_timer t(this_class_str + "2-avcodec_encode_video2" + timer_format_str);
#endif
    ret = avcodec_encode_video2(_stream->codec, &_packet, frame, &got_output);
    } // END auto_cpu_timer scope

    if (ret < 0)
        throw VideoTargetError("Error encoding frame");

    if (got_output)
    {
        { // START auto_cpu_timer scope
#ifdef GENERATE_PERFORMANCE_OUTPUT
        boost::timer::auto_cpu_timer t(this_class_str + "2-av_packet_rescale_ts" + timer_format_str);
#endif
        /* rescale output packet timestamp values from codec to stream timebase */
        av_packet_rescale_ts(&_packet, _stream->codec->time_base, _stream->time_base);
        // TODO - above time bases are the same, or not?
        _packet.stream_index = _stream->index;
        } // END auto_cpu_timer scope

        { // START auto_cpu_timer scope
#ifdef GENERATE_PERFORMANCE_OUTPUT
        boost::timer::auto_cpu_timer t(this_class_str + "2-av_interleaved_write_frame" + timer_format_str);
#endif
        /* Write the compressed frame to the media file. */
        ret = av_interleaved_write_frame(_format_context, &_packet);
        }

        if (ret < 0)
            throw VideoTargetError("Could not interleaved write frame");
//        av_packet_unref(&packet); taken care of by av_interleaved_write_frame
    }
}

void VideoTargetFFmpeg::finalise()
{
    /* This condition means that append
     * has been called at least once
     * successfully (see Issue#36)
     */
    if (_frame)
    {
        /* get the delayed frames */
        for (int got_output = 1; got_output; )
            encode_and_write(NULL, got_output);

        /* Write the trailer, if any. The trailer must be written before you
         * close the CodecContexts open when you wrote the header; otherwise
         * av_write_trailer() may try to use memory that was freed on
         * av_codec_close(). */
        av_write_trailer(_format_context);
    }

    if (_stream->codec) avcodec_close(_stream->codec);
    if (_frame) av_frame_free(&_frame);
//  av_freep(&_frame->data[0]); no need for this because _frame never manages its own data
    if (_sws_context) sws_freeContext(_sws_context);

    if (!(_format_context->oformat->flags & AVFMT_NOFILE))
        if (_format_context->pb)
            /* Close the output file. */
            avio_closep(&_format_context->pb);
    /* free the stream */
    avformat_free_context(_format_context);

    // default values, for next init
    _codec = NULL;
    _frame = NULL;
    _framerate = -1;
    _sws_context = NULL;
    _format_context = NULL;
    _stream = NULL;
    _frame_index = 0;
}

}
<commit_msg>Issue #48: ffmpeg_frame checks frame not null right at the beginning now<commit_after>#include "ffmpeg_video_target.h"
#include "except.h"

#ifdef GENERATE_PERFORMANCE_OUTPUT
#include <boost/timer/timer.hpp>
#endif

namespace gg
{

VideoTargetFFmpeg::VideoTargetFFmpeg(const std::string codec) :
    _codec(NULL),
    _codec_name(""),
    _frame(NULL),
    _first_frame(true),
    _framerate(-1),
    _sws_context(NULL),
    _format_context(NULL),
    _stream(NULL),
    _frame_index(0)
{
    if (codec != "H265")
    {
        std::string msg;
        msg.append("Codec ")
           .append(codec)
           .append(" not recognised");
        throw VideoTargetError(msg);
    }
#ifdef FFMPEG_HWACCEL
    _codec_name = "nvenc_hevc";
#else
    _codec_name = "libx265";
#endif

    av_register_all();
}

void VideoTargetFFmpeg::init(const std::string filepath, const float framerate)
{
    if (framerate <= 0)
        throw VideoTargetError("Negative fps does not make sense");
    if (framerate - (int) framerate > 0)
        throw VideoTargetError("Only integer framerates are supported");
    _framerate = (int) framerate;

    check_filetype_support(filepath, "mp4");

    _filepath = filepath;

    /* allocate the output media context */
    avformat_alloc_output_context2(&_format_context, NULL, NULL, _filepath.c_str());
    if (_format_context == NULL)
        // Use MP4 as default if context cannot be deduced from file extension
        avformat_alloc_output_context2(&_format_context, NULL, "mp4", NULL);
    if (_format_context == NULL)
        throw VideoTargetError("Could not allocate output media context");

    _codec = avcodec_find_encoder_by_name(_codec_name.c_str());
    if (not _codec)
        throw VideoTargetError("Codec not found");

    _stream = avformat_new_stream(_format_context, _codec);
    if (_stream == NULL)
        throw VideoTargetError("Could not allocate stream");
    _stream->id = _format_context->nb_streams-1; // TODO isn't this wrong?

    // allocate FFmpeg frame
    _frame = av_frame_alloc();
    if (not _frame)
        throw VideoTargetError("Could not allocate video frame");
    _first_frame = true;
}

void VideoTargetFFmpeg::append(const VideoFrame_BGRA & frame)
{
    ffmpeg_frame(frame.data(),
                 frame.data_length(),
                 frame.cols(), frame.rows(),
                 AV_PIX_FMT_BGRA, _frame);

    { // START auto_cpu_timer scope
#ifdef GENERATE_PERFORMANCE_OUTPUT
    boost::timer::auto_cpu_timer t(this_class_str + "1-encode_and_write" + timer_format_str);
#endif

    /* encode the image */
    int got_output;
    encode_and_write(_frame, got_output);

    } // END auto_cpu_timer scope
}

void VideoTargetFFmpeg::append(const VideoFrame_I420 & frame)
{
    // TODO
}

void VideoTargetFFmpeg::ffmpeg_frame(const unsigned char * data,
                                     const size_t data_length,
                                     const int width, const int height,
                                     const AVPixelFormat colour_space,
                                     AVFrame * frame)
{
    if (_framerate <= 0)
        throw VideoTargetError("Video target not initialised");

    if (not frame)
        throw VideoTargetError("FFmpeg frame not initialised");

    // return value buffers
    int ret;

    // if first frame, initialise
    if (_first_frame)
    {
#ifdef GENERATE_PERFORMANCE_OUTPUT
#ifndef timer_format_str
#define timer_format_str \
        std::string(", %w, %u, %s, %t, %p" \
                    ", wall (s), user (s), system (s), user+system (s), CPU (\%)\n")
#endif
#ifndef this_class_str
#define this_class_str std::string("VideoTargetFFmpeg-")
#endif
        boost::timer::auto_cpu_timer t(this_class_str + "first-frame" + timer_format_str);
#endif
        // TODO - is _codec_context ever being modified after first frame?
        /* TODO: using default reduces filesize
         * but should we set it nonetheless?
         */
//        _stream->codec->bit_rate = 400000;
        _stream->codec->width = width;
        _stream->codec->height = height;
        _stream->time_base = (AVRational){ 1, _framerate };
        _stream->codec->time_base = _stream->time_base;
        _stream->codec->gop_size = 12;
        /* TODO emit one intra frame every twelve frames at most */
        _stream->codec->pix_fmt = AV_PIX_FMT_YUV420P;
        /* Some formats want stream headers to be separate. */
        if (_format_context->oformat->flags & AVFMT_GLOBALHEADER)
            _stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

        switch (_stream->codec->codec_id)
        {
        case AV_CODEC_ID_H264:
        case AV_CODEC_ID_HEVC:
#ifdef FFMPEG_HWACCEL
            // nop
            ret = 0;
#else
            /* TODO will this work in real-time with a framegrabber ?
             * "slow" produces 2x larger file compared to "ultrafast",
             * but with a substantial visual quality degradation
             * (judged using the coloured chessboard pattern)
             * "fast" is a trade-off: visual quality looks similar
             * while file size is reasonable
             */
            ret = av_opt_set(_stream->codec->priv_data, "preset", "fast", 0);
#endif
            if (ret != 0)
                throw VideoTargetError("Could not set codec-specific options");

            /* Resolution must be a multiple of two, as required
             * by H264 and H265. Introduce a one-pixel padding for
             * non-complying dimension(s).
             */
            _stream->codec->width +=
                    _stream->codec->width % 2 == 0 ? 0 : 1;
            _stream->codec->height +=
                    _stream->codec->height % 2 == 0 ? 0 : 1;
            break;
        default:
            // nop
            break;
        }

        /* open it */
        if (avcodec_open2(_stream->codec, _codec, NULL) < 0)
            throw VideoTargetError("Could not open codec");

        frame->format = _stream->codec->pix_fmt;
        frame->width  = _stream->codec->width;
        frame->height = _stream->codec->height;
        /* allocate the buffers for the frame data */
        // TODO #25 what influence does 32 have on performance?
        ret = av_frame_get_buffer(frame, 32);
        if (ret < 0)
            throw VideoTargetError("Could not allocate frame data");

        /* Now that all the parameters are set, we can open the audio and
         * video codecs and allocate the necessary encode buffers. */
        av_dump_format(_format_context, 0, _filepath.c_str(), 1);
        /* open the output file, if needed */
        if (!(_format_context->oformat->flags & AVFMT_NOFILE))
        {
            ret = avio_open(&_format_context->pb, _filepath.c_str(), AVIO_FLAG_WRITE);
            if (ret < 0)
            {
                std::string msg;
                msg.append("File ")
                   .append(_filepath)
                   .append(" could not be opened");
                throw VideoTargetError(msg);
            }
        }

        /* Write the stream header, if any. */
        ret = avformat_write_header(_format_context, NULL);
        if (ret < 0)
            throw VideoTargetError("Could not write header to file");

        /* TODO USE_COLOUR_SPACE_I420 also implicitly provides
         * this check, but selective code compilation might make
         * code faster, due to not having the conditional checks
         */
        if (colour_space == AV_PIX_FMT_BGRA)
        {
            /* Open context for converting BGRA pixels to YUV420p */
            _sws_context = sws_getContext(
                        width, height, AV_PIX_FMT_BGRA,
                        width, height, _stream->codec->pix_fmt,
                        0, NULL, NULL, NULL);
            if (_sws_context == NULL)
                throw VideoTargetError("Could not allocate Sws context");
        }
        else if (colour_space != AV_PIX_FMT_YUV420P)
            throw VideoTargetError("Colour space not supported");

        // To be incremented for each frame, used as pts
        _frame_index = 0;

        // Packet to be used when writing frames
        av_init_packet(&_packet);
        // TODO #25 data gets allocated each time?
        _packet.data = NULL;    // packet data will be allocated by the encoder
        _packet.size = 0;

        _bgra_stride[0] = 4*width;

        _first_frame = false;
    }

    { // START auto_cpu_timer scope
#ifdef GENERATE_PERFORMANCE_OUTPUT
    boost::timer::auto_cpu_timer t(this_class_str + "1-av_frame_make_writable" + timer_format_str);
#endif

    /* when we pass a frame to the encoder, it may keep a reference to it
     * internally;
     * make sure we do not overwrite it here
     */
    // TODO #25 why not only once?
    ret = av_frame_make_writable(frame);
    if (ret < 0)
        throw VideoTargetError("Could not make frame writeable");

    } // END auto_cpu_timer scope

    { // START auto_cpu_timer scope
#ifdef GENERATE_PERFORMANCE_OUTPUT
    boost::timer::auto_cpu_timer t(this_class_str + "1-sws_scale" + timer_format_str);
#endif

    _src_data_ptr[0] = data;
    /* TODO USE_COLOUR_SPACE_I420 also implicitly provides
     * this check, but selective code compilation might make
     * code faster, due to not having the conditional checks
     */
    switch(colour_space)
    {
    case AV_PIX_FMT_BGRA:
        /* convert pixel format */
        sws_scale(_sws_context,
                  _src_data_ptr, _bgra_stride, // BGRA has one plane
                  0, height,
                  frame->data, frame->linesize
                  );
        break;
    case AV_PIX_FMT_YUV420P:
        // TODO, in first frame?
        break;
    default:
        throw VideoTargetError("Colour space not supported");
    }

    frame->pts = _frame_index++;

    } // END auto_cpu_timer scope
}

void VideoTargetFFmpeg::encode_and_write(AVFrame * frame, int & got_output)
{
    int ret;

    { // START auto_cpu_timer scope
#ifdef GENERATE_PERFORMANCE_OUTPUT
    boost::timer::auto_cpu_timer t(this_class_str + "2-avcodec_encode_video2" + timer_format_str);
#endif
    ret = avcodec_encode_video2(_stream->codec, &_packet, frame, &got_output);
    } // END auto_cpu_timer scope

    if (ret < 0)
        throw VideoTargetError("Error encoding frame");

    if (got_output)
    {
        { // START auto_cpu_timer scope
#ifdef GENERATE_PERFORMANCE_OUTPUT
        boost::timer::auto_cpu_timer t(this_class_str + "2-av_packet_rescale_ts" + timer_format_str);
#endif
        /* rescale output packet timestamp values from codec to stream timebase */
        av_packet_rescale_ts(&_packet, _stream->codec->time_base, _stream->time_base);
        // TODO - above time bases are the same, or not?
        _packet.stream_index = _stream->index;
        } // END auto_cpu_timer scope

        { // START auto_cpu_timer scope
#ifdef GENERATE_PERFORMANCE_OUTPUT
        boost::timer::auto_cpu_timer t(this_class_str + "2-av_interleaved_write_frame" + timer_format_str);
#endif
        /* Write the compressed frame to the media file. */
        ret = av_interleaved_write_frame(_format_context, &_packet);
        }

        if (ret < 0)
            throw VideoTargetError("Could not interleaved write frame");
//        av_packet_unref(&packet); taken care of by av_interleaved_write_frame
    }
}

void VideoTargetFFmpeg::finalise()
{
    /* This condition means that append
     * has been called at least once
     * successfully (see Issue#36)
     */
    if (_frame)
    {
        /* get the delayed frames */
        for (int got_output = 1; got_output; )
            encode_and_write(NULL, got_output);

        /* Write the trailer, if any. The trailer must be written before you
         * close the CodecContexts open when you wrote the header; otherwise
         * av_write_trailer() may try to use memory that was freed on
         * av_codec_close(). */
        av_write_trailer(_format_context);
    }

    if (_stream->codec) avcodec_close(_stream->codec);
    if (_frame) av_frame_free(&_frame);
//  av_freep(&_frame->data[0]); no need for this because _frame never manages its own data
    if (_sws_context) sws_freeContext(_sws_context);

    if (!(_format_context->oformat->flags & AVFMT_NOFILE))
        if (_format_context->pb)
            /* Close the output file. */
            avio_closep(&_format_context->pb);
    /* free the stream */
    avformat_free_context(_format_context);

    // default values, for next init
    _codec = NULL;
    _frame = NULL;
    _framerate = -1;
    _sws_context = NULL;
    _format_context = NULL;
    _stream = NULL;
    _frame_index = 0;
}

}
<|endoftext|>


<commit_before>///
/// @file  pi_lmo_parallel3.cpp
/// @brief Parallel implementation of the Lagarias-Miller-Odlyzko
///        prime counting algorithm using OpenMP. This implementation
///        is based on pi_lmo_parallel2(x) but has an improved
///        load balancing.
///
/// Copyright (C) 2014 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primecount-internal.hpp>
#include <aligned_vector.hpp>
#include <BitSieve.hpp>
#include <generate.hpp>
#include <pmath.hpp>
#include <PhiTiny.hpp>
#include <S1.hpp>
#include <S2LoadBalancer.hpp>
#include <S2Status.hpp>
#include <tos_counters.hpp>

#include <stdint.h>
#include <algorithm>
#include <iostream>
#include <vector>

#ifdef _OPENMP
  #include <omp.h>
#endif

using namespace std;
using namespace primecount;

namespace {

/// For each prime calculate its first multiple >= low
vector<int64_t> generate_next_multiples(int64_t low, int64_t size, vector<int32_t>& primes)
{
  vector<int64_t> next;

  next.reserve(size);
  next.push_back(0);

  for (int64_t b = 1; b < size; b++)
  {
    int64_t prime = primes[b];
    int64_t next_multiple = ceil_div(low, prime) * prime;
    next_multiple += prime * (~next_multiple & 1);
    next.push_back(next_multiple);
  }

  return next;
}

template <typename T>
void cross_off(int64_t prime,
               int64_t low,
               int64_t high,
               int64_t& next_multiple,
               BitSieve& sieve,
               T& counters)
{
  int64_t segment_size = sieve.size();
  int64_t k = next_multiple;

  for (; k < high; k += prime * 2)
  {
    if (sieve[k - low])
    {
      sieve.unset(k - low);
      cnt_update(counters, k - low, segment_size);
    }
  }
  next_multiple = k;
}

/// Compute the S2 contribution for the interval
/// [low_process, low_process + segments * segment_size[.
/// The missing special leaf contributions for the interval
/// [1, low_process[ are later reconstructed and added in
/// the calling (parent) S2 function.
///
int64_t S2_thread(int64_t x,
                  int64_t y,
                  int64_t c,
                  int64_t segment_size,
                  int64_t segments_per_thread,
                  int64_t thread_num,
                  int64_t low,
                  int64_t limit,
                  vector<int32_t>& pi,
                  vector<int32_t>& primes,
                  vector<int32_t>& lpf,
                  vector<int32_t>& mu,
                  vector<int64_t>& mu_sum,
                  vector<int64_t>& phi)
{
  low += segment_size * segments_per_thread * thread_num;
  limit = min(low + segment_size * segments_per_thread, limit);
  int64_t size = pi[min(isqrt(x / low), y)] + 1;
  int64_t pi_sqrty = pi[isqrt(y)];
  int64_t pi_y = pi[y];

  if (c >= size - 1)
    return 0;

  int64_t S2_thread = 0;
  BitSieve sieve(segment_size);
  vector<int32_t> counters(segment_size);
  vector<int64_t> next = generate_next_multiples(low, size, primes);
  phi.resize(size, 0);
  mu_sum.resize(size, 0);

  // Process the segments assigned to the current thread
  for (; low < limit; low += segment_size)
  {
    // Current segment = interval [low, high[
    int64_t high = min(low + segment_size, limit);
    int64_t b = 2;

    sieve.fill(low, high);

    // phi(y, b) nodes with b <= c do not contribute to S2, so we
    // simply sieve out the multiples of the first c primes
    for (; b <= c; b++)
    {
      int64_t k = next[b];
      for (int64_t prime = primes[b]; k < high; k += prime * 2)
        sieve.unset(k - low);
      next[b] = k;
    }

    // Initialize special tree data structure from sieve
    cnt_finit(sieve, counters, segment_size);

    // For c + 1 <= b < pi_sqrty
    // Find all special leaves: n = primes[b] * m
    // which satisfy:  mu[m] != 0 && primes[b] < lpf[m], low <= (x / n) < high
    for (; b < min(pi_sqrty, size); b++)
    {
      int64_t prime = primes[b];
      int64_t min_m = max(x / (prime * high), y / prime);
      int64_t max_m = min(x / (prime * low), y);

      if (prime >= max_m)
        goto next_segment;

      for (int64_t m = max_m; m > min_m; m--)
      {
        if (mu[m] != 0 && prime < lpf[m])
        {
          int64_t n = prime * m;
          int64_t count = cnt_query(counters, (x / n) - low);
          int64_t phi_xn = phi[b] + count;
          S2_thread -= mu[m] * phi_xn;
          mu_sum[b] -= mu[m];
        }
      }

      phi[b] += cnt_query(counters, (high - 1) - low);
      cross_off(prime, low, high, next[b], sieve, counters);
    }

    // For pi_sqrty <= b < pi_y
    // Find all special leaves: n = primes[b] * prime2
    // which satisfy: low <= (x / n) < high
    for (; b < min(pi_y, size); b++)
    {
      int64_t prime = primes[b];
      int64_t l = pi[min(x / (prime * low), y)];
      int64_t min_m = max3(x / (prime * high), y / prime, prime);

      if (prime >= primes[l])
        goto next_segment;

      for (; primes[l] > min_m; l--)
      {
        int64_t n = prime * primes[l];
        int64_t count = cnt_query(counters, (x / n) - low);
        int64_t phi_xn = phi[b] + count;
        S2_thread += phi_xn;
        mu_sum[b]++;
      }

      phi[b] += cnt_query(counters, (high - 1) - low);
      cross_off(prime, low, high, next[b], sieve, counters);
    }

    next_segment:;
  }

  return S2_thread;
}

/// Calculate the contribution of the special leaves.
/// This is a parallel implementation with advanced load balancing.
/// As most special leaves tend to be in the first segments we
/// start off with a small segment size and few segments
/// per thread, after each iteration we dynamically increase
/// the segment size and the segments per thread.
/// @pre y > 0 && c > 1
///
int64_t S2(int64_t x,
           int64_t y,
           int64_t c,
           int64_t s2_approx,
           vector<int32_t>& primes,
           vector<int32_t>& lpf,
           vector<int32_t>& mu,
           int threads)
{
  if (print_status())
  {
    cout << endl;
    cout << "=== S2(x, y) ===" << endl;
    cout << "Computation of the special leaves" << endl;
  }

  int64_t S2_total = 0;
  int64_t low = 1;
  int64_t limit = x / y + 1;
  threads = validate_threads(threads, limit);

  S2Status status(s2_approx);
  S2LoadBalancer loadBalancer(x, limit, threads);
  int64_t segment_size = loadBalancer.get_min_segment_size();
  int64_t segments_per_thread = 1;

  double time = get_wtime();
  vector<int32_t> pi = generate_pi(y);
  vector<int64_t> phi_total(primes.size(), 0);

  while (low < limit)
  {
    int64_t segments = ceil_div(limit - low, segment_size);
    threads = in_between(1, threads, segments);
    segments_per_thread = in_between(1, segments_per_thread, ceil_div(segments, threads));

    aligned_vector<vector<int64_t> > phi(threads);
    aligned_vector<vector<int64_t> > mu_sum(threads);
    aligned_vector<double> timings(threads);

    #pragma omp parallel for num_threads(threads) reduction(+: S2_total)
    for (int i = 0; i < threads; i++)
    {
      timings[i] = get_wtime();
      S2_total += S2_thread(x, y, c, segment_size, segments_per_thread,
          i, low, limit, pi, primes, lpf, mu, mu_sum[i], phi[i]);
      timings[i] = get_wtime() - timings[i];
    }

    // Once all threads have finished reconstruct and add the
    // missing contribution of all special leaves. This must
    // be done in order as each thread (i) requires the sum of
    // the phi values from the previous threads.
    //
    for (int i = 0; i < threads; i++)
    {
      for (size_t j = 1; j < phi[i].size(); j++)
      {
        S2_total += phi_total[j] * mu_sum[i][j];
        phi_total[j] += phi[i][j];
      }
    }

    low += segments_per_thread * threads * segment_size;
    loadBalancer.update(low, threads, &segment_size, &segments_per_thread, timings);

    if (print_status())
      status.print(S2_total, loadBalancer.get_rsd());
  }

  if (print_status())
    print_result("S2", S2_total, time);

  return S2_total;
}

/// alpha is a tuning factor which should grow like (log(x))^2
/// for the Lagarias-Miller-Odlyzko algorithm
///
double compute_alpha(int64_t x)
{
  double d = (double) x;
  return in_between(1, log(d) * log(d) / 300, iroot<6>(x));
}

} // namespace

namespace primecount {

/// Calculate the number of primes below x using the
/// Lagarias-Miller-Odlyzko algorithm.
/// Run time: O(x^(2/3) / log x) operations, O(x^(1/3) * (log x)^2) space.
///
int64_t pi_lmo_parallel3(int64_t x, int threads)
{
  if (x < 2)
    return 0;

  double alpha = compute_alpha(x);
  int64_t x13 = iroot<3>(x);
  int64_t y = (int64_t) (x13 * alpha);

  if (print_status())
  {
    cout << endl;
    cout << "=== pi_lmo_parallel3(x) ===" << endl;
    cout << "pi(x) = S1 + S2 + pi(y) - 1 - P2" << endl;
    cout << "x = " << x << endl;
    cout << "y = " << y << endl;
    cout << "c = " << PhiTiny::max_a() << endl;
    cout << "threads = " << validate_threads(threads) << endl;
  }

  int64_t p2 = P2(x, y, threads);

  vector<int32_t> mu = generate_moebius(y);
  vector<int32_t> lpf = generate_least_prime_factors(y);
  vector<int32_t> primes = generate_primes(y);

  int64_t pi_y = primes.size() - 1;
  int64_t c = min(pi_y, PhiTiny::max_a());
  int64_t s1 = S1(x, y, c, primes[c], lpf , mu, threads);
  int64_t s2_approx = S2_approx(x, pi_y, p2, s1);
  int64_t s2 = S2(x, y, c, s2_approx, primes, lpf , mu, threads);
  int64_t phi = s1 + s2;
  int64_t sum = phi + pi_y - 1 - p2;

  return sum;
}

} // namespace primecount
<commit_msg>Update pi_lmo_parallel3.cpp<commit_after>///
/// @file  pi_lmo_parallel3.cpp
/// @brief Parallel implementation of the Lagarias-Miller-Odlyzko
///        prime counting algorithm using OpenMP. This implementation
///        is based on pi_lmo_parallel2(x) but has an improved
///        load balancing.
///
/// Copyright (C) 2014 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primecount-internal.hpp>
#include <aligned_vector.hpp>
#include <BitSieve.hpp>
#include <generate.hpp>
#include <pmath.hpp>
#include <PhiTiny.hpp>
#include <S1.hpp>
#include <S2LoadBalancer.hpp>
#include <S2Status.hpp>
#include <tos_counters.hpp>

#include <stdint.h>
#include <algorithm>
#include <iostream>
#include <vector>

#ifdef _OPENMP
  #include <omp.h>
#endif

using namespace std;
using namespace primecount;

namespace {

/// For each prime calculate its first multiple >= low
vector<int64_t> generate_next_multiples(int64_t low, int64_t size, vector<int32_t>& primes)
{
  vector<int64_t> next;

  next.reserve(size);
  next.push_back(0);

  for (int64_t b = 1; b < size; b++)
  {
    int64_t prime = primes[b];
    int64_t next_multiple = ceil_div(low, prime) * prime;
    next_multiple += prime * (~next_multiple & 1);
    next.push_back(next_multiple);
  }

  return next;
}

template <typename T>
void cross_off(int64_t prime,
               int64_t low,
               int64_t high,
               int64_t& next_multiple,
               BitSieve& sieve,
               T& counters)
{
  int64_t segment_size = sieve.size();
  int64_t k = next_multiple;

  for (; k < high; k += prime * 2)
  {
    if (sieve[k - low])
    {
      sieve.unset(k - low);
      cnt_update(counters, k - low, segment_size);
    }
  }
  next_multiple = k;
}

/// Compute the S2 contribution for the interval
/// [low_process, low_process + segments * segment_size[.
/// The missing special leaf contributions for the interval
/// [1, low_process[ are later reconstructed and added in
/// the calling (parent) S2 function.
///
int64_t S2_thread(int64_t x,
                  int64_t y,
                  int64_t c,
                  int64_t segment_size,
                  int64_t segments_per_thread,
                  int64_t thread_num,
                  int64_t low,
                  int64_t limit,
                  vector<int32_t>& pi,
                  vector<int32_t>& primes,
                  vector<int32_t>& lpf,
                  vector<int32_t>& mu,
                  vector<int64_t>& mu_sum,
                  vector<int64_t>& phi)
{
  low += segment_size * segments_per_thread * thread_num;
  limit = min(low + segment_size * segments_per_thread, limit);
  int64_t size = pi[min(isqrt(x / low), y)] + 1;
  int64_t pi_sqrty = pi[isqrt(y)];
  int64_t pi_y = pi[y];

  if (c >= size - 1)
    return 0;

  int64_t S2_thread = 0;
  BitSieve sieve(segment_size);
  vector<int32_t> counters(segment_size);
  vector<int64_t> next = generate_next_multiples(low, size, primes);
  phi.resize(size, 0);
  mu_sum.resize(size, 0);

  // Process the segments assigned to the current thread
  for (; low < limit; low += segment_size)
  {
    // Current segment = interval [low, high[
    int64_t high = min(low + segment_size, limit);
    int64_t b = 2;

    sieve.fill(low, high);

    // phi(y, b) nodes with b <= c do not contribute to S2, so we
    // simply sieve out the multiples of the first c primes
    for (; b <= c; b++)
    {
      int64_t k = next[b];
      for (int64_t prime = primes[b]; k < high; k += prime * 2)
        sieve.unset(k - low);
      next[b] = k;
    }

    // Initialize special tree data structure from sieve
    cnt_finit(sieve, counters, segment_size);

    // For c + 1 <= b < pi_sqrty
    // Find all special leaves: n = primes[b] * m
    // which satisfy:  mu[m] != 0 && primes[b] < lpf[m], low <= (x / n) < high
    for (; b < min(pi_sqrty, size); b++)
    {
      int64_t prime = primes[b];
      int64_t min_m = max(x / (prime * high), y / prime);
      int64_t max_m = min(x / (prime * low), y);

      if (prime >= max_m)
        goto next_segment;

      for (int64_t m = max_m; m > min_m; m--)
      {
        if (mu[m] != 0 && prime < lpf[m])
        {
          int64_t n = prime * m;
          int64_t count = cnt_query(counters, (x / n) - low);
          int64_t phi_xn = phi[b] + count;
          S2_thread -= mu[m] * phi_xn;
          mu_sum[b] -= mu[m];
        }
      }

      phi[b] += cnt_query(counters, (high - 1) - low);
      cross_off(prime, low, high, next[b], sieve, counters);
    }

    // For pi_sqrty <= b < pi_y
    // Find all special leaves: n = primes[b] * prime2
    // which satisfy: low <= (x / n) < high
    for (; b < min(pi_y, size); b++)
    {
      int64_t prime = primes[b];
      int64_t l = pi[min(x / (prime * low), y)];
      int64_t min_m = max3(x / (prime * high), y / prime, prime);

      if (prime >= primes[l])
        goto next_segment;

      for (; primes[l] > min_m; l--)
      {
        int64_t n = prime * primes[l];
        int64_t count = cnt_query(counters, (x / n) - low);
        int64_t phi_xn = phi[b] + count;
        S2_thread += phi_xn;
        mu_sum[b]++;
      }

      phi[b] += cnt_query(counters, (high - 1) - low);
      cross_off(prime, low, high, next[b], sieve, counters);
    }

    next_segment:;
  }

  return S2_thread;
}

/// Calculate the contribution of the special leaves.
/// This is a parallel implementation with advanced load balancing.
/// As most special leaves tend to be in the first segments we
/// start off with a small segment size and few segments
/// per thread, after each iteration we dynamically increase
/// the segment size and the segments per thread.
/// @pre y > 0 && c > 1
///
int64_t S2(int64_t x,
           int64_t y,
           int64_t c,
           int64_t s2_approx,
           vector<int32_t>& primes,
           vector<int32_t>& lpf,
           vector<int32_t>& mu,
           int threads)
{
  if (print_status())
  {
    cout << endl;
    cout << "=== S2(x, y) ===" << endl;
    cout << "Computation of the special leaves" << endl;
  }

  int64_t S2_total = 0;
  int64_t low = 1;
  int64_t limit = x / y + 1;
  threads = validate_threads(threads, limit);

  S2Status status;
  S2LoadBalancer loadBalancer(x, limit, threads);
  int64_t segment_size = loadBalancer.get_min_segment_size();
  int64_t segments_per_thread = 1;

  double time = get_wtime();
  vector<int32_t> pi = generate_pi(y);
  vector<int64_t> phi_total(primes.size(), 0);

  while (low < limit)
  {
    int64_t segments = ceil_div(limit - low, segment_size);
    threads = in_between(1, threads, segments);
    segments_per_thread = in_between(1, segments_per_thread, ceil_div(segments, threads));

    aligned_vector<vector<int64_t> > phi(threads);
    aligned_vector<vector<int64_t> > mu_sum(threads);
    aligned_vector<double> timings(threads);

    #pragma omp parallel for num_threads(threads) reduction(+: S2_total)
    for (int i = 0; i < threads; i++)
    {
      timings[i] = get_wtime();
      S2_total += S2_thread(x, y, c, segment_size, segments_per_thread,
          i, low, limit, pi, primes, lpf, mu, mu_sum[i], phi[i]);
      timings[i] = get_wtime() - timings[i];
    }

    // Once all threads have finished reconstruct and add the
    // missing contribution of all special leaves. This must
    // be done in order as each thread (i) requires the sum of
    // the phi values from the previous threads.
    //
    for (int i = 0; i < threads; i++)
    {
      for (size_t j = 1; j < phi[i].size(); j++)
      {
        S2_total += phi_total[j] * mu_sum[i][j];
        phi_total[j] += phi[i][j];
      }
    }

    low += segments_per_thread * threads * segment_size;
    loadBalancer.update(low, threads, &segment_size, &segments_per_thread, timings);

    if (print_status())
      status.print(S2_total, s2_approx, loadBalancer.get_rsd());
  }

  if (print_status())
    print_result("S2", S2_total, time);

  return S2_total;
}

/// alpha is a tuning factor which should grow like (log(x))^2
/// for the Lagarias-Miller-Odlyzko algorithm
///
double compute_alpha(int64_t x)
{
  double d = (double) x;
  return in_between(1, log(d) * log(d) / 300, iroot<6>(x));
}

} // namespace

namespace primecount {

/// Calculate the number of primes below x using the
/// Lagarias-Miller-Odlyzko algorithm.
/// Run time: O(x^(2/3) / log x) operations, O(x^(1/3) * (log x)^2) space.
///
int64_t pi_lmo_parallel3(int64_t x, int threads)
{
  if (x < 2)
    return 0;

  double alpha = compute_alpha(x);
  int64_t x13 = iroot<3>(x);
  int64_t y = (int64_t) (x13 * alpha);

  if (print_status())
  {
    cout << endl;
    cout << "=== pi_lmo_parallel3(x) ===" << endl;
    cout << "pi(x) = S1 + S2 + pi(y) - 1 - P2" << endl;
    cout << "x = " << x << endl;
    cout << "y = " << y << endl;
    cout << "c = " << PhiTiny::max_a() << endl;
    cout << "threads = " << validate_threads(threads) << endl;
  }

  int64_t p2 = P2(x, y, threads);

  vector<int32_t> mu = generate_moebius(y);
  vector<int32_t> lpf = generate_least_prime_factors(y);
  vector<int32_t> primes = generate_primes(y);

  int64_t pi_y = primes.size() - 1;
  int64_t c = min(pi_y, PhiTiny::max_a());
  int64_t s1 = S1(x, y, c, primes[c], lpf , mu, threads);
  int64_t s2_approx = S2_approx(x, pi_y, p2, s1);
  int64_t s2 = S2(x, y, c, s2_approx, primes, lpf , mu, threads);
  int64_t phi = s1 + s2;
  int64_t sum = phi + pi_y - 1 - p2;

  return sum;
}

} // namespace primecount
<|endoftext|>


<commit_before>#include "devicesdialog.h"
#include "ui_devicesdialog.h"
#include "utils.h"
#include <usb/Context.h>
#include <mtp/ptp/Device.h>
#include <mtp/ptp/PipePacketer.h>
#include <QDebug>
#include <QMessageBox>
#include <QPushButton>
#include <algorithm>

DevicesDialog::DevicesDialog(bool resetDevice, QWidget *parent) :
	QDialog(parent),
	_resetDevice(resetDevice),
	ui(new Ui::DevicesDialog)
{
	ui->setupUi(this);
	_buttonScan = ui->buttonBox->addButton(tr("Rescan Devices"), QDialogButtonBox::ActionRole);
	_buttonKill = ui->buttonBox->addButton(tr("Kill Users"), QDialogButtonBox::ActionRole);
	connect(ui->listWidget, SIGNAL(itemClicked(QListWidgetItem *)), SLOT(itemClicked(QListWidgetItem *)));
	connect(ui->listWidget, SIGNAL(itemDoubleClicked(QListWidgetItem *)), SLOT(itemDoubleClicked(QListWidgetItem *)));
	connect(_buttonScan, SIGNAL(clicked()), SLOT(scan()));
	connect(_buttonKill, SIGNAL(clicked()), SLOT(kill()));
}

mtp::DevicePtr DevicesDialog::getDevice()
{
	int row = ui->listWidget->currentRow();
	if (row >= 0 && row < static_cast<int>(_devices.size()))
		return _devices[row].Device;
	else
		return nullptr;
}

void DevicesDialog::kill()
{
	qDebug("kill");

	int index = ui->listWidget->currentRow();
	if (index < 0 && index >= static_cast<int>(_devices.size()))
		return;

	auto & row = _devices[index];

	bool canKill = !row.Processes.empty();
	QString processList;
	for (auto & desc : row.Processes)
	{
		processList += QString("%1 (pid: %2)\n").arg(fromUtf8(desc.Name)).arg(desc.Id);
	}
	if (canKill)
		processList = tr("The following processes are keeping file descriptors for your device:\n") + processList;

	QMessageBox dialog(
		QMessageBox::Warning,
		tr("Device is busy"),
		tr("Device is busy, maybe another process is using it.\n\n") +
		processList +
		tr("Close other MTP applications and restart Android File Transfer.\n"
		"\nPress Abort to kill them or Ignore to try next device."),
		(canKill? QMessageBox::Ok: QMessageBox::StandardButton(0)) | QMessageBox::Cancel,
		this
	);

	dialog.setDefaultButton(QMessageBox::Ignore);
	dialog.setEscapeButton(QMessageBox::Ignore);
	auto r = dialog.exec();

	if ((r & QMessageBox::Ok) == QMessageBox::Ok)
	{
		qDebug("kill'em all");
		mtp::usb::DeviceBusyException::Kill(row.Processes);
		scan();
	}
}

void DevicesDialog::scan()
{
	qDebug("scan");
	bool claimInterface = true;
	bool resetDevice = _resetDevice;

	_devices.clear();

	mtp::usb::ContextPtr ctx(new mtp::usb::Context);

	auto devices = ctx->GetDevices();
	for (auto desc = devices.begin(); desc != devices.end(); ++desc)
	{
		qDebug("probing device...");
		try
		{
			auto device = mtp::Device::Open(ctx, *desc, claimInterface, resetDevice);
			_devices.push_back({ *desc, device, {} });
		}
		catch(const mtp::usb::DeviceBusyException &ex)
		{
			if (!ex.Processes.empty())
				_devices.push_back(Row { *desc, nullptr, ex.Processes });
		}
		catch(const std::exception &ex)
		{ qWarning("Device::Find failed: %s", ex.what()); }
	}

	std::stable_sort(_devices.begin(), _devices.end(), [](const Row & a, const Row & b) {
		return a.Device > b.Device;
	});

	auto it = std::remove_if(_devices.begin(), _devices.end(), [](const Row & row) {
		return !row.Device && row.Processes.empty();
	});
	_devices.erase(it, _devices.end());

	ui->listWidget->clear();
	for(auto & row : _devices)
	{
		QString name;
		if (row.Device)
		{
			auto info = row.Device->GetInfo();
			name = QString("%1 %2 %3")
				.arg(fromUtf8(info.Manufacturer))
				.arg(fromUtf8(info.Model))
				.arg(fromUtf8(info.SerialNumber));
		}
		else
		{
			auto & desc = row.Descriptor;
			name = QString(tr("USB Device %1:%2"))
				.arg(static_cast<int>(desc->GetVendorId()), 4, 16, QChar('0'))
				.arg(static_cast<int>(desc->GetProductId()), 4, 16, QChar('0'));
		}
		ui->listWidget->addItem(name);
	}

	if (!_devices.empty())
		ui->listWidget->setCurrentRow(0);

	updateButtons();
}

int DevicesDialog::exec()
{
	scan();

	if (_devices.empty())
		return QDialog::Rejected;

	return QDialog::exec();
}

void DevicesDialog::updateButtons()
{
	_buttonKill->setEnabled(false);
	int row = ui->listWidget->currentRow();
	if (row >= 0 && row < static_cast<int>(_devices.size()))
	{
		_buttonKill->setEnabled(!_devices[row].Processes.empty());
	}
}

void DevicesDialog::itemClicked(QListWidgetItem *)
{ updateButtons(); }

void DevicesDialog::itemDoubleClicked(QListWidgetItem *)
{ updateButtons(); accept(); }

DevicesDialog::~DevicesDialog()
{
	delete ui;
}
<commit_msg>do not show device dialog for single opened mtp device<commit_after>#include "devicesdialog.h"
#include "ui_devicesdialog.h"
#include "utils.h"
#include <usb/Context.h>
#include <mtp/ptp/Device.h>
#include <mtp/ptp/PipePacketer.h>
#include <QDebug>
#include <QMessageBox>
#include <QPushButton>
#include <algorithm>

DevicesDialog::DevicesDialog(bool resetDevice, QWidget *parent) :
	QDialog(parent),
	_resetDevice(resetDevice),
	ui(new Ui::DevicesDialog)
{
	ui->setupUi(this);
	_buttonScan = ui->buttonBox->addButton(tr("Rescan Devices"), QDialogButtonBox::ActionRole);
	_buttonKill = ui->buttonBox->addButton(tr("Kill Users"), QDialogButtonBox::ActionRole);
	connect(ui->listWidget, SIGNAL(itemClicked(QListWidgetItem *)), SLOT(itemClicked(QListWidgetItem *)));
	connect(ui->listWidget, SIGNAL(itemDoubleClicked(QListWidgetItem *)), SLOT(itemDoubleClicked(QListWidgetItem *)));
	connect(_buttonScan, SIGNAL(clicked()), SLOT(scan()));
	connect(_buttonKill, SIGNAL(clicked()), SLOT(kill()));
}

mtp::DevicePtr DevicesDialog::getDevice()
{
	int row = ui->listWidget->currentRow();
	if (row >= 0 && row < static_cast<int>(_devices.size()))
		return _devices[row].Device;
	else
		return nullptr;
}

void DevicesDialog::kill()
{
	qDebug("kill");

	int index = ui->listWidget->currentRow();
	if (index < 0 && index >= static_cast<int>(_devices.size()))
		return;

	auto & row = _devices[index];

	bool canKill = !row.Processes.empty();
	QString processList;
	for (auto & desc : row.Processes)
	{
		processList += QString("%1 (pid: %2)\n").arg(fromUtf8(desc.Name)).arg(desc.Id);
	}
	if (canKill)
		processList = tr("The following processes are keeping file descriptors for your device:\n") + processList;

	QMessageBox dialog(
		QMessageBox::Warning,
		tr("Device is busy"),
		tr("Device is busy, maybe another process is using it.\n\n") +
		processList +
		tr("Close other MTP applications and restart Android File Transfer.\n"
		"\nPress Abort to kill them or Ignore to try next device."),
		(canKill? QMessageBox::Ok: QMessageBox::StandardButton(0)) | QMessageBox::Cancel,
		this
	);

	dialog.setDefaultButton(QMessageBox::Ignore);
	dialog.setEscapeButton(QMessageBox::Ignore);
	auto r = dialog.exec();

	if ((r & QMessageBox::Ok) == QMessageBox::Ok)
	{
		qDebug("kill'em all");
		mtp::usb::DeviceBusyException::Kill(row.Processes);
		scan();
	}
}

void DevicesDialog::scan()
{
	qDebug("scan");
	bool claimInterface = true;
	bool resetDevice = _resetDevice;

	_devices.clear();

	mtp::usb::ContextPtr ctx(new mtp::usb::Context);

	auto devices = ctx->GetDevices();
	for (auto desc = devices.begin(); desc != devices.end(); ++desc)
	{
		qDebug("probing device...");
		try
		{
			auto device = mtp::Device::Open(ctx, *desc, claimInterface, resetDevice);
			_devices.push_back({ *desc, device, {} });
		}
		catch(const mtp::usb::DeviceBusyException &ex)
		{
			if (!ex.Processes.empty())
				_devices.push_back(Row { *desc, nullptr, ex.Processes });
		}
		catch(const std::exception &ex)
		{ qWarning("Device::Find failed: %s", ex.what()); }
	}

	std::stable_sort(_devices.begin(), _devices.end(), [](const Row & a, const Row & b) {
		return a.Device > b.Device;
	});

	auto it = std::remove_if(_devices.begin(), _devices.end(), [](const Row & row) {
		return !row.Device && row.Processes.empty();
	});
	_devices.erase(it, _devices.end());

	ui->listWidget->clear();
	for(auto & row : _devices)
	{
		QString name;
		if (row.Device)
		{
			auto info = row.Device->GetInfo();
			name = QString("%1 %2 %3")
				.arg(fromUtf8(info.Manufacturer))
				.arg(fromUtf8(info.Model))
				.arg(fromUtf8(info.SerialNumber));
		}
		else
		{
			auto & desc = row.Descriptor;
			name = QString(tr("USB Device %1:%2"))
				.arg(static_cast<int>(desc->GetVendorId()), 4, 16, QChar('0'))
				.arg(static_cast<int>(desc->GetProductId()), 4, 16, QChar('0'));
		}
		ui->listWidget->addItem(name);
	}

	if (!_devices.empty())
		ui->listWidget->setCurrentRow(0);

	updateButtons();
}

int DevicesDialog::exec()
{
	scan();

	if (_devices.empty())
		return QDialog::Rejected;

	if (_devices.size() == 1 && _devices.front().Device)
	{
		return QDialog::Accepted;
	}

	return QDialog::exec();
}

void DevicesDialog::updateButtons()
{
	_buttonKill->setEnabled(false);
	int row = ui->listWidget->currentRow();
	if (row >= 0 && row < static_cast<int>(_devices.size()))
	{
		_buttonKill->setEnabled(!_devices[row].Processes.empty());
	}
}

void DevicesDialog::itemClicked(QListWidgetItem *)
{ updateButtons(); }

void DevicesDialog::itemDoubleClicked(QListWidgetItem *)
{ updateButtons(); accept(); }

DevicesDialog::~DevicesDialog()
{
	delete ui;
}
<|endoftext|>


<commit_before>#include <taichi/hdr/tone_mapper.h>
#include <taichi/math/array_op.h>
#include <taichi/math/array_3d.h>
#include <taichi/physics/physics_constants.h>

TC_NAMESPACE_BEGIN

class HETMO final : public ToneMapper {
protected:
    int num_bins;
public:
    void initialize(const Config &config) override {
        num_bins = config.get_int("num_bins");
    }

    virtual Array2D<Vector3> apply(const Array2D<Vector3> &inp) override {
        int width = inp.get_width(), height = inp.get_height();
        Array2D<real> lum(inp.get_width(), inp.get_height());
        for (auto &ind : inp.get_region()) {
            lum[ind] = luminance(inp[ind]);
        }
        auto scale = num_bins / (1e-30f + lum.max());
        std::vector<int> cdf(num_bins, 0);
        for (auto &ind : inp.get_region()) {
            cdf[std::min(num_bins - 1, (int)(scale * lum[ind]))] += 1;
        }
        for (int i = 0; i < num_bins - 1; i++) {
            cdf[i + 1] += cdf[i];
        }
        auto oup = inp;
        for (auto &ind : oup.get_region()) {
            real new_lum = 1.0f * cdf[std::min(num_bins - 1, (int)(scale * lum[ind]))]
                / (width * height);
            for (int i = 0; i < 3; i++) {
                oup[ind][i] = inp[ind][i] / (lum[ind] + 1e-30f) * new_lum;
            }
        }
        return oup;
    }
};

TC_IMPLEMENTATION(ToneMapper, HETMO, "he")

class CLAHETMO final : public ToneMapper {
protected:
    int num_bins;
    int num_slices;
    real contrast_limit;
public:
    void initialize(const Config &config) override {
        num_bins = config.get_int("num_bins");
        num_slices = config.get_int("num_slices");
        contrast_limit = config.get("contrast_limit", 0.0f);
    }

    virtual Array2D<Vector3> apply(const Array2D<Vector3> &inp) override {
        int width = inp.get_width(), height = inp.get_height();
        int x_slices = num_slices;
        int y_slices = num_slices;
        int x_slice_size = (int)std::ceil(1.0f * width / num_slices);
        int y_slice_size = (int)std::ceil(1.0f * height / num_slices);
        Array2D<real> lum(inp.get_width(), inp.get_height());
        for (auto &ind : inp.get_region()) {
            lum[ind] = luminance(inp[ind]);
        }
        real max_lum = lum.max() + 1e-20f;
        real scale = num_bins / max_lum;
        Array3D<real> histograms(Vector3i(x_slices, y_slices, num_bins));
        for (int i = 0; i < x_slices; i++) {
            for (int j = 0; j < y_slices; j++) {
                int x_start = std::max(0, (i - 1) * x_slice_size);
                int x_end = std::min((i + 2) * x_slice_size, width);
                int y_start = std::max(0, (j - 1) * y_slice_size);
                int y_end = std::min((j + 2) * y_slice_size, height);
                std::vector<int> cdf(num_bins, 0);
                for (int x = x_start; x < x_end; x++) {
                    for (int y = y_start; y < y_end; y++) {
                        cdf[std::min(num_bins - 1, (int)(scale * lum[x][y]))] += 1;
                    }
                }
                int num_pixels = (x_end - x_start) * (y_end - y_start);
                int threshold = int(1.0f * num_pixels / num_bins * contrast_limit);
                int clipped = 0;
                if (contrast_limit != 0.0f) {
                    for (int k = 0; k < num_bins; k++) {
                        if (cdf[k] > threshold) {
                            clipped += cdf[k] - threshold;
                            cdf[k] = threshold;
                        }
                    }
                    int gain = clipped / num_bins;
                    for (int k = 0; k < num_bins; k++) {
                        cdf[k] += gain;
                    }
                }
                for (int k = 0; k < num_bins - 1; k++) {
                    cdf[k + 1] += cdf[k];
                }
                real inv_scale = 1.0f / num_pixels;
                for (int k = num_bins - 2; k >= 0; k--) {
                    cdf[k + 1] = cdf[k];
                }
                cdf[0] = 0;
                for (int k = 0; k < num_bins; k++) {
                    histograms[i][j][k] = cdf[k] * inv_scale;
                }
            }
        }

        auto oup = inp;
        for (auto &ind : oup.get_region()) {
            real new_lum = histograms.sample_relative_coord(
                1.0f * ind.i / width, 1.0f * ind.j / height, lum[ind] / max_lum);
            for (int i = 0; i < 3; i++) {
                oup[ind][i] = inp[ind][i] / (lum[ind] + 1e-30f) * new_lum;
            }
        }
        return oup;
    }
};

TC_IMPLEMENTATION(ToneMapper, CLAHETMO, "clahe")

TC_NAMESPACE_END<commit_msg>Fixed compilation<commit_after>#include <taichi/image/tone_mapper.h>
#include <taichi/math/array_op.h>
#include <taichi/math/array_3d.h>
#include <taichi/physics/physics_constants.h>

TC_NAMESPACE_BEGIN

class HETMO final : public ToneMapper {
protected:
    int num_bins;
public:
    void initialize(const Config &config) override {
        num_bins = config.get_int("num_bins");
    }

    virtual Array2D<Vector3> apply(const Array2D<Vector3> &inp) override {
        int width = inp.get_width(), height = inp.get_height();
        Array2D<real> lum(inp.get_width(), inp.get_height());
        for (auto &ind : inp.get_region()) {
            lum[ind] = luminance(inp[ind]);
        }
        auto scale = num_bins / (1e-30f + lum.max());
        std::vector<int> cdf(num_bins, 0);
        for (auto &ind : inp.get_region()) {
            cdf[std::min(num_bins - 1, (int)(scale * lum[ind]))] += 1;
        }
        for (int i = 0; i < num_bins - 1; i++) {
            cdf[i + 1] += cdf[i];
        }
        auto oup = inp;
        for (auto &ind : oup.get_region()) {
            real new_lum = 1.0f * cdf[std::min(num_bins - 1, (int)(scale * lum[ind]))]
                / (width * height);
            for (int i = 0; i < 3; i++) {
                oup[ind][i] = inp[ind][i] / (lum[ind] + 1e-30f) * new_lum;
            }
        }
        return oup;
    }
};

TC_IMPLEMENTATION(ToneMapper, HETMO, "he")

class CLAHETMO final : public ToneMapper {
protected:
    int num_bins;
    int num_slices;
    real contrast_limit;
public:
    void initialize(const Config &config) override {
        num_bins = config.get_int("num_bins");
        num_slices = config.get_int("num_slices");
        contrast_limit = config.get("contrast_limit", 0.0f);
    }

    virtual Array2D<Vector3> apply(const Array2D<Vector3> &inp) override {
        int width = inp.get_width(), height = inp.get_height();
        int x_slices = num_slices;
        int y_slices = num_slices;
        int x_slice_size = (int)std::ceil(1.0f * width / num_slices);
        int y_slice_size = (int)std::ceil(1.0f * height / num_slices);
        Array2D<real> lum(inp.get_width(), inp.get_height());
        for (auto &ind : inp.get_region()) {
            lum[ind] = luminance(inp[ind]);
        }
        real max_lum = lum.max() + 1e-20f;
        real scale = num_bins / max_lum;
        Array3D<real> histograms(Vector3i(x_slices, y_slices, num_bins));
        for (int i = 0; i < x_slices; i++) {
            for (int j = 0; j < y_slices; j++) {
                int x_start = std::max(0, (i - 1) * x_slice_size);
                int x_end = std::min((i + 2) * x_slice_size, width);
                int y_start = std::max(0, (j - 1) * y_slice_size);
                int y_end = std::min((j + 2) * y_slice_size, height);
                std::vector<int> cdf(num_bins, 0);
                for (int x = x_start; x < x_end; x++) {
                    for (int y = y_start; y < y_end; y++) {
                        cdf[std::min(num_bins - 1, (int)(scale * lum[x][y]))] += 1;
                    }
                }
                int num_pixels = (x_end - x_start) * (y_end - y_start);
                int threshold = int(1.0f * num_pixels / num_bins * contrast_limit);
                int clipped = 0;
                if (contrast_limit != 0.0f) {
                    for (int k = 0; k < num_bins; k++) {
                        if (cdf[k] > threshold) {
                            clipped += cdf[k] - threshold;
                            cdf[k] = threshold;
                        }
                    }
                    int gain = clipped / num_bins;
                    for (int k = 0; k < num_bins; k++) {
                        cdf[k] += gain;
                    }
                }
                for (int k = 0; k < num_bins - 1; k++) {
                    cdf[k + 1] += cdf[k];
                }
                real inv_scale = 1.0f / num_pixels;
                for (int k = num_bins - 2; k >= 0; k--) {
                    cdf[k + 1] = cdf[k];
                }
                cdf[0] = 0;
                for (int k = 0; k < num_bins; k++) {
                    histograms[i][j][k] = cdf[k] * inv_scale;
                }
            }
        }

        auto oup = inp;
        for (auto &ind : oup.get_region()) {
            real new_lum = histograms.sample_relative_coord(
                1.0f * ind.i / width, 1.0f * ind.j / height, lum[ind] / max_lum);
            for (int i = 0; i < 3; i++) {
                oup[ind][i] = inp[ind][i] / (lum[ind] + 1e-30f) * new_lum;
            }
        }
        return oup;
    }
};

TC_IMPLEMENTATION(ToneMapper, CLAHETMO, "clahe")

TC_NAMESPACE_END<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/include/util/impl/shared_ptr.H $                          */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015                             */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
#ifndef __UTIL_IMPL_SHARED_PTR_H
#define __UTIL_IMPL_SHARED_PTR_H

#include <cstddef>
#include <utility>
#include <stdint.h>

namespace std
{
    namespace __impl
    {
        class shared_ptr_count
        {
            public:
                shared_ptr_count() : count(1) {};
                ~shared_ptr_count() = default;

                void increment() { __sync_add_and_fetch(&count, 1); };
                bool decrement()
                    { return 0 == __sync_add_and_fetch(&count, -1); };
                size_t use_count() { return count; };

            private:
                size_t count;
        };
    }

    template <typename T>
    class shared_ptr
    {
        public:
            typedef T element_type;

            constexpr shared_ptr() :
                count(nullptr), pointer(nullptr), owner(nullptr) {};
            constexpr shared_ptr(nullptr_t) :
                count(nullptr), pointer(nullptr), owner(nullptr) {};

            template<typename U> explicit shared_ptr(U* ptr)
            {
                _setup(ptr);
            }

            template<typename U> shared_ptr(const shared_ptr<U>& r, T* ptr)
                { _copy(r); pointer = ptr; }

            shared_ptr(const shared_ptr& r) { _copy(r); }
            template<typename U> shared_ptr(const shared_ptr<U>& r)
                { _copy(r); }

            shared_ptr(shared_ptr&& r) { _swap(std::move(r)); }
            template<typename U> shared_ptr(shared_ptr<U>&& r)
                { _swap(std::move(r)); }

            ~shared_ptr() { _cleanup(); }

            shared_ptr& operator=(const shared_ptr& r)
            {
                _cleanup();
                _copy(r);

                return *this;
            }
            template<typename U> shared_ptr& operator=(const shared_ptr<U>& r)
            {
                _cleanup();
                _copy(r);

                return *this;
            }

            shared_ptr& operator=(shared_ptr&& r)
            {
                _cleanup();
                _swap(std::move(r));

                return *this;
            }
            template<typename U> shared_ptr& operator=(shared_ptr<U>&& r)
            {
                _cleanup();
                _swap(std::move(r));

                return *this;
            }

            void reset() { _cleanup(); }
            template<typename U> void reset(U* ptr) { _cleanup(); _setup(ptr); }

            void swap(shared_ptr& r)
            {
                T* tmp0 = r.owner;
                T* tmp1 = r.pointer;
                __impl::shared_ptr_count* tmp2 = r.count;
                r.owner = owner;
                r.pointer = pointer;
                r.count = count;
                owner = tmp0;
                pointer = tmp1;
                count = tmp2;
            }

            T* get() const { return pointer; }

            T& operator*() const { return *pointer; }
            T* operator->() const { return pointer; }

            long use_count() const
            {
                if (count) return count->use_count();
                return 0;
            }
            bool unique() const { return use_count() == 1; }

            explicit operator bool() const { return nullptr != get(); }

            template<typename U>
            bool owner_before(const shared_ptr<U>& other) const
            {
                return (owner < other.owner);
            }

            template <typename U> friend class shared_ptr;

        private:
            __impl::shared_ptr_count* count;
            T* pointer;
            T* owner;

            template<typename U> void _setup(U* ptr)
            {
                owner = pointer = static_cast<T*>(ptr);
                if (pointer)
                {
                    count = new __impl::shared_ptr_count();
                }
                else
                {
                    count = nullptr;
                }
            }

            void _cleanup()
            {
                if (!count) return;

                if (count->decrement())
                {
                    delete count;
                    count = nullptr;
                    delete owner;
                    owner = nullptr;
                    pointer = nullptr;
                }
            }

            template<typename U> void _copy(const shared_ptr<U>& r)
            {
                if (r.count) r.count->increment();
                count = r.count;
                owner = static_cast<T*>(r.owner);
                pointer = static_cast<T*>(r.pointer);
            }

            template<typename U> void _swap(shared_ptr<U>&& r)
            {
                count = r.count;
                owner = r.owner;
                pointer = r.pointer;
                r.count = nullptr;
                r.owner = nullptr;
                r.pointer = nullptr;
            }
    };

    template <typename T, typename... Args>
    shared_ptr<T> make_shared( Args&&... args)
    {
        return shared_ptr<T>(new T(std::forward<Args>(args)...));
    }

    template <typename T, typename U>
    shared_ptr<T> static_pointer_cast(const shared_ptr<U>& r)
    {
        return shared_ptr<T>(r,
            static_cast<typename shared_ptr<T>::element_type*>(r.get()));
    }

    template <typename T, typename U>
    shared_ptr<T> dynamic_pointer_cast(const shared_ptr<U>& r)
    {
        return shared_ptr<T>(r,
            dynamic_cast<typename shared_ptr<T>::element_type*>(r.get()));
    }

    template <typename T, typename U>
    shared_ptr<T> const_pointer_cast(const shared_ptr<U>& r)
    {
        return shared_ptr<T>(r,
            const_cast<typename shared_ptr<T>::element_type*>(r.get()));
    }

    template <typename T>
    void swap(shared_ptr<T>& l, shared_ptr<T>& r) { return l.swap(r); }
}

#endif
<commit_msg>shared_ptr::reset did not work for shared pointer<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/include/util/impl/shared_ptr.H $                          */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2016                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
#ifndef __UTIL_IMPL_SHARED_PTR_H
#define __UTIL_IMPL_SHARED_PTR_H

#include <cstddef>
#include <utility>
#include <stdint.h>

namespace std
{
    namespace __impl
    {
        class shared_ptr_count
        {
            public:
                shared_ptr_count() : count(1) {};
                ~shared_ptr_count() = default;

                void increment() { __sync_add_and_fetch(&count, 1); };
                bool decrement()
                    { return 0 == __sync_add_and_fetch(&count, -1); };
                size_t use_count() { return count; };

            private:
                size_t count;
        };
    }

    template <typename T>
    class shared_ptr
    {
        public:
            typedef T element_type;

            constexpr shared_ptr() :
                count(nullptr), pointer(nullptr), owner(nullptr) {};
            constexpr shared_ptr(nullptr_t) :
                count(nullptr), pointer(nullptr), owner(nullptr) {};

            template<typename U> explicit shared_ptr(U* ptr)
            {
                _setup(ptr);
            }

            template<typename U> shared_ptr(const shared_ptr<U>& r, T* ptr)
                { _copy(r); pointer = ptr; }

            shared_ptr(const shared_ptr& r) { _copy(r); }
            template<typename U> shared_ptr(const shared_ptr<U>& r)
                { _copy(r); }

            shared_ptr(shared_ptr&& r) { _swap(std::move(r)); }
            template<typename U> shared_ptr(shared_ptr<U>&& r)
                { _swap(std::move(r)); }

            ~shared_ptr() { _cleanup(); }

            shared_ptr& operator=(const shared_ptr& r)
            {
                _cleanup();
                _copy(r);

                return *this;
            }
            template<typename U> shared_ptr& operator=(const shared_ptr<U>& r)
            {
                _cleanup();
                _copy(r);

                return *this;
            }

            shared_ptr& operator=(shared_ptr&& r)
            {
                _cleanup();
                _swap(std::move(r));

                return *this;
            }
            template<typename U> shared_ptr& operator=(shared_ptr<U>&& r)
            {
                _cleanup();
                _swap(std::move(r));

                return *this;
            }

            void reset() { _cleanup(); }
            template<typename U> void reset(U* ptr) { _cleanup(); _setup(ptr); }

            void swap(shared_ptr& r)
            {
                T* tmp0 = r.owner;
                T* tmp1 = r.pointer;
                __impl::shared_ptr_count* tmp2 = r.count;
                r.owner = owner;
                r.pointer = pointer;
                r.count = count;
                owner = tmp0;
                pointer = tmp1;
                count = tmp2;
            }

            T* get() const { return pointer; }

            T& operator*() const { return *pointer; }
            T* operator->() const { return pointer; }

            long use_count() const
            {
                if (count) return count->use_count();
                return 0;
            }
            bool unique() const { return use_count() == 1; }

            explicit operator bool() const { return nullptr != get(); }

            template<typename U>
            bool owner_before(const shared_ptr<U>& other) const
            {
                return (owner < other.owner);
            }

            template <typename U> friend class shared_ptr;

        private:
            __impl::shared_ptr_count* count;
            T* pointer;
            T* owner;

            template<typename U> void _setup(U* ptr)
            {
                owner = pointer = static_cast<T*>(ptr);
                if (pointer)
                {
                    count = new __impl::shared_ptr_count();
                }
                else
                {
                    count = nullptr;
                }
            }

            void _cleanup()
            {
                if (!count) return;

                if (count->decrement())
                {
                    delete count;
                    delete owner;
                }

                count = nullptr;
                owner = nullptr;
                pointer = nullptr;
            }

            template<typename U> void _copy(const shared_ptr<U>& r)
            {
                if (r.count) r.count->increment();
                count = r.count;
                owner = static_cast<T*>(r.owner);
                pointer = static_cast<T*>(r.pointer);
            }

            template<typename U> void _swap(shared_ptr<U>&& r)
            {
                count = r.count;
                owner = r.owner;
                pointer = r.pointer;
                r.count = nullptr;
                r.owner = nullptr;
                r.pointer = nullptr;
            }
    };

    template <typename T, typename... Args>
    shared_ptr<T> make_shared( Args&&... args)
    {
        return shared_ptr<T>(new T(std::forward<Args>(args)...));
    }

    template <typename T, typename U>
    shared_ptr<T> static_pointer_cast(const shared_ptr<U>& r)
    {
        return shared_ptr<T>(r,
            static_cast<typename shared_ptr<T>::element_type*>(r.get()));
    }

    template <typename T, typename U>
    shared_ptr<T> dynamic_pointer_cast(const shared_ptr<U>& r)
    {
        return shared_ptr<T>(r,
            dynamic_cast<typename shared_ptr<T>::element_type*>(r.get()));
    }

    template <typename T, typename U>
    shared_ptr<T> const_pointer_cast(const shared_ptr<U>& r)
    {
        return shared_ptr<T>(r,
            const_cast<typename shared_ptr<T>::element_type*>(r.get()));
    }

    template <typename T>
    void swap(shared_ptr<T>& l, shared_ptr<T>& r) { return l.swap(r); }
}

#endif
<|endoftext|>


<commit_before>/**
  * (T)hread-(S)afe cached data (W)riter for C++ 11
  *
  * Copyright (c) 2015 Jan Pipek (MIT licence)
  *
  * This file can be used as is without external dependencies,
  * see https://github.com/janpipek/tsw .
  */

#include <tuple>
#include <vector>
#include <iostream>
#include <utility>
#include <array>
#include <mutex>
#include <fstream>
#include <iomanip>

#ifdef TSW_USE_POSIX_THREADS
    #include <pthread.h>
    #include <stdexcept>
    #define TSW_MUTEX_DECLARATION pthread_mutex_t _mutex;
    #define TSW_MUTEX_INITIALIZATION pthread_mutexattr_t attr;\
        pthread_mutexattr_init(&attr);\
        pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);\
        pthread_mutex_init(&_mutex, &attr);
    #define TSW_LOCK bool ok = true;\
        pthread_mutex_lock(&_mutex);\
        try {
    #define TSW_UNLOCK } \
        catch(...) { ok = false; }\
        pthread_mutex_unlock(&_mutex);\
        if (!ok) {\
            throw std::runtime_error("Error in threaded writing");\
        }
#else
    #ifdef TSW_NO_THREADS
        #define TSW_MUTEX_INITIALIZATION
        #define TSW_MUTEX_DECLARATION
        #define TSW_LOCK
        #define TSW_UNLOCK
    #else
        #define TSW_USE_CPPT11_THREADS
        #include <thread>
        #define TSW_MUTEX_INITIALIZATION
        #define TSW_MUTEX_DECLARATION std::recursive_mutex _mutex;
        #define TSW_LOCK { std::lock_guard<std::recursive_mutex> lock(_mutex);
        #define TSW_UNLOCK }
    #endif
#endif

namespace tsw
{
    class ThreadSafeWriter
    {
    public:
        virtual void Flush() = 0;

        virtual ~ThreadSafeWriter() = default;     // Enable polymorphism
    };

    template <class... Ts> class BaseThreadSafeWriter : public ThreadSafeWriter { };

    template <class U, class... Ts> class BaseThreadSafeWriter<U, Ts...> : public BaseThreadSafeWriter<>
    {
    public:
        BaseThreadSafeWriter() : _columnNames(nullptr)
        {
            TSW_MUTEX_INITIALIZATION;
        }

        const static size_t itemDim = sizeof...(Ts) + 1;

        typedef std::array<std::string, itemDim> nameCollectionT;

        typedef std::tuple<U, Ts...> itemT;

        void SetColumnNames(const nameCollectionT& columnNames)
        {
            _columnNames = new nameCollectionT(columnNames);
        }

        template <class... Vs> void SetColumnNames(const std::string& name1, const Vs&... names)
        {
            static_assert(sizeof...(Vs) == (itemDim - 1), "Column names must be of the same dimension as data.");
            if (_columnNames)
            {
                delete _columnNames;
            }
            auto temp = nameCollectionT{name1, names...};
            _columnNames = new nameCollectionT(temp);
        }

        virtual ~BaseThreadSafeWriter()
        {
            if (_columnNames)
            {
                delete _columnNames;
            }
        }

        void Store(const itemT& item)
        {
            TSW_LOCK;
            _data.push_back(item);
            if (IsFlushRequired())
            {
                Flush();
            }
            TSW_UNLOCK;
        }

        void Store(const U& first, const Ts&... args)
        {
            Store(std::make_tuple(first, args...));
        }

        virtual bool IsFlushRequired()
        {
            return _data.size() == _cacheCapacity;
        }

        virtual void SetCacheCapacity(size_t capacity)
        {
            _cacheCapacity = capacity;
            if (IsFlushRequired())
            {
                Flush();
            }
        }

        void Flush() override
        {
            TSW_LOCK;
            for (auto item : _data) {
                Write(item);
            }
            FinishFlush();
            _data.clear();
            TSW_UNLOCK;
        }

        virtual void FinishFlush() { }

    protected:
        virtual void Write(const std::tuple<U, Ts...>& item) = 0;

        size_t _cacheCapacity = 1000;

        std::vector<itemT> _data;

        TSW_MUTEX_DECLARATION;

        nameCollectionT* _columnNames;
    };

    template <class... Ts> class TSVWriter : public BaseThreadSafeWriter<> { };

    template <class U, class... Ts> class TSVWriter<U, Ts...> : public BaseThreadSafeWriter<U, Ts...>
    {
    protected:
        using BaseThreadSafeWriter<U, Ts...>::_columnNames;

        // using BaseThreadSafeWriter<U, Ts...>::Flush();

    public:
        using BaseThreadSafeWriter<U, Ts...>::itemDim;

        TSVWriter(const std::string& fileName) : _fileName(fileName), _stream(nullptr), _separator("\t"), _precision(6)
        {
        }

        virtual ~TSVWriter()
        {
            BaseThreadSafeWriter<U, Ts...>::Flush();
            if (_opened)
            {
                _stream->close();
                delete _stream;
            }
        }

        void SetSeparator(const std::string& sep)
        {
            _separator = sep;
        }

        void SetPrecision(int digits)
        {
            _precision = digits;
            if (_opened)
            {
                (*_stream) << std::setprecision(_precision);
            }
        }

    protected:
        void Open()
        {
            _stream = new std::ofstream(_fileName);
            (*_stream) << std::setprecision(_precision);
            if (_columnNames)
            {
                for (size_t i = 0; i < itemDim - 1; i++)
                {
                    *_stream << (*_columnNames)[i] << _separator;
                }
                *_stream << (*_columnNames)[itemDim - 1] << std::endl;
            }
            _opened = true;
        }

        bool _opened = false;

        int _precision;

        std::string _separator;

        std::ofstream* _stream;

        std::string _fileName;

        virtual void FinishFlush()
        {
            _stream->flush();
        }

        virtual void Write(const std::tuple<U, Ts...>& item) override
        {
            if (!_opened)
            {
                Open();
            }
            WriteItem(item);
        }

        template<std::size_t I = 0, typename... Vs> inline typename std::enable_if<I == sizeof...(Vs), void>::type WriteItem(const std::tuple<Vs...>& t)
        {
            *_stream << "\n";
        }

        template<std::size_t I = 0, typename... Vs> inline typename std::enable_if<I < sizeof...(Vs), void>::type WriteItem(const std::tuple<Vs...>& t)
        {
            *_stream << std::get<I>(t) << _separator;
            WriteItem<I + 1, Vs...>(t);
        }
    };
}
<commit_msg>Some optimization for vector capacity<commit_after>/**
  * (T)hread-(S)afe cached data (W)riter for C++ 11
  *
  * Copyright (c) 2015 Jan Pipek (MIT licence)
  *
  * This file can be used as is without external dependencies,
  * see https://github.com/janpipek/tsw .
  */

#include <tuple>
#include <vector>
#include <iostream>
#include <utility>
#include <array>
#include <mutex>
#include <fstream>
#include <iomanip>

#ifdef TSW_USE_POSIX_THREADS
    #include <pthread.h>
    #include <stdexcept>
    #define TSW_MUTEX_DECLARATION pthread_mutex_t _mutex
    #define TSW_MUTEX_INITIALIZATION pthread_mutexattr_t attr;\
        pthread_mutexattr_init(&attr);\
        pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);\
        pthread_mutex_init(&_mutex, &attr)
    #define TSW_LOCK bool ok = true;\
        pthread_mutex_lock(&_mutex);\
        try {
    #define TSW_UNLOCK } \
        catch(...) { ok = false; }\
        pthread_mutex_unlock(&_mutex);\
        if (!ok) {\
            throw std::runtime_error("Error in threaded writing");\
        }
#else
    #ifdef TSW_NO_THREADS
        #define TSW_MUTEX_INITIALIZATION
        #define TSW_MUTEX_DECLARATION
        #define TSW_LOCK
        #define TSW_UNLOCK
    #else
        #define TSW_USE_CPPT11_THREADS
        #include <thread>
        #define TSW_MUTEX_INITIALIZATION
        #define TSW_MUTEX_DECLARATION std::recursive_mutex _mutex
        #define TSW_LOCK { std::lock_guard<std::recursive_mutex> lock(_mutex)
        #define TSW_UNLOCK }
    #endif
#endif

namespace tsw
{
    class ThreadSafeWriter
    {
    public:
        virtual void Flush() = 0;

        virtual ~ThreadSafeWriter() = default;     // Enable polymorphism
    };

    template <class... Ts> class BaseThreadSafeWriter : public ThreadSafeWriter { };

    template <class U, class... Ts> class BaseThreadSafeWriter<U, Ts...> : public BaseThreadSafeWriter<>
    {
    public:
        BaseThreadSafeWriter() : _columnNames(nullptr)
        {
            TSW_MUTEX_INITIALIZATION;
        }

        const static size_t itemDim = sizeof...(Ts) + 1;

        typedef std::array<std::string, itemDim> nameCollectionT;

        typedef std::tuple<U, Ts...> itemT;

        void SetColumnNames(const nameCollectionT& columnNames)
        {
            _columnNames = new nameCollectionT(columnNames);
        }

        template <class... Vs> void SetColumnNames(const std::string& name1, const Vs&... names)
        {
            static_assert(sizeof...(Vs) == (itemDim - 1), "Column names must be of the same dimension as data.");
            if (_columnNames)
            {
                delete _columnNames;
            }
            auto temp = nameCollectionT{name1, names...};
            _columnNames = new nameCollectionT(temp);
        }

        virtual ~BaseThreadSafeWriter()
        {
            if (_columnNames)
            {
                delete _columnNames;
            }
        }

        void Store(const itemT& item)
        {
            TSW_LOCK;
            _data.push_back(item);
            if (IsFlushRequired())
            {
                Flush();
            }
            TSW_UNLOCK;
        }

        void Store(const U& first, const Ts&... args)
        {
            Store(std::make_tuple(first, args...));
        }

        virtual bool IsFlushRequired()
        {
            return _data.size() == _cacheCapacity;
        }

        virtual void SetCacheCapacity(size_t capacity)
        {
            TSW_LOCK;
            _cacheCapacity = capacity;
            if (IsFlushRequired())
            {
                Flush();
            }
            else
            {
                _data.reserve(_cacheCapacity);
            }
            TSW_UNLOCK;
        }

        void Flush() override
        {
            TSW_LOCK;
            for (auto item : _data) {
                Write(item);
            }
            FinishFlush();
            _data.clear();
            _data.reserve(_cacheCapacity);
            TSW_UNLOCK;
        }

        virtual void FinishFlush() { }

    protected:
        virtual void Write(const std::tuple<U, Ts...>& item) = 0;

        size_t _cacheCapacity = 1000;

        std::vector<itemT> _data;

        TSW_MUTEX_DECLARATION;

        nameCollectionT* _columnNames;
    };

    template <class... Ts> class TSVWriter : public BaseThreadSafeWriter<> { };

    template <class U, class... Ts> class TSVWriter<U, Ts...> : public BaseThreadSafeWriter<U, Ts...>
    {
    protected:
        using BaseThreadSafeWriter<U, Ts...>::_columnNames;

        // using BaseThreadSafeWriter<U, Ts...>::Flush();

    public:
        using BaseThreadSafeWriter<U, Ts...>::itemDim;

        TSVWriter(const std::string& fileName) : _fileName(fileName), _stream(nullptr), _separator("\t"), _precision(6)
        {
        }

        virtual ~TSVWriter()
        {
            BaseThreadSafeWriter<U, Ts...>::Flush();
            if (_opened)
            {
                _stream->close();
                delete _stream;
            }
        }

        void SetSeparator(const std::string& sep)
        {
            _separator = sep;
        }

        void SetPrecision(int digits)
        {
            _precision = digits;
            if (_opened)
            {
                (*_stream) << std::setprecision(_precision);
            }
        }

    protected:
        void Open()
        {
            _stream = new std::ofstream(_fileName);
            (*_stream) << std::setprecision(_precision);
            if (_columnNames)
            {
                for (size_t i = 0; i < itemDim - 1; i++)
                {
                    *_stream << (*_columnNames)[i] << _separator;
                }
                *_stream << (*_columnNames)[itemDim - 1] << std::endl;
            }
            _opened = true;
        }

        bool _opened = false;

        int _precision;

        std::string _separator;

        std::ofstream* _stream;

        std::string _fileName;

        virtual void FinishFlush()
        {
            _stream->flush();
        }

        virtual void Write(const std::tuple<U, Ts...>& item) override
        {
            if (!_opened)
            {
                Open();
            }
            WriteItem(item);
        }

        template<std::size_t I = 0, typename... Vs> inline typename std::enable_if<I == sizeof...(Vs), void>::type WriteItem(const std::tuple<Vs...>& t)
        {
            *_stream << "\n";
        }

        template<std::size_t I = 0, typename... Vs> inline typename std::enable_if<I < sizeof...(Vs), void>::type WriteItem(const std::tuple<Vs...>& t)
        {
            *_stream << std::get<I>(t) << _separator;
            WriteItem<I + 1, Vs...>(t);
        }
    };
}
<|endoftext|>