<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2011 Ulrich von Zadow
//
//  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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//
//  Original author of this file is Nick Hebner (hebnern@gmail.com).
//

#include "AudioDecoderThread.h"

#include "AsyncDemuxer.h"

#include "../base/Logger.h"
#include "../base/TimeSource.h"

// In Audio frames.
#define AUDIO_BUFFER_SIZE 256

using namespace std;

namespace avg {

AudioDecoderThread::AudioDecoderThread(CQueue& cmdQ, AudioMsgQueue& msgQ,
        FFMpegDecoderPtr pDecoder, const AudioParams& ap)
    : WorkerThread<AudioDecoderThread>(string("AudioDecoderThread"), cmdQ),
      m_MsgQ(msgQ),
      m_AP(ap),
      m_pAudioResampleContext(0),
      m_bEOF(false)
{
    m_pCurAudioPacket = 0;
    m_pTempAudioPacket = 0;
    m_LastFrameTime = 0;
    m_AudioStartTimestamp = 0;

    m_pAStream = pDecoder->getAudioStream();
    m_AStreamIndex = pDecoder->getAStreamIndex();
    m_pDemuxer = dynamic_cast<AsyncDemuxer*>(pDecoder->getDemuxer());
    if (m_pAStream->start_time != (long long)AV_NOPTS_VALUE) {
        m_AudioStartTimestamp = float(av_q2d(m_pAStream->time_base)*m_pAStream->start_time);
    }
    m_EffectiveSampleRate = (int)(m_pAStream->codec->sample_rate);
}

AudioDecoderThread::~AudioDecoderThread()
{
    deleteCurAudioPacket();

    if (m_pAudioResampleContext) {
        audio_resample_close(m_pAudioResampleContext);
        m_pAudioResampleContext = 0;
    }

    m_LastFrameTime = 0;
    m_AudioStartTimestamp = 0;
}

bool AudioDecoderThread::work()
{
    if (m_bEOF) {
        msleep(10);
        int seqNum;
        float seekTime = m_pDemuxer->isSeekDone(m_AStreamIndex, seqNum, false);
        if (seekTime != -1) {
            m_bEOF = false;
            handleSeekDone(seqNum, seekTime);
        }
        if (m_pDemuxer->isClosed(m_AStreamIndex)) {
            close();
        }
    } else {
        AudioBufferPtr pBuffer = getAudioBuffer();
        if (pBuffer) {
            pushAudioMsg(pBuffer, m_LastFrameTime);
        } else {
            if (m_SeekTime != -1) {
                handleSeekDone(-1, m_SeekTime);
                m_SeekTime = -1;
            }
            if (m_pDemuxer->isClosed(m_AStreamIndex)) {
                close();
            }
        }
    }
    ThreadProfiler::get()->reset();
    return true;
}

void AudioDecoderThread::close()
{
    m_MsgQ.clear();
    stop();
}

AudioBufferPtr AudioDecoderThread::getAudioBuffer()
{
    short* pDecodedData = (short*)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE +
            FF_INPUT_BUFFER_PADDING_SIZE);

    int bytesConsumed = 0;
    int bytesDecoded = 0;
    while (bytesDecoded == 0) {
        if (!m_pCurAudioPacket) {
            int seqNum;
            m_SeekTime = m_pDemuxer->isSeekDone(m_AStreamIndex, seqNum);
            if (m_SeekTime != -1) {
                av_free(pDecodedData);
                return AudioBufferPtr();
            }
            m_pCurAudioPacket = m_pDemuxer->getPacket(m_AStreamIndex);
            if (!m_pCurAudioPacket) {
                handleNoPacketMsg();
                av_free(pDecodedData);
                return AudioBufferPtr();
            }
            m_pTempAudioPacket = new AVPacket;
            av_init_packet(m_pTempAudioPacket);
            m_pTempAudioPacket->data = m_pCurAudioPacket->data;
            m_pTempAudioPacket->size = m_pCurAudioPacket->size;
        }
        bytesDecoded = AVCODEC_MAX_AUDIO_FRAME_SIZE;
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(52, 31, 0)
        bytesConsumed = avcodec_decode_audio3(m_pAStream->codec, pDecodedData,
                &bytesDecoded, m_pTempAudioPacket);
#else
        bytesConsumed = avcodec_decode_audio2(m_pAStream->codec, pDecodedData,
                &bytesDecoded, m_pTempAudioPacket->data, m_pTempAudioPacket->size);
#endif
        if (bytesConsumed < 0) {
            // Error decoding -> throw away current packet.
            bytesDecoded = 0;
            deleteCurAudioPacket();
        } else {
            m_pTempAudioPacket->data += bytesConsumed;
            m_pTempAudioPacket->size -= bytesConsumed;

            if (m_pTempAudioPacket->size <= 0) {
                deleteCurAudioPacket();
            }
        }
    }
    int framesDecoded = bytesDecoded/(m_pAStream->codec->channels*sizeof(short));
    AudioBufferPtr pBuffer;
    bool bNeedsResample = (m_EffectiveSampleRate != m_AP.m_SampleRate ||
            m_pAStream->codec->channels != m_AP.m_Channels);
    if (bNeedsResample) {
        pBuffer = resampleAudio(pDecodedData, framesDecoded);
    } else {
        pBuffer = AudioBufferPtr(new AudioBuffer(framesDecoded, m_AP));
        memcpy(pBuffer->getData(), pDecodedData, bytesDecoded);
    }
    m_LastFrameTime += float(pBuffer->getNumFrames())/m_AP.m_SampleRate;
    av_free(pDecodedData);
    return pBuffer;
}

AudioBufferPtr AudioDecoderThread::resampleAudio(short* pDecodedData, int framesDecoded)
{
    if (!m_pAudioResampleContext) {
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52, 24, 0)
        m_pAudioResampleContext = av_audio_resample_init(m_AP.m_Channels,
                m_pAStream->codec->channels, m_AP.m_SampleRate, m_EffectiveSampleRate,
                SAMPLE_FMT_S16, SAMPLE_FMT_S16, 16, 10, 0, 0.8);
#else
        m_pAudioResampleContext = audio_resample_init(m_AP.m_Channels,
                m_pAStream->codec->channels, m_AP.m_SampleRate, m_EffectiveSampleRate);
#endif
    }

    short pResampledData[AVCODEC_MAX_AUDIO_FRAME_SIZE/2];
    int framesResampled = audio_resample(m_pAudioResampleContext, pResampledData,
            pDecodedData, framesDecoded);
    AudioBufferPtr pBuffer(new AudioBuffer(framesResampled, m_AP));
    memcpy(pBuffer->getData(), pResampledData,
            framesResampled*m_AP.m_Channels*sizeof(short));
    return pBuffer;
}

void AudioDecoderThread::handleSeekDone(int seqNum, float seekTime)
{
    avcodec_flush_buffers(m_pAStream->codec);
    m_MsgQ.clear();

    // Get the next packet so we know at what time we actually arrived.
    deleteCurAudioPacket();
    m_pCurAudioPacket = m_pDemuxer->getPacket(m_AStreamIndex);
    if (!m_pCurAudioPacket) {
        handleNoPacketMsg();
    } else {
        m_LastFrameTime = float(m_pCurAudioPacket->dts*av_q2d(m_pAStream->time_base))
                - m_AudioStartTimestamp;

        if (fabs(m_LastFrameTime - seekTime) < 0.05) {
            pushSeekDone(m_LastFrameTime, seqNum);
        } else {
            if (m_LastFrameTime-0.05f < seekTime) {
                // Received frame that's earlier than the destination, so throw away frames
                // until the time is correct.
                while (m_LastFrameTime-0.05f < seekTime) {
                    deleteCurAudioPacket();
                    float seekTime = m_pDemuxer->isSeekDone(m_AStreamIndex, seqNum);
                    AVG_ASSERT(seekTime == -1);
                    m_pCurAudioPacket = m_pDemuxer->getPacket(m_AStreamIndex);
                    if (!m_pCurAudioPacket) {
                        handleNoPacketMsg();
                        return;
                    }
                    AVG_ASSERT(m_pCurAudioPacket);
                    m_LastFrameTime =
                            float(m_pCurAudioPacket->dts*av_q2d(m_pAStream->time_base))
                            - m_AudioStartTimestamp;
                }

                pushSeekDone(m_LastFrameTime, seqNum);
            } else {
                // Received frame that's too late, so insert a buffer of silence to compensate.
                pushSeekDone(m_LastFrameTime, seqNum);

                // send empty buffer
                int numDelaySamples = (m_LastFrameTime - seekTime)*m_AP.m_SampleRate;
                AudioBufferPtr pBuffer(new AudioBuffer(numDelaySamples, m_AP));
                pBuffer->clear();
                m_LastFrameTime = seekTime;
                pushAudioMsg(pBuffer, m_LastFrameTime);
            }
        }

        AVG_ASSERT(m_pCurAudioPacket);
        m_pTempAudioPacket = new AVPacket;
        av_init_packet(m_pTempAudioPacket);
        m_pTempAudioPacket->data = m_pCurAudioPacket->data;
        m_pTempAudioPacket->size = m_pCurAudioPacket->size;
    }
}

void AudioDecoderThread::handleNoPacketMsg()
{
    // Either close or eof
    if (!m_pDemuxer->isClosed(m_AStreamIndex)) {
        // Early out: EOF during seek
        m_bEOF = true;
        pushEOF();
    }
}

void AudioDecoderThread::pushAudioMsg(AudioBufferPtr pBuffer, float time)
{
    VideoMsgPtr pMsg(new VideoMsg());
    pMsg->setAudio(pBuffer, time);
    m_MsgQ.push(pMsg);
}

void AudioDecoderThread::pushSeekDone(float time, int seqNum)
{
    VideoMsgPtr pMsg(new VideoMsg());
    pMsg->setSeekDone(seqNum, time);
    m_MsgQ.push(pMsg);
}

void AudioDecoderThread::pushEOF()
{
    VideoMsgPtr pMsg(new VideoMsg());
    pMsg->setEOF();
    m_MsgQ.push(pMsg);
}

