<commit_before>/*
 * Copyright 2009 The VOTCA Development Team (http://www.votca.org)
 *
 * 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 <fstream>
#include "cgengine.h"
#include <votca/tools/tokenizer.h>
#include "version.h"

namespace po = boost::program_options;

CGEngine::CGEngine()
    : _op_desc("Allowed options"), _op_desc_specific("Specific options")
{
    InitializeStandardOptions();
}

CGEngine::~CGEngine()
{
    map<string, CGMoleculeDef *>::iterator i;
    for(i=_molecule_defs.begin(); i!=_molecule_defs.end();++i)
        delete (*i).second;
    _molecule_defs.clear();
}

void CGEngine::Initialize()
{
    TrajectoryWriter::RegisterPlugins();
    TrajectoryReader::RegisterPlugins();
    TopologyReader::RegisterPlugins();
}

void CGEngine::ParseCommandLine(int argc, char **argv)
{
    _op_desc.add(_op_desc_specific);
    namespace po=boost::program_options;
    try {
        po::store(po::parse_command_line(argc, argv, _op_desc), _op_vm);
        po::notify(_op_vm);
    }
    catch(boost::program_options::error err) {
        throw runtime_error(string("error parsing command line: ") + err.what());
    }
}

/**
    \todo melts with different molecules
*/
TopologyMap *CGEngine::CreateCGTopology(Topology &in, Topology &out)
{
    MoleculeContainer &mols = in.Molecules();
    MoleculeContainer::iterator iter;
    TopologyMap *m = new TopologyMap(&in, &out);
    for(iter=mols.begin(); iter!=mols.end(); ++iter) {
        Molecule *mol = *iter;
        CGMoleculeDef *def = getMoleculeDef(mol->getName());
        if(!def) {
            cout << "--------------------------------------\n"
                 << "WARNING: unknown molecule \"" << mol->getName() << "\" with id "
                 << mol->getId() << " in topology" << endl
                 << "molecule will not be mapped to CG representation\n"
                 << "Check weather a mapping file for all molecule exists, was specified in --cg "
                 << "separated by ; and the ident tag in xml-file matches the molecule name\n"
                 << "--------------------------------------\n";
            continue;
        }
        Molecule *mcg = def->CreateMolecule(out);
        Map *map = def->CreateMap(*mol, *mcg);
        m->AddMoleculeMap(map);
    }
    out.RebuildExclusions();
    return m;
}

void CGEngine::LoadMoleculeType(string filename)
{
    Tokenizer tok(filename, ";");
    Tokenizer::iterator iter;

    for(iter=tok.begin(); iter!=tok.end(); ++iter) {
        CGMoleculeDef *def = new CGMoleculeDef();
        string  file = *iter;
        boost::trim(file);
        def->Load(file);
        _molecule_defs[def->getIdent()] = def;
    }
}

void CGEngine::BeginCG(Topology &top)
{
    list<CGObserver *>::iterator iter;
    for(iter=_observers.begin(); iter!=_observers.end(); ++iter)
        (*iter)->BeginCG(&top);
}

void CGEngine::EndCG()
{
    list<CGObserver *>::iterator iter;
    for(iter=_observers.begin(); iter!=_observers.end(); ++iter)
        (*iter)->EndCG();
}

void CGEngine::EvalConfiguration(Topology &top_cg)
{
    list<CGObserver *>::iterator iter;
    for(iter=_observers.begin(); iter!=_observers.end(); ++iter)
        (*iter)->EvalConfiguration(&top_cg);
}

void CGEngine::InitializeStandardOptions()
{
    po::options_description trj("Trajectory options");
    _op_desc.add_options()
    ("help", "  produce this help message")
    ("top", boost::program_options::value<string>(), "  atomistic topology file")
    ("cg", boost::program_options::value<string>(), "  coarse graining definitions (xml-file)")
    ;

    trj.add_options()
    ("trj", boost::program_options::value<string>(), "  atomistic trajectory file")
    ("begin", boost::program_options::value<double>(), "  skip frames before this time")
    ("first-frame", boost::program_options::value<int>()->default_value(0), "  start with this frame")
    ("nframes", boost::program_options::value<int>(), "  process so many frames")
    ;

    _op_desc.add(trj);
}

void CGEngine::Run()
{
    TopologyReader *reader;
    TrajectoryReader *traj_reader;
    Topology top;
    Topology top_cg;
    TopologyMap *map;
    double begin;
    int first_frame;

    bool has_begin=false;

//    if (vm.count("version")) {
//        votca::csg::HelpTextHeader("csg");
//        exit(0);
//    }

    if (!_op_vm.count("top")) {
        cout << _op_desc << endl;
        throw runtime_error("no topology file specified");
    }
    if (!_op_vm.count("cg")) {
        cout << _op_desc << endl;
        throw runtime_error("no coarse graining definition specified");
    }

    if(_op_vm.count("begin")) {
        has_begin = true;
        begin = _op_vm["begin"].as<double>();
    }

    int nframes = -1;
    if(_op_vm.count("nframes")) {
        nframes = _op_vm["nframes"].as<int>();
    }

    first_frame = _op_vm["first-frame"].as<int>();

    // create reader for atomistic topology
    reader = TopReaderFactory().Create(_op_vm["top"].as<string>());
    if(reader == NULL)
        throw runtime_error(string("input format not supported: ") + _op_vm["top"].as<string>());

    // read in the atomistic topology
    reader->ReadTopology(_op_vm["top"].as<string>(), top);
    cout << "I have " << top.BeadCount() << " beads in " << top.MoleculeCount() << " molecules" << endl;
    top.CheckMoleculeNaming();

    //top.CreateMoleculesByResidue();
    //top.CreateOneBigMolecule("PS1");

    // read in the coarse graining definitions (xml files)
    LoadMoleculeType(_op_vm["cg"].as<string>());
    // create the mapping + cg topology
    map = CreateCGTopology(top, top_cg);
    //cg_def.CreateMolecule(top_cg);

    cout << "I have " << top_cg.BeadCount() << " beads in " << top_cg.MoleculeCount() << " molecules for the coarsegraining" << endl;

    // if trj is given, process trajectory file
    if (_op_vm.count("trj")) {
        // create reader for trajectory
        traj_reader = TrjReaderFactory().Create(_op_vm["trj"].as<string>());
        if(traj_reader == NULL)
            throw runtime_error(string("input format not supported: ") + _op_vm["trj"].as<string>());
        // open the trajectory
        traj_reader->Open(_op_vm["trj"].as<string>());
        // read in first frame
        traj_reader->FirstFrame(top);

        // notify all observer that coarse graining has begun

        map->Apply();
        BeginCG(top_cg);

        for(bool bok=true; bok==true; bok = traj_reader->NextFrame(top)) {
            if(((top.getTime() < begin) && has_begin)|| first_frame > 0) {
                first_frame--;
                continue;
            }
            if(nframes == 0 ) break;
            map->Apply();
            EvalConfiguration(top_cg);
            nframes--;
        }
        EndCG();
        traj_reader->Close();
    }
    delete traj_reader;
    delete reader;
    delete map;
}
<commit_msg>removed conditional jump on uninitialized value by giving "begin" a default value of zero<commit_after>/*
 * Copyright 2009 The VOTCA Development Team (http://www.votca.org)
 *
 * 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 <fstream>
#include "cgengine.h"
#include <votca/tools/tokenizer.h>
#include "version.h"

namespace po = boost::program_options;

CGEngine::CGEngine()
    : _op_desc("Allowed options"), _op_desc_specific("Specific options")
{
    InitializeStandardOptions();
}

CGEngine::~CGEngine()
{
    map<string, CGMoleculeDef *>::iterator i;
    for(i=_molecule_defs.begin(); i!=_molecule_defs.end();++i)
        delete (*i).second;
    _molecule_defs.clear();
}

void CGEngine::Initialize()
{
    TrajectoryWriter::RegisterPlugins();
    TrajectoryReader::RegisterPlugins();
    TopologyReader::RegisterPlugins();
}

void CGEngine::ParseCommandLine(int argc, char **argv)
{
    _op_desc.add(_op_desc_specific);
    namespace po=boost::program_options;
    try {
        po::store(po::parse_command_line(argc, argv, _op_desc), _op_vm);
        po::notify(_op_vm);
    }
    catch(boost::program_options::error err) {
        throw runtime_error(string("error parsing command line: ") + err.what());
    }
}

/**
    \todo melts with different molecules
*/
TopologyMap *CGEngine::CreateCGTopology(Topology &in, Topology &out)
{
    MoleculeContainer &mols = in.Molecules();
    MoleculeContainer::iterator iter;
    TopologyMap *m = new TopologyMap(&in, &out);
    for(iter=mols.begin(); iter!=mols.end(); ++iter) {
        Molecule *mol = *iter;
        CGMoleculeDef *def = getMoleculeDef(mol->getName());
        if(!def) {
            cout << "--------------------------------------\n"
                 << "WARNING: unknown molecule \"" << mol->getName() << "\" with id "
                 << mol->getId() << " in topology" << endl
                 << "molecule will not be mapped to CG representation\n"
                 << "Check weather a mapping file for all molecule exists, was specified in --cg "
                 << "separated by ; and the ident tag in xml-file matches the molecule name\n"
                 << "--------------------------------------\n";
            continue;
        }
        Molecule *mcg = def->CreateMolecule(out);
        Map *map = def->CreateMap(*mol, *mcg);
        m->AddMoleculeMap(map);
    }
    out.RebuildExclusions();
    return m;
}

void CGEngine::LoadMoleculeType(string filename)
{
    Tokenizer tok(filename, ";");
    Tokenizer::iterator iter;

    for(iter=tok.begin(); iter!=tok.end(); ++iter) {
        CGMoleculeDef *def = new CGMoleculeDef();
        string  file = *iter;
        boost::trim(file);
        def->Load(file);
        _molecule_defs[def->getIdent()] = def;
    }
}

void CGEngine::BeginCG(Topology &top)
{
    list<CGObserver *>::iterator iter;
    for(iter=_observers.begin(); iter!=_observers.end(); ++iter)
        (*iter)->BeginCG(&top);
}

void CGEngine::EndCG()
{
    list<CGObserver *>::iterator iter;
    for(iter=_observers.begin(); iter!=_observers.end(); ++iter)
        (*iter)->EndCG();
}

void CGEngine::EvalConfiguration(Topology &top_cg)
{
    list<CGObserver *>::iterator iter;
    for(iter=_observers.begin(); iter!=_observers.end(); ++iter)
        (*iter)->EvalConfiguration(&top_cg);
}