void AudioDecoderThread::deleteCurAudioPacket()
{
    if (m_pCurAudioPacket) {
        av_free_packet(m_pCurAudioPacket);
        delete m_pCurAudioPacket;
        m_pCurAudioPacket = 0;
    }
    if (m_pTempAudioPacket) {
        delete m_pTempAudioPacket;
        m_pTempAudioPacket = 0;
    }
}

}
<commit_msg>video branch: Windows warning fix.<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2011 Ulrich von Zadow
//
//  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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//
//  Original author of this file is Nick Hebner (hebnern@gmail.com).
//

#include "AudioDecoderThread.h"

#include "AsyncDemuxer.h"

#include "../base/Logger.h"
#include "../base/TimeSource.h"

// In Audio frames.
#define AUDIO_BUFFER_SIZE 256

using namespace std;

namespace avg {

AudioDecoderThread::AudioDecoderThread(CQueue& cmdQ, AudioMsgQueue& msgQ,
        FFMpegDecoderPtr pDecoder, const AudioParams& ap)
    : WorkerThread<AudioDecoderThread>(string("AudioDecoderThread"), cmdQ),
      m_MsgQ(msgQ),
      m_AP(ap),
      m_pAudioResampleContext(0),
      m_bEOF(false)
{
    m_pCurAudioPacket = 0;
    m_pTempAudioPacket = 0;
    m_LastFrameTime = 0;
    m_AudioStartTimestamp = 0;

    m_pAStream = pDecoder->getAudioStream();
    m_AStreamIndex = pDecoder->getAStreamIndex();
    m_pDemuxer = dynamic_cast<AsyncDemuxer*>(pDecoder->getDemuxer());
    if (m_pAStream->start_time != (long long)AV_NOPTS_VALUE) {
        m_AudioStartTimestamp = float(av_q2d(m_pAStream->time_base)*m_pAStream->start_time);
    }
    m_EffectiveSampleRate = (int)(m_pAStream->codec->sample_rate);
}

AudioDecoderThread::~AudioDecoderThread()
{
    deleteCurAudioPacket();

    if (m_pAudioResampleContext) {
        audio_resample_close(m_pAudioResampleContext);
        m_pAudioResampleContext = 0;
    }

    m_LastFrameTime = 0;
    m_AudioStartTimestamp = 0;
}

bool AudioDecoderThread::work()
{
    if (m_bEOF) {
        msleep(10);
        int seqNum;
        float seekTime = m_pDemuxer->isSeekDone(m_AStreamIndex, seqNum, false);
        if (seekTime != -1) {
            m_bEOF = false;
            handleSeekDone(seqNum, seekTime);
        }
        if (m_pDemuxer->isClosed(m_AStreamIndex)) {
            close();
        }
    } else {
        AudioBufferPtr pBuffer = getAudioBuffer();
        if (pBuffer) {
            pushAudioMsg(pBuffer, m_LastFrameTime);
        } else {
            if (m_SeekTime != -1) {
                handleSeekDone(-1, m_SeekTime);
                m_SeekTime = -1;
            }
            if (m_pDemuxer->isClosed(m_AStreamIndex)) {
                close();
            }
        }
    }
    ThreadProfiler::get()->reset();
    return true;
}

void AudioDecoderThread::close()
{
    m_MsgQ.clear();
    stop();
}

AudioBufferPtr AudioDecoderThread::getAudioBuffer()
{
    short* pDecodedData = (short*)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE +
            FF_INPUT_BUFFER_PADDING_SIZE);

    int bytesConsumed = 0;
    int bytesDecoded = 0;
    while (bytesDecoded == 0) {
        if (!m_pCurAudioPacket) {
            int seqNum;
            m_SeekTime = m_pDemuxer->isSeekDone(m_AStreamIndex, seqNum);
            if (m_SeekTime != -1) {
                av_free(pDecodedData);
                return AudioBufferPtr();
            }
            m_pCurAudioPacket = m_pDemuxer->getPacket(m_AStreamIndex);
            if (!m_pCurAudioPacket) {
                handleNoPacketMsg();
                av_free(pDecodedData);
                return AudioBufferPtr();
            }
            m_pTempAudioPacket = new AVPacket;
            av_init_packet(m_pTempAudioPacket);
            m_pTempAudioPacket->data = m_pCurAudioPacket->data;
            m_pTempAudioPacket->size = m_pCurAudioPacket->size;
        }
        bytesDecoded = AVCODEC_MAX_AUDIO_FRAME_SIZE;
#if LIBAVCODEC_VERSION_INT > AV_VERSION_INT(52, 31, 0)
        bytesConsumed = avcodec_decode_audio3(m_pAStream->codec, pDecodedData,
                &bytesDecoded, m_pTempAudioPacket);
#else
        bytesConsumed = avcodec_decode_audio2(m_pAStream->codec, pDecodedData,
                &bytesDecoded, m_pTempAudioPacket->data, m_pTempAudioPacket->size);
#endif
        if (bytesConsumed < 0) {
            // Error decoding -> throw away current packet.
            bytesDecoded = 0;
            deleteCurAudioPacket();
        } else {
            m_pTempAudioPacket->data += bytesConsumed;
            m_pTempAudioPacket->size -= bytesConsumed;

            if (m_pTempAudioPacket->size <= 0) {
                deleteCurAudioPacket();
            }
        }
    }
    int framesDecoded = bytesDecoded/(m_pAStream->codec->channels*sizeof(short));
    AudioBufferPtr pBuffer;
    bool bNeedsResample = (m_EffectiveSampleRate != m_AP.m_SampleRate ||
            m_pAStream->codec->channels != m_AP.m_Channels);
    if (bNeedsResample) {
        pBuffer = resampleAudio(pDecodedData, framesDecoded);
    } else {
        pBuffer = AudioBufferPtr(new AudioBuffer(framesDecoded, m_AP));
        memcpy(pBuffer->getData(), pDecodedData, bytesDecoded);
    }
    m_LastFrameTime += float(pBuffer->getNumFrames())/m_AP.m_SampleRate;
    av_free(pDecodedData);
    return pBuffer;
}

AudioBufferPtr AudioDecoderThread::resampleAudio(short* pDecodedData, int framesDecoded)
{
    if (!m_pAudioResampleContext) {
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52, 24, 0)
        m_pAudioResampleContext = av_audio_resample_init(m_AP.m_Channels,
                m_pAStream->codec->channels, m_AP.m_SampleRate, m_EffectiveSampleRate,
                SAMPLE_FMT_S16, SAMPLE_FMT_S16, 16, 10, 0, 0.8);
#else
        m_pAudioResampleContext = audio_resample_init(m_AP.m_Channels,
                m_pAStream->codec->channels, m_AP.m_SampleRate, m_EffectiveSampleRate);
#endif
    }

    short pResampledData[AVCODEC_MAX_AUDIO_FRAME_SIZE/2];
    int framesResampled = audio_resample(m_pAudioResampleContext, pResampledData,
            pDecodedData, framesDecoded);
    AudioBufferPtr pBuffer(new AudioBuffer(framesResampled, m_AP));
    memcpy(pBuffer->getData(), pResampledData,
            framesResampled*m_AP.m_Channels*sizeof(short));
    return pBuffer;
}

void AudioDecoderThread::handleSeekDone(int seqNum, float seekTime)
{
    avcodec_flush_buffers(m_pAStream->codec);
    m_MsgQ.clear();

    // Get the next packet so we know at what time we actually arrived.
    deleteCurAudioPacket();
    m_pCurAudioPacket = m_pDemuxer->getPacket(m_AStreamIndex);
    if (!m_pCurAudioPacket) {
        handleNoPacketMsg();
    } else {
        m_LastFrameTime = float(m_pCurAudioPacket->dts*av_q2d(m_pAStream->time_base))
                - m_AudioStartTimestamp;

        if (fabs(m_LastFrameTime - seekTime) < 0.05) {
            pushSeekDone(m_LastFrameTime, seqNum);
        } else {
            if (m_LastFrameTime-0.05f < seekTime) {
                // Received frame that's earlier than the destination, so throw away frames
                // until the time is correct.
                while (m_LastFrameTime-0.05f < seekTime) {
                    deleteCurAudioPacket();
                    float seekTime = m_pDemuxer->isSeekDone(m_AStreamIndex, seqNum);
                    AVG_ASSERT(seekTime == -1);
                    m_pCurAudioPacket = m_pDemuxer->getPacket(m_AStreamIndex);
                    if (!m_pCurAudioPacket) {
                        handleNoPacketMsg();
                        return;
                    }
                    AVG_ASSERT(m_pCurAudioPacket);
                    m_LastFrameTime =
                            float(m_pCurAudioPacket->dts*av_q2d(m_pAStream->time_base))
                            - m_AudioStartTimestamp;
                }

                pushSeekDone(m_LastFrameTime, seqNum);
            } else {
                // Received frame that's too late, so insert a buffer of silence to compensate.
                pushSeekDone(m_LastFrameTime, seqNum);

                // send empty buffer
                int numDelaySamples = int((m_LastFrameTime - seekTime)*m_AP.m_SampleRate);
                AudioBufferPtr pBuffer(new AudioBuffer(numDelaySamples, m_AP));
                pBuffer->clear();
                m_LastFrameTime = seekTime;
                pushAudioMsg(pBuffer, m_LastFrameTime);
            }
        }

        AVG_ASSERT(m_pCurAudioPacket);
        m_pTempAudioPacket = new AVPacket;
        av_init_packet(m_pTempAudioPacket);
        m_pTempAudioPacket->data = m_pCurAudioPacket->data;
        m_pTempAudioPacket->size = m_pCurAudioPacket->size;
    }
}

void AudioDecoderThread::handleNoPacketMsg()
{
    // Either close or eof
    if (!m_pDemuxer->isClosed(m_AStreamIndex)) {
        // Early out: EOF during seek
        m_bEOF = true;
        pushEOF();
    }
}

void AudioDecoderThread::pushAudioMsg(AudioBufferPtr pBuffer, float time)
{
    VideoMsgPtr pMsg(new VideoMsg());
    pMsg->setAudio(pBuffer, time);
    m_MsgQ.push(pMsg);
}

void AudioDecoderThread::pushSeekDone(float time, int seqNum)
{
    VideoMsgPtr pMsg(new VideoMsg());
    pMsg->setSeekDone(seqNum, time);
    m_MsgQ.push(pMsg);
}

void AudioDecoderThread::pushEOF()
{
    VideoMsgPtr pMsg(new VideoMsg());
    pMsg->setEOF();
    m_MsgQ.push(pMsg);
}

void AudioDecoderThread::deleteCurAudioPacket()
{
    if (m_pCurAudioPacket) {
        av_free_packet(m_pCurAudioPacket);
        delete m_pCurAudioPacket;
        m_pCurAudioPacket = 0;
    }
    if (m_pTempAudioPacket) {
        delete m_pTempAudioPacket;
        m_pTempAudioPacket = 0;
    }
}

}
<|endoftext|>


<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2008 Ulrich von Zadow
//
//  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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "VideoDemuxerThread.h"
#include "FrameVideoMsg.h"
#include "ErrorVideoMsg.h"
#include "EOFVideoMsg.h"

#include "../base/Logger.h"
#include "../base/TimeSource.h"

#include <climits>

using namespace std;

namespace avg {

VideoDemuxerThread::VideoDemuxerThread(CmdQueue& CmdQ,
                AVFormatContext * pFormatContext)
    : WorkerThread<VideoDemuxerThread>("VideoDemuxer", CmdQ),
      m_bEOF(false),
      m_pFormatContext(pFormatContext),
      m_pDemuxer()

{
}

VideoDemuxerThread::~VideoDemuxerThread()
{
}

bool VideoDemuxerThread::init()
{
    m_pDemuxer = FFMpegDemuxerPtr(new FFMpegDemuxer(m_pFormatContext));
    return true;
};

bool VideoDemuxerThread::work()
{
    if (m_PacketQs.empty() || m_bEOF) {
        // replace this with waitForMessage()
        msleep(10);
    } else {

        map<int, VideoPacketQueuePtr>::iterator it;
        int ShortestQ = -1;
        int ShortestLength = INT_MAX;
        for (it=m_PacketQs.begin(); it != m_PacketQs.end(); it++) {
            if (it->second->size() < ShortestLength &&
                    it->second->size() < it->second->getMaxSize() &&
                    !m_PacketQbEOF[it->first])
            {
                ShortestLength = it->second->size();
                ShortestQ = it->first;
            }
        }

        if (ShortestQ < 0) {
            // All queues are at their max capacity. Take a nap and try again later.
            msleep(10);
            return true;
        }

        AVPacket * pPacket = m_pDemuxer->getPacket(ShortestQ);
        if (pPacket == 0) {
            onStreamEOF(ShortestQ);
        }

        // On EOF, we send a message which has pPacket=0
        m_PacketQs[ShortestQ]->push(PacketVideoMsgPtr(new PacketVideoMsg(pPacket, false)));
        msleep(0);
    }
    return true;
}

void VideoDemuxerThread::deinit()
{
}

void VideoDemuxerThread::enableStream(VideoPacketQueuePtr pPacketQ, int StreamIndex)
{
    m_PacketQs[StreamIndex] = pPacketQ;
    m_PacketQbEOF[StreamIndex] = false;
    m_pDemuxer->enableStream(StreamIndex);
}

void VideoDemuxerThread::seek(long long DestTime)
{
    map<int, VideoPacketQueuePtr>::iterator it;
    m_pDemuxer->seek(DestTime);
    for (it=m_PacketQs.begin(); it != m_PacketQs.end(); it++) {
        VideoPacketQueuePtr pPacketQ = it->second;
        pPacketQ->push(PacketVideoMsgPtr(new PacketVideoMsg(0, true)));
        m_PacketQbEOF[it->first] = false;
    }
    m_bEOF = false;
}

void VideoDemuxerThread::onStreamEOF(int StreamIndex)
{
    m_PacketQbEOF[StreamIndex] = true;

    m_bEOF = true;
    map<int, bool>::iterator it;
    for (it=m_PacketQbEOF.begin(); it != m_PacketQbEOF.end(); it++) {
        if (!it->second) {
            m_bEOF = false;
            break;
        }
    }
}

}
<commit_msg>Fixed hang on end of video decoding for very short videos with audio.<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2008 Ulrich von Zadow
//
//  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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "VideoDemuxerThread.h"
#include "FrameVideoMsg.h"
#include "ErrorVideoMsg.h"
#include "EOFVideoMsg.h"

#include "../base/Logger.h"
#include "../base/TimeSource.h"

#include <climits>

using namespace std;

namespace avg {

VideoDemuxerThread::VideoDemuxerThread(CmdQueue& CmdQ,
                AVFormatContext * pFormatContext)
    : WorkerThread<VideoDemuxerThread>("VideoDemuxer", CmdQ),
      m_bEOF(false),
      m_pFormatContext(pFormatContext),
      m_pDemuxer()

{
}

VideoDemuxerThread::~VideoDemuxerThread()
{
}

bool VideoDemuxerThread::init()
{
    m_pDemuxer = FFMpegDemuxerPtr(new FFMpegDemuxer(m_pFormatContext));
    return true;
};

bool VideoDemuxerThread::work()
{
    if (m_PacketQs.empty() || m_bEOF) {
        // replace this with waitForMessage()
        msleep(10);
    } else {

        map<int, VideoPacketQueuePtr>::iterator it;
        int ShortestQ = -1;
        int ShortestLength = INT_MAX;
        for (it=m_PacketQs.begin(); it != m_PacketQs.end(); it++) {
            if (it->second->size() < ShortestLength &&
                    it->second->size() < it->second->getMaxSize() &&
                    !m_PacketQbEOF[it->first])
            {
                ShortestLength = it->second->size();
                ShortestQ = it->first;
            }
        }

        if (ShortestQ < 0) {
            // All queues are at their max capacity. Take a nap and try again later.
            msleep(10);
            return true;
        }

        AVPacket * pPacket = m_pDemuxer->getPacket(ShortestQ);
        if (pPacket == 0) {
            onStreamEOF(ShortestQ);
        }

        // On EOF, we send a message which has pPacket=0
        m_PacketQs[ShortestQ]->push(PacketVideoMsgPtr(new PacketVideoMsg(pPacket, false)));
        msleep(0);
    }
    return true;
}

void VideoDemuxerThread::deinit()
{
}

void VideoDemuxerThread::enableStream(VideoPacketQueuePtr pPacketQ, int StreamIndex)
{
    m_PacketQs[StreamIndex] = pPacketQ;
    m_PacketQbEOF[StreamIndex] = false;
    m_pDemuxer->enableStream(StreamIndex);
    m_bEOF = false;
}

void VideoDemuxerThread::seek(long long DestTime)
{
    map<int, VideoPacketQueuePtr>::iterator it;
    m_pDemuxer->seek(DestTime);
    for (it=m_PacketQs.begin(); it != m_PacketQs.end(); it++) {
        VideoPacketQueuePtr pPacketQ = it->second;
        pPacketQ->push(PacketVideoMsgPtr(new PacketVideoMsg(0, true)));
        m_PacketQbEOF[it->first] = false;
    }
    m_bEOF = false;
}

void VideoDemuxerThread::onStreamEOF(int StreamIndex)
{
    m_PacketQbEOF[StreamIndex] = true;

    m_bEOF = true;
    map<int, bool>::iterator it;
    for (it=m_PacketQbEOF.begin(); it != m_PacketQbEOF.end(); it++) {
        if (!it->second) {
            m_bEOF = false;
            break;
        }
    }
}

}
<|endoftext|>


<commit_before>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

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.
==============================================================================*/
#include "tensorflow/lite/profiling/memory_info.h"

#ifdef __linux__
#include <malloc.h>
#include <sys/resource.h>
#include <sys/time.h>
#elif defined(__APPLE__)
#include <mach/mach.h>
#include <malloc/malloc.h>
#endif

namespace tflite {
namespace profiling {
namespace memory {

const size_t MemoryUsage::kValueNotSet = 0;

bool MemoryUsage::IsSupported() {
#if defined(__linux__) || defined(__APPLE__)
  return true;
#endif
  return false;
}

MemoryUsage GetMemoryUsage() {
  MemoryUsage result;
#ifdef __linux__
  rusage res;
  if (getrusage(RUSAGE_SELF, &res) == 0) {
    result.mem_footprint_kb = res.ru_maxrss;
  }
#if defined(__GLIBC__) && __GLIBC_MINOR__ >= 33
  const auto mem = mallinfo2();
#else
  const auto mem = mallinfo();
#endif  // defined(__GLIBC__)
  result.total_allocated_bytes = mem.arena;
  result.in_use_allocated_bytes = mem.uordblks;
#elif defined(__APPLE__)
  struct task_vm_info vm_info;
  mach_msg_type_number_t count = TASK_VM_INFO_COUNT;
  auto status = task_info(mach_task_self(), TASK_VM_INFO,
                          reinterpret_cast<task_info_t>(&vm_info), &count);
  if (status == KERN_SUCCESS) {
    result.mem_footprint_kb =
        static_cast<int64_t>(vm_info.phys_footprint / 1024.0);
  }
  struct mstats stats = mstats();
  result.total_allocated_bytes = stats.bytes_total;
  result.in_use_allocated_bytes = stats.bytes_used;
#endif  // __linux__
  return result;
}

void MemoryUsage::AllStatsToStream(std::ostream* stream) const {
  *stream << "max resident set size/physical footprint = "
          << mem_footprint_kb / 1024.0 << " MB, total malloc-ed size = "
          << total_allocated_bytes / 1024.0 / 1024.0
          << " MB, in-use allocated/mmapped size = "
          << in_use_allocated_bytes / 1024.0 / 1024.0 << " MB";
}

}  // namespace memory
}  // namespace profiling
}  // namespace tflite
<commit_msg>Internal changes<commit_after>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

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.
==============================================================================*/
#include "tensorflow/lite/profiling/memory_info.h"