void CGEngine::InitializeStandardOptions()
{
    po::options_description trj("Trajectory options");
    _op_desc.add_options()
    ("help", "  produce this help message")
    ("top", boost::program_options::value<string>(), "  atomistic topology file")
    ("cg", boost::program_options::value<string>(), "  coarse graining definitions (xml-file)")
    ;

    trj.add_options()
    ("trj", boost::program_options::value<string>(), "  atomistic trajectory file")
    ("begin", boost::program_options::value<double>()->default_value(0.0), "  skip frames before this time")
    ("first-frame", boost::program_options::value<int>()->default_value(0), "  start with this frame")
    ("nframes", boost::program_options::value<int>(), "  process so many frames")
    ;

    _op_desc.add(trj);
}

void CGEngine::Run()
{
    TopologyReader *reader;
    TrajectoryReader *traj_reader;
    Topology top;
    Topology top_cg;
    TopologyMap *map;
    double begin;
    int first_frame;

    bool has_begin=false;

//    if (vm.count("version")) {
//        votca::csg::HelpTextHeader("csg");
//        exit(0);
//    }

    if (!_op_vm.count("top")) {
        cout << _op_desc << endl;
        throw runtime_error("no topology file specified");
    }
    if (!_op_vm.count("cg")) {
        cout << _op_desc << endl;
        throw runtime_error("no coarse graining definition specified");
    }

    if(_op_vm.count("begin")) {
        has_begin = true;
        begin = _op_vm["begin"].as<double>();
    }

    int nframes = -1;
    if(_op_vm.count("nframes")) {
        nframes = _op_vm["nframes"].as<int>();
    }

    first_frame = _op_vm["first-frame"].as<int>();

    // create reader for atomistic topology
    reader = TopReaderFactory().Create(_op_vm["top"].as<string>());
    if(reader == NULL)
        throw runtime_error(string("input format not supported: ") + _op_vm["top"].as<string>());

    // read in the atomistic topology
    reader->ReadTopology(_op_vm["top"].as<string>(), top);
    cout << "I have " << top.BeadCount() << " beads in " << top.MoleculeCount() << " molecules" << endl;
    top.CheckMoleculeNaming();

    //top.CreateMoleculesByResidue();
    //top.CreateOneBigMolecule("PS1");

    // read in the coarse graining definitions (xml files)
    LoadMoleculeType(_op_vm["cg"].as<string>());
    // create the mapping + cg topology
    map = CreateCGTopology(top, top_cg);
    //cg_def.CreateMolecule(top_cg);

    cout << "I have " << top_cg.BeadCount() << " beads in " << top_cg.MoleculeCount() << " molecules for the coarsegraining" << endl;

    // if trj is given, process trajectory file
    if (_op_vm.count("trj")) {
        // create reader for trajectory
        traj_reader = TrjReaderFactory().Create(_op_vm["trj"].as<string>());
        if(traj_reader == NULL)
            throw runtime_error(string("input format not supported: ") + _op_vm["trj"].as<string>());
        // open the trajectory
        traj_reader->Open(_op_vm["trj"].as<string>());
        // read in first frame
        traj_reader->FirstFrame(top);

        // notify all observer that coarse graining has begun

        map->Apply();
        BeginCG(top_cg);

        for(bool bok=true; bok==true; bok = traj_reader->NextFrame(top)) {
            if(((top.getTime() < begin) && has_begin)|| first_frame > 0) {
                first_frame--;
                continue;
            }
            if(nframes == 0 ) break;
            map->Apply();
            EvalConfiguration(top_cg);
            nframes--;
        }
        EndCG();
        traj_reader->Close();
    }
    delete traj_reader;
    delete reader;
    delete map;
}
<|endoftext|>


<commit_before>#include <Core/Animation/Skinning/DualQuaternionSkinning.hpp>

namespace Ra {
namespace Core {
namespace Animation {

void computeDQ( const Pose& pose, const WeightMatrix& weight, DQList& DQ ) {
    CORE_ASSERT( ( pose.size() == weight.cols() ), "pose/weight size mismatch." );
    DQ.clear();
    DQ.resize( weight.rows(), DualQuaternion( Quaternion( 0, 0, 0, 0 ), Quaternion( 0, 0, 0, 0 ) ) );

    // Stores the first non-zero quaternion for each vertex.
    std::vector<uint> firstNonZero( weight.rows(), std::numeric_limits<uint>::max());

    // Contains the converted dual quaternions from the pose
    std::vector<DualQuaternion> poseDQ;
    poseDQ.reserve( pose.size());

    // Loop through all transforms Tj
    for( int j = 0; j < weight.outerSize(); ++j ) {

        poseDQ[j] = DualQuaternion( pose[j]);
        // Count how many vertices are influenced by the given transform
        const int nonZero = weight.col( j ).nonZeros();
#if defined CORE_USE_OMP
        omp_set_dynamic(0);
        #pragma omp parallel for schedule( static ) num_threads(4)
#endif
        // This for loop is here just because OpenMP wants classic for loops.
        // Since we cannot iterate directly through the non-zero elements using the InnerIterator,
        // we initialize an InnerIterator to the first element and then we increase it nz times.
        /*
        * This crappy piece of code was done in order to avoid the critical section
        *           DQ[i] += wq;
        *
        * that was occurring when parallelizing the main for loop.
        *
        * NOTE: this could be definitely improved by using std::thread
        */
        // Loop trhough all vertices vi who depend on Tj
        WeightMatrix::InnerIterator it0( weight, j );
        for( int nz = 0; nz < nonZero; ++nz ) {

            WeightMatrix::InnerIterator itn = it0 + nz;
            const uint   i  = itn.row();
            const Scalar w  = itn.value();

            firstNonZero[i] = std::min( firstNonZero[i], uint(j) );
            const Scalar sign =  Ra::Core::Math::signNZ(  poseDQ[j].getQ0().dot(poseDQ[firstNonZero[i]].getQ0()));

            const auto  wq = poseDQ[j] * w * sign;
            DQ[i] += wq;
        }
    }

    // Normalize all dual quats.
#if defined CORE_USE_OMP
    omp_set_dynamic(0);
    #pragma omp parallel for schedule( static ) num_threads(4)
#endif
    for( int i = 0; i < int(DQ.size()) ; ++i) {
        DQ[i].normalize();
    }
}

// alternate naive version, for reference purposes.
// See Kavan , Collins, Zara and O'Sullivan, 2008
void computeDQ_naive( const Pose& pose, const WeightMatrix& weight, DQList& DQ ) {
    CORE_ASSERT( ( pose.size() == weight.cols() ), "pose/weight size mismatch." );
    DQ.clear();
    DQ.resize( weight.rows(), DualQuaternion( Quaternion( 0, 0, 0, 0 ), Quaternion( 0, 0, 0, 0 ) ) );

    std::vector<DualQuaternion> poseDQ;
    poseDQ.reserve( pose.size());

    // 1. Convert all transforms to DQ
    for ( uint j = 0 ; j < weight.cols(); ++j)
    {
        poseDQ.push_back(DualQuaternion(pose[j]));
    }

    // 2. for all vertices, blend the dual quats.
    for (uint i = 0; i < weight.rows(); ++i)
    {
        int firstNonZero = -1;
        for (uint j = 0; j < weight.cols(); ++j)
        {
            const Scalar& w = weight.coeff(i,j);
            if ( w  == 0) { continue;}

            if (firstNonZero < 0) { firstNonZero = j;}

            // Flip the dual quaternion sign according to the dot product with the first non-null dual quat
            // see Algorithm 2 in section 4.1 of the paper.
            Scalar sign = Ra::Core::Math::signNZ(  poseDQ[j].getQ0().dot(poseDQ[firstNonZero].getQ0()));

            DQ[i]+= sign * w * poseDQ[j];
        }
    }

    // 3. renormalize all dual quats.
    for( int i = 0; i < int(DQ.size()) ; ++i) {
        DQ[i].normalize();
    }
}

void dualQuaternionSkinning( const Vector3Array& input, const DQList& DQ, Vector3Array& output ) {
    const uint size = input.size();
    CORE_ASSERT( ( size == DQ.size() ), "input/DQ size mismatch." );
    output.resize( size );
#if defined CORE_USE_OMP
    omp_set_dynamic(0);
    #pragma omp parallel for schedule( static ) num_threads(4)
#endif
    for( int i = 0; i < int(size); ++i ) {
        output[i] = DQ[i].transform( input[i] );
    }
}

} // namespace Animation
} // namespace Core
} // namespace Ra
<commit_msg>now compiling with OMP<commit_after>#include <Core/Animation/Skinning/DualQuaternionSkinning.hpp>