#ifdef __linux__
#include <malloc.h>
#include <sys/resource.h>
#include <sys/time.h>
#elif defined(__APPLE__)
#include <mach/mach.h>
#include <malloc/malloc.h>
#endif

namespace tflite {
namespace profiling {
namespace memory {

const size_t MemoryUsage::kValueNotSet = 0;

bool MemoryUsage::IsSupported() {
#if defined(__linux__) || defined(__APPLE__)
  return true;
#endif
  return false;
}

MemoryUsage GetMemoryUsage() {
  MemoryUsage result;
#ifdef __linux__
  rusage res;
  if (getrusage(RUSAGE_SELF, &res) == 0) {
    result.mem_footprint_kb = res.ru_maxrss;
  }
#if defined(__NO_MALLINFO__)
  result.total_allocated_bytes = -1;
  result.in_use_allocated_bytes = -1;
#elif defined(__GLIBC__) && __GLIBC_MINOR__ >= 33
  const auto mem = mallinfo2();
  result.total_allocated_bytes = mem.arena;
  result.in_use_allocated_bytes = mem.uordblks;
#else
  const auto mem = mallinfo();
  result.total_allocated_bytes = mem.arena;
  result.in_use_allocated_bytes = mem.uordblks;
#endif  // defined(__NO_MALLINFO__)
#elif defined(__APPLE__)
  struct task_vm_info vm_info;
  mach_msg_type_number_t count = TASK_VM_INFO_COUNT;
  auto status = task_info(mach_task_self(), TASK_VM_INFO,
                          reinterpret_cast<task_info_t>(&vm_info), &count);
  if (status == KERN_SUCCESS) {
    result.mem_footprint_kb =
        static_cast<int64_t>(vm_info.phys_footprint / 1024.0);
  }
  struct mstats stats = mstats();
  result.total_allocated_bytes = stats.bytes_total;
  result.in_use_allocated_bytes = stats.bytes_used;
#endif  // __linux__
  return result;
}

void MemoryUsage::AllStatsToStream(std::ostream* stream) const {
  *stream << "max resident set size/physical footprint = "
          << mem_footprint_kb / 1024.0 << " MB, total malloc-ed size = "
          << total_allocated_bytes / 1024.0 / 1024.0
          << " MB, in-use allocated/mmapped size = "
          << in_use_allocated_bytes / 1024.0 / 1024.0 << " MB";
}

}  // namespace memory
}  // namespace profiling
}  // namespace tflite
<|endoftext|>


<commit_before>#include "kernel.h"
#include "ilwisdata.h"
#include "datadefinition.h"
#include "columndefinition.h"
#include "table.h"
#include "geometries.h"
#include "georeference.h"
#include "uicontextmodel.h"
#include "ilwiscontext.h"

quint64 UIContextModel::_objectCounter = 0;
std::unique_ptr<UIContextModel> UIContextModel::_uicontext;

UIContextModel::UIContextModel(QObject *parent) :
    QObject(parent)
{

}

LayerManager *UIContextModel::createLayerManager(const QString& objectName)
{
    QObject *object =_qmlcontext->findChild<QObject *>(objectName);
    QObject *newparent = object == 0 ? this : object;
    LayerManager *manager =  new LayerManager(newparent, this);

    return manager;
}

TableModel *UIContextModel::createTableModel(QObject *parent,const QString& url, const QString& type)
{

    IlwisTypes tp = IlwisObject::name2Type(type);
    Resource resource = mastercatalog()->name2Resource(url,tp);
    if ( resource.isValid()){
        return new TableModel(resource, parent);
    }
    return 0;
}

QString UIContextModel::uniqueName()
{
    return "ilwis_ui_object_" + QString::number(_objectCounter++);
}

QList<VisualAttributeEditor *> UIContextModel::propertyEditors(CoverageLayerModel *parentLayer, const IIlwisObject &obj, const ColumnDefinition &coldef)
{
    QList<VisualAttributeEditor *> editors;
    for ( const auto& editorItem : _propertyEditors){
        auto *editor = editorItem.second();
        if ( editor){
            if ( editor->canUse(obj, coldef)){
                editor->prepare(parentLayer, obj, coldef);
                editors.append(editor);
            }
            else
                delete editor;
        }
    }
    return editors;
}

QList<VisualAttributeEditor *> UIContextModel::propertyEditors(CoverageLayerModel *parentLayer, const IIlwisObject &obj, const QString& name){
    QList<VisualAttributeEditor *> editors;
    for ( const auto& editorItem : _propertyEditors){
        auto *editor = editorItem.second();
        if ( editor){
            if ( editor->canUse(obj, name)){
                editor->prepare(parentLayer, obj);
                editors.append(editor);
            }
            else
                delete editor;
        }
    }
    return editors;
}

void UIContextModel::qmlContext(QQmlContext *ctx)
{
    _qmlcontext = ctx;
}

void UIContextModel::rootObject(QObject *root)
{
    _rootObject = root;
}

QObject *UIContextModel::rootObject() const
{
    return _rootObject;
}

QQmlContext* UIContextModel::rootContext() const
{
    return _qmlcontext;
}

int UIContextModel::activeSplit() const
{
    return _activeSplit;
}

void UIContextModel::setActiveSplit(int index)
{
    if ( index == 1 || index == 2){
        _activeSplit = index;
    }
}

void UIContextModel::addViewer(LayersViewCommandInterface *viewer, quint64 vid)
{
    _viewers[vid] = viewer;
}

LayersViewCommandInterface *UIContextModel::viewer(quint64 viewerid)
{
    auto iter = _viewers.find(viewerid);
    if ( iter != _viewers.end()){
        return (*iter).second;
    }
    return 0;
}

void UIContextModel::removeViewer(quint64 viewerid)
{
    auto iter= _viewers.find(viewerid)    ;
    if ( iter != _viewers.end()){
        _viewers.erase(iter);
    }
}

void UIContextModel::currentKey(int ev)
{
    _currentKey = ev;
}

int UIContextModel::currentKey() const
{
    return _currentKey;
}

QStringList UIContextModel::colorNames() const
{
    return _colorNames;
}

void UIContextModel::prepare()
{
    QString ilwisloc = context()->ilwisFolder().absoluteFilePath();
    QString colornames = ilwisloc + "/resources/svgcolornames.txt";
    std::ifstream fstream;
    fstream.open(colornames.toStdString());
    if ( fstream.is_open()){
        char txt[100];
        while (fstream.getline(txt,100)){
            _colorNames.push_back(txt);
        }
    }
}

int UIContextModel::addPropertyEditor(const QString &propertyName, CreatePropertyEditor func)
{
    _propertyEditors[propertyName] = func;

    return 0;
}

<commit_msg>prepare adds tableoperation factory to the factory list and registers new operations<commit_after>#include "kernel.h"
#include "ilwisdata.h"
#include "datadefinition.h"
#include "columndefinition.h"
#include "table.h"
#include "geometries.h"
#include "georeference.h"
#include "uicontextmodel.h"
#include "factory.h"
#include "abstractfactory.h"
#include "tableoperations/tableoperation.h"
#include "tableoperations/sortcolumn.h"
#include "tableoperations/tableoperationfactory.h"
#include "ilwiscontext.h"

quint64 UIContextModel::_objectCounter = 0;
std::unique_ptr<UIContextModel> UIContextModel::_uicontext;

UIContextModel::UIContextModel(QObject *parent) :
    QObject(parent)
{

}

LayerManager *UIContextModel::createLayerManager(const QString& objectName)
{
    QObject *object =_qmlcontext->findChild<QObject *>(objectName);
    QObject *newparent = object == 0 ? this : object;
    LayerManager *manager =  new LayerManager(newparent, this);

    return manager;
}

TableModel *UIContextModel::createTableModel(QObject *parent,const QString& url, const QString& type)
{

    IlwisTypes tp = IlwisObject::name2Type(type);
    Resource resource = mastercatalog()->name2Resource(url,tp);
    if ( resource.isValid()){
        return new TableModel(resource, parent);
    }
    return 0;
}

QString UIContextModel::uniqueName()
{
    return "ilwis_ui_object_" + QString::number(_objectCounter++);
}

QList<VisualAttributeEditor *> UIContextModel::propertyEditors(CoverageLayerModel *parentLayer, const IIlwisObject &obj, const ColumnDefinition &coldef)
{
    QList<VisualAttributeEditor *> editors;
    for ( const auto& editorItem : _propertyEditors){
        auto *editor = editorItem.second();
        if ( editor){
            if ( editor->canUse(obj, coldef)){
                editor->prepare(parentLayer, obj, coldef);
                editors.append(editor);
            }
            else
                delete editor;
        }
    }
    return editors;
}

QList<VisualAttributeEditor *> UIContextModel::propertyEditors(CoverageLayerModel *parentLayer, const IIlwisObject &obj, const QString& name){
    QList<VisualAttributeEditor *> editors;
    for ( const auto& editorItem : _propertyEditors){
        auto *editor = editorItem.second();
        if ( editor){
            if ( editor->canUse(obj, name)){
                editor->prepare(parentLayer, obj);
                editors.append(editor);
            }
            else
                delete editor;
        }
    }
    return editors;
}

void UIContextModel::qmlContext(QQmlContext *ctx)
{
    _qmlcontext = ctx;
}

void UIContextModel::rootObject(QObject *root)
{
    _rootObject = root;
}

QObject *UIContextModel::rootObject() const
{
    return _rootObject;
}

QQmlContext* UIContextModel::rootContext() const
{
    return _qmlcontext;
}

int UIContextModel::activeSplit() const
{
    return _activeSplit;
}

void UIContextModel::setActiveSplit(int index)
{
    if ( index == 1 || index == 2){
        _activeSplit = index;
    }
}

void UIContextModel::addViewer(LayersViewCommandInterface *viewer, quint64 vid)
{
    _viewers[vid] = viewer;
}

LayersViewCommandInterface *UIContextModel::viewer(quint64 viewerid)
{
    auto iter = _viewers.find(viewerid);
    if ( iter != _viewers.end()){
        return (*iter).second;
    }
    return 0;
}

void UIContextModel::removeViewer(quint64 viewerid)
{
    auto iter= _viewers.find(viewerid)    ;
    if ( iter != _viewers.end()){
        _viewers.erase(iter);
    }
}

void UIContextModel::currentKey(int ev)
{
    _currentKey = ev;
}

int UIContextModel::currentKey() const
{
    return _currentKey;
}

QStringList UIContextModel::colorNames() const
{
    return _colorNames;
}

void UIContextModel::prepare()
{
    QString ilwisloc = context()->ilwisFolder().absoluteFilePath();
    QString colornames = ilwisloc + "/resources/svgcolornames.txt";
    std::ifstream fstream;
    fstream.open(colornames.toStdString());
    if ( fstream.is_open()){
        char txt[100];
        while (fstream.getline(txt,100)){
            _colorNames.push_back(txt);
        }
    }
    Ilwis::Desktop::TableOperationFactory *factory = new Ilwis::Desktop::TableOperationFactory();
    factory->registerTableOperation("sortcolumn",Ilwis::Desktop::SortColumn::create);
    Ilwis::kernel()->addFactory(factory);

}

int UIContextModel::addPropertyEditor(const QString &propertyName, CreatePropertyEditor func)
{
    _propertyEditors[propertyName] = func;

    return 0;
}

<|endoftext|>


<commit_before>#ifndef named_type_impl_h
#define named_type_impl_h

#include <type_traits>
#include <utility>

// Enable empty base class optimization with multiple inheritance on Visual Studio.
#if defined(_MSC_VER) && _MSC_VER >= 1910
#    define FLUENT_EBCO __declspec(empty_bases)
#else
#    define FLUENT_EBCO
#endif

#if defined(__clang__) || defined(__GNUC__)
#   define IGNORE_SHOULD_RETURN_REFERENCE_TO_THIS_BEGIN                                                                \
    _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Weffc++\"")
#   define IGNORE_SHOULD_RETURN_REFERENCE_TO_THIS_END _Pragma("GCC diagnostic pop")
#else
#   define IGNORE_SHOULD_RETURN_REFERENCE_TO_THIS_BEGIN /* Nothing */
#   define IGNORE_SHOULD_RETURN_REFERENCE_TO_THIS_END   /* Nothing */
#endif

namespace fluent
{

template <typename T>
using IsNotReference = typename std::enable_if<!std::is_reference<T>::value, void>::type;

template <typename T, typename Parameter, template <typename> class... Skills>
class FLUENT_EBCO NamedType : public Skills<NamedType<T, Parameter, Skills...>>...
{
public:
    using UnderlyingType = T;

    // constructor
    template <typename T_ = T, typename = std::enable_if<std::is_default_constructible<T>::value, void>>
    constexpr NamedType() noexcept(std::is_nothrow_constructible<T>::value)
    {
    }

    explicit constexpr NamedType(T const& value) noexcept(std::is_nothrow_copy_constructible<T>::value) : value_(value)
    {
    }

    template <typename T_ = T, typename = IsNotReference<T_>>
    explicit constexpr NamedType(T&& value) noexcept(std::is_nothrow_move_constructible<T>::value)
        : value_(std::move(value))
    {
    }

    // get
    constexpr T& get() noexcept
    {
        return value_;
    }

    constexpr std::remove_reference_t<T> const& get() const noexcept
    {
        return value_;
    }

    // conversions
    using ref = NamedType<T&, Parameter, Skills...>;
    operator ref()
    {
        return ref(value_);
    }

    struct argument
    {
       NamedType operator=(T&& value) const
       {
           return NamedType(std::forward<T>(value));
       }
        template <typename U>
        NamedType operator=(U&& value) const
        {
            IGNORE_SHOULD_RETURN_REFERENCE_TO_THIS_BEGIN

            return NamedType(std::forward<U>(value));

            IGNORE_SHOULD_RETURN_REFERENCE_TO_THIS_END
        }

        argument() = default;
        argument(argument const&) = delete;
        argument(argument&&) = delete;
        argument& operator=(argument const&) = delete;
        argument& operator=(argument&&) = delete;
    };

private:
    T value_;
};

template <template <typename T> class StrongType, typename T>
constexpr StrongType<T> make_named(T const& value)
{
    return StrongType<T>(value);
}

namespace details {
template <class F, class... Ts>
struct AnyOrderCallable{
   F f;
   template <class... Us>
   auto operator()(Us&&...args) const
   {
       static_assert(sizeof...(Ts) == sizeof...(Us), "Passing wrong number of arguments");
       auto x = std::make_tuple(std::forward<Us>(args)...);
       return f(std::move(std::get<Ts>(x))...);
   }
};
} //namespace details

// EXPERIMENTAL - CAN BE CHANGED IN THE FUTURE. FEEDBACK WELCOME FOR IMPROVEMENTS!
template <class... Args, class F>
auto make_named_arg_function(F&& f)
{
   return details::AnyOrderCallable<F, Args...>{std::forward<F>(f)};
}
} // namespace fluent

#endif /* named_type_impl_h */
<commit_msg>Add missing include of <tuple><commit_after>#ifndef named_type_impl_h
#define named_type_impl_h

#include <tuple>
#include <type_traits>
#include <utility>

// Enable empty base class optimization with multiple inheritance on Visual Studio.
#if defined(_MSC_VER) && _MSC_VER >= 1910
#    define FLUENT_EBCO __declspec(empty_bases)
#else
#    define FLUENT_EBCO
#endif

#if defined(__clang__) || defined(__GNUC__)
#   define IGNORE_SHOULD_RETURN_REFERENCE_TO_THIS_BEGIN                                                                \
    _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Weffc++\"")
#   define IGNORE_SHOULD_RETURN_REFERENCE_TO_THIS_END _Pragma("GCC diagnostic pop")
#else
#   define IGNORE_SHOULD_RETURN_REFERENCE_TO_THIS_BEGIN /* Nothing */
#   define IGNORE_SHOULD_RETURN_REFERENCE_TO_THIS_END   /* Nothing */
#endif

namespace fluent
{

template <typename T>
using IsNotReference = typename std::enable_if<!std::is_reference<T>::value, void>::type;

template <typename T, typename Parameter, template <typename> class... Skills>
class FLUENT_EBCO NamedType : public Skills<NamedType<T, Parameter, Skills...>>...
{
public:
    using UnderlyingType = T;

    // constructor
    template <typename T_ = T, typename = std::enable_if<std::is_default_constructible<T>::value, void>>
    constexpr NamedType() noexcept(std::is_nothrow_constructible<T>::value)
    {
    }

    explicit constexpr NamedType(T const& value) noexcept(std::is_nothrow_copy_constructible<T>::value) : value_(value)
    {
    }

    template <typename T_ = T, typename = IsNotReference<T_>>
    explicit constexpr NamedType(T&& value) noexcept(std::is_nothrow_move_constructible<T>::value)
        : value_(std::move(value))
    {
    }

    // get
    constexpr T& get() noexcept
    {
        return value_;
    }

    constexpr std::remove_reference_t<T> const& get() const noexcept
    {
        return value_;
    }

    // conversions
    using ref = NamedType<T&, Parameter, Skills...>;
    operator ref()
    {
        return ref(value_);
    }

    struct argument
    {
       NamedType operator=(T&& value) const
       {
           return NamedType(std::forward<T>(value));
       }
        template <typename U>
        NamedType operator=(U&& value) const
        {
            IGNORE_SHOULD_RETURN_REFERENCE_TO_THIS_BEGIN

            return NamedType(std::forward<U>(value));

            IGNORE_SHOULD_RETURN_REFERENCE_TO_THIS_END
        }

        argument() = default;
        argument(argument const&) = delete;
        argument(argument&&) = delete;
        argument& operator=(argument const&) = delete;
        argument& operator=(argument&&) = delete;
    };

private:
    T value_;
};

template <template <typename T> class StrongType, typename T>
constexpr StrongType<T> make_named(T const& value)
{
    return StrongType<T>(value);
}

namespace details {
template <class F, class... Ts>
struct AnyOrderCallable{
   F f;
   template <class... Us>
   auto operator()(Us&&...args) const
   {
       static_assert(sizeof...(Ts) == sizeof...(Us), "Passing wrong number of arguments");
       auto x = std::make_tuple(std::forward<Us>(args)...);
       return f(std::move(std::get<Ts>(x))...);
   }
};
} //namespace details

// EXPERIMENTAL - CAN BE CHANGED IN THE FUTURE. FEEDBACK WELCOME FOR IMPROVEMENTS!
template <class... Args, class F>
auto make_named_arg_function(F&& f)
{
   return details::AnyOrderCallable<F, Args...>{std::forward<F>(f)};
}
} // namespace fluent

#endif /* named_type_impl_h */
<|endoftext|>


<commit_before>/**
 * @file spgemm.hxx
 * @author Muhammad Osama (mosama@ucdavis.edu)
 * @brief Sparse-Matrix-Matrix multiplication.
 * @version 0.1
 * @date 2022-01-04
 *
 * @copyright Copyright (c) 2022
 *
 */

#pragma once

#include <gunrock/algorithms/algorithms.hxx>

// Thrust includes (scan, reduce)
#include <thrust/reduce.h>
#include <thrust/scan.h>

namespace gunrock {
namespace spgemm {

template <typename graph_t>
struct param_t {
  graph_t& A;
  graph_t& B;
  param_t(graph_t& _A, graph_t& _B) : A(_A), B(_B) {}
};

template <typename csr_t>
struct result_t {
  csr_t& C;
  result_t(csr_t& _C) : C(_C) {}
};

template <typename graph_t, typename param_type, typename result_type>
struct problem_t : gunrock::problem_t<graph_t> {
  using edge_t = typename graph_t::edge_type;
  using vertex_t = typename graph_t::vertex_type;
  using weight_t = typename graph_t::weight_type;