namespace Ra {
namespace Core {
namespace Animation {

void computeDQ( const Pose& pose, const WeightMatrix& weight, DQList& DQ ) {
    CORE_ASSERT( ( pose.size() == weight.cols() ), "pose/weight size mismatch." );
    DQ.clear();
    DQ.resize( weight.rows(), DualQuaternion( Quaternion( 0, 0, 0, 0 ), Quaternion( 0, 0, 0, 0 ) ) );

    // Stores the first non-zero quaternion for each vertex.
    std::vector<uint> firstNonZero( weight.rows(), std::numeric_limits<uint>::max());

    // Contains the converted dual quaternions from the pose
    std::vector<DualQuaternion> poseDQ;
    poseDQ.reserve( pose.size());

    // Loop through all transforms Tj
    for( int j = 0; j < weight.outerSize(); ++j ) {

        poseDQ[j] = DualQuaternion( pose[j]);
        // Count how many vertices are influenced by the given transform
        const int nonZero = weight.col( j ).nonZeros();

        WeightMatrix::InnerIterator it0( weight, j );
#if defined CORE_USE_OMP
        omp_set_dynamic(0);
        #pragma omp parallel for schedule( static ) num_threads(4)
#endif
        // This for loop is here just because OpenMP wants classic for loops.
        // Since we cannot iterate directly through the non-zero elements using the InnerIterator,
        // we initialize an InnerIterator to the first element and then we increase it nz times.
        /*
        * This crappy piece of code was done in order to avoid the critical section
        *           DQ[i] += wq;
        *
        * that was occurring when parallelizing the main for loop.
        *
        * NOTE: this could be definitely improved by using std::thread
        */
        // Loop trhough all vertices vi who depend on Tj

        for( int nz = 0; nz < nonZero; ++nz ) {

            WeightMatrix::InnerIterator itn = it0 + nz;
            const uint   i  = itn.row();
            const Scalar w  = itn.value();

            firstNonZero[i] = std::min( firstNonZero[i], uint(j) );
            const Scalar sign =  Ra::Core::Math::signNZ(  poseDQ[j].getQ0().dot(poseDQ[firstNonZero[i]].getQ0()));

            const auto  wq = poseDQ[j] * w * sign;
            DQ[i] += wq;
        }
    }

    // Normalize all dual quats.
#if defined CORE_USE_OMP
    omp_set_dynamic(0);
    #pragma omp parallel for schedule( static ) num_threads(4)
#endif
    for( int i = 0; i < int(DQ.size()) ; ++i) {
        DQ[i].normalize();
    }
}

// alternate naive version, for reference purposes.
// See Kavan , Collins, Zara and O'Sullivan, 2008
void computeDQ_naive( const Pose& pose, const WeightMatrix& weight, DQList& DQ ) {
    CORE_ASSERT( ( pose.size() == weight.cols() ), "pose/weight size mismatch." );
    DQ.clear();
    DQ.resize( weight.rows(), DualQuaternion( Quaternion( 0, 0, 0, 0 ), Quaternion( 0, 0, 0, 0 ) ) );

    std::vector<DualQuaternion> poseDQ;
    poseDQ.reserve( pose.size());

    // 1. Convert all transforms to DQ
    for ( uint j = 0 ; j < weight.cols(); ++j)
    {
        poseDQ.push_back(DualQuaternion(pose[j]));
    }

    // 2. for all vertices, blend the dual quats.
    for (uint i = 0; i < weight.rows(); ++i)
    {
        int firstNonZero = -1;
        for (uint j = 0; j < weight.cols(); ++j)
        {
            const Scalar& w = weight.coeff(i,j);
            if ( w  == 0) { continue;}

            if (firstNonZero < 0) { firstNonZero = j;}

            // Flip the dual quaternion sign according to the dot product with the first non-null dual quat
            // see Algorithm 2 in section 4.1 of the paper.
            Scalar sign = Ra::Core::Math::signNZ(  poseDQ[j].getQ0().dot(poseDQ[firstNonZero].getQ0()));

            DQ[i]+= sign * w * poseDQ[j];
        }
    }

    // 3. renormalize all dual quats.
    for( int i = 0; i < int(DQ.size()) ; ++i) {
        DQ[i].normalize();
    }
}

void dualQuaternionSkinning( const Vector3Array& input, const DQList& DQ, Vector3Array& output ) {
    const uint size = input.size();
    CORE_ASSERT( ( size == DQ.size() ), "input/DQ size mismatch." );
    output.resize( size );
#if defined CORE_USE_OMP
    omp_set_dynamic(0);
    #pragma omp parallel for schedule( static ) num_threads(4)
#endif
    for( int i = 0; i < int(size); ++i ) {
        output[i] = DQ[i].transform( input[i] );
    }
}

} // namespace Animation
} // namespace Core
} // namespace Ra
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/audio/mac/audio_output_mac.h"

#include "base/basictypes.h"
#include "base/logging.h"
#include "media/audio/audio_util.h"
#include "media/audio/mac/audio_manager_mac.h"

// A custom data structure to store information an AudioQueue buffer.
struct AudioQueueUserData {
  AudioQueueUserData() : empty_buffer(false) {}
  bool empty_buffer;
};

// Overview of operation:
// 1) An object of PCMQueueOutAudioOutputStream is created by the AudioManager
// factory: audio_man->MakeAudioStream(). This just fills some structure.
// 2) Next some thread will call Open(), at that point the underliying OS
// queue is created and the audio buffers allocated.
// 3) Then some thread will call Start(source) At this point the source will be
// called to fill the initial buffers in the context of that same thread.
// Then the OS queue is started which will create its own thread which
// periodically will call the source for more data as buffers are being
// consumed.
// 4) At some point some thread will call Stop(), which we handle by directly
// stoping the OS queue.
// 5) One more callback to the source could be delivered in in the context of
// the queue's own thread. Data, if any will be discared.
// 6) The same thread that called stop will call Close() where we cleanup
// and notifiy the audio manager, which likley will destroy this object.

#if !defined(MAC_OS_X_VERSION_10_6) || \
    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
enum {
  kAudioQueueErr_EnqueueDuringReset = -66632
};
#endif

PCMQueueOutAudioOutputStream::PCMQueueOutAudioOutputStream(
    AudioManagerMac* manager, AudioParameters params)
    : format_(),
      audio_queue_(NULL),
      buffer_(),
      source_(NULL),
      manager_(manager),
      silence_bytes_(0),
      volume_(1),
      pending_bytes_(0) {
  // We must have a manager.
  DCHECK(manager_);
  // A frame is one sample across all channels. In interleaved audio the per
  // frame fields identify the set of n |channels|. In uncompressed audio, a
  // packet is always one frame.
  format_.mSampleRate = params.sample_rate;
  format_.mFormatID = kAudioFormatLinearPCM;
  format_.mFormatFlags = kLinearPCMFormatFlagIsPacked |
                         kLinearPCMFormatFlagIsSignedInteger;
  format_.mBitsPerChannel = params.bits_per_sample;
  format_.mChannelsPerFrame = params.channels;
  format_.mFramesPerPacket = 1;
  format_.mBytesPerPacket = (format_.mBitsPerChannel * params.channels) / 8;
  format_.mBytesPerFrame = format_.mBytesPerPacket;

  packet_size_ = params.GetPacketSize();

  // Silence buffer has a duration of 6ms to simulate the behavior of Windows.
  // This value is choosen by experiments and macs cannot keep up with
  // anything less than 6ms.
  silence_bytes_ = format_.mBytesPerFrame * params.sample_rate * 6 / 1000;
}

PCMQueueOutAudioOutputStream::~PCMQueueOutAudioOutputStream() {
}

void PCMQueueOutAudioOutputStream::HandleError(OSStatus err) {
  // source_ can be set to NULL from another thread. We need to cache its
  // pointer while we operate here. Note that does not mean that the source
  // has been destroyed.
  AudioSourceCallback* source = source_;
  if (source)
    source->OnError(this, static_cast<int>(err));
  NOTREACHED() << "error code " << err;
}

bool PCMQueueOutAudioOutputStream::Open() {
  // Create the actual queue object and let the OS use its own thread to
  // run its CFRunLoop.
  OSStatus err = AudioQueueNewOutput(&format_, RenderCallback, this, NULL,
                                     kCFRunLoopCommonModes, 0, &audio_queue_);
  if (err != noErr) {
    HandleError(err);
    return false;
  }
  // Allocate the hardware-managed buffers.
  for (uint32 ix = 0; ix != kNumBuffers; ++ix) {
    err = AudioQueueAllocateBuffer(audio_queue_, packet_size_, &buffer_[ix]);
    if (err != noErr) {
      HandleError(err);
      return false;
    }
    // Allocate memory for user data.
    buffer_[ix]->mUserData = new AudioQueueUserData();
  }
  // Set initial volume here.
  err = AudioQueueSetParameter(audio_queue_, kAudioQueueParam_Volume, 1.0);
  if (err != noErr) {
    HandleError(err);
    return false;
  }
  return true;
}

void PCMQueueOutAudioOutputStream::Close() {
  // It is valid to call Close() before calling Open(), thus audio_queue_
  // might be NULL.
  if (audio_queue_) {
    OSStatus err = 0;
    for (uint32 ix = 0; ix != kNumBuffers; ++ix) {
      if (buffer_[ix]) {
        // Free user data.
        delete static_cast<AudioQueueUserData*>(buffer_[ix]->mUserData);
        // Free AudioQueue buffer.
        err = AudioQueueFreeBuffer(audio_queue_, buffer_[ix]);
        if (err != noErr) {
          HandleError(err);
          break;
        }
      }
    }
    err = AudioQueueDispose(audio_queue_, true);
    if (err != noErr)
      HandleError(err);
  }
  // Inform the audio manager that we have been closed. This can cause our
  // destruction.
  manager_->ReleaseOutputStream(this);
}

void PCMQueueOutAudioOutputStream::Stop() {
  // We request a synchronous stop, so the next call can take some time. In
  // the windows implementation we block here as well.
  source_ = NULL;
  // We set the source to null to signal to the data queueing thread it can stop
  // queueing data, however at most one callback might still be in flight which
  // could attempt to enqueue right after the next call. Rather that trying to
  // use a lock we rely on the internal Mac queue lock so the enqueue might
  // succeed or might fail but it won't crash or leave the queue itself in an
  // inconsistent state.
  OSStatus err = AudioQueueStop(audio_queue_, true);
  if (err != noErr)
    HandleError(err);
}

void PCMQueueOutAudioOutputStream::SetVolume(double volume) {
  if (!audio_queue_)
    return;
  volume_ = static_cast<float>(volume);
  OSStatus err = AudioQueueSetParameter(audio_queue_,
                                        kAudioQueueParam_Volume,
                                        volume);
  if (err != noErr) {
    HandleError(err);
  }
}

void PCMQueueOutAudioOutputStream::GetVolume(double* volume) {
  if (!audio_queue_)
    return;
  *volume = volume_;
}

// Reorder PCM from AAC layout to Core Audio layout.
// TODO(fbarchard): Switch layout when ffmpeg is updated.
template<class Format>
static void SwizzleLayout(Format* b, uint32 filled) {
  static const int kNumSurroundChannels = 6;
  Format aac[kNumSurroundChannels];
  for (uint32 i = 0; i < filled; i += sizeof(aac), b += kNumSurroundChannels) {
    memcpy(aac, b, sizeof(aac));
    b[0] = aac[1];  // L
    b[1] = aac[2];  // R
    b[2] = aac[0];  // C
    b[3] = aac[5];  // LFE
    b[4] = aac[3];  // Ls
    b[5] = aac[4];  // Rs
  }
}