  param_type param;
  result_type result;

  problem_t(graph_t& A,
            param_type& _param,
            result_type& _result,
            std::shared_ptr<cuda::multi_context_t> _context)
      : gunrock::problem_t<graph_t>(A, _context),
        param(_param),
        result(_result) {}

  thrust::device_vector<edge_t> estimated_nz_per_row;
  thrust::host_vector<edge_t> nnz;

  void init() override {
    auto& A = this->param.A;
    auto& C = this->result.C;

    C.row_offsets.resize(A.get_number_of_vertices() + 1);
    estimated_nz_per_row.resize(A.get_number_of_vertices());
    nnz.resize(1);
  }

  void reset() override {
    auto policy = this->context->get_context(0)->execution_policy();
    thrust::fill(policy, estimated_nz_per_row.begin(),
                 estimated_nz_per_row.end(), 0);
    nnz[0] = 0;
  }
};

template <typename problem_t>
struct enactor_t : gunrock::enactor_t<problem_t> {
  enactor_t(problem_t* _problem,
            std::shared_ptr<cuda::multi_context_t> _context,
            enactor_properties_t _properties = enactor_properties_t())
      : gunrock::enactor_t<problem_t>(_problem, _context, _properties) {}

  using vertex_t = typename problem_t::vertex_t;
  using edge_t = typename problem_t::edge_t;
  using weight_t = typename problem_t::weight_t;

  void loop(cuda::multi_context_t& context) override {
    auto E = this->get_enactor();
    auto P = this->get_problem();

    auto policy = this->context->get_context(0)->execution_policy();

    auto& A = P->param.A;
    auto& B = P->param.B;
    auto& C = P->result.C;

    auto& row_offsets = C.row_offsets;
    auto& column_indices = C.column_indices;
    auto& nonzero_values = C.nonzero_values;

    auto& estimated_nz_per_row = P->estimated_nz_per_row;
    auto estimated_nz_ptr = estimated_nz_per_row.data().get();

    thrust::fill(policy, estimated_nz_per_row.begin(),
                 estimated_nz_per_row.end(), 0);

    /// Step 1. Count the upperbound of number of nonzeros per row of C.
    auto upperbound_nonzeros =
        [=] __host__ __device__(vertex_t const& m,  // ... source (row index)
                                vertex_t const& k,  // neighbor (column index)
                                edge_t const& nz_idx,  // edge (row ↦ column)
                                weight_t const& nz     // weight (nonzero).
                                ) -> bool {
      // Compute number of nonzeros of the sparse-matrix C for each row.
      math::atomic::add(&(estimated_nz_ptr[m]), B.get_number_of_neighbors(k));
      return false;
    };

    operators::advance::execute<operators::load_balance_t::block_mapped,
                                operators::advance_direction_t::forward,
                                operators::advance_io_type_t::graph,
                                operators::advance_io_type_t::none>(
        A, E, upperbound_nonzeros, context);

    /// Step X. Calculate upperbound of C's row-offsets.
    thrust::exclusive_scan(policy, P->estimated_nz_per_row.begin(),
                           P->estimated_nz_per_row.end(), row_offsets.begin(),
                           edge_t(0), thrust::plus<edge_t>());

    thrust::copy(row_offsets.begin() + A.get_number_of_vertices() - 1,
                 row_offsets.begin() + A.get_number_of_vertices(),
                 row_offsets.begin() + A.get_number_of_vertices());

    /// Step X. Calculate the upperbound of total number of nonzeros in the
    /// sparse-matrix C.
    thrust::copy(row_offsets.begin() + A.get_number_of_vertices(),
                 row_offsets.begin() + A.get_number_of_vertices() + 1,
                 P->nnz.begin());

    edge_t estimated_nzs = P->nnz[0];

    /// Step . Allocate upperbound memory for C's values and column indices.
    column_indices.resize(estimated_nzs, -1);
    nonzero_values.resize(estimated_nzs, weight_t(0));

    edge_t* row_off = row_offsets.data().get();
    vertex_t* col_ind = column_indices.data().get();
    weight_t* nz_vals = nonzero_values.data().get();

    /// Step X. Calculate C's column indices and values.
    auto gustavsons =
        [=] __device__(
            vertex_t const& m,  // ... source (A: row index)
            vertex_t const& k,  // neighbor (A: column index or B: row index)
            edge_t const& a_nz_idx,  // edge (A: row ↦ column)
            weight_t const& a_nz     // weight (A: nonzero).
            ) -> bool {
      // Get the number of nonzeros in row k of sparse-matrix B.
      auto offset = B.get_starting_edge(k);
      auto nnz = B.get_number_of_neighbors(k);
      auto c_offset = row_off[m];

      // Loop over all the nonzeros in row k of sparse-matrix B.
      for (edge_t b_nz_idx = offset; b_nz_idx < (offset + nnz); ++b_nz_idx) {
        auto n = B.get_destination_vertex(b_nz_idx);
        auto b_nz = B.get_edge_weight(b_nz_idx);
        std::size_t c_nz_idx = c_offset + n;
        col_ind[c_nz_idx] = n;
        math::atomic::add(nz_vals + c_nz_idx, a_nz * b_nz);
        if (c_nz_idx < 13)
          printf("%f, ", nz_vals[c_nz_idx]);
      }
    };

    operators::advance::execute<operators::load_balance_t::block_mapped,
                                operators::advance_direction_t::forward,
                                operators::advance_io_type_t::graph,
                                operators::advance_io_type_t::none>(
        A, E, gustavsons, context);

    /// Step X. Fix-up, i.e., remove overestimated nonzeros and rellocate the
    /// storage as necessary.
    auto real_nonzeros = [=] __device__(vertex_t const& row) -> void {
      edge_t overestimated_nzs = 0;
      // For all nonzeros within the row of C.
      for (auto nz = row_off[row]; nz < row_off[row + 1]; ++nz) {
        // Find the invalid column indices and zero-values, they represent
        // overestimated nonzeros.
        if (col_ind[nz] == -1)
          overestimated_nzs += 1;
      }
      // Remove overestimated nonzeros.
      estimated_nz_ptr[row] -= overestimated_nzs;
    };

    operators::parallel_for::execute<operators::parallel_for_each_t::vertex>(
        A, real_nonzeros, context);

    thrust::exclusive_scan(policy, P->estimated_nz_per_row.begin(),
                           P->estimated_nz_per_row.end(), row_offsets.begin(),
                           edge_t(0), thrust::plus<edge_t>());

    thrust::copy(row_offsets.begin() + A.get_number_of_vertices() - 1,
                 row_offsets.begin() + A.get_number_of_vertices(),
                 row_offsets.begin() + A.get_number_of_vertices());

    /// Step X. Calculate the upperbound of total number of nonzeros in the
    /// sparse-matrix C.
    thrust::copy(row_offsets.begin() + A.get_number_of_vertices(),
                 row_offsets.begin() + A.get_number_of_vertices() + 1,
                 P->nnz.begin());

    auto itc = thrust::copy_if(
        policy, column_indices.begin(), column_indices.end(),
        column_indices.begin(),
        [] __device__(const vertex_t& x) -> bool { return x != -1; });

    auto itv = thrust::copy_if(policy, nonzero_values.begin(),
                               nonzero_values.end(), nonzero_values.begin(),
                               [] __device__(const weight_t& nz) -> bool {
                                 return nz != weight_t(0);
                               });

    auto idx_nnz = thrust::distance(column_indices.begin(), itc);
    auto nz_nnz = thrust::distance(nonzero_values.begin(), itv);

    std::cout << std::endl;
    std::cout << "idx_nnz ? nz_nnz : " << idx_nnz << " ? " << nz_nnz
              << std::endl;

    /// Step X. Make sure C is set.
    C.number_of_rows = A.get_number_of_vertices();
    C.number_of_columns = B.get_number_of_vertices();
    C.number_of_nonzeros = P->nnz[0];
  }

  /**
   * @brief SpGEMM converges within one iteration.
   *
   * @param context The context of the execution (unused).
   * @return true returns true after one iteration.
   */
  virtual bool is_converged(cuda::multi_context_t& context) {
    return this->iteration == 0 ? false : true;
  }
};  // struct enactor_t

template <typename graph_t, typename csr_t>
float run(graph_t& A,
          graph_t& B,
          csr_t& C,
          std::shared_ptr<cuda::multi_context_t> context =
              std::shared_ptr<cuda::multi_context_t>(
                  new cuda::multi_context_t(0))  // Context
) {
  using param_type = param_t<graph_t>;
  using result_type = result_t<csr_t>;

  param_type param(A, B);
  result_type result(C);

  using problem_type = problem_t<graph_t, param_type, result_type>;
  using enactor_type = enactor_t<problem_type>;

  problem_type problem(A, param, result, context);
  problem.init();
  problem.reset();

  // Disable internal-frontiers:
  enactor_properties_t props;
  props.self_manage_frontiers = true;

  enactor_type enactor(&problem, context, props);
  return enactor.enact();
}

}  // namespace spgemm
}  // namespace gunrock<commit_msg>Cleaned-up, still a bug with generated nonzeros (col_ids and offsets working).<commit_after>/**
 * @file spgemm.hxx
 * @author Muhammad Osama (mosama@ucdavis.edu)
 * @brief Sparse-Matrix-Matrix multiplication.
 * @version 0.1
 * @date 2022-01-04
 *
 * @copyright Copyright (c) 2022
 *
 */

#pragma once

#include <gunrock/algorithms/algorithms.hxx>

// Thrust includes (scan, reduce)
#include <thrust/reduce.h>
#include <thrust/scan.h>