// Note to future hackers of this function: Do not add locks here because we
// call out to third party source that might do crazy things including adquire
// external locks or somehow re-enter here because its legal for them to call
// some audio functions.
void PCMQueueOutAudioOutputStream::RenderCallback(void* p_this,
                                                  AudioQueueRef queue,
                                                  AudioQueueBufferRef buffer) {
  PCMQueueOutAudioOutputStream* audio_stream =
      static_cast<PCMQueueOutAudioOutputStream*>(p_this);
  // Call the audio source to fill the free buffer with data. Not having a
  // source means that the queue has been closed. This is not an error.
  AudioSourceCallback* source = audio_stream->source_;
  if (!source)
    return;

  // Adjust the number of pending bytes by subtracting the amount played.
  if (!static_cast<AudioQueueUserData*>(buffer->mUserData)->empty_buffer)
    audio_stream->pending_bytes_ -= buffer->mAudioDataByteSize;
  uint32 capacity = buffer->mAudioDataBytesCapacity;
  // TODO(sergeyu): Specify correct hardware delay for AudioBuffersState.
  uint32 filled = source->OnMoreData(
      audio_stream, reinterpret_cast<uint8*>(buffer->mAudioData), capacity,
      AudioBuffersState(audio_stream->pending_bytes_, 0));

  // In order to keep the callback running, we need to provide a positive amount
  // of data to the audio queue. To simulate the behavior of Windows, we write
  // a buffer of silence.
  if (!filled) {
    CHECK(audio_stream->silence_bytes_ <= static_cast<int>(capacity));
    filled = audio_stream->silence_bytes_;
    memset(buffer->mAudioData, 0, filled);
    static_cast<AudioQueueUserData*>(buffer->mUserData)->empty_buffer = true;
  } else if (filled > capacity) {
    // User probably overran our buffer.
    audio_stream->HandleError(0);
    return;
  } else {
    static_cast<AudioQueueUserData*>(buffer->mUserData)->empty_buffer = false;
  }

  // Handle channel order for 5.1 audio.
  if (audio_stream->format_.mChannelsPerFrame == 6) {
    if (audio_stream->format_.mBitsPerChannel == 8) {
      SwizzleLayout(reinterpret_cast<uint8*>(buffer->mAudioData), filled);
    } else if (audio_stream->format_.mBitsPerChannel == 16) {
      SwizzleLayout(reinterpret_cast<int16*>(buffer->mAudioData), filled);
    } else if (audio_stream->format_.mBitsPerChannel == 32) {
      SwizzleLayout(reinterpret_cast<int32*>(buffer->mAudioData), filled);
    }
  }

  buffer->mAudioDataByteSize = filled;

  // Incremnet bytes by amount filled into audio buffer if this is not a
  // silence buffer.
  if (!static_cast<AudioQueueUserData*>(buffer->mUserData)->empty_buffer)
    audio_stream->pending_bytes_ += filled;
  if (NULL == queue)
    return;
  // Queue the audio data to the audio driver.
  OSStatus err = AudioQueueEnqueueBuffer(queue, buffer, 0, NULL);
  if (err != noErr) {
    if (err == kAudioQueueErr_EnqueueDuringReset) {
      // This is the error you get if you try to enqueue a buffer and the
      // queue has been closed. Not really a problem if indeed the queue
      // has been closed.
      if (!audio_stream->source_)
        return;
    }
    audio_stream->HandleError(err);
  }
}

void PCMQueueOutAudioOutputStream::Start(AudioSourceCallback* callback) {
  DCHECK(callback);
  OSStatus err = noErr;
  source_ = callback;
  pending_bytes_ = 0;
  // Ask the source to pre-fill all our buffers before playing.
  for (uint32 ix = 0; ix != kNumBuffers; ++ix) {
    buffer_[ix]->mAudioDataByteSize = 0;
    RenderCallback(this, NULL, buffer_[ix]);
  }

  // Queue the buffers to the audio driver, sounds starts now.
  for (uint32 ix = 0; ix != kNumBuffers; ++ix) {
    err = AudioQueueEnqueueBuffer(audio_queue_, buffer_[ix], 0, NULL);
    if (err != noErr) {
      HandleError(err);
      return;
    }
  }
  err  = AudioQueueStart(audio_queue_, NULL);
  if (err != noErr) {
    HandleError(err);
    return;
  }
}
<commit_msg>Mac platform was not treating 8bit PCM audio as unsigned data.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/audio/mac/audio_output_mac.h"

#include "base/basictypes.h"
#include "base/logging.h"
#include "media/audio/audio_util.h"
#include "media/audio/mac/audio_manager_mac.h"

// A custom data structure to store information an AudioQueue buffer.
struct AudioQueueUserData {
  AudioQueueUserData() : empty_buffer(false) {}
  bool empty_buffer;
};

// Overview of operation:
// 1) An object of PCMQueueOutAudioOutputStream is created by the AudioManager
// factory: audio_man->MakeAudioStream(). This just fills some structure.
// 2) Next some thread will call Open(), at that point the underliying OS
// queue is created and the audio buffers allocated.
// 3) Then some thread will call Start(source) At this point the source will be
// called to fill the initial buffers in the context of that same thread.
// Then the OS queue is started which will create its own thread which
// periodically will call the source for more data as buffers are being
// consumed.
// 4) At some point some thread will call Stop(), which we handle by directly
// stoping the OS queue.
// 5) One more callback to the source could be delivered in in the context of
// the queue's own thread. Data, if any will be discared.
// 6) The same thread that called stop will call Close() where we cleanup
// and notifiy the audio manager, which likley will destroy this object.

#if !defined(MAC_OS_X_VERSION_10_6) || \
    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
enum {
  kAudioQueueErr_EnqueueDuringReset = -66632
};
#endif

PCMQueueOutAudioOutputStream::PCMQueueOutAudioOutputStream(
    AudioManagerMac* manager, AudioParameters params)
    : format_(),
      audio_queue_(NULL),
      buffer_(),
      source_(NULL),
      manager_(manager),
      silence_bytes_(0),
      volume_(1),
      pending_bytes_(0) {
  // We must have a manager.
  DCHECK(manager_);
  // A frame is one sample across all channels. In interleaved audio the per
  // frame fields identify the set of n |channels|. In uncompressed audio, a
  // packet is always one frame.
  format_.mSampleRate = params.sample_rate;
  format_.mFormatID = kAudioFormatLinearPCM;
  format_.mFormatFlags = kLinearPCMFormatFlagIsPacked;
  format_.mBitsPerChannel = params.bits_per_sample;
  format_.mChannelsPerFrame = params.channels;
  format_.mFramesPerPacket = 1;
  format_.mBytesPerPacket = (format_.mBitsPerChannel * params.channels) / 8;
  format_.mBytesPerFrame = format_.mBytesPerPacket;

  packet_size_ = params.GetPacketSize();

  if (params.bits_per_sample > 8) {
    format_.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
  }

  // Silence buffer has a duration of 6ms to simulate the behavior of Windows.
  // This value is choosen by experiments and macs cannot keep up with
  // anything less than 6ms.
  silence_bytes_ = format_.mBytesPerFrame * params.sample_rate * 6 / 1000;
}

PCMQueueOutAudioOutputStream::~PCMQueueOutAudioOutputStream() {
}

void PCMQueueOutAudioOutputStream::HandleError(OSStatus err) {
  // source_ can be set to NULL from another thread. We need to cache its
  // pointer while we operate here. Note that does not mean that the source
  // has been destroyed.
  AudioSourceCallback* source = source_;
  if (source)
    source->OnError(this, static_cast<int>(err));
  NOTREACHED() << "error code " << err;
}

bool PCMQueueOutAudioOutputStream::Open() {
  // Create the actual queue object and let the OS use its own thread to
  // run its CFRunLoop.
  OSStatus err = AudioQueueNewOutput(&format_, RenderCallback, this, NULL,
                                     kCFRunLoopCommonModes, 0, &audio_queue_);
  if (err != noErr) {
    HandleError(err);
    return false;
  }
  // Allocate the hardware-managed buffers.
  for (uint32 ix = 0; ix != kNumBuffers; ++ix) {
    err = AudioQueueAllocateBuffer(audio_queue_, packet_size_, &buffer_[ix]);
    if (err != noErr) {
      HandleError(err);
      return false;
    }
    // Allocate memory for user data.
    buffer_[ix]->mUserData = new AudioQueueUserData();
  }
  // Set initial volume here.
  err = AudioQueueSetParameter(audio_queue_, kAudioQueueParam_Volume, 1.0);
  if (err != noErr) {
    HandleError(err);
    return false;
  }
  return true;
}

void PCMQueueOutAudioOutputStream::Close() {
  // It is valid to call Close() before calling Open(), thus audio_queue_
  // might be NULL.
  if (audio_queue_) {
    OSStatus err = 0;
    for (uint32 ix = 0; ix != kNumBuffers; ++ix) {
      if (buffer_[ix]) {
        // Free user data.
        delete static_cast<AudioQueueUserData*>(buffer_[ix]->mUserData);
        // Free AudioQueue buffer.
        err = AudioQueueFreeBuffer(audio_queue_, buffer_[ix]);
        if (err != noErr) {
          HandleError(err);
          break;
        }
      }
    }
    err = AudioQueueDispose(audio_queue_, true);
    if (err != noErr)
      HandleError(err);
  }
  // Inform the audio manager that we have been closed. This can cause our
  // destruction.
  manager_->ReleaseOutputStream(this);
}

void PCMQueueOutAudioOutputStream::Stop() {
  // We request a synchronous stop, so the next call can take some time. In
  // the windows implementation we block here as well.
  source_ = NULL;
  // We set the source to null to signal to the data queueing thread it can stop
  // queueing data, however at most one callback might still be in flight which
  // could attempt to enqueue right after the next call. Rather that trying to
  // use a lock we rely on the internal Mac queue lock so the enqueue might
  // succeed or might fail but it won't crash or leave the queue itself in an
  // inconsistent state.
  OSStatus err = AudioQueueStop(audio_queue_, true);
  if (err != noErr)
    HandleError(err);
}

void PCMQueueOutAudioOutputStream::SetVolume(double volume) {
  if (!audio_queue_)
    return;
  volume_ = static_cast<float>(volume);
  OSStatus err = AudioQueueSetParameter(audio_queue_,
                                        kAudioQueueParam_Volume,
                                        volume);
  if (err != noErr) {
    HandleError(err);
  }
}

void PCMQueueOutAudioOutputStream::GetVolume(double* volume) {
  if (!audio_queue_)
    return;
  *volume = volume_;
}

// Reorder PCM from AAC layout to Core Audio layout.
// TODO(fbarchard): Switch layout when ffmpeg is updated.
template<class Format>
static void SwizzleLayout(Format* b, uint32 filled) {
  static const int kNumSurroundChannels = 6;
  Format aac[kNumSurroundChannels];
  for (uint32 i = 0; i < filled; i += sizeof(aac), b += kNumSurroundChannels) {
    memcpy(aac, b, sizeof(aac));
    b[0] = aac[1];  // L
    b[1] = aac[2];  // R
    b[2] = aac[0];  // C
    b[3] = aac[5];  // LFE
    b[4] = aac[3];  // Ls
    b[5] = aac[4];  // Rs
  }
}