namespace gunrock {
namespace spgemm {

template <typename graph_t>
struct param_t {
  graph_t& A;
  graph_t& B;
  param_t(graph_t& _A, graph_t& _B) : A(_A), B(_B) {}
};

template <typename csr_t>
struct result_t {
  csr_t& C;
  result_t(csr_t& _C) : C(_C) {}
};

template <typename graph_t, typename param_type, typename result_type>
struct problem_t : gunrock::problem_t<graph_t> {
  using edge_t = typename graph_t::edge_type;
  using vertex_t = typename graph_t::vertex_type;
  using weight_t = typename graph_t::weight_type;

  param_type& param;
  result_type& result;

  problem_t(graph_t& A,
            param_type& _param,
            result_type& _result,
            std::shared_ptr<cuda::multi_context_t> _context)
      : gunrock::problem_t<graph_t>(A, _context),
        param(_param),
        result(_result) {}

  thrust::device_vector<edge_t> estimated_nz_per_row;
  thrust::host_vector<edge_t> nnz;

  void init() override {
    auto& A = this->param.A;
    // auto& C = this->result.C;

    estimated_nz_per_row.resize(A.get_number_of_vertices());
    nnz.resize(1);
  }

  void reset() override {
    auto policy = this->context->get_context(0)->execution_policy();
    thrust::fill(policy, estimated_nz_per_row.begin(),
                 estimated_nz_per_row.end(), 0);

    // Reset NNZ.
    nnz[0] = 0;

    // Reset sparse-matrix C.
    auto& C = this->result.C;
    C.row_offsets.clear();
    C.column_indices.clear();
    C.nonzero_values.clear();
  }
};

template <typename problem_t>
struct enactor_t : gunrock::enactor_t<problem_t> {
  enactor_t(problem_t* _problem,
            std::shared_ptr<cuda::multi_context_t> _context,
            enactor_properties_t _properties = enactor_properties_t())
      : gunrock::enactor_t<problem_t>(_problem, _context, _properties) {}

  using vertex_t = typename problem_t::vertex_t;
  using edge_t = typename problem_t::edge_t;
  using weight_t = typename problem_t::weight_t;

  void loop(cuda::multi_context_t& context) override {
    auto E = this->get_enactor();
    auto P = this->get_problem();

    auto policy = this->context->get_context(0)->execution_policy();

    auto& A = P->param.A;
    auto& B = P->param.B;
    auto& C = P->result.C;

    auto& row_offsets = C.row_offsets;
    auto& column_indices = C.column_indices;
    auto& nonzero_values = C.nonzero_values;

    auto& estimated_nz_per_row = P->estimated_nz_per_row;
    auto estimated_nz_ptr = estimated_nz_per_row.data().get();

    // Resize row-offsets.
    row_offsets.resize(A.get_number_of_vertices() + 1);

    thrust::fill(policy, estimated_nz_per_row.begin(),
                 estimated_nz_per_row.end(), 0);

    /// Step 1. Count the upperbound of number of nonzeros per row of C.
    auto upperbound_nonzeros =
        [=] __host__ __device__(vertex_t const& m,  // ... source (row index)
                                vertex_t const& k,  // neighbor (column index)
                                edge_t const& nz_idx,  // edge (row ↦ column)
                                weight_t const& nz     // weight (nonzero).
                                ) -> bool {
      // Compute number of nonzeros of the sparse-matrix C for each row.
      math::atomic::add(&(estimated_nz_ptr[m]), B.get_number_of_neighbors(k));
      return false;
    };

    operators::advance::execute<operators::load_balance_t::block_mapped,
                                operators::advance_direction_t::forward,
                                operators::advance_io_type_t::graph,
                                operators::advance_io_type_t::none>(
        A, E, upperbound_nonzeros, context);

    /// Step X. Calculate upperbound of C's row-offsets.
    thrust::exclusive_scan(policy, P->estimated_nz_per_row.begin(),
                           P->estimated_nz_per_row.end(), row_offsets.begin(),
                           edge_t(0), thrust::plus<edge_t>());

    thrust::copy(row_offsets.begin() + A.get_number_of_vertices() - 1,
                 row_offsets.begin() + A.get_number_of_vertices(),
                 row_offsets.begin() + A.get_number_of_vertices());

    /// Step X. Calculate the upperbound of total number of nonzeros in the
    /// sparse-matrix C.
    thrust::copy(row_offsets.begin() + A.get_number_of_vertices(),
                 row_offsets.begin() + A.get_number_of_vertices() + 1,
                 P->nnz.begin());

    edge_t estimated_nzs = P->nnz[0];

    /// Step . Allocate upperbound memory for C's values and column indices.
    column_indices.resize(estimated_nzs, -1);
    nonzero_values.resize(estimated_nzs, weight_t(0));

    edge_t* row_off = row_offsets.data().get();
    vertex_t* col_ind = column_indices.data().get();
    weight_t* nz_vals = nonzero_values.data().get();

    /// Step X. Calculate C's column indices and values.
    auto gustavsons =
        [=] __host__ __device__(
            vertex_t const& m,  // ... source (A: row index)
            vertex_t const& k,  // neighbor (A: column index or B: row index)
            edge_t const& a_nz_idx,  // edge (A: row ↦ column)
            weight_t const& a_nz     // weight (A: nonzero).
            ) -> bool {
      // Get the number of nonzeros in row k of sparse-matrix B.
      auto offset = B.get_starting_edge(k);
      auto nnz = B.get_number_of_neighbors(k);
      auto c_offset = thread::load(&row_off[m]);

      // Loop over all the nonzeros in row k of sparse-matrix B.
      for (edge_t b_nz_idx = offset; b_nz_idx < (offset + nnz); ++b_nz_idx) {
        auto n = B.get_destination_vertex(b_nz_idx);
        auto b_nz = B.get_edge_weight(b_nz_idx);

        // Calculate c's nonzero index.
        std::size_t c_nz_idx = c_offset + n;

        // Assign column index.
        thread::store(&col_ind[c_nz_idx], n);

        // Accumulate the nonzero value.
        math::atomic::add(nz_vals + c_nz_idx, a_nz * b_nz);
      }
      return false;
    };

    operators::advance::execute<operators::load_balance_t::block_mapped,
                                operators::advance_direction_t::forward,
                                operators::advance_io_type_t::graph,
                                operators::advance_io_type_t::none>(
        A, E, gustavsons, context);

    /// Step X. Fix-up, i.e., remove overestimated nonzeros and rellocate the
    /// storage as necessary.
    auto real_nonzeros = [=] __host__ __device__(vertex_t const& row) -> void {
      edge_t overestimated_nzs = 0;
      // For all nonzeros within the row of C.
      for (auto nz = row_off[row]; nz < row_off[row + 1]; ++nz) {
        // Find the invalid column indices and zero-values, they represent
        // overestimated nonzeros.
        if (col_ind[nz] == -1)
          overestimated_nzs += 1;
      }
      // Remove overestimated nonzeros.
      estimated_nz_ptr[row] -= overestimated_nzs;
    };

    operators::parallel_for::execute<operators::parallel_for_each_t::vertex>(
        A, real_nonzeros, context);

    thrust::exclusive_scan(policy, P->estimated_nz_per_row.begin(),
                           P->estimated_nz_per_row.end(), row_offsets.begin(),
                           edge_t(0), thrust::plus<edge_t>());

    thrust::copy(row_offsets.begin() + A.get_number_of_vertices() - 1,
                 row_offsets.begin() + A.get_number_of_vertices(),
                 row_offsets.begin() + A.get_number_of_vertices());

    /// Step X. Calculate the upperbound of total number of nonzeros in the
    /// sparse-matrix C.
    thrust::copy(row_offsets.begin() + A.get_number_of_vertices(),
                 row_offsets.begin() + A.get_number_of_vertices() + 1,
                 P->nnz.begin());

    auto itc = thrust::copy_if(
        policy, column_indices.begin(), column_indices.end(),
        column_indices.begin(),
        [] __device__(const vertex_t& x) -> bool { return x != -1; });

    auto itv = thrust::copy_if(policy, nonzero_values.begin(),
                               nonzero_values.end(), nonzero_values.begin(),
                               [] __device__(const weight_t& nz) -> bool {
                                 return nz != weight_t(0);
                               });

    auto idx_nnz = thrust::distance(column_indices.begin(), itc);
    auto nz_nnz = thrust::distance(nonzero_values.begin(), itv);

    std::cout << "idx_nnz ? nz_nnz : " << idx_nnz << " ? " << nz_nnz
              << std::endl;

    /// Step X. Make sure C is set.
    C.number_of_rows = A.get_number_of_vertices();
    C.number_of_columns = B.get_number_of_vertices();
    C.number_of_nonzeros = P->nnz[0];
  }

  /**
   * @brief SpGEMM converges within one iteration.
   *
   * @param context The context of the execution (unused).
   * @return true returns true after one iteration.
   */
  virtual bool is_converged(cuda::multi_context_t& context) {
    return this->iteration == 0 ? false : true;
  }
};  // struct enactor_t

template <typename graph_t, typename csr_t>
float run(graph_t& A,
          graph_t& B,
          csr_t& C,
          std::shared_ptr<cuda::multi_context_t> context =
              std::shared_ptr<cuda::multi_context_t>(
                  new cuda::multi_context_t(0))  // Context
) {
  using param_type = param_t<graph_t>;
  using result_type = result_t<csr_t>;

  param_type param(A, B);
  result_type result(C);

  using problem_type = problem_t<graph_t, param_type, result_type>;
  using enactor_type = enactor_t<problem_type>;

  problem_type problem(A, param, result, context);
  problem.init();
  problem.reset();

  // Disable internal-frontiers:
  enactor_properties_t props;
  props.self_manage_frontiers = true;

  enactor_type enactor(&problem, context, props);
  return enactor.enact();
}

}  // namespace spgemm
}  // namespace gunrock<|endoftext|>


<commit_before><commit_msg>HTMLAudioElement spec<commit_after>#ifndef GUARD_HTML5_HTML_INTERFACE_AUDIO_HH_INCLUDED
#define GUARD_HTML5_HTML_INTERFACE_AUDIO_HH_INCLUDED

#include <html5/html/interface/media.hh>

namespace html5 {
namespace html {
namespace interface {

class audio : public media {
public:
	audio();
	virtual ~audio();

	//	W3C HTMLAudioElement
	//		Attributes:
	//			src
	//			preload
	//			autoplay
	//			mediagroup
	//			loop
	//			muted
	//			controls
};

}}}

#endif //GUARD_HTML5_HTML_INTERFACE_AUDIO_HH_INCLUDED

<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TORRENT_CHAINED_BUFFER_HPP_INCLUDED
#define TORRENT_CHAINED_BUFFER_HPP_INCLUDED

#include <boost/function/function1.hpp>
#include <boost/version.hpp>
#if BOOST_VERSION < 103500
#include <asio/buffer.hpp>
#else
#include <boost/asio/buffer.hpp>
#endif
#include <list>
#include <cstring>

namespace libtorrent
{
#if BOOST_VERSION >= 103500
	namespace asio = boost::asio;
#endif
	struct chained_buffer
	{
		chained_buffer(): m_bytes(0), m_capacity(0) {}

		struct buffer_t
		{
			boost::function<void(char*)> free; // destructs the buffer
			char* buf; // the first byte of the buffer
			int size; // the total size of the buffer

			char* start; // the first byte to send/receive in the buffer
			int used_size; // this is the number of bytes to send/receive
		};

		bool empty() const { return m_bytes == 0; }
		int size() const { return m_bytes; }
		int capacity() const { return m_capacity; }

		void pop_front(int bytes_to_pop)
		{
			TORRENT_ASSERT(bytes_to_pop <= m_bytes);
			while (bytes_to_pop > 0 && !m_vec.empty())
			{
				buffer_t& b = m_vec.front();
				if (b.used_size > bytes_to_pop)
				{
					b.start += bytes_to_pop;
					b.used_size -= bytes_to_pop;
					m_bytes -= bytes_to_pop;
					TORRENT_ASSERT(m_bytes <= m_capacity);
					TORRENT_ASSERT(m_bytes >= 0);
					TORRENT_ASSERT(m_capacity >= 0);
					break;
				}

				b.free(b.buf);
				m_bytes -= b.used_size;
				m_capacity -= b.size;
				bytes_to_pop -= b.used_size;
				TORRENT_ASSERT(m_bytes >= 0);
				TORRENT_ASSERT(m_capacity >= 0);
				TORRENT_ASSERT(m_bytes <= m_capacity);
				m_vec.pop_front();
			}
		}

		template <class D>
		void append_buffer(char* buffer, int s, int used_size, D const& destructor)
		{
			TORRENT_ASSERT(s >= used_size);
			buffer_t b;
			b.buf = buffer;
			b.size = s;
			b.start = buffer;
			b.used_size = used_size;
			b.free = destructor;
			m_vec.push_back(b);

			m_bytes += used_size;
			m_capacity += s;
			TORRENT_ASSERT(m_bytes <= m_capacity);
		}

		// returns the number of bytes available at the
		// end of the last chained buffer.
		int space_in_last_buffer()
		{
			if (m_vec.empty()) return 0;
			buffer_t& b = m_vec.back();
			return b.size - b.used_size - (b.start - b.buf);
		}

		// tries to copy the given buffer to the end of the
		// last chained buffer. If there's not enough room
		// it returns false
		bool append(char const* buf, int s)
		{
			char* insert = allocate_appendix(s);
			if (insert == 0) return false;
			std::memcpy(insert, buf, s);
			return true;
		}

		// tries to allocate memory from the end
		// of the last buffer. If there isn't
		// enough room, returns 0
		char* allocate_appendix(int s)
		{
			if (m_vec.empty()) return 0;
			buffer_t& b = m_vec.back();
			char* insert = b.start + b.used_size;
			if (insert + s > b.buf + b.size) return 0;
			b.used_size += s;
			m_bytes += s;
			TORRENT_ASSERT(m_bytes <= m_capacity);
			return insert;
		}

		std::list<asio::const_buffer> const& build_iovec(int to_send)
		{
			m_tmp_vec.clear();

			for (std::list<buffer_t>::iterator i = m_vec.begin()
				, end(m_vec.end()); to_send > 0 && i != end; ++i)
			{
				if (i->used_size > to_send)
				{
					TORRENT_ASSERT(to_send > 0);
					m_tmp_vec.push_back(asio::const_buffer(i->start, to_send));
					break;
				}
				TORRENT_ASSERT(i->used_size > 0);
				m_tmp_vec.push_back(asio::const_buffer(i->start, i->used_size));
				to_send -= i->used_size;
			}
			return m_tmp_vec;
		}

		~chained_buffer()
		{
			for (std::list<buffer_t>::iterator i = m_vec.begin()
				, end(m_vec.end()); i != end; ++i)
			{
				i->free(i->buf);
			}
		}

	private:

		// this is the list of all the buffers we want to
		// send
		std::list<buffer_t> m_vec;

		// this is the number of bytes in the send buf.
		// this will always be equal to the sum of the
		// size of all buffers in vec
		int m_bytes;

		// the total size of all buffers in the chain
		// including unused space
		int m_capacity;

		// this is the vector of buffers used when
		// invoking the async write call
		std::list<asio::const_buffer> m_tmp_vec;
	};
}

#endif

<commit_msg>use memcpy() instead of std::memcpy()<commit_after>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TORRENT_CHAINED_BUFFER_HPP_INCLUDED
#define TORRENT_CHAINED_BUFFER_HPP_INCLUDED

#include <boost/function/function1.hpp>
#include <boost/version.hpp>
#if BOOST_VERSION < 103500
#include <asio/buffer.hpp>
#else
#include <boost/asio/buffer.hpp>
#endif
#include <list>
#include	<string.h> // for memcpy

namespace libtorrent
{
#if BOOST_VERSION >= 103500
	namespace asio = boost::asio;
#endif
	struct chained_buffer
	{
		chained_buffer(): m_bytes(0), m_capacity(0) {}

		struct buffer_t
		{
			boost::function<void(char*)> free; // destructs the buffer
			char* buf; // the first byte of the buffer
			int size; // the total size of the buffer

			char* start; // the first byte to send/receive in the buffer
			int used_size; // this is the number of bytes to send/receive
		};

		bool empty() const { return m_bytes == 0; }
		int size() const { return m_bytes; }
		int capacity() const { return m_capacity; }

		void pop_front(int bytes_to_pop)
		{
			TORRENT_ASSERT(bytes_to_pop <= m_bytes);
			while (bytes_to_pop > 0 && !m_vec.empty())
			{
				buffer_t& b = m_vec.front();
				if (b.used_size > bytes_to_pop)
				{
					b.start += bytes_to_pop;
					b.used_size -= bytes_to_pop;
					m_bytes -= bytes_to_pop;
					TORRENT_ASSERT(m_bytes <= m_capacity);
					TORRENT_ASSERT(m_bytes >= 0);
					TORRENT_ASSERT(m_capacity >= 0);
					break;
				}

				b.free(b.buf);
				m_bytes -= b.used_size;
				m_capacity -= b.size;
				bytes_to_pop -= b.used_size;
				TORRENT_ASSERT(m_bytes >= 0);
				TORRENT_ASSERT(m_capacity >= 0);
				TORRENT_ASSERT(m_bytes <= m_capacity);
				m_vec.pop_front();
			}
		}

		template <class D>
		void append_buffer(char* buffer, int s, int used_size, D const& destructor)
		{
			TORRENT_ASSERT(s >= used_size);
			buffer_t b;
			b.buf = buffer;
			b.size = s;
			b.start = buffer;
			b.used_size = used_size;
			b.free = destructor;
			m_vec.push_back(b);

			m_bytes += used_size;
			m_capacity += s;
			TORRENT_ASSERT(m_bytes <= m_capacity);
		}

		// returns the number of bytes available at the
		// end of the last chained buffer.
		int space_in_last_buffer()
		{
			if (m_vec.empty()) return 0;
			buffer_t& b = m_vec.back();
			return b.size - b.used_size - (b.start - b.buf);
		}

		// tries to copy the given buffer to the end of the
		// last chained buffer. If there's not enough room
		// it returns false
		bool append(char const* buf, int s)
		{
			char* insert = allocate_appendix(s);
			if (insert == 0) return false;
			memcpy(insert, buf, s);
			return true;
		}

		// tries to allocate memory from the end
		// of the last buffer. If there isn't
		// enough room, returns 0
		char* allocate_appendix(int s)
		{
			if (m_vec.empty()) return 0;
			buffer_t& b = m_vec.back();
			char* insert = b.start + b.used_size;
			if (insert + s > b.buf + b.size) return 0;
			b.used_size += s;
			m_bytes += s;
			TORRENT_ASSERT(m_bytes <= m_capacity);
			return insert;
		}

		std::list<asio::const_buffer> const& build_iovec(int to_send)
		{
			m_tmp_vec.clear();

			for (std::list<buffer_t>::iterator i = m_vec.begin()
				, end(m_vec.end()); to_send > 0 && i != end; ++i)
			{
				if (i->used_size > to_send)
				{
					TORRENT_ASSERT(to_send > 0);
					m_tmp_vec.push_back(asio::const_buffer(i->start, to_send));
					break;
				}
				TORRENT_ASSERT(i->used_size > 0);
				m_tmp_vec.push_back(asio::const_buffer(i->start, i->used_size));
				to_send -= i->used_size;
			}
			return m_tmp_vec;
		}

		~chained_buffer()
		{
			for (std::list<buffer_t>::iterator i = m_vec.begin()
				, end(m_vec.end()); i != end; ++i)
			{
				i->free(i->buf);
			}
		}

	private:

		// this is the list of all the buffers we want to
		// send
		std::list<buffer_t> m_vec;

		// this is the number of bytes in the send buf.
		// this will always be equal to the sum of the
		// size of all buffers in vec
		int m_bytes;

		// the total size of all buffers in the chain
		// including unused space
		int m_capacity;

		// this is the vector of buffers used when
		// invoking the async write call
		std::list<asio::const_buffer> m_tmp_vec;
	};
}

#endif

<|endoftext|>