// Note to future hackers of this function: Do not add locks here because we
// call out to third party source that might do crazy things including adquire
// external locks or somehow re-enter here because its legal for them to call
// some audio functions.
void PCMQueueOutAudioOutputStream::RenderCallback(void* p_this,
                                                  AudioQueueRef queue,
                                                  AudioQueueBufferRef buffer) {
  PCMQueueOutAudioOutputStream* audio_stream =
      static_cast<PCMQueueOutAudioOutputStream*>(p_this);
  // Call the audio source to fill the free buffer with data. Not having a
  // source means that the queue has been closed. This is not an error.
  AudioSourceCallback* source = audio_stream->source_;
  if (!source)
    return;

  // Adjust the number of pending bytes by subtracting the amount played.
  if (!static_cast<AudioQueueUserData*>(buffer->mUserData)->empty_buffer)
    audio_stream->pending_bytes_ -= buffer->mAudioDataByteSize;
  uint32 capacity = buffer->mAudioDataBytesCapacity;
  // TODO(sergeyu): Specify correct hardware delay for AudioBuffersState.
  uint32 filled = source->OnMoreData(
      audio_stream, reinterpret_cast<uint8*>(buffer->mAudioData), capacity,
      AudioBuffersState(audio_stream->pending_bytes_, 0));

  // In order to keep the callback running, we need to provide a positive amount
  // of data to the audio queue. To simulate the behavior of Windows, we write
  // a buffer of silence.
  if (!filled) {
    CHECK(audio_stream->silence_bytes_ <= static_cast<int>(capacity));
    filled = audio_stream->silence_bytes_;

    // Assume unsigned audio.
    int silence_value = 128;
    if (audio_stream->format_.mBitsPerChannel > 8) {
      // When bits per channel is greater than 8, audio is signed.
      silence_value = 0;
    }

    memset(buffer->mAudioData, silence_value, filled);
    static_cast<AudioQueueUserData*>(buffer->mUserData)->empty_buffer = true;
  } else if (filled > capacity) {
    // User probably overran our buffer.
    audio_stream->HandleError(0);
    return;
  } else {
    static_cast<AudioQueueUserData*>(buffer->mUserData)->empty_buffer = false;
  }

  // Handle channel order for 5.1 audio.
  if (audio_stream->format_.mChannelsPerFrame == 6) {
    if (audio_stream->format_.mBitsPerChannel == 8) {
      SwizzleLayout(reinterpret_cast<uint8*>(buffer->mAudioData), filled);
    } else if (audio_stream->format_.mBitsPerChannel == 16) {
      SwizzleLayout(reinterpret_cast<int16*>(buffer->mAudioData), filled);
    } else if (audio_stream->format_.mBitsPerChannel == 32) {
      SwizzleLayout(reinterpret_cast<int32*>(buffer->mAudioData), filled);
    }
  }

  buffer->mAudioDataByteSize = filled;

  // Increment bytes by amount filled into audio buffer if this is not a
  // silence buffer.
  if (!static_cast<AudioQueueUserData*>(buffer->mUserData)->empty_buffer)
    audio_stream->pending_bytes_ += filled;
  if (NULL == queue)
    return;
  // Queue the audio data to the audio driver.
  OSStatus err = AudioQueueEnqueueBuffer(queue, buffer, 0, NULL);
  if (err != noErr) {
    if (err == kAudioQueueErr_EnqueueDuringReset) {
      // This is the error you get if you try to enqueue a buffer and the
      // queue has been closed. Not really a problem if indeed the queue
      // has been closed.
      if (!audio_stream->source_)
        return;
    }
    audio_stream->HandleError(err);
  }
}

void PCMQueueOutAudioOutputStream::Start(AudioSourceCallback* callback) {
  DCHECK(callback);
  OSStatus err = noErr;
  source_ = callback;
  pending_bytes_ = 0;
  // Ask the source to pre-fill all our buffers before playing.
  for (uint32 ix = 0; ix != kNumBuffers; ++ix) {
    buffer_[ix]->mAudioDataByteSize = 0;
    RenderCallback(this, NULL, buffer_[ix]);
  }

  // Queue the buffers to the audio driver, sounds starts now.
  for (uint32 ix = 0; ix != kNumBuffers; ++ix) {
    err = AudioQueueEnqueueBuffer(audio_queue_, buffer_[ix], 0, NULL);
    if (err != noErr) {
      HandleError(err);
      return;
    }
  }
  err  = AudioQueueStart(audio_queue_, NULL);
  if (err != noErr) {
    HandleError(err);
    return;
  }
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
#ifndef ATOMIC_HH
#define ATOMIC_HH

#include <pthread.h>
#include <queue>
#include <sched.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>

#include "callbacks.hh"
#include "locks.hh"

#define MAX_THREADS 100

#if defined(HAVE_GCC_ATOMICS)
#include "atomic/gcc_atomics.h"
#elif defined(HAVE_ATOMIC_H)
#include "atomic/libatomic.h"
#else
#error "Don't know how to use atomics on your target system!"
#endif

extern "C" {
   typedef void (*ThreadLocalDestructor)(void *);
}

/**
 * Container of thread-local data.
 */
template<typename T>
class ThreadLocal {
public:
    ThreadLocal(ThreadLocalDestructor destructor = NULL) {
        int rc = pthread_key_create(&key, destructor);
        if (rc != 0) {
            fprintf(stderr, "Failed to create a thread-specific key: %s\n", strerror(rc));
            abort();
        }
    }

    ~ThreadLocal() {
        pthread_key_delete(key);
    }

    void set(const T &newValue) {
        int rc = pthread_setspecific(key, newValue);
        if (rc != 0) {
            std::stringstream ss;
            ss << "Failed to store thread specific value: " << strerror(rc);
            throw std::runtime_error(ss.str().c_str());
        }
    }

    T get() const {
        return reinterpret_cast<T>(pthread_getspecific(key));
    }

    void operator =(const T &newValue) {
        set(newValue);
    }

    operator T() const {
        return get();
    }

private:
    pthread_key_t key;
};

 /**
  * Container for a thread-local pointer.
  */
template <typename T>
class ThreadLocalPtr : public ThreadLocal<T*> {
public:
    ThreadLocalPtr(ThreadLocalDestructor destructor = NULL) : ThreadLocal<T*>(destructor) {}

    ~ThreadLocalPtr() {}

    T *operator ->() {
        return ThreadLocal<T*>::get();
    }

    T operator *() {
        return *ThreadLocal<T*>::get();
    }

    void operator =(T *newValue) {
        set(newValue);
    }
};

/**
 * Holder of atomic values.
 */
template <typename T>
class Atomic {
public:

    Atomic(const T &initial = 0) {
        set(initial);
    }

    ~Atomic() {}

    T get() const {
        return value;
    }

    void set(const T &newValue) {
        value = newValue;
        ep_sync_synchronize();
    }

    operator T() const {
        return get();
    }

    void operator =(const T &newValue) {
        set(newValue);
    }

    bool cas(const T &oldValue, const T &newValue) {
        return ep_sync_bool_compare_and_swap(&value, oldValue, newValue);
    }

    T operator ++() { // prefix
        return ep_sync_add_and_fetch(&value, 1);
    }

    T operator ++(int) { // postfix
        return ep_sync_fetch_and_add(&value, 1);
    }

    T operator --() { // prefix
        return ep_sync_add_and_fetch(&value, -1);
    }

    T operator --(int) { // postfix
        return ep_sync_fetch_and_add(&value, -1);
    }

    T operator +=(T increment) {
        // Returns the new value
        return ep_sync_add_and_fetch(&value, increment);
    }

    T operator -=(T decrement) {
        return ep_sync_add_and_fetch(&value, -decrement);
    }

    T incr(const T &increment) {
        // Returns the old value
        return ep_sync_fetch_and_add(&value, increment);
    }

    T decr(const T &decrement) {
        return ep_sync_add_and_fetch(&value, -decrement);
    }

    T swap(const T &newValue) {
        T rv;
        while (true) {
            rv = get();
            if (cas(rv, newValue)) {
                break;
            }
        }
        return rv;
    }

    T swapIfNot(const T &badValue, const T &newValue) {
        T oldValue;
        while (true) {
            oldValue = get();
            if (oldValue != badValue) {
                if (cas(oldValue, newValue)) {
                    break;
                }
            } else {
                break;
            }
        }
        return oldValue;
    }

   void setIfLess(const T &newValue) {
      T oldValue = get();

      while (newValue < oldValue) {
         if (cas(oldValue, newValue)) {
            break;
         }
         oldValue = get();
      }
   }

   void setIfBigger(const T &newValue) {
      T oldValue = get();

      while (newValue > oldValue) {
         if (cas(oldValue, newValue)) {
            break;
         }
         oldValue = get();
      }
   }

private:
    volatile T value;
};

/**
 * Atomic pointer.
 *
 * This does *not* make the item that's pointed to atomic.
 */
template <typename T>
class AtomicPtr : public Atomic<T*> {
public:
    AtomicPtr(T *initial = NULL) : Atomic<T*>(initial) {}

    ~AtomicPtr() {}

    T *operator ->() {
        return Atomic<T*>::get();
    }

    T &operator *() {
        return *Atomic<T*>::get();
    }

    operator bool() const {
        return Atomic<T*>::get() != NULL;
    }

    bool operator !() const {
        return  Atomic<T*>::get() == NULL;
    }
};

/**
 * A lighter-weight, smaller lock than a mutex.
 *
 * This is primarily useful when contention is rare.
 */
class SpinLock {
public:
    // It seems like inlining the code caused the dtrace probe to
    // be optimized away ;)
    SpinLock();
    ~SpinLock();

    void acquire(void);
    void release(void);

private:
    bool tryAcquire() {
       return ep_sync_lock_test_and_set(&lock, 1) == 0;
    }

    volatile int lock;
    DISALLOW_COPY_AND_ASSIGN(SpinLock);
};

/**
 * Safe LockHolder for SpinLock instances.
 */
class SpinLockHolder {
public:
    SpinLockHolder(SpinLock *theLock) : sl(theLock) {
        lock();
    }

    ~SpinLockHolder() {
        unlock();
    }

    void lock() {
        sl->acquire();
        locked = true;
    }

    void unlock() {
        if (locked) {
            sl->release();
            locked = false;
        }
    }
private:
    SpinLock *sl;
    bool locked;
};

template <class T> class RCPtr;
template <class S> class SingleThreadedRCPtr;

/**
 * A reference counted value (used by RCPtr and SingleThreadedRCPtr).
 */
class RCValue {
public:
    RCValue() : _rc_refcount(0) {}
    RCValue(const RCValue &) : _rc_refcount(0) {}
    ~RCValue() {}
private:
    template <class MyTT> friend class RCPtr;
    template <class MySS> friend class SingleThreadedRCPtr;
    int _rc_incref() const {
        return ++_rc_refcount;
    }

    int _rc_decref() const {
        return --_rc_refcount;
    }

    mutable Atomic<int> _rc_refcount;
};

/**
 * Concurrent reference counted pointer.
 */
template <class C>
class RCPtr {
public:
    RCPtr(C *init = NULL) : value(init) {
        if (init != NULL) {
            static_cast<RCValue*>(value)->_rc_incref();
        }
    }

    RCPtr(const RCPtr<C> &other) : value(other.gimme()) {}

    ~RCPtr() {
        if (value && static_cast<RCValue *>(value)->_rc_decref() == 0) {
            delete value;
        }
    }

    void reset(C *newValue = NULL) {
        if (newValue != NULL) {
            static_cast<RCValue *>(newValue)->_rc_incref();
        }
        swap(newValue);
    }

    void reset(const RCPtr<C> &other) {
        swap(other.gimme());
    }

    bool cas(RCPtr<C> &oldValue, RCPtr<C> &newValue) {
        SpinLockHolder lh(&lock);
        if (value == oldValue.get()) {
            C *tmp = value;
            value = newValue.gimme();
            if (tmp != NULL &&
                static_cast<RCValue *>(tmp)->_rc_decref() == 0) {
                lh.unlock();
                delete tmp;
            }
            return true;
        }
        return false;
    }

    // safe for the lifetime of this instance
    C *get() const {
        return value;
    }

    RCPtr<C> & operator =(const RCPtr<C> &other) {
        reset(other);
        return *this;
    }

    C &operator *() const {
        return *value;
    }

    C *operator ->() const {
        return value;
    }

    bool operator! () const {
        return !value;
    }

    operator bool () const {
        return (bool)value;
    }

private:
    C *gimme() const {
        SpinLockHolder lh(&lock);
        if (value) {
            static_cast<RCValue *>(value)->_rc_incref();
        }
        return value;
    }

    void swap(C *newValue) {
        SpinLockHolder lh(&lock);
        C *tmp(value.swap(newValue));
        lh.unlock();
        if (tmp != NULL && static_cast<RCValue *>(tmp)->_rc_decref() == 0) {
            delete tmp;
        }
    }

    AtomicPtr<C> value;
    mutable SpinLock lock; // exists solely for the purpose of implementing reset() safely
};

/**
 * Single-threaded reference counted pointer.
 * "Single-threaded" means that the reference counted pointer should be accessed
 * by only one thread at any time or accesses to the reference counted pointer
 * by multiple threads should be synchronized by the external lock.
 */
template <class T>
class SingleThreadedRCPtr {
public:
    SingleThreadedRCPtr(T *init = NULL) : value(init) {
        if (init != NULL) {
            static_cast<RCValue*>(value)->_rc_incref();
        }
    }

    SingleThreadedRCPtr(const SingleThreadedRCPtr<T> &other) : value(other.gimme()) {}

    ~SingleThreadedRCPtr() {
        if (value && static_cast<RCValue *>(value)->_rc_decref() == 0) {
            delete value;
        }
    }

    void reset(T *newValue = NULL) {
        if (newValue != NULL) {
            static_cast<RCValue *>(newValue)->_rc_incref();
        }
        swap(newValue);
    }

    void reset(const SingleThreadedRCPtr<T> &other) {
        swap(other.gimme());
    }

    // safe for the lifetime of this instance
    T *get() const {
        return value;
    }

    SingleThreadedRCPtr<T> & operator =(const SingleThreadedRCPtr<T> &other) {
        reset(other);
        return *this;
    }

    T &operator *() const {
        return *value;
    }

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

    bool operator! () const {
        return !value;
    }

    operator bool () const {
        return (bool)value;
    }

private:
    T *gimme() const {
        if (value) {
            static_cast<RCValue *>(value)->_rc_incref();
        }
        return value;
    }

    void swap(T *newValue) {
        T *old = value;
        value = newValue;
        if (old != NULL && static_cast<RCValue *>(old)->_rc_decref() == 0) {
            delete old;
        }
    }

    T *value;
};

/**
 * Efficient approximate-FIFO queue optimize for concurrent writers.
 */
template <typename T>
class AtomicQueue {
public:
    AtomicQueue() : counter(0), numItems(0) {}

    ~AtomicQueue() {
        size_t i;
        for (i = 0; i < counter; ++i) {
            delete queues[i];
        }
    }

    /**
     * Place an item in the queue.
     */
    void push(T &value) {
        std::queue<T> *q = swapQueue(); // steal our queue
        q->push(value);
        ++numItems;
        q = swapQueue(q);
    }

    void pushQueue(std::queue<T> &inQueue) {
        std::queue<T> *q = swapQueue(); // steal our queue
        numItems.incr(inQueue.size());
        while (!inQueue.empty()) {
            q->push(inQueue.front());
            inQueue.pop();
        }
        q = swapQueue(q);
    }

    /**
     * Grab all items from this queue an place them into the provided
     * output queue.
     *
     * @param outQueue a destination queue to fill
     */
    void getAll(std::queue<T> &outQueue) {
        std::queue<T> *q(swapQueue()); // Grab my own queue
        std::queue<T> *newQueue(NULL);
        int count(0);

        // Will start empty unless this thread is adding stuff
        while (!q->empty()) {
            outQueue.push(q->front());
            q->pop();
            ++count;
        }

        size_t c(counter);
        for (size_t i = 0; i < c; ++i) {
            // Swap with another thread
            newQueue = queues[i].swapIfNot(NULL, q);
            // Empty the queue
            if (newQueue != NULL) {
                q = newQueue;
                while (!q->empty()) {
                    outQueue.push(q->front());
                    q->pop();
                    ++count;
                }
            }
        }

        q = swapQueue(q);
        numItems -= count;
    }

    /**
     * Pop all the items from this queue and put them into the output vector instance.
     *
     * @param outVector a destination vector to fill
     */
    void toArray(std::vector<T> &outVector) {
        std::queue<T> q;
        getAll(q);
        while (!q.empty()) {
            outVector.push_back(q.front());
            q.pop();
        }
    }

    /**
     * Get the number of queues internally maintained.
     */
    size_t getNumQueues() const {
        return counter;
    }

    /**
     * True if this queue is empty.
     */
    bool empty() const {
        return size() == 0;
    }

    /**
     * Return the number of queued items.
     */
    size_t size() const {
        return numItems;
    }
private:
    AtomicPtr<std::queue<T> > *initialize() {
        std::queue<T> *q = new std::queue<T>;
        size_t i(counter++);
        queues[i] = q;
        threadQueue = &queues[i];
        return &queues[i];
    }

    std::queue<T> *swapQueue(std::queue<T> *newQueue = NULL) {
        AtomicPtr<std::queue<T> > *qPtr(threadQueue);
        if (qPtr == NULL) {
            qPtr = initialize();
        }
        return qPtr->swap(newQueue);
    }

    ThreadLocalPtr<AtomicPtr<std::queue<T> > > threadQueue;
    AtomicPtr<std::queue<T> > queues[MAX_THREADS];
    Atomic<size_t> counter;
    Atomic<size_t> numItems;
    DISALLOW_COPY_AND_ASSIGN(AtomicQueue);
};

#endif // ATOMIC_HH
<commit_msg>MB-100 Fix compilation on gcc 4.8.<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
#ifndef ATOMIC_HH
#define ATOMIC_HH

#include <pthread.h>
#include <queue>
#include <sched.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>

#include "callbacks.hh"
#include "locks.hh"

#define MAX_THREADS 100

#if defined(HAVE_GCC_ATOMICS)
#include "atomic/gcc_atomics.h"
#elif defined(HAVE_ATOMIC_H)
#include "atomic/libatomic.h"
#else
#error "Don't know how to use atomics on your target system!"
#endif

extern "C" {
   typedef void (*ThreadLocalDestructor)(void *);
}

/**
 * Container of thread-local data.
 */
template<typename T>
class ThreadLocal {
public:
    ThreadLocal(ThreadLocalDestructor destructor = NULL) {
        int rc = pthread_key_create(&key, destructor);
        if (rc != 0) {
            fprintf(stderr, "Failed to create a thread-specific key: %s\n", strerror(rc));
            abort();
        }
    }

    ~ThreadLocal() {
        pthread_key_delete(key);
    }

    void set(const T &newValue) {
        int rc = pthread_setspecific(key, newValue);
        if (rc != 0) {
            std::stringstream ss;
            ss << "Failed to store thread specific value: " << strerror(rc);
            throw std::runtime_error(ss.str().c_str());
        }
    }

    T get() const {
        return reinterpret_cast<T>(pthread_getspecific(key));
    }

    void operator =(const T &newValue) {
        set(newValue);
    }

    operator T() const {
        return get();
    }

private:
    pthread_key_t key;
};

 /**
  * Container for a thread-local pointer.
  */
template <typename T>
class ThreadLocalPtr : public ThreadLocal<T*> {
public:
    ThreadLocalPtr(ThreadLocalDestructor destructor = NULL) : ThreadLocal<T*>(destructor) {}

    ~ThreadLocalPtr() {}

    T *operator ->() {
        return ThreadLocal<T*>::get();
    }

    T operator *() {
        return *ThreadLocal<T*>::get();
    }

    void operator =(T *newValue) {
        this->set(newValue);
    }
};

/**
 * Holder of atomic values.
 */
template <typename T>
class Atomic {
public:

    Atomic(const T &initial = 0) {
        set(initial);
    }

    ~Atomic() {}

    T get() const {
        return value;
    }

    void set(const T &newValue) {
        value = newValue;
        ep_sync_synchronize();
    }

    operator T() const {
        return get();
    }

    void operator =(const T &newValue) {
        set(newValue);
    }

    bool cas(const T &oldValue, const T &newValue) {
        return ep_sync_bool_compare_and_swap(&value, oldValue, newValue);
    }

    T operator ++() { // prefix
        return ep_sync_add_and_fetch(&value, 1);
    }

    T operator ++(int) { // postfix
        return ep_sync_fetch_and_add(&value, 1);
    }

    T operator --() { // prefix
        return ep_sync_add_and_fetch(&value, -1);
    }

    T operator --(int) { // postfix
        return ep_sync_fetch_and_add(&value, -1);
    }

    T operator +=(T increment) {
        // Returns the new value
        return ep_sync_add_and_fetch(&value, increment);
    }

    T operator -=(T decrement) {
        return ep_sync_add_and_fetch(&value, -decrement);
    }

    T incr(const T &increment) {
        // Returns the old value
        return ep_sync_fetch_and_add(&value, increment);
    }

    T decr(const T &decrement) {
        return ep_sync_add_and_fetch(&value, -decrement);
    }

    T swap(const T &newValue) {
        T rv;
        while (true) {
            rv = get();
            if (cas(rv, newValue)) {
                break;
            }
        }
        return rv;
    }

    T swapIfNot(const T &badValue, const T &newValue) {
        T oldValue;
        while (true) {
            oldValue = get();
            if (oldValue != badValue) {
                if (cas(oldValue, newValue)) {
                    break;
                }
            } else {
                break;
            }
        }
        return oldValue;
    }

   void setIfLess(const T &newValue) {
      T oldValue = get();

      while (newValue < oldValue) {
         if (cas(oldValue, newValue)) {
            break;
         }
         oldValue = get();
      }
   }

   void setIfBigger(const T &newValue) {
      T oldValue = get();

      while (newValue > oldValue) {
         if (cas(oldValue, newValue)) {
            break;
         }
         oldValue = get();
      }
   }

private:
    volatile T value;
};

/**
 * Atomic pointer.
 *
 * This does *not* make the item that's pointed to atomic.
 */
template <typename T>
class AtomicPtr : public Atomic<T*> {
public:
    AtomicPtr(T *initial = NULL) : Atomic<T*>(initial) {}

    ~AtomicPtr() {}

    T *operator ->() {
        return Atomic<T*>::get();
    }

    T &operator *() {
        return *Atomic<T*>::get();
    }

    operator bool() const {
        return Atomic<T*>::get() != NULL;
    }

    bool operator !() const {
        return  Atomic<T*>::get() == NULL;
    }
};

/**
 * A lighter-weight, smaller lock than a mutex.
 *
 * This is primarily useful when contention is rare.
 */
class SpinLock {
public:
    // It seems like inlining the code caused the dtrace probe to
    // be optimized away ;)
    SpinLock();
    ~SpinLock();

    void acquire(void);
    void release(void);

private:
    bool tryAcquire() {
       return ep_sync_lock_test_and_set(&lock, 1) == 0;
    }

    volatile int lock;
    DISALLOW_COPY_AND_ASSIGN(SpinLock);
};

/**
 * Safe LockHolder for SpinLock instances.
 */
class SpinLockHolder {
public:
    SpinLockHolder(SpinLock *theLock) : sl(theLock) {
        lock();
    }

    ~SpinLockHolder() {
        unlock();
    }

    void lock() {
        sl->acquire();
        locked = true;
    }

    void unlock() {
        if (locked) {
            sl->release();
            locked = false;
        }
    }
private:
    SpinLock *sl;
    bool locked;
};

template <class T> class RCPtr;
template <class S> class SingleThreadedRCPtr;

/**
 * A reference counted value (used by RCPtr and SingleThreadedRCPtr).
 */
class RCValue {
public:
    RCValue() : _rc_refcount(0) {}
    RCValue(const RCValue &) : _rc_refcount(0) {}
    ~RCValue() {}
private:
    template <class MyTT> friend class RCPtr;
    template <class MySS> friend class SingleThreadedRCPtr;
    int _rc_incref() const {
        return ++_rc_refcount;
    }

    int _rc_decref() const {
        return --_rc_refcount;
    }

    mutable Atomic<int> _rc_refcount;
};

/**
 * Concurrent reference counted pointer.
 */
template <class C>
class RCPtr {
public:
    RCPtr(C *init = NULL) : value(init) {
        if (init != NULL) {
            static_cast<RCValue*>(value)->_rc_incref();
        }
    }

    RCPtr(const RCPtr<C> &other) : value(other.gimme()) {}

    ~RCPtr() {
        if (value && static_cast<RCValue *>(value)->_rc_decref() == 0) {
            delete value;
        }
    }

    void reset(C *newValue = NULL) {
        if (newValue != NULL) {
            static_cast<RCValue *>(newValue)->_rc_incref();
        }
        swap(newValue);
    }

    void reset(const RCPtr<C> &other) {
        swap(other.gimme());
    }

    bool cas(RCPtr<C> &oldValue, RCPtr<C> &newValue) {
        SpinLockHolder lh(&lock);
        if (value == oldValue.get()) {
            C *tmp = value;
            value = newValue.gimme();
            if (tmp != NULL &&
                static_cast<RCValue *>(tmp)->_rc_decref() == 0) {
                lh.unlock();
                delete tmp;
            }
            return true;
        }
        return false;
    }

    // safe for the lifetime of this instance
    C *get() const {
        return value;
    }

    RCPtr<C> & operator =(const RCPtr<C> &other) {
        reset(other);
        return *this;
    }

    C &operator *() const {
        return *value;
    }

    C *operator ->() const {
        return value;
    }

    bool operator! () const {
        return !value;
    }

    operator bool () const {
        return (bool)value;
    }

private:
    C *gimme() const {
        SpinLockHolder lh(&lock);
        if (value) {
            static_cast<RCValue *>(value)->_rc_incref();
        }
        return value;
    }

    void swap(C *newValue) {
        SpinLockHolder lh(&lock);
        C *tmp(value.swap(newValue));
        lh.unlock();
        if (tmp != NULL && static_cast<RCValue *>(tmp)->_rc_decref() == 0) {
            delete tmp;
        }
    }

    AtomicPtr<C> value;
    mutable SpinLock lock; // exists solely for the purpose of implementing reset() safely
};

/**
 * Single-threaded reference counted pointer.
 * "Single-threaded" means that the reference counted pointer should be accessed
 * by only one thread at any time or accesses to the reference counted pointer
 * by multiple threads should be synchronized by the external lock.
 */
template <class T>
class SingleThreadedRCPtr {
public:
    SingleThreadedRCPtr(T *init = NULL) : value(init) {
        if (init != NULL) {
            static_cast<RCValue*>(value)->_rc_incref();
        }
    }

    SingleThreadedRCPtr(const SingleThreadedRCPtr<T> &other) : value(other.gimme()) {}

    ~SingleThreadedRCPtr() {
        if (value && static_cast<RCValue *>(value)->_rc_decref() == 0) {
            delete value;
        }
    }

    void reset(T *newValue = NULL) {
        if (newValue != NULL) {
            static_cast<RCValue *>(newValue)->_rc_incref();
        }
        swap(newValue);
    }

    void reset(const SingleThreadedRCPtr<T> &other) {
        swap(other.gimme());
    }

    // safe for the lifetime of this instance
    T *get() const {
        return value;
    }

    SingleThreadedRCPtr<T> & operator =(const SingleThreadedRCPtr<T> &other) {
        reset(other);
        return *this;
    }

    T &operator *() const {
        return *value;
    }

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

    bool operator! () const {
        return !value;
    }

    operator bool () const {
        return (bool)value;
    }

private:
    T *gimme() const {
        if (value) {
            static_cast<RCValue *>(value)->_rc_incref();
        }
        return value;
    }

    void swap(T *newValue) {
        T *old = value;
        value = newValue;
        if (old != NULL && static_cast<RCValue *>(old)->_rc_decref() == 0) {
            delete old;
        }
    }

    T *value;
};

/**
 * Efficient approximate-FIFO queue optimize for concurrent writers.
 */
template <typename T>
class AtomicQueue {
public:
    AtomicQueue() : counter(0), numItems(0) {}

    ~AtomicQueue() {
        size_t i;
        for (i = 0; i < counter; ++i) {
            delete queues[i];
        }
    }

    /**
     * Place an item in the queue.
     */
    void push(T &value) {
        std::queue<T> *q = swapQueue(); // steal our queue
        q->push(value);
        ++numItems;
        q = swapQueue(q);
    }

    void pushQueue(std::queue<T> &inQueue) {
        std::queue<T> *q = swapQueue(); // steal our queue
        numItems.incr(inQueue.size());
        while (!inQueue.empty()) {
            q->push(inQueue.front());
            inQueue.pop();
        }
        q = swapQueue(q);
    }

    /**
     * Grab all items from this queue an place them into the provided
     * output queue.
     *
     * @param outQueue a destination queue to fill
     */
    void getAll(std::queue<T> &outQueue) {
        std::queue<T> *q(swapQueue()); // Grab my own queue
        std::queue<T> *newQueue(NULL);
        int count(0);

        // Will start empty unless this thread is adding stuff
        while (!q->empty()) {
            outQueue.push(q->front());
            q->pop();
            ++count;
        }

        size_t c(counter);
        for (size_t i = 0; i < c; ++i) {
            // Swap with another thread
            newQueue = queues[i].swapIfNot(NULL, q);
            // Empty the queue
            if (newQueue != NULL) {
                q = newQueue;
                while (!q->empty()) {
                    outQueue.push(q->front());
                    q->pop();
                    ++count;
                }
            }
        }

        q = swapQueue(q);
        numItems -= count;
    }

    /**
     * Pop all the items from this queue and put them into the output vector instance.
     *
     * @param outVector a destination vector to fill
     */
    void toArray(std::vector<T> &outVector) {
        std::queue<T> q;
        getAll(q);
        while (!q.empty()) {
            outVector.push_back(q.front());
            q.pop();
        }
    }

    /**
     * Get the number of queues internally maintained.
     */
    size_t getNumQueues() const {
        return counter;
    }

    /**
     * True if this queue is empty.
     */
    bool empty() const {
        return size() == 0;
    }

    /**
     * Return the number of queued items.
     */
    size_t size() const {
        return numItems;
    }
private:
    AtomicPtr<std::queue<T> > *initialize() {
        std::queue<T> *q = new std::queue<T>;
        size_t i(counter++);
        queues[i] = q;
        threadQueue = &queues[i];
        return &queues[i];
    }

    std::queue<T> *swapQueue(std::queue<T> *newQueue = NULL) {
        AtomicPtr<std::queue<T> > *qPtr(threadQueue);
        if (qPtr == NULL) {
            qPtr = initialize();
        }
        return qPtr->swap(newQueue);
    }

    ThreadLocalPtr<AtomicPtr<std::queue<T> > > threadQueue;
    AtomicPtr<std::queue<T> > queues[MAX_THREADS];
    Atomic<size_t> counter;
    Atomic<size_t> numItems;
    DISALLOW_COPY_AND_ASSIGN(AtomicQueue);
};

#endif // ATOMIC_HH
<|endoftext|>


<commit_before>/* FasTC
 * Copyright (c) 2014 University of North Carolina at Chapel Hill.
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for educational, research, and non-profit purposes, without
 * fee, and without a written agreement is hereby granted, provided that the
 * above copyright notice, this paragraph, and the following four paragraphs
 * appear in all copies.
 *
 * Permission to incorporate this software into commercial products may be
 * obtained by contacting the authors or the Office of Technology Development
 * at the University of North Carolina at Chapel Hill <otd@unc.edu>.
 *
 * This software program and documentation are copyrighted by the University of
 * North Carolina at Chapel Hill. The software program and documentation are
 * supplied "as is," without any accompanying services from the University of
 * North Carolina at Chapel Hill or the authors. The University of North
 * Carolina at Chapel Hill and the authors do not warrant that the operation of
 * the program will be uninterrupted or error-free. The end-user understands
 * that the program was developed for research purposes and is advised not to
 * rely exclusively on the program for any reason.
 *
 * IN NO EVENT SHALL THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL OR THE
 * AUTHORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL,
 * OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF
 * THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF NORTH CAROLINA
 * AT CHAPEL HILL OR THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 * THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL AND THE AUTHORS SPECIFICALLY
 * DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AND ANY
 * STATUTORY WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE PROVIDED HEREUNDER IS ON
 * AN "AS IS" BASIS, AND THE UNIVERSITY  OF NORTH CAROLINA AT CHAPEL HILL AND
 * THE AUTHORS HAVE NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
 * ENHANCEMENTS, OR MODIFICATIONS.
 *
 * Please send all BUG REPORTS to <pavel@cs.unc.edu>.
 *
 * The authors may be contacted via:
 *
 * Pavel Krajcevski
 * Dept of Computer Science
 * 201 S Columbia St
 * Frederick P. Brooks, Jr. Computer Science Bldg
 * Chapel Hill, NC 27599-3175
 * USA
 *
 * <http://gamma.cs.unc.edu/FasTC/>
 */

#include "ImageWriterKTX.h"

#include <cstdlib>
#include <cstdio>
#include <cstring>

#include "Image.h"
#include "Pixel.h"

#include "CompressedImage.h"
#include "GLDefines.h"

ImageWriterKTX::ImageWriterKTX(FasTC::Image<> &im)
  : ImageWriter(im.GetWidth(), im.GetHeight(), NULL)
  , m_Image(im)
{ }

class ByteWriter {
 private:
  uint8 *m_Head;
  uint32 m_BytesWritten;
 public:
  ByteWriter(uint8 *dst) : m_Head(dst), m_BytesWritten(0) { }

  uint32 GetBytesWritten() const { return m_BytesWritten; }

  void Write(const uint32 v) {
    memcpy(m_Head, &v, 4);
    m_Head += 4;
    m_BytesWritten += 4;
  }

  void Write(const void *src, const uint32 nBytes) {
    memcpy(m_Head, src, nBytes);
    m_Head += nBytes;
    m_BytesWritten += nBytes;
  }
};

bool ImageWriterKTX::WriteImage() {
  ByteWriter wtr (m_RawFileData);

  const uint8 kIdentifier[12] = {
    0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A
  };
  wtr.Write(kIdentifier, 12);
  wtr.Write(0x04030201);

  const char *orientationKey = "KTXorientation";
  const char *orientationValue = "S=r,T=u";
  const uint32 kvSz =
    strlen(orientationKey) + 1 // key
    + strlen(orientationValue) + 1; // value
  uint32 tkvSz = kvSz + 4; // total kv size
  tkvSz = (tkvSz + 3) & ~0x3; // 4-byte aligned

  CompressedImage *ci = dynamic_cast<CompressedImage *>(&m_Image);
  if(ci && ci->GetFormat() == FasTC::eCompressionFormat_BPTC) {
    wtr.Write(0);  // glType
    wtr.Write(1);  // glTypeSize
    wtr.Write(GL_RGBA);  // glFormat
    wtr.Write(GL_COMPRESSED_RGBA_BPTC_UNORM);  // glInternalFormat
    wtr.Write(GL_RGBA);  // glBaseFormat
  } else {
    wtr.Write(GL_BYTE);  // glType
    wtr.Write(1);  // glTypeSize
    wtr.Write(GL_RGBA);  // glFormat
    wtr.Write(GL_RGBA8);  // glInternalFormat
    wtr.Write(GL_RGBA);  // glBaseFormat
  }

  wtr.Write(m_Width);  // pixelWidth
  wtr.Write(m_Height); // pixelHeight
  wtr.Write(0);        // pixelDepth
  wtr.Write(0);        // numberOfArrayElements
  wtr.Write(1);        // numberOfFaces
  wtr.Write(1);        // numberOfMipmapLevels
  wtr.Write(tkvSz);    // total key value size
  wtr.Write(kvSz);     // key value size
  wtr.Write(orientationKey, strlen(orientationKey) + 1); // key
  wtr.Write(orientationValue, strlen(orientationValue) + 1); // value
  wtr.Write(orientationKey, tkvSz - kvSz); // padding

  if(ci && ci->GetFormat() == FasTC::eCompressionFormat_BPTC) {
    static const uint32 kImageSize = m_Width * m_Height;
    wtr.Write(kImageSize); // imageSize
    wtr.Write(ci->GetCompressedData(), kImageSize); // imagedata...
  } else {
    static const uint32 kImageSize = m_Width * m_Height * 4;
    wtr.Write(kImageSize); // imageSize
    wtr.Write(m_Image.GetPixels(), kImageSize); // imagedata...
  }

  m_RawFileDataSz = wtr.GetBytesWritten();
  return true;
}
<commit_msg>Add growable buffer to support dynamic ktx file sizes.<commit_after>/* FasTC
 * Copyright (c) 2014 University of North Carolina at Chapel Hill.
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for educational, research, and non-profit purposes, without
 * fee, and without a written agreement is hereby granted, provided that the
 * above copyright notice, this paragraph, and the following four paragraphs
 * appear in all copies.
 *
 * Permission to incorporate this software into commercial products may be
 * obtained by contacting the authors or the Office of Technology Development
 * at the University of North Carolina at Chapel Hill <otd@unc.edu>.
 *
 * This software program and documentation are copyrighted by the University of
 * North Carolina at Chapel Hill. The software program and documentation are
 * supplied "as is," without any accompanying services from the University of
 * North Carolina at Chapel Hill or the authors. The University of North
 * Carolina at Chapel Hill and the authors do not warrant that the operation of
 * the program will be uninterrupted or error-free. The end-user understands
 * that the program was developed for research purposes and is advised not to
 * rely exclusively on the program for any reason.
 *
 * IN NO EVENT SHALL THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL OR THE
 * AUTHORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL,
 * OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF
 * THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF NORTH CAROLINA
 * AT CHAPEL HILL OR THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 * THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL AND THE AUTHORS SPECIFICALLY
 * DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AND ANY
 * STATUTORY WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE PROVIDED HEREUNDER IS ON
 * AN "AS IS" BASIS, AND THE UNIVERSITY  OF NORTH CAROLINA AT CHAPEL HILL AND
 * THE AUTHORS HAVE NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
 * ENHANCEMENTS, OR MODIFICATIONS.
 *
 * Please send all BUG REPORTS to <pavel@cs.unc.edu>.
 *
 * The authors may be contacted via:
 *
 * Pavel Krajcevski
 * Dept of Computer Science
 * 201 S Columbia St
 * Frederick P. Brooks, Jr. Computer Science Bldg
 * Chapel Hill, NC 27599-3175
 * USA
 *
 * <http://gamma.cs.unc.edu/FasTC/>
 */

#include "ImageWriterKTX.h"

#include <cstdlib>
#include <cstdio>
#include <cstring>

#include "Image.h"
#include "Pixel.h"

#include "CompressedImage.h"
#include "GLDefines.h"

ImageWriterKTX::ImageWriterKTX(FasTC::Image<> &im)
  : ImageWriter(im.GetWidth(), im.GetHeight(), NULL)
  , m_Image(im)
{ }

class ByteWriter {
 private:
  uint8 *m_Base;
  uint8 *m_Head;
  uint32 m_BytesWritten;
  uint32 m_BufferSz;
 public:
  ByteWriter(uint8 *dst, uint32 sz)
  : m_Base(dst), m_Head(dst), m_BytesWritten(0), m_BufferSz(dst? sz : 0) { }

  uint8 *GetBytes() const { return m_Base; }
  uint32 GetBytesWritten() const { return m_BytesWritten; }

  void Write(const void *src, const uint32 nBytes) {
    while(m_BytesWritten + nBytes > m_BufferSz) {
      m_BufferSz <<= 1;
      uint8 *newBuffer = new uint8[m_BufferSz];
      memcpy(newBuffer, m_Base, m_BytesWritten);
      delete m_Base;
      m_Base = newBuffer;
      m_Head = m_Base + m_BytesWritten;
    }

    memcpy(m_Head, src, nBytes);
    m_Head += nBytes;
    m_BytesWritten += nBytes;
  }

  void Write(const uint32 v) {
    Write(&v, 4);
  }
};

bool ImageWriterKTX::WriteImage() {
  ByteWriter wtr (m_RawFileData, m_RawFileDataSz);

  const uint8 kIdentifier[12] = {
    0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A
  };
  wtr.Write(kIdentifier, 12);
  wtr.Write(0x04030201);

  const char *orientationKey = "KTXorientation";
  const char *orientationValue = "S=r,T=u";
  const uint32 kvSz =
    strlen(orientationKey) + 1 // key
    + strlen(orientationValue) + 1; // value
  uint32 tkvSz = kvSz + 4; // total kv size
  tkvSz = (tkvSz + 3) & ~0x3; // 4-byte aligned

  CompressedImage *ci = dynamic_cast<CompressedImage *>(&m_Image);
  if(ci && ci->GetFormat() == FasTC::eCompressionFormat_BPTC) {
    wtr.Write(0);  // glType
    wtr.Write(1);  // glTypeSize
    wtr.Write(GL_RGBA);  // glFormat
    wtr.Write(GL_COMPRESSED_RGBA_BPTC_UNORM);  // glInternalFormat
    wtr.Write(GL_RGBA);  // glBaseFormat
  } else {
    wtr.Write(GL_BYTE);  // glType
    wtr.Write(1);  // glTypeSize
    wtr.Write(GL_RGBA);  // glFormat
    wtr.Write(GL_RGBA8);  // glInternalFormat
    wtr.Write(GL_RGBA);  // glBaseFormat
  }

  wtr.Write(m_Width);  // pixelWidth
  wtr.Write(m_Height); // pixelHeight
  wtr.Write(0);        // pixelDepth
  wtr.Write(0);        // numberOfArrayElements
  wtr.Write(1);        // numberOfFaces
  wtr.Write(1);        // numberOfMipmapLevels
  wtr.Write(tkvSz);    // total key value size
  wtr.Write(kvSz);     // key value size
  wtr.Write(orientationKey, strlen(orientationKey) + 1); // key
  wtr.Write(orientationValue, strlen(orientationValue) + 1); // value
  wtr.Write(orientationKey, tkvSz - kvSz); // padding

  if(ci && ci->GetFormat() == FasTC::eCompressionFormat_BPTC) {
    static const uint32 kImageSize = m_Width * m_Height;
    wtr.Write(kImageSize); // imageSize
    wtr.Write(ci->GetCompressedData(), kImageSize); // imagedata...
  } else {
    static const uint32 kImageSize = m_Width * m_Height * 4;
    wtr.Write(kImageSize); // imageSize
    wtr.Write(m_Image.GetPixels(), kImageSize); // imagedata...
  }

  m_RawFileData = wtr.GetBytes();
  m_RawFileDataSz = wtr.GetBytesWritten();
  return true;
}
<|endoftext|>