<commit_before>/***********************************************************************
 beemutex.cpp - Implements the BeecryptMutex class.  The name comes
 	from the fact that we lifted this essentially intact from the
	Beecrypt library, which is also LGPL.  See beecrypt.h for the list
	of changes we made on integrating it into MySQL++.

 Copyright (c) 2004 Beeyond Software Holding BV and (c) 2007 by
 Educational Technology Resources, Inc.  Others may also hold
 copyrights on code in this file.  See the CREDITS file in the top
 directory of the distribution for details.

 This file is part of MySQL++.

 MySQL++ is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published
 by the Free Software Foundation; either version 2.1 of the License, or
 (at your option) any later version.

 MySQL++ 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 MySQL++; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#define MYSQLPP_NOT_HEADER
#include "beemutex.h"

#include "common.h"

#include <errno.h>

namespace mysqlpp {

#define ACTUALLY_DOES_SOMETHING
#if defined(HAVE_SYNCH_H)
    typedef mutex_t bc_mutex_t;
#elif defined(HAVE_PTHREAD)
    typedef pthread_mutex_t bc_mutex_t;
#elif defined(MYSQLPP_PLATFORM_WINDOWS)
    typedef HANDLE bc_mutex_t;
#else
// No supported mutex type found, so class becomes a no-op.
#	undef ACTUALLY_DOES_SOMETHING
#endif

#if defined(ACTUALLY_DOES_SOMETHING)
	static bc_mutex_t* impl_ptr(void* p)
			{ return static_cast<bc_mutex_t*>(p); }
#	if defined(MYSQLPP_PLATFORM_WINDOWS)
		static bc_mutex_t impl_val(void* p)
				{ return *static_cast<bc_mutex_t*>(p); }
#	endif
#endif

BeecryptMutex::BeecryptMutex() throw (MutexFailed)
#if defined(ACTUALLY_DOES_SOMETHING)
	: pmutex_(new bc_mutex_t)
#endif
{
#if defined(MYSQLPP_PLATFORM_WINDOWS)
	*impl_ptr(pmutex_) = CreateMutex((LPSECURITY_ATTRIBUTES) 0, FALSE,
			(LPCTSTR) 0);
	if (!impl_val(pmutex_))
		throw MutexFailed("CreateMutex failed");
#else
#	if HAVE_SYNCH_H || HAVE_PTHREAD
	register int rc;
#	endif
#	if HAVE_SYNCH_H
		if ((rc = mutex_init(impl_ptr(pmutex_), USYNC_THREAD, 0)))
			throw MutexFailed(strerror(rc));
#	elif HAVE_PTHREAD
		if ((rc = pthread_mutex_init(impl_ptr(pmutex_), 0)))
			throw MutexFailed(strerror(rc));
#	endif
#endif
}

BeecryptMutex::~BeecryptMutex()
{
#if defined(ACTUALLY_DOES_SOMETHING)
#	if defined(MYSQLPP_PLATFORM_WINDOWS)
		CloseHandle(impl_val(pmutex_));
#	elif HAVE_SYNCH_H
		mutex_destroy(impl_ptr(pmutex_));
#	elif HAVE_PTHREAD
		pthread_mutex_destroy(impl_ptr(pmutex_));
#	endif

	delete impl_ptr(pmutex_);
#endif
}

void
BeecryptMutex::lock() throw (MutexFailed)
{
#if defined(MYSQLPP_PLATFORM_WINDOWS)
	if (WaitForSingleObject(impl_val(pmutex_), INFINITE) == WAIT_OBJECT_0)
		return;
	throw MutexFailed("WaitForSingleObject failed");
#else
#	if HAVE_SYNCH_H || HAVE_PTHREAD
	register int rc;
#	endif
#	if HAVE_SYNCH_H
		if ((rc = mutex_lock(impl_ptr(pmutex_))))
			throw MutexFailed(strerror(rc));
#	elif HAVE_PTHREAD
		if ((rc = pthread_mutex_lock(impl_ptr(pmutex_))))
			throw MutexFailed(strerror(rc));
#	endif
#endif
}

bool
BeecryptMutex::trylock() throw (MutexFailed)
{
#if defined(ACTUALLY_DOES_SOMETHING)
#	if defined(MYSQLPP_PLATFORM_WINDOWS)
		switch (WaitForSingleObject(impl_val(pmutex_), 0)) {
			case WAIT_TIMEOUT:
				return false;
			case WAIT_OBJECT_0:
				return true;
			default:
				throw MutexFailed("WaitForSingleObbject failed");
		}
#	else
		register int rc;
#		if HAVE_SYNCH_H
			if ((rc = mutex_trylock(impl_ptr(pmutex_))) == 0)
				return true;
			if (rc == EBUSY)
				return false;
			throw MutexFailed(strerror(rc));
#		elif HAVE_PTHREAD
			if ((rc = pthread_mutex_trylock(impl_ptr(pmutex_))) == 0)
				return true;
			if (rc == EBUSY)
				return false;
			throw MutexFailed(strerror(rc));
#		endif
#	endif
#else
	return true;		// no-op build, so always succeed
#endif
}

void
BeecryptMutex::unlock() throw (MutexFailed)
{
#if defined(MYSQLPP_PLATFORM_WINDOWS)
	if (!ReleaseMutex(impl_val(pmutex_)))
		throw MutexFailed("ReleaseMutex failed");
#else
#	if HAVE_SYNCH_H || HAVE_PTHREAD
		register int rc;
#	endif
#	if HAVE_SYNCH_H
		if ((rc = mutex_unlock(impl_ptr(pmutex_))))
			throw MutexFailed(strerror(rc));
#	elif HAVE_PTHREAD
		if ((rc = pthread_mutex_unlock(impl_ptr(pmutex_))))
			throw MutexFailed(strerror(rc));
#	endif
#endif
}

} // end namespace mysqlpp

<commit_msg>#include fix for GCC 4.3<commit_after>/***********************************************************************
 beemutex.cpp - Implements the BeecryptMutex class.  The name comes
 	from the fact that we lifted this essentially intact from the
	Beecrypt library, which is also LGPL.  See beecrypt.h for the list
	of changes we made on integrating it into MySQL++.

 Copyright (c) 2004 Beeyond Software Holding BV and (c) 2007 by
 Educational Technology Resources, Inc.  Others may also hold
 copyrights on code in this file.  See the CREDITS file in the top
 directory of the distribution for details.

 This file is part of MySQL++.

 MySQL++ is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published
 by the Free Software Foundation; either version 2.1 of the License, or
 (at your option) any later version.

 MySQL++ 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 MySQL++; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#define MYSQLPP_NOT_HEADER
#include "beemutex.h"

#include "common.h"

#include <errno.h>
#include <string.h>

namespace mysqlpp {

#define ACTUALLY_DOES_SOMETHING
#if defined(HAVE_SYNCH_H)
    typedef mutex_t bc_mutex_t;
#elif defined(HAVE_PTHREAD)
    typedef pthread_mutex_t bc_mutex_t;
#elif defined(MYSQLPP_PLATFORM_WINDOWS)
    typedef HANDLE bc_mutex_t;
#else
// No supported mutex type found, so class becomes a no-op.
#	undef ACTUALLY_DOES_SOMETHING
#endif

#if defined(ACTUALLY_DOES_SOMETHING)
	static bc_mutex_t* impl_ptr(void* p)
			{ return static_cast<bc_mutex_t*>(p); }
#	if defined(MYSQLPP_PLATFORM_WINDOWS)
		static bc_mutex_t impl_val(void* p)
				{ return *static_cast<bc_mutex_t*>(p); }
#	endif
#endif

BeecryptMutex::BeecryptMutex() throw (MutexFailed)
#if defined(ACTUALLY_DOES_SOMETHING)
	: pmutex_(new bc_mutex_t)
#endif
{
#if defined(MYSQLPP_PLATFORM_WINDOWS)
	*impl_ptr(pmutex_) = CreateMutex((LPSECURITY_ATTRIBUTES) 0, FALSE,
			(LPCTSTR) 0);
	if (!impl_val(pmutex_))
		throw MutexFailed("CreateMutex failed");
#else
#	if HAVE_SYNCH_H || HAVE_PTHREAD
	register int rc;
#	endif
#	if HAVE_SYNCH_H
		if ((rc = mutex_init(impl_ptr(pmutex_), USYNC_THREAD, 0)))
			throw MutexFailed(strerror(rc));
#	elif HAVE_PTHREAD
		if ((rc = pthread_mutex_init(impl_ptr(pmutex_), 0)))
			throw MutexFailed(strerror(rc));
#	endif
#endif
}

BeecryptMutex::~BeecryptMutex()
{
#if defined(ACTUALLY_DOES_SOMETHING)
#	if defined(MYSQLPP_PLATFORM_WINDOWS)
		CloseHandle(impl_val(pmutex_));
#	elif HAVE_SYNCH_H
		mutex_destroy(impl_ptr(pmutex_));
#	elif HAVE_PTHREAD
		pthread_mutex_destroy(impl_ptr(pmutex_));
#	endif

	delete impl_ptr(pmutex_);
#endif
}

void
BeecryptMutex::lock() throw (MutexFailed)
{
#if defined(MYSQLPP_PLATFORM_WINDOWS)
	if (WaitForSingleObject(impl_val(pmutex_), INFINITE) == WAIT_OBJECT_0)
		return;
	throw MutexFailed("WaitForSingleObject failed");
#else
#	if HAVE_SYNCH_H || HAVE_PTHREAD
	register int rc;
#	endif
#	if HAVE_SYNCH_H
		if ((rc = mutex_lock(impl_ptr(pmutex_))))
			throw MutexFailed(strerror(rc));
#	elif HAVE_PTHREAD
		if ((rc = pthread_mutex_lock(impl_ptr(pmutex_))))
			throw MutexFailed(strerror(rc));
#	endif
#endif
}

bool
BeecryptMutex::trylock() throw (MutexFailed)
{
#if defined(ACTUALLY_DOES_SOMETHING)
#	if defined(MYSQLPP_PLATFORM_WINDOWS)
		switch (WaitForSingleObject(impl_val(pmutex_), 0)) {
			case WAIT_TIMEOUT:
				return false;
			case WAIT_OBJECT_0:
				return true;
			default:
				throw MutexFailed("WaitForSingleObbject failed");
		}
#	else
		register int rc;
#		if HAVE_SYNCH_H
			if ((rc = mutex_trylock(impl_ptr(pmutex_))) == 0)
				return true;
			if (rc == EBUSY)
				return false;
			throw MutexFailed(strerror(rc));
#		elif HAVE_PTHREAD
			if ((rc = pthread_mutex_trylock(impl_ptr(pmutex_))) == 0)
				return true;
			if (rc == EBUSY)
				return false;
			throw MutexFailed(strerror(rc));
#		endif
#	endif
#else
	return true;		// no-op build, so always succeed
#endif
}

void
BeecryptMutex::unlock() throw (MutexFailed)
{
#if defined(MYSQLPP_PLATFORM_WINDOWS)
	if (!ReleaseMutex(impl_val(pmutex_)))
		throw MutexFailed("ReleaseMutex failed");
#else
#	if HAVE_SYNCH_H || HAVE_PTHREAD
		register int rc;
#	endif
#	if HAVE_SYNCH_H
		if ((rc = mutex_unlock(impl_ptr(pmutex_))))
			throw MutexFailed(strerror(rc));
#	elif HAVE_PTHREAD
		if ((rc = pthread_mutex_unlock(impl_ptr(pmutex_))))
			throw MutexFailed(strerror(rc));
#	endif
#endif
}

} // end namespace mysqlpp

<|endoftext|>


<commit_before>#ifndef AMGCL_IO_MM_HPP
#define AMGCL_IO_MM_HPP

/*
The MIT License

Copyright (c) 2012-2019 Denis Demidov <dennis.demidov@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

/**
 * \file   amgcl/io/mm.hpp
 * \author Denis Demidov <dennis.demidov@gmail.com>
 * \brief  Readers for Matrix Market sparse matrices and dense vectors.
 */

#include <vector>
#include <string>
#include <fstream>
#include <sstream>
#include <numeric>

#include <type_traits>
#include <tuple>

#include <amgcl/util.hpp>
#include <amgcl/backend/interface.hpp>
#include <amgcl/value_type/interface.hpp>
#include <amgcl/detail/sort_row.hpp>

namespace amgcl {
namespace io {

/// Matrix market reader.
class mm_reader {
    public:
        /// Open the file by name
        mm_reader(const std::string &fname) : f(fname.c_str()) {
            precondition(f, "Failed to open file \"" + fname + "\"");

            // Read banner.
            std::string line;
            precondition(std::getline(f, line), format_error());

            std::istringstream is(line);
            std::string banner, mtx, coord, dtype, storage;

            precondition(
                    is >> banner >> mtx >> coord >> dtype >> storage,
                    format_error());

            precondition(banner  == "%%MatrixMarket", format_error("no banner"));
            precondition(mtx     == "matrix",         format_error("not a matrix"));

            if (storage == "general") {
                _symmetric = false;
            } else if (storage == "symmetric") {
                _symmetric = true;
            } else {
                precondition(false, "unsupported storage type");
            }

            if (coord == "coordinate") {
                _sparse = true;
            } else if (coord == "array") {
                _sparse = false;
            } else {
                precondition(false, format_error("unsupported coordinate type"));
            }

            if (dtype == "real") {
                _complex = false;
                _integer = false;
            } else if (dtype == "complex") {
                _complex = true;
                _integer = false;
            } else if (dtype == "integer") {
                _complex = false;
                _integer = true;
            } else {
                precondition(false, format_error("unsupported data type"));
            }

            // Skip comments.
            std::streampos pos;
            do {
                pos = f.tellg();
                precondition(std::getline(f, line), format_error("unexpected eof"));
            } while (line[0] == '%');

            // Get back to the first non-comment line.
            f.seekg(pos);

            // Read matrix size
            is.clear(); is.str(line);
            precondition(is >> nrows >> ncols, format_error());
        }

        /// Matrix in the file is symmetric.
        bool is_symmetric()  const { return _symmetric; }

        /// Matrix in the file is sparse.
        bool is_sparse()  const { return _sparse; }

        /// Matrix in the file is complex-valued.
        bool is_complex() const { return _complex; }

        /// Matrix in the file is integer-valued.
        bool is_integer() const { return _integer; }

        /// Number of rows.
        size_t rows() const { return nrows; }

        /// Number of rows.
        size_t cols() const { return ncols; }

        /// Read sparse matrix from the file.
        template <typename Idx, typename Val>
        std::tuple<size_t, size_t> operator()(
                std::vector<Idx> &ptr,
                std::vector<Idx> &col,
                std::vector<Val> &val,
                ptrdiff_t row_beg = -1,
                ptrdiff_t row_end = -1
                )
        {
            precondition(_sparse, format_error("not a sparse matrix"));
            precondition(amgcl::is_complex<Val>::value == _complex,
                    _complex ?
                        "attempt to read complex values into real vector" :
                        "attempt to read real values into complex vector"
                        );
            precondition(std::is_integral<Val>::value == _integer,
                    _integer ?
                        "attempt to read integer values into real vector" :
                        "attempt to read real values into integer vector"
                        );

            // Read sizes
            ptrdiff_t n, m;
            size_t nnz;
            std::string line;
            std::istringstream is;
            {
                precondition(std::getline(f, line), format_error("unexpected eof"));
                is.clear(); is.str(line);
                precondition(is >> n >> m >> nnz, format_error());
            }

            if (row_beg < 0) row_beg = 0;
            if (row_end < 0) row_end = n;

            precondition(row_beg >= 0 && row_end <= n,
                    "Wrong subset of rows is requested");

            ptrdiff_t _nnz = _symmetric ? 2 * nnz : nnz;

            if (row_beg != 0 || row_end != n)
                _nnz *= 1.2 * (row_end - row_beg) / n;

            std::vector<Idx> _row; _row.reserve(_nnz);
            std::vector<Idx> _col; _col.reserve(_nnz);
            std::vector<Val> _val; _val.reserve(_nnz);

            ptrdiff_t chunk = row_end - row_beg;

            ptr.resize(chunk + 1); std::fill(ptr.begin(), ptr.end(), 0);

            for(size_t k = 0; k < nnz; ++k) {
                precondition(std::getline(f, line), format_error("unexpected eof"));
                is.clear(); is.str(line);

                Idx i, j;
                Val v;

                precondition(is >> i >> j, format_error());

                i -= 1;
                j -= 1;

                v = read_value<Val>(is);

                if (row_beg <= i && i < row_end) {
                    ++ptr[i - row_beg + 1];

                    _row.push_back(i - row_beg);
                    _col.push_back(j);
                    _val.push_back(v);
                }

                if (_symmetric && i != j && row_beg <= j && j < row_end) {
                    ++ptr[j - row_beg + 1];

                    _row.push_back(j - row_beg);
                    _col.push_back(i);
                    _val.push_back(v);
                }
            }

            std::partial_sum(ptr.begin(), ptr.end(), ptr.begin());

            col.resize(ptr.back());
            val.resize(ptr.back());

            for(size_t k = 0, e = val.size(); k < e; ++k) {
                Idx i = _row[k];
                Idx j = _col[k];
                Val v = _val[k];

                Idx head = ptr[i]++;
                col[head] = j;
                val[head] = v;
            }

            std::rotate(ptr.begin(), ptr.end() - 1, ptr.end());
            ptr.front() = 0;

#pragma omp parallel for
            for(ptrdiff_t i = 0; i < chunk; ++i) {
                Idx beg = ptr[i];
                Idx end = ptr[i+1];

                amgcl::detail::sort_row(&col[0] + beg, &val[0] + beg, end - beg);
            }

            return std::make_tuple(chunk, m);
        }

        /// Read dense array from the file.
        template <typename Val>
        std::tuple<size_t, size_t> operator()(
                std::vector<Val> &val,
                ptrdiff_t row_beg = -1,
                ptrdiff_t row_end = -1
                )
        {
            precondition(!_sparse, format_error("not a dense array"));
            precondition(amgcl::is_complex<Val>::value == _complex,
                    _complex ?
                        "attempt to read complex values into real vector" :
                        "attempt to read real values into complex vector"
                        );
            precondition(std::is_integral<Val>::value == _integer,
                    _integer ?
                        "attempt to read integer values into real vector" :
                        "attempt to read real values into integer vector"
                        );

            // Read sizes
            ptrdiff_t n, m;
            std::string line;
            std::istringstream is;
            {
                precondition(std::getline(f, line), format_error("unexpected eof"));
                is.clear(); is.str(line);
                precondition(is >> n >> m, format_error());
            }

            if (row_beg < 0) row_beg = 0;
            if (row_end < 0) row_end = n;

            precondition(row_beg >= 0 && row_end <= n,
                    "Wrong subset of rows is requested");

            val.resize((row_end - row_beg) * m);

            for(ptrdiff_t j = 0; j < m; ++j) {
                for(ptrdiff_t i = 0; i < n; ++i) {
                    precondition(std::getline(f, line), format_error("unexpected eof"));
                    if (row_beg <= i && i < row_end) {
                        is.clear(); is.str(line);
                        val[(i - row_beg) * m + j] = read_value<Val>(is);
                    }
                }
            }

            return std::make_tuple(row_end - row_beg, m);
        }
    private:
        std::ifstream f;

        bool _sparse;
        bool _symmetric;
        bool _complex;
        bool _integer;

        size_t nrows, ncols;

        std::string format_error(const std::string &msg = "") const {
            std::string err_string = "MatrixMarket format error";
            if (!msg.empty())
                err_string += " (" + msg + ")";
            return err_string;
        }

        template <typename T>
        typename std::enable_if<amgcl::is_complex<T>::value, T>::type
        read_value(std::istream &s) {
            typename math::scalar_of<T>::type x,y;
            precondition(s >> x >> y, format_error());
            return T(x,y);
        }

        template <typename T>
        typename std::enable_if<!amgcl::is_complex<T>::value, T>::type
        read_value(std::istream &s) {
            T x;
            if (std::is_same<T, char>::value) {
                // Special case:
                // We want to read 8bit integers from MatrixMarket, not chars.
                int i;
                precondition(s >> i, format_error());
                x = static_cast<char>(i);
            } else {
                precondition(s >> x, format_error());
            }
            return x;
        }

};

namespace detail {
template <typename Val>
typename std::enable_if<is_complex<Val>::value, std::ostream&>::type
write_value(std::ostream &s, Val v) {
    return s << std::real(v) << " " << std::imag(v);
}

template <typename Val>
typename std::enable_if<!is_complex<Val>::value, std::ostream&>::type
write_value(std::ostream &s, Val v) {
    return s << v;
}

} // namespace detail

/// Write dense array in Matrix Market format.
template <typename Val>
void mm_write(
        const std::string &fname,
        const Val *data,
        size_t rows,
        size_t cols = 1
        )
{
    std::ofstream f(fname.c_str());
    precondition(f, "Failed to open file \"" + fname + "\" for writing");

    // Banner
    f << "%%MatrixMarket matrix array ";
    if (is_complex<Val>::value) {
        f << "complex ";
    } else if(std::is_integral<Val>::value) {
        f << "integer ";
    } else {
        f << "real ";
    }
    f << "general\n";

    // Sizes
    f << rows << " " << cols << "\n";

    // Data
    for(size_t j = 0; j < cols; ++j) {
        for(size_t i = 0; i < rows; ++i) {
            detail::write_value(f, data[i * cols + j]) << "\n";
        }
    }
}

/// Write sparse matrix in Matrix Market format.
template <class Matrix>
void mm_write(const std::string &fname, const Matrix &A) {
    typedef typename backend::value_type<Matrix>::type Val;

    const size_t rows = backend::rows(A);
    const size_t cols = backend::cols(A);
    const size_t nnz  = backend::nonzeros(A);

    std::ofstream f(fname.c_str());
    precondition(f, "Failed to open file \"" + fname + "\" for writing");

    // Banner
    f << "%%MatrixMarket matrix coordinate ";
    if (is_complex<Val>::value) {
        f << "complex ";
    } else if(std::is_integral<Val>::value) {
        f << "integer ";
    } else {
        f << "real ";
    }
    f << "general\n";

    // Sizes
    f << rows << " " << cols << " " << nnz << "\n";

    // Data
    for(size_t i = 0; i < rows; ++i) {
        for(auto a = backend::row_begin(A, i); a; ++a) {
            f << i + 1 << " " << a.col() + 1 << " ";
            detail::write_value(f, a.value()) << "\n";
        }
    }
}

} // namespace io
} // namespace amgcl

#endif
<commit_msg>Use scientific format in io::mm_write()<commit_after>#ifndef AMGCL_IO_MM_HPP
#define AMGCL_IO_MM_HPP

/*
The MIT License

Copyright (c) 2012-2019 Denis Demidov <dennis.demidov@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

/**
 * \file   amgcl/io/mm.hpp
 * \author Denis Demidov <dennis.demidov@gmail.com>
 * \brief  Readers for Matrix Market sparse matrices and dense vectors.
 */

#include <vector>
#include <string>
#include <fstream>
#include <sstream>
#include <numeric>

#include <type_traits>
#include <tuple>

#include <amgcl/util.hpp>
#include <amgcl/backend/interface.hpp>
#include <amgcl/value_type/interface.hpp>
#include <amgcl/detail/sort_row.hpp>

namespace amgcl {
namespace io {

/// Matrix market reader.
class mm_reader {
    public:
        /// Open the file by name
        mm_reader(const std::string &fname) : f(fname.c_str()) {
            precondition(f, "Failed to open file \"" + fname + "\"");

            // Read banner.
            std::string line;
            precondition(std::getline(f, line), format_error());

            std::istringstream is(line);
            std::string banner, mtx, coord, dtype, storage;

            precondition(
                    is >> banner >> mtx >> coord >> dtype >> storage,
                    format_error());

            precondition(banner  == "%%MatrixMarket", format_error("no banner"));
            precondition(mtx     == "matrix",         format_error("not a matrix"));

            if (storage == "general") {
                _symmetric = false;
            } else if (storage == "symmetric") {
                _symmetric = true;
            } else {
                precondition(false, "unsupported storage type");
            }

            if (coord == "coordinate") {
                _sparse = true;
            } else if (coord == "array") {
                _sparse = false;
            } else {
                precondition(false, format_error("unsupported coordinate type"));
            }

            if (dtype == "real") {
                _complex = false;
                _integer = false;
            } else if (dtype == "complex") {
                _complex = true;
                _integer = false;
            } else if (dtype == "integer") {
                _complex = false;
                _integer = true;
            } else {
                precondition(false, format_error("unsupported data type"));
            }

            // Skip comments.
            std::streampos pos;
            do {
                pos = f.tellg();
                precondition(std::getline(f, line), format_error("unexpected eof"));
            } while (line[0] == '%');

            // Get back to the first non-comment line.
            f.seekg(pos);

            // Read matrix size
            is.clear(); is.str(line);
            precondition(is >> nrows >> ncols, format_error());
        }

        /// Matrix in the file is symmetric.
        bool is_symmetric()  const { return _symmetric; }

        /// Matrix in the file is sparse.
        bool is_sparse()  const { return _sparse; }

        /// Matrix in the file is complex-valued.
        bool is_complex() const { return _complex; }

        /// Matrix in the file is integer-valued.
        bool is_integer() const { return _integer; }

        /// Number of rows.
        size_t rows() const { return nrows; }

        /// Number of rows.
        size_t cols() const { return ncols; }

        /// Read sparse matrix from the file.
        template <typename Idx, typename Val>
        std::tuple<size_t, size_t> operator()(
                std::vector<Idx> &ptr,
                std::vector<Idx> &col,
                std::vector<Val> &val,
                ptrdiff_t row_beg = -1,
                ptrdiff_t row_end = -1
                )
        {
            precondition(_sparse, format_error("not a sparse matrix"));
            precondition(amgcl::is_complex<Val>::value == _complex,
                    _complex ?
                        "attempt to read complex values into real vector" :
                        "attempt to read real values into complex vector"
                        );
            precondition(std::is_integral<Val>::value == _integer,
                    _integer ?
                        "attempt to read integer values into real vector" :
                        "attempt to read real values into integer vector"
                        );

            // Read sizes
            ptrdiff_t n, m;
            size_t nnz;
            std::string line;
            std::istringstream is;
            {
                precondition(std::getline(f, line), format_error("unexpected eof"));
                is.clear(); is.str(line);
                precondition(is >> n >> m >> nnz, format_error());
            }

            if (row_beg < 0) row_beg = 0;
            if (row_end < 0) row_end = n;

            precondition(row_beg >= 0 && row_end <= n,
                    "Wrong subset of rows is requested");

            ptrdiff_t _nnz = _symmetric ? 2 * nnz : nnz;

            if (row_beg != 0 || row_end != n)
                _nnz *= 1.2 * (row_end - row_beg) / n;

            std::vector<Idx> _row; _row.reserve(_nnz);
            std::vector<Idx> _col; _col.reserve(_nnz);
            std::vector<Val> _val; _val.reserve(_nnz);

            ptrdiff_t chunk = row_end - row_beg;

            ptr.resize(chunk + 1); std::fill(ptr.begin(), ptr.end(), 0);

            for(size_t k = 0; k < nnz; ++k) {
                precondition(std::getline(f, line), format_error("unexpected eof"));
                is.clear(); is.str(line);

                Idx i, j;
                Val v;

                precondition(is >> i >> j, format_error());

                i -= 1;
                j -= 1;

                v = read_value<Val>(is);

                if (row_beg <= i && i < row_end) {
                    ++ptr[i - row_beg + 1];

                    _row.push_back(i - row_beg);
                    _col.push_back(j);
                    _val.push_back(v);
                }

                if (_symmetric && i != j && row_beg <= j && j < row_end) {
                    ++ptr[j - row_beg + 1];

                    _row.push_back(j - row_beg);
                    _col.push_back(i);
                    _val.push_back(v);
                }
            }

            std::partial_sum(ptr.begin(), ptr.end(), ptr.begin());

            col.resize(ptr.back());
            val.resize(ptr.back());

            for(size_t k = 0, e = val.size(); k < e; ++k) {
                Idx i = _row[k];
                Idx j = _col[k];
                Val v = _val[k];

                Idx head = ptr[i]++;
                col[head] = j;
                val[head] = v;
            }

            std::rotate(ptr.begin(), ptr.end() - 1, ptr.end());
            ptr.front() = 0;

#pragma omp parallel for
            for(ptrdiff_t i = 0; i < chunk; ++i) {
                Idx beg = ptr[i];
                Idx end = ptr[i+1];

                amgcl::detail::sort_row(&col[0] + beg, &val[0] + beg, end - beg);
            }

            return std::make_tuple(chunk, m);
        }

        /// Read dense array from the file.
        template <typename Val>
        std::tuple<size_t, size_t> operator()(
                std::vector<Val> &val,
                ptrdiff_t row_beg = -1,
                ptrdiff_t row_end = -1
                )
        {
            precondition(!_sparse, format_error("not a dense array"));
            precondition(amgcl::is_complex<Val>::value == _complex,
                    _complex ?
                        "attempt to read complex values into real vector" :
                        "attempt to read real values into complex vector"
                        );
            precondition(std::is_integral<Val>::value == _integer,
                    _integer ?
                        "attempt to read integer values into real vector" :
                        "attempt to read real values into integer vector"
                        );

            // Read sizes
            ptrdiff_t n, m;
            std::string line;
            std::istringstream is;
            {
                precondition(std::getline(f, line), format_error("unexpected eof"));
                is.clear(); is.str(line);
                precondition(is >> n >> m, format_error());
            }

            if (row_beg < 0) row_beg = 0;
            if (row_end < 0) row_end = n;

            precondition(row_beg >= 0 && row_end <= n,
                    "Wrong subset of rows is requested");

            val.resize((row_end - row_beg) * m);

            for(ptrdiff_t j = 0; j < m; ++j) {
                for(ptrdiff_t i = 0; i < n; ++i) {
                    precondition(std::getline(f, line), format_error("unexpected eof"));
                    if (row_beg <= i && i < row_end) {
                        is.clear(); is.str(line);
                        val[(i - row_beg) * m + j] = read_value<Val>(is);
                    }
                }
            }

            return std::make_tuple(row_end - row_beg, m);
        }
    private:
        std::ifstream f;

        bool _sparse;
        bool _symmetric;
        bool _complex;
        bool _integer;

        size_t nrows, ncols;

        std::string format_error(const std::string &msg = "") const {
            std::string err_string = "MatrixMarket format error";
            if (!msg.empty())
                err_string += " (" + msg + ")";
            return err_string;
        }

        template <typename T>
        typename std::enable_if<amgcl::is_complex<T>::value, T>::type
        read_value(std::istream &s) {
            typename math::scalar_of<T>::type x,y;
            precondition(s >> x >> y, format_error());
            return T(x,y);
        }

        template <typename T>
        typename std::enable_if<!amgcl::is_complex<T>::value, T>::type
        read_value(std::istream &s) {
            T x;
            if (std::is_same<T, char>::value) {
                // Special case:
                // We want to read 8bit integers from MatrixMarket, not chars.
                int i;
                precondition(s >> i, format_error());
                x = static_cast<char>(i);
            } else {
                precondition(s >> x, format_error());
            }
            return x;
        }

};

namespace detail {
template <typename Val>
typename std::enable_if<is_complex<Val>::value, std::ostream&>::type
write_value(std::ostream &s, Val v) {
    return s << std::scientific << std::setprecision(20) << std::real(v) << " " << std::imag(v);
}

template <typename Val>
typename std::enable_if<!is_complex<Val>::value, std::ostream&>::type
write_value(std::ostream &s, Val v) {
    return s << std::scientific << std::setprecision(20) << v;
}

} // namespace detail

/// Write dense array in Matrix Market format.
template <typename Val>
void mm_write(
        const std::string &fname,
        const Val *data,
        size_t rows,
        size_t cols = 1
        )
{
    std::ofstream f(fname.c_str());
    precondition(f, "Failed to open file \"" + fname + "\" for writing");

    // Banner
    f << "%%MatrixMarket matrix array ";
    if (is_complex<Val>::value) {
        f << "complex ";
    } else if(std::is_integral<Val>::value) {
        f << "integer ";
    } else {
        f << "real ";
    }
    f << "general\n";

    // Sizes
    f << rows << " " << cols << "\n";

    // Data
    for(size_t j = 0; j < cols; ++j) {
        for(size_t i = 0; i < rows; ++i) {
            detail::write_value(f, data[i * cols + j]) << "\n";
        }
    }
}

/// Write sparse matrix in Matrix Market format.
template <class Matrix>
void mm_write(const std::string &fname, const Matrix &A) {
    typedef typename backend::value_type<Matrix>::type Val;

    const size_t rows = backend::rows(A);
    const size_t cols = backend::cols(A);
    const size_t nnz  = backend::nonzeros(A);

    std::ofstream f(fname.c_str());
    precondition(f, "Failed to open file \"" + fname + "\" for writing");

    // Banner
    f << "%%MatrixMarket matrix coordinate ";
    if (is_complex<Val>::value) {
        f << "complex ";
    } else if(std::is_integral<Val>::value) {
        f << "integer ";
    } else {
        f << "real ";
    }
    f << "general\n";

    // Sizes
    f << rows << " " << cols << " " << nnz << "\n";

    // Data
    for(size_t i = 0; i < rows; ++i) {
        for(auto a = backend::row_begin(A, i); a; ++a) {
            f << i + 1 << " " << a.col() + 1 << " ";
            detail::write_value(f, a.value()) << "\n";
        }
    }
}

} // namespace io
} // namespace amgcl

#endif
<|endoftext|>


<commit_before>#include <sndfile.h>
#include <string>

namespace DG {
namespace Sound {

class WAV {
public:
  struct Invalid_format_exception : public std::exception {

  WAV(const std::string& fname) { open(fname); }

  void open(const std::string& fname);

  // write wav out to the file fname
  void write(const std::string& fname);
private:
};

}
}
<commit_msg>Fixed retarded compile-time error<commit_after>#include <sndfile.h>
#include <string>

namespace DG {
namespace Sound {

class WAV {
public:
  WAV(const std::string& fname) { open(fname); }

  void open(const std::string& fname);

  // write wav out to the file fname
  void write(const std::string& fname);
private:
};

}
}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "PluginWindow.h"

#define HIDE(window) (window)->Visibility = System::Windows::Visibility::Collapsed
#define ISVISIBLE(window) ((window)->Visibility == System::Windows::Visibility::Visible)

PluginWindow::PluginWindow()
{
	InitializeComponent();
}

void PluginWindow::Init()
{
	MainWindow = gcnew PluginWindow();
	Application ^ app = Application::Current;
	if (app == nullptr)
	{
		app = gcnew Application();
	}
	app->Run(MainWindow);
}

void PluginWindow::InitializeComponent()
{
	//ʼ趨
	//
	this->Height = SystemParameters::WorkArea.Height / 2;
	this->Width = SystemParameters::WorkArea.Width / 4;
	this->Topmost = true;
	this->ShowInTaskbar = false;
	this->Visibility = System::Windows::Visibility::Hidden;
	this->WindowStyle = System::Windows::WindowStyle::None;
	this->ResizeMode = System::Windows::ResizeMode::NoResize;
	this->PreviewKeyDown += gcnew System::Windows::Input::KeyEventHandler(this, &PluginWindow::window_PreviewKeyDown);
	this->IsClosing = false;
	//ӿؼ
	Grid ^ grid = gcnew Grid();
	this->Content = grid;
	grid->Margin = *gcnew Thickness(2);

	RowDefinition ^ rd;
	grid->RowDefinitions->Add(rd = gcnew RowDefinition());
	rd->Height = GridLength::Auto;
	grid->RowDefinitions->Add(rd = gcnew RowDefinition());
	rd->Height = *gcnew GridLength(1, GridUnitType::Star);

	txtFilter = gcnew TextBox();
	lstPlaylist = gcnew ListBox();
	Playlist = gcnew ObservableCollection<Track^>();
	PlaylistView = (CollectionView^)CollectionViewSource::GetDefaultView(Playlist);

	grid->Children->Add(txtFilter);
	txtFilter->SetValue(Grid::RowProperty, (Object^)0);
	txtFilter->Margin = *gcnew Thickness(1);
	txtFilter->Height = txtFilter->FontSize * txtFilter->FontFamily->LineSpacing * 1.25;
	txtFilter->TextWrapping = TextWrapping::NoWrap;
	txtFilter->TabIndex = 0;
	txtFilter->TextChanged += gcnew TextChangedEventHandler(this, &PluginWindow::txtFilter_TextChanged);
	txtFilter->KeyDown += gcnew System::Windows::Input::KeyEventHandler(this, &PluginWindow::txtFilter_KeyDown);

	grid->Children->Add(lstPlaylist);
	lstPlaylist->SetValue(Grid::RowProperty, (Object^)1);
	lstPlaylist->Margin = *gcnew Thickness(1);
	lstPlaylist->ItemsSource = this->Playlist;
	lstPlaylist->TabIndex = 1;
	lstPlaylist->KeyDown += gcnew System::Windows::Input::KeyEventHandler(this, &PluginWindow::lstPlaylist_KeyDown);
	lstPlaylist->MouseDoubleClick += gcnew System::Windows::Input::MouseButtonEventHandler(this, &PluginWindow::lstPlaylist_MouseDoubleClick);
	PlaylistView->Filter = gcnew Predicate<Object^>(this, &PluginWindow::Filter);

	SAFcallback = gcnew Action(this, &PluginWindow::ShowAndFocus);
	RLcallback = gcnew Action(this, &PluginWindow::RefreshList);
	this->PlaylistLock = gcnew System::Threading::Mutex();
	this->RefreshList();
	//йãӳٵ˴JTFEδض޷APIӿ
	factory = WASABI_API_SVC->service_getServiceByGuid(QueueManagerApiGUID);
	if (factory)
	{
		QueueApi = (api_queue *)factory->getInterface();
	}
	else
	{
		QueueApi = NULL;
	}
}

bool PluginWindow::Filter(Object^ obj)
{
	if ((obj != nullptr) && (obj->GetType() == Track::typeid))
	{
		Track^ t = (Track^)obj;
		return	t->Filename->ToUpper()->Contains(txtFilter->Text->ToUpper()) ||
			t->Title->ToUpper()->Contains(txtFilter->Text->ToUpper());
	}
	return obj->ToString()->Contains(txtFilter->Text);
}

void PluginWindow::RefreshList()
{
	if (PlaylistLock->WaitOne(0))
	{
		int i, length = GetListLength();
		Action<Track^>^ add = gcnew Action<Track^>(Playlist, &ObservableCollection<Track^>::Add);
		this->Invoke(gcnew Action(Playlist, &ObservableCollection<Track^>::Clear));
		for (i = 0; i < length; i++)
		{
			this->AsyncInvoke(add, gcnew Track(GetPlayListFile(i), GetPlayListTitle(i)));
		}
		PlaylistLock->ReleaseMutex();
	}
}

void PluginWindow::OnSourceInitialized(EventArgs^ e)
{
	Window::OnSourceInitialized(e);
	HIDE(this);
}

void PluginWindow::OnDeactivated(EventArgs^ e)
{
	Window::OnActivated(e);
	HIDE(this);
}

void PluginWindow::OnMouseLeftButtonDown(System::Windows::Input::MouseButtonEventArgs^ e)
{
	Window::OnMouseLeftButtonDown(e);
	DragMove();
}

void PluginWindow::OnClosing(System::ComponentModel::CancelEventArgs ^e)
{
	Window::OnClosing(e);
	if (!IsClosing)
	{
		e->Cancel = true;
		HIDE(this);
	}
}

void PluginWindow::txtFilter_TextChanged(System::Object ^sender, TextChangedEventArgs ^e)
{
	if (Visibility != System::Windows::Visibility::Visible) return;
	PlaylistView->Refresh();
}

//txtFilterеİ¼
void PluginWindow::txtFilter_KeyDown(System::Object ^sender, System::Windows::Input::KeyEventArgs ^e)
{
	if (!ISVISIBLE(this)) return;
	if (e->Key == System::Windows::Input::Key::Enter)
	{
		if (PlaylistView->Count <= 0) return;
		PlaylistView->MoveCurrentToFirst();
		PlayIndex(Playlist->IndexOf((Track^)PlaylistView->CurrentItem));
		HIDE(this);
	}
	else if (e->Key == System::Windows::Input::Key::Tab)
	{
		if (PlaylistView->Count == 0)
		{
			e->Handled = true;
			System::Media::SystemSounds::Question->Play();
			return;
		}
		PlaylistView->MoveCurrentToFirst();
		if (PlaylistView->CurrentItem != nullptr)
		{
			lstPlaylist->SelectedItem = PlaylistView->CurrentItem;
		}
		else
		{
			return;
		}
		lstPlaylist->ScrollIntoView(lstPlaylist->SelectedItem);
	}
}

//lstPlaylistеİ¼
void PluginWindow::lstPlaylist_KeyDown(System::Object ^sender, System::Windows::Input::KeyEventArgs ^e)
{
	if (!ISVISIBLE(this)) return;
	if (e->Key == System::Windows::Input::Key::Enter)
	{
		PlayIndex(Playlist->IndexOf((Track^)lstPlaylist->SelectedItem));
		HIDE(this);
	}
	else if (e->Key == System::Windows::Input::Key::Tab)
	{
		if (!(PlaylistView->MoveCurrentToNext()))
		{
			PlaylistView->MoveCurrentToFirst();
		}
		lstPlaylist->SelectedItem = PlaylistView->CurrentItem;
		lstPlaylist->ScrollIntoView(lstPlaylist->SelectedItem);
		e->Handled = true;
	}
	else if (e->Key == System::Windows::Input::Key::Q)
	{
		QueueIndex(Playlist->IndexOf((Track^)lstPlaylist->SelectedItem));
		HIDE(this);
	}
}

//˫ʱѡ
void PluginWindow::lstPlaylist_MouseDoubleClick(System::Object ^sender, System::Windows::Input::MouseButtonEventArgs ^e)
{
	DependencyObject^ obj = dynamic_cast<DependencyObject^>(e->OriginalSource);
	while ((obj != nullptr) && (obj != lstPlaylist))
	{
		if (obj->GetType() == ListBoxItem::typeid)
		{
			Object^ t = (dynamic_cast<ListBoxItem^>(obj))->DataContext;
			if (t->GetType() == Track::typeid)
			{
				PlayIndex(Playlist->IndexOf(dynamic_cast<Track^>(t)));
				HIDE(this);
			}
			break;
		}
		obj = System::Windows::Media::VisualTreeHelper::GetParent(obj);
	}
}

void PluginWindow::window_PreviewKeyDown(System::Object ^sender, System::Windows::Input::KeyEventArgs ^e)
{
	if (e->Key == System::Windows::Input::Key::Escape)
	{
		e->Handled = true;
		HIDE(this);
	}
	else if (e->Key == System::Windows::Input::Key::F5)
	{
		e->Handled = true;
		RLcallback->BeginInvoke(nullptr, nullptr);
	}
}

void PluginWindow::ShowAndFocus()
{
	if (ISVISIBLE(this)) return;
	this->Visibility = System::Windows::Visibility::Visible;
	Activate();
	txtFilter->Focus();
	txtFilter->Text = String::Empty;
	PlaylistView->MoveCurrentToFirst();
	lstPlaylist->SelectedItem = PlaylistView->CurrentItem;
}

void PluginWindow::AsyncInvoke(Action^ callback)
{
	if (callback == nullptr) return;
	this->Dispatcher->BeginInvoke(System::Windows::Threading::DispatcherPriority::Normal, callback);
}

generic <typename T>void PluginWindow::AsyncInvoke(Action<T>^ callback, T arg)
{
	if (callback == nullptr) return;
	this->Dispatcher->BeginInvoke(System::Windows::Threading::DispatcherPriority::Normal, callback, arg);
}

void PluginWindow::Invoke(Action^ callback)
{
	if (callback == nullptr) return;
	this->Dispatcher->Invoke(System::Windows::Threading::DispatcherPriority::Normal, callback);
}

//WINAMP API
void PluginWindow::QueueIndex(int index)
{
	if (QueueApi != NULL)
	{
		QueueApi->AddItemToQueue(index, 1, NULL);
	}
}

String ^ PluginWindow::GetPlayListFile(int index)
{
	return gcnew String((wchar_t*)SendMessage(plugin.hwndParent, WM_WA_IPC, (WPARAM)index, IPC_GETPLAYLISTFILEW));
}

String ^ PluginWindow::GetPlayListTitle(int index)
{
	return gcnew String((wchar_t*)SendMessage(plugin.hwndParent, WM_WA_IPC, (WPARAM)index, IPC_GETPLAYLISTTITLEW));
}

int PluginWindow::GetListLength()
{
	return SendMessage(plugin.hwndParent, WM_WA_IPC, 0, IPC_GETLISTLENGTH);
}

void PluginWindow::PlayIndex(int index)
{
	SendMessage(plugin.hwndParent, WM_WA_IPC, (WPARAM)index, IPC_SETPLAYLISTPOS);
	SendMessage(plugin.hwndParent, WM_COMMAND, MAKEWPARAM(WINAMP_BUTTON2, 0), 0);
}<commit_msg>添加部件初始化通知的调用，对Mutex进行谨慎处理<commit_after>#include "stdafx.h"
#include "PluginWindow.h"

#define HIDE(window) (window)->Visibility = System::Windows::Visibility::Collapsed
#define ISVISIBLE(window) ((window)->Visibility == System::Windows::Visibility::Visible)

PluginWindow::PluginWindow()
{
	InitializeComponent();
}

void PluginWindow::Init()
{
	MainWindow = gcnew PluginWindow();
	Application ^ app = Application::Current;
	if (app == nullptr)
	{
		app = gcnew Application();
	}
	app->Run(MainWindow);
}

void PluginWindow::InitializeComponent()
{
	//ʼ趨
	//
	this->BeginInit();
	this->Height = SystemParameters::WorkArea.Height / 2;
	this->Width = SystemParameters::WorkArea.Width / 4;
	this->Topmost = true;
	this->ShowInTaskbar = false;
	this->Visibility = System::Windows::Visibility::Hidden;
	this->WindowStyle = System::Windows::WindowStyle::None;
	this->ResizeMode = System::Windows::ResizeMode::NoResize;
	this->PreviewKeyDown += gcnew System::Windows::Input::KeyEventHandler(this, &PluginWindow::window_PreviewKeyDown);
	this->IsClosing = false;
	//ӿؼ
	Grid ^ grid = gcnew Grid();
	grid->BeginInit();
	this->Content = grid;
	grid->Margin = *gcnew Thickness(2);

	RowDefinition ^ rd;
	grid->RowDefinitions->Add(rd = gcnew RowDefinition());
	rd->Height = GridLength::Auto;
	grid->RowDefinitions->Add(rd = gcnew RowDefinition());
	rd->Height = *gcnew GridLength(1, GridUnitType::Star);

	txtFilter = gcnew TextBox();
	lstPlaylist = gcnew ListBox();
	Playlist = gcnew ObservableCollection<Track^>();
	PlaylistView = (CollectionView^)CollectionViewSource::GetDefaultView(Playlist);

	txtFilter->BeginInit();
	grid->Children->Add(txtFilter);
	txtFilter->SetValue(Grid::RowProperty, (Object^)0);
	txtFilter->Margin = *gcnew Thickness(1);
	txtFilter->Height = txtFilter->FontSize * txtFilter->FontFamily->LineSpacing * 1.25;
	txtFilter->TextWrapping = TextWrapping::NoWrap;
	txtFilter->TabIndex = 0;
	txtFilter->TextChanged += gcnew TextChangedEventHandler(this, &PluginWindow::txtFilter_TextChanged);
	txtFilter->KeyDown += gcnew System::Windows::Input::KeyEventHandler(this, &PluginWindow::txtFilter_KeyDown);
	txtFilter->EndInit();

	lstPlaylist->BeginInit();
	grid->Children->Add(lstPlaylist);
	lstPlaylist->SetValue(Grid::RowProperty, (Object^)1);
	lstPlaylist->Margin = *gcnew Thickness(1);
	lstPlaylist->ItemsSource = this->Playlist;
	lstPlaylist->TabIndex = 1;
	lstPlaylist->KeyDown += gcnew System::Windows::Input::KeyEventHandler(this, &PluginWindow::lstPlaylist_KeyDown);
	lstPlaylist->MouseDoubleClick += gcnew System::Windows::Input::MouseButtonEventHandler(this, &PluginWindow::lstPlaylist_MouseDoubleClick);
	PlaylistView->Filter = gcnew Predicate<Object^>(this, &PluginWindow::Filter);
	lstPlaylist->EndInit();

	grid->EndInit();

	SAFcallback = gcnew Action(this, &PluginWindow::ShowAndFocus);
	RLcallback = gcnew Action(this, &PluginWindow::RefreshList);
	this->PlaylistLock = gcnew System::Threading::Mutex();
	this->EndInit();
	this->RefreshList();
	//йãӳٵ˴JTFEδض޷APIӿ
	factory = WASABI_API_SVC->service_getServiceByGuid(QueueManagerApiGUID);
	if (factory)
	{
		QueueApi = (api_queue *)factory->getInterface();
	}
	else
	{
		QueueApi = NULL;
	}
}

bool PluginWindow::Filter(Object^ obj)
{
	if ((obj != nullptr) && (obj->GetType() == Track::typeid))
	{
		Track^ t = (Track^)obj;
		return	t->Filename->ToUpper()->Contains(txtFilter->Text->ToUpper()) ||
			t->Title->ToUpper()->Contains(txtFilter->Text->ToUpper());
	}
	return obj->ToString()->Contains(txtFilter->Text);
}

void PluginWindow::RefreshList()
{
	if ((PlaylistLock != nullptr) && (PlaylistLock->WaitOne(0)))
	{
		try
		{
			int i, length = GetListLength();
			Action<Track^>^ add = gcnew Action<Track^>(Playlist, &ObservableCollection<Track^>::Add);
			this->Invoke(gcnew Action(Playlist, &ObservableCollection<Track^>::Clear));
			for (i = 0; i < length; i++)
			{
				this->AsyncInvoke(add, gcnew Track(GetPlayListFile(i), GetPlayListTitle(i)));
			}
		}
		finally
		{
			PlaylistLock->ReleaseMutex();
		}
	}
}

void PluginWindow::OnSourceInitialized(EventArgs^ e)
{
	Window::OnSourceInitialized(e);
	HIDE(this);
}

void PluginWindow::OnDeactivated(EventArgs^ e)
{
	Window::OnActivated(e);
	HIDE(this);
}

void PluginWindow::OnMouseLeftButtonDown(System::Windows::Input::MouseButtonEventArgs^ e)
{
	Window::OnMouseLeftButtonDown(e);
	DragMove();
}

void PluginWindow::OnClosing(System::ComponentModel::CancelEventArgs ^e)
{
	Window::OnClosing(e);
	if (!IsClosing)
	{
		e->Cancel = true;
		HIDE(this);
	}
	else
	{
		this->PlaylistLock->Close();	//ֻwinamp˳ŻöδMutexΪ̶֮٣һǼ
		this->PlaylistLock = nullptr;
	}
}

void PluginWindow::txtFilter_TextChanged(System::Object ^sender, TextChangedEventArgs ^e)
{
	if (Visibility != System::Windows::Visibility::Visible) return;
	PlaylistView->Refresh();
}

//txtFilterеİ¼
void PluginWindow::txtFilter_KeyDown(System::Object ^sender, System::Windows::Input::KeyEventArgs ^e)
{
	if (!ISVISIBLE(this)) return;
	if (e->Key == System::Windows::Input::Key::Enter)
	{
		if (PlaylistView->Count <= 0) return;
		PlaylistView->MoveCurrentToFirst();
		PlayIndex(Playlist->IndexOf((Track^)PlaylistView->CurrentItem));
		HIDE(this);
	}
	else if (e->Key == System::Windows::Input::Key::Tab)
	{
		if (PlaylistView->Count == 0)
		{
			e->Handled = true;
			System::Media::SystemSounds::Question->Play();
			return;
		}
		PlaylistView->MoveCurrentToFirst();
		if (PlaylistView->CurrentItem != nullptr)
		{
			lstPlaylist->SelectedItem = PlaylistView->CurrentItem;
		}
		else
		{
			return;
		}
		lstPlaylist->ScrollIntoView(lstPlaylist->SelectedItem);
	}
}

//lstPlaylistеİ¼
void PluginWindow::lstPlaylist_KeyDown(System::Object ^sender, System::Windows::Input::KeyEventArgs ^e)
{
	if (!ISVISIBLE(this)) return;
	if (e->Key == System::Windows::Input::Key::Enter)
	{
		PlayIndex(Playlist->IndexOf((Track^)lstPlaylist->SelectedItem));
		HIDE(this);
	}
	else if (e->Key == System::Windows::Input::Key::Tab)
	{
		if (!(PlaylistView->MoveCurrentToNext()))
		{
			PlaylistView->MoveCurrentToFirst();
		}
		lstPlaylist->SelectedItem = PlaylistView->CurrentItem;
		lstPlaylist->ScrollIntoView(lstPlaylist->SelectedItem);
		e->Handled = true;
	}
	else if (e->Key == System::Windows::Input::Key::Q)
	{
		QueueIndex(Playlist->IndexOf((Track^)lstPlaylist->SelectedItem));
		HIDE(this);
	}
}

//˫ʱѡ
void PluginWindow::lstPlaylist_MouseDoubleClick(System::Object ^sender, System::Windows::Input::MouseButtonEventArgs ^e)
{
	DependencyObject^ obj = dynamic_cast<DependencyObject^>(e->OriginalSource);
	while ((obj != nullptr) && (obj != lstPlaylist))
	{
		if (obj->GetType() == ListBoxItem::typeid)
		{
			Object^ t = (dynamic_cast<ListBoxItem^>(obj))->DataContext;
			if (t->GetType() == Track::typeid)
			{
				PlayIndex(Playlist->IndexOf(dynamic_cast<Track^>(t)));
				HIDE(this);
			}
			break;
		}
		obj = System::Windows::Media::VisualTreeHelper::GetParent(obj);
	}
}

void PluginWindow::window_PreviewKeyDown(System::Object ^sender, System::Windows::Input::KeyEventArgs ^e)
{
	if (e->Key == System::Windows::Input::Key::Escape)
	{
		e->Handled = true;
		HIDE(this);
	}
	else if (e->Key == System::Windows::Input::Key::F5)
	{
		e->Handled = true;
		RLcallback->BeginInvoke(nullptr, nullptr);
	}
}

void PluginWindow::ShowAndFocus()
{
	if (ISVISIBLE(this)) return;
	this->Visibility = System::Windows::Visibility::Visible;
	Activate();
	txtFilter->Focus();
	txtFilter->Text = String::Empty;
	PlaylistView->MoveCurrentToFirst();
	lstPlaylist->SelectedItem = PlaylistView->CurrentItem;
}

void PluginWindow::AsyncInvoke(Action^ callback)
{
	if (callback == nullptr) return;
	this->Dispatcher->BeginInvoke(System::Windows::Threading::DispatcherPriority::Normal, callback);
}

generic <typename T>void PluginWindow::AsyncInvoke(Action<T>^ callback, T arg)
{
	if (callback == nullptr) return;
	this->Dispatcher->BeginInvoke(System::Windows::Threading::DispatcherPriority::Normal, callback, arg);
}

void PluginWindow::Invoke(Action^ callback)
{
	if (callback == nullptr) return;
	this->Dispatcher->Invoke(System::Windows::Threading::DispatcherPriority::Normal, callback);
}

//WINAMP API
void PluginWindow::QueueIndex(int index)
{
	if (QueueApi != NULL)
	{
		QueueApi->AddItemToQueue(index, 1, NULL);
	}
}

String ^ PluginWindow::GetPlayListFile(int index)
{
	return gcnew String((wchar_t*)SendMessage(plugin.hwndParent, WM_WA_IPC, (WPARAM)index, IPC_GETPLAYLISTFILEW));
}

String ^ PluginWindow::GetPlayListTitle(int index)
{
	return gcnew String((wchar_t*)SendMessage(plugin.hwndParent, WM_WA_IPC, (WPARAM)index, IPC_GETPLAYLISTTITLEW));
}

int PluginWindow::GetListLength()
{
	return SendMessage(plugin.hwndParent, WM_WA_IPC, 0, IPC_GETLISTLENGTH);
}

void PluginWindow::PlayIndex(int index)
{
	SendMessage(plugin.hwndParent, WM_WA_IPC, (WPARAM)index, IPC_SETPLAYLISTPOS);
	SendMessage(plugin.hwndParent, WM_COMMAND, MAKEWPARAM(WINAMP_BUTTON2, 0), 0);
}<|endoftext|>


<commit_before>/*
This file is part of khmer, https://github.com/dib-lab/khmer/, and is
Copyright (C) 2010-2015, Michigan State University.
Copyright (C) 2015-2016, The Regents of the University of California.

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 Michigan State University 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
HOLDER 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.
LICENSE (END)

Contact: khmer-project@idyll.org
*/
#ifndef KMER_HASH_HH
#define KMER_HASH_HH

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>

#include "khmer.hh"

// test validity
#ifdef KHMER_EXTRA_SANITY_CHECKS
#   define is_valid_dna(ch) ((toupper(ch)) == 'A' || (toupper(ch)) == 'C' || \
			    (toupper(ch)) == 'G' || (toupper(ch)) == 'T')
#else
// NOTE: Assumes data is already sanitized as it should be by parsers.
//	     This assumption eliminates 4 function calls.
#   define is_valid_dna(ch) ((ch) == 'A' || (ch) == 'C' || \
			     (ch) == 'G' || (ch) == 'T')
#endif

// bit representation of A/T/C/G.
#ifdef KHMER_EXTRA_SANITY_CHECKS
#   define twobit_repr(ch) ((toupper(ch)) == 'A' ? 0LL : \
			    (toupper(ch)) == 'T' ? 1LL : \
			    (toupper(ch)) == 'C' ? 2LL : 3LL)
#else
// NOTE: Assumes data is already sanitized as it should be by parsers.
//	     This assumption eliminates 4 function calls.
#   define twobit_repr(ch) ((ch) == 'A' ? 0LL : \
			    (ch) == 'T' ? 1LL : \
			    (ch) == 'C' ? 2LL : 3LL)
#endif

#define revtwobit_repr(n) ((n) == 0 ? 'A' : \
                           (n) == 1 ? 'T' : \
                           (n) == 2 ? 'C' : 'G')

#ifdef KHMER_EXTRA_SANITY_CHECKS
#   define twobit_comp(ch) ((toupper(ch)) == 'A' ? 1LL : \
			    (toupper(ch)) == 'T' ? 0LL : \
			    (toupper(ch)) == 'C' ? 3LL : 2LL)
#else
// NOTE: Assumes data is already sanitized as it should be by parsers.
//	     This assumption eliminates 4 function calls.
#   define twobit_comp(ch) ((ch) == 'A' ? 1LL : \
			    (ch) == 'T' ? 0LL : \
			    (ch) == 'C' ? 3LL : 2LL)
#endif

// choose wisely between forward and rev comp.
#ifndef NO_UNIQUE_RC
#define uniqify_rc(f, r) ((f) < (r) ? (f) : (r))
#else
#define uniqify_rc(f,r)(f)
#endif

namespace khmer
{
// two-way hash functions.
HashIntoType _hash(const char * kmer, const WordLength k);
HashIntoType _hash(const char * kmer, const WordLength k,
                   HashIntoType& h, HashIntoType& r);
HashIntoType _hash(const std::string kmer, const WordLength k);
HashIntoType _hash(const std::string kmer, const WordLength k,
                   HashIntoType& h, HashIntoType& r);
HashIntoType _hash_forward(const char * kmer, WordLength k);

std::string _revhash(HashIntoType hash, WordLength k);
std::string _revcomp(const std::string& kmer);

// two-way hash functions, MurmurHash3.
HashIntoType _hash_murmur(const std::string& kmer);
HashIntoType _hash_murmur(const std::string& kmer,
                          HashIntoType& h, HashIntoType& r);
HashIntoType _hash_murmur_forward(const std::string& kmer);

/**
 * \class Kmer
 *
 * \brief Hold the hash values corresponding to a single k-mer.
 *
 * This class stores the forward, reverse complement, and
 * uniqified hash values for a given k-mer. It also defines
 * some basic operators and a utility function for getting
 * the string representation of the sequence. This is meant
 * to replace the original inelegant macros used for hashing.
 *
 * \author Camille Scott
 *
 * Contact: camille.scott.w@gmail.com
 *
 */
class Kmer
{

public:

    /// The forward hash
    HashIntoType kmer_f;
    /// The reverse (complement) hash
    HashIntoType kmer_r;
    /// The uniqified hash
    HashIntoType kmer_u;

    /** @param[in]   f forward hash.
     *  @param[in]   r reverse (complement) hash.
     *  @param[in]   u uniqified hash.
     */
    Kmer(HashIntoType f, HashIntoType r, HashIntoType u)
    {
        kmer_f = f;
        kmer_r = r;
        kmer_u = u;
    }

    /** @param[in]   s     DNA k-mer
        @param[in]   ksize k-mer size
     */
    Kmer(const std::string s, WordLength ksize)
    {
        kmer_u = _hash(s.c_str(), ksize, kmer_f, kmer_r);
    }

    /// @warning The default constructor builds an invalid k-mer.
    Kmer()
    {
        kmer_f = kmer_r = kmer_u = 0;
    }

    void set_from_unique_hash(HashIntoType h, WordLength ksize)
    {
        std::string s = _revhash(h, ksize);
        kmer_u = _hash(s.c_str(), ksize, kmer_f, kmer_r);
    }

    /// Allows complete backwards compatibility
    operator HashIntoType() const
    {
        return kmer_u;
    }

    bool operator< (const Kmer &other) const
    {
        return kmer_u < other.kmer_u;
    }

    std::string get_string_rep(WordLength K) const
    {
        return _revhash(kmer_u, K);
    }

    char get_last_base() const
    {
        return revtwobit_repr(kmer_f & 3);
    }

};

/**
 * \class KmerFactory
 *
 * \brief Build complete Kmer objects.
 *
 * The KmerFactory is a simple construct to emit complete
 * Kmer objects. The design decision leading to this class
 * stems from the issue of overloading the Kmer constructor
 * while also giving it a K size: you get ambiguous signatures
 * between the (kmer_u, K) and (kmer_f, kmer_r) cases. This
 * implementation also allows a logical architecture wherein
 * KmerIterator and Hashtable inherit directly from KmerFactory,
 * extending the latter's purpose of "create k-mers" to
 * "emit k-mers from a sequence" and "create and store k-mers".
 *
 * \author Camille Scott
 *
 * Contact: camille.scott.w@gmail.com
 *
 */
class KmerFactory
{
protected:
    WordLength _ksize;

public:

    explicit KmerFactory(WordLength K): _ksize(K) {}

    /** @param[in]  kmer_u Uniqified hash value.
     *  @return A complete Kmer object.
     */
    Kmer build_kmer(HashIntoType kmer_u)
    {
        HashIntoType kmer_f, kmer_r;
        std:: string kmer_s = _revhash(kmer_u, _ksize);
        _hash(kmer_s.c_str(), _ksize, kmer_f, kmer_r);
        return Kmer(kmer_f, kmer_r, kmer_u);
    }

    /** Call the uniqify function and build a complete Kmer.
     *
     *  @param[in]  kmer_f Forward hash value.
     *  @param[in]  kmer_r Reverse complement hash value.
     *  @return A complete Kmer object.
     */
    Kmer build_kmer(HashIntoType kmer_f, HashIntoType kmer_r)
    {
        HashIntoType kmer_u = uniqify_rc(kmer_f, kmer_r);
        return Kmer(kmer_f, kmer_r, kmer_u);
    }

    /** Hash the given sequence and call the uniqify function
     *  on its results to build a complete Kmer.
     *
     *  @param[in]  kmer_s String representation of a k-mer.
     *  @return A complete Kmer object hashed from the given string.
     */
    Kmer build_kmer(std::string kmer_s) const
    {
        HashIntoType kmer_f, kmer_r, kmer_u;
        kmer_u = _hash(kmer_s.c_str(), _ksize, kmer_f, kmer_r);
        return Kmer(kmer_f, kmer_r, kmer_u);
    }

    /** Hash the given sequence and call the uniqify function
     *  on its results to build a complete Kmer.
     *
     *  @param[in]  kmer_c The character array representation of a k-mer.
     *  @return A complete Kmer object hashed from the given char array.
     */
    Kmer build_kmer(const char * kmer_c) const
    {
        HashIntoType kmer_f, kmer_r, kmer_u;
        kmer_u = _hash(kmer_c, _ksize, kmer_f, kmer_r);
        return Kmer(kmer_f, kmer_r, kmer_u);
    }
};

/**
 * \class KmerIterator
 *
 * \brief Emit Kmer objects generated from the given sequence.
 *
 * Given a string \f$S\f$ and a length \f$K > 0\f$, we define
 * the k-mers of \f$S\f$ as the set \f$S_{i..i+K} \forall i \in \{0..|S|-K+1\}\f$,
 * where \f$|S|\f$ is the length and \f$S_{j..k}\f$ is the half-open
 * substring starting at \f$j\f$ and terminating at \f$k\f$.
 *
 * KmerIterator mimics a python-style generator function which
 * emits the k-mers of the given sequence, in order, as Kmer objects.
 *
 * @warning This is not actually a valid C++ iterator, though it is close.
 *
 * \author Camille Scott
 *
 * Contact: camille.scott.w@gmail.com
 *
 */
class KmerIterator: public KmerFactory
{
protected:
    const char * _seq;

    HashIntoType _kmer_f, _kmer_r;
    HashIntoType bitmask;
    unsigned int _nbits_sub_1;
    unsigned int index;
    size_t length;
    bool initialized;
public:
    KmerIterator(const char * seq, unsigned char k);

    /** @param[in]  f The forward hash value.
     *  @param[in]  r The reverse complement hash value.
     *  @return The first Kmer of the sequence.
     */
    Kmer first(HashIntoType& f, HashIntoType& r);

    /** @param[in]  f The current forward hash value
     *  @param[in]  r The current reverse complement hash value
     *  @return The next Kmer in the sequence
     */
    Kmer next(HashIntoType& f, HashIntoType& r);

    Kmer first()
    {
        return first(_kmer_f, _kmer_r);
    }

    Kmer next()
    {
        return next(_kmer_f, _kmer_r);
    }

    /// @return Whether or not the iterator has completed.
    bool done()
    {
        return index >= length;
    }

    unsigned int get_start_pos() const
    {
        return index - _ksize;
    }

    unsigned int get_end_pos() const
    {
        return index;
    }
}; // class KmerIterator

}

#endif // KMER_HASH_HH
<commit_msg>Add string representation for Kmer<commit_after>/*
This file is part of khmer, https://github.com/dib-lab/khmer/, and is
Copyright (C) 2010-2015, Michigan State University.
Copyright (C) 2015-2016, The Regents of the University of California.

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 Michigan State University 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
HOLDER 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.
LICENSE (END)

Contact: khmer-project@idyll.org
*/
#ifndef KMER_HASH_HH
#define KMER_HASH_HH

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>

#include "khmer.hh"

// test validity
#ifdef KHMER_EXTRA_SANITY_CHECKS
#   define is_valid_dna(ch) ((toupper(ch)) == 'A' || (toupper(ch)) == 'C' || \
			    (toupper(ch)) == 'G' || (toupper(ch)) == 'T')
#else
// NOTE: Assumes data is already sanitized as it should be by parsers.
//	     This assumption eliminates 4 function calls.
#   define is_valid_dna(ch) ((ch) == 'A' || (ch) == 'C' || \
			     (ch) == 'G' || (ch) == 'T')
#endif

// bit representation of A/T/C/G.
#ifdef KHMER_EXTRA_SANITY_CHECKS
#   define twobit_repr(ch) ((toupper(ch)) == 'A' ? 0LL : \
			    (toupper(ch)) == 'T' ? 1LL : \
			    (toupper(ch)) == 'C' ? 2LL : 3LL)
#else
// NOTE: Assumes data is already sanitized as it should be by parsers.
//	     This assumption eliminates 4 function calls.
#   define twobit_repr(ch) ((ch) == 'A' ? 0LL : \
			    (ch) == 'T' ? 1LL : \
			    (ch) == 'C' ? 2LL : 3LL)
#endif

#define revtwobit_repr(n) ((n) == 0 ? 'A' : \
                           (n) == 1 ? 'T' : \
                           (n) == 2 ? 'C' : 'G')

#ifdef KHMER_EXTRA_SANITY_CHECKS
#   define twobit_comp(ch) ((toupper(ch)) == 'A' ? 1LL : \
			    (toupper(ch)) == 'T' ? 0LL : \
			    (toupper(ch)) == 'C' ? 3LL : 2LL)
#else
// NOTE: Assumes data is already sanitized as it should be by parsers.
//	     This assumption eliminates 4 function calls.
#   define twobit_comp(ch) ((ch) == 'A' ? 1LL : \
			    (ch) == 'T' ? 0LL : \
			    (ch) == 'C' ? 3LL : 2LL)
#endif

// choose wisely between forward and rev comp.
#ifndef NO_UNIQUE_RC
#define uniqify_rc(f, r) ((f) < (r) ? (f) : (r))
#else
#define uniqify_rc(f,r)(f)
#endif

namespace khmer
{
// two-way hash functions.
HashIntoType _hash(const char * kmer, const WordLength k);
HashIntoType _hash(const char * kmer, const WordLength k,
                   HashIntoType& h, HashIntoType& r);
HashIntoType _hash(const std::string kmer, const WordLength k);
HashIntoType _hash(const std::string kmer, const WordLength k,
                   HashIntoType& h, HashIntoType& r);
HashIntoType _hash_forward(const char * kmer, WordLength k);

std::string _revhash(HashIntoType hash, WordLength k);
std::string _revcomp(const std::string& kmer);

// two-way hash functions, MurmurHash3.
HashIntoType _hash_murmur(const std::string& kmer);
HashIntoType _hash_murmur(const std::string& kmer,
                          HashIntoType& h, HashIntoType& r);
HashIntoType _hash_murmur_forward(const std::string& kmer);

/**
 * \class Kmer
 *
 * \brief Hold the hash values corresponding to a single k-mer.
 *
 * This class stores the forward, reverse complement, and
 * uniqified hash values for a given k-mer. It also defines
 * some basic operators and a utility function for getting
 * the string representation of the sequence. This is meant
 * to replace the original inelegant macros used for hashing.
 *
 * \author Camille Scott
 *
 * Contact: camille.scott.w@gmail.com
 *
 */
class Kmer
{

public:

    /// The forward hash
    HashIntoType kmer_f;
    /// The reverse (complement) hash
    HashIntoType kmer_r;
    /// The uniqified hash
    HashIntoType kmer_u;

    /** @param[in]   f forward hash.
     *  @param[in]   r reverse (complement) hash.
     *  @param[in]   u uniqified hash.
     */
    Kmer(HashIntoType f, HashIntoType r, HashIntoType u)
    {
        kmer_f = f;
        kmer_r = r;
        kmer_u = u;
    }

    /** @param[in]   s     DNA k-mer
        @param[in]   ksize k-mer size
     */
    Kmer(const std::string s, WordLength ksize)
    {
        kmer_u = _hash(s.c_str(), ksize, kmer_f, kmer_r);
    }

    /// @warning The default constructor builds an invalid k-mer.
    Kmer()
    {
        kmer_f = kmer_r = kmer_u = 0;
    }

    void set_from_unique_hash(HashIntoType h, WordLength ksize)
    {
        std::string s = _revhash(h, ksize);
        kmer_u = _hash(s.c_str(), ksize, kmer_f, kmer_r);
    }

    /// Allows complete backwards compatibility
    operator HashIntoType() const
    {
        return kmer_u;
    }

    bool operator< (const Kmer &other) const
    {
        return kmer_u < other.kmer_u;
    }

    std::string get_string_rep(WordLength K) const
    {
        return _revhash(kmer_u, K);
    }

    char get_last_base() const
    {
        return revtwobit_repr(kmer_f & 3);
    }

    std::string repr(WordLength K)
    {
        std::string s = "<Us=" + _revhash(kmer_u, K) + ", Fs=" +
            _revhash(kmer_f, K) + ", Rs=" + _revhash(kmer_r, K) +
            ", U=" + std::to_string(kmer_u) + ", F=" + std::to_string(kmer_f) +
            ", R=" + std::to_string(kmer_r) + ">";
        return s;
    }
};

/**
 * \class KmerFactory
 *
 * \brief Build complete Kmer objects.
 *
 * The KmerFactory is a simple construct to emit complete
 * Kmer objects. The design decision leading to this class
 * stems from the issue of overloading the Kmer constructor
 * while also giving it a K size: you get ambiguous signatures
 * between the (kmer_u, K) and (kmer_f, kmer_r) cases. This
 * implementation also allows a logical architecture wherein
 * KmerIterator and Hashtable inherit directly from KmerFactory,
 * extending the latter's purpose of "create k-mers" to
 * "emit k-mers from a sequence" and "create and store k-mers".
 *
 * \author Camille Scott
 *
 * Contact: camille.scott.w@gmail.com
 *
 */
class KmerFactory
{
protected:
    WordLength _ksize;

public:

    explicit KmerFactory(WordLength K): _ksize(K) {}

    /** @param[in]  kmer_u Uniqified hash value.
     *  @return A complete Kmer object.
     */
    Kmer build_kmer(HashIntoType kmer_u)
    {
        HashIntoType kmer_f, kmer_r;
        std:: string kmer_s = _revhash(kmer_u, _ksize);
        _hash(kmer_s.c_str(), _ksize, kmer_f, kmer_r);
        return Kmer(kmer_f, kmer_r, kmer_u);
    }

    /** Call the uniqify function and build a complete Kmer.
     *
     *  @param[in]  kmer_f Forward hash value.
     *  @param[in]  kmer_r Reverse complement hash value.
     *  @return A complete Kmer object.
     */
    Kmer build_kmer(HashIntoType kmer_f, HashIntoType kmer_r)
    {
        HashIntoType kmer_u = uniqify_rc(kmer_f, kmer_r);
        return Kmer(kmer_f, kmer_r, kmer_u);
    }

    /** Hash the given sequence and call the uniqify function
     *  on its results to build a complete Kmer.
     *
     *  @param[in]  kmer_s String representation of a k-mer.
     *  @return A complete Kmer object hashed from the given string.
     */
    Kmer build_kmer(std::string kmer_s) const
    {
        HashIntoType kmer_f, kmer_r, kmer_u;
        kmer_u = _hash(kmer_s.c_str(), _ksize, kmer_f, kmer_r);
        return Kmer(kmer_f, kmer_r, kmer_u);
    }

    /** Hash the given sequence and call the uniqify function
     *  on its results to build a complete Kmer.
     *
     *  @param[in]  kmer_c The character array representation of a k-mer.
     *  @return A complete Kmer object hashed from the given char array.
     */
    Kmer build_kmer(const char * kmer_c) const
    {
        HashIntoType kmer_f, kmer_r, kmer_u;
        kmer_u = _hash(kmer_c, _ksize, kmer_f, kmer_r);
        return Kmer(kmer_f, kmer_r, kmer_u);
    }
};

/**
 * \class KmerIterator
 *
 * \brief Emit Kmer objects generated from the given sequence.
 *
 * Given a string \f$S\f$ and a length \f$K > 0\f$, we define
 * the k-mers of \f$S\f$ as the set \f$S_{i..i+K} \forall i \in \{0..|S|-K+1\}\f$,
 * where \f$|S|\f$ is the length and \f$S_{j..k}\f$ is the half-open
 * substring starting at \f$j\f$ and terminating at \f$k\f$.
 *
 * KmerIterator mimics a python-style generator function which
 * emits the k-mers of the given sequence, in order, as Kmer objects.
 *
 * @warning This is not actually a valid C++ iterator, though it is close.
 *
 * \author Camille Scott
 *
 * Contact: camille.scott.w@gmail.com
 *
 */
class KmerIterator: public KmerFactory
{
protected:
    const char * _seq;

    HashIntoType _kmer_f, _kmer_r;
    HashIntoType bitmask;
    unsigned int _nbits_sub_1;
    unsigned int index;
    size_t length;
    bool initialized;
public:
    KmerIterator(const char * seq, unsigned char k);

    /** @param[in]  f The forward hash value.
     *  @param[in]  r The reverse complement hash value.
     *  @return The first Kmer of the sequence.
     */
    Kmer first(HashIntoType& f, HashIntoType& r);

    /** @param[in]  f The current forward hash value
     *  @param[in]  r The current reverse complement hash value
     *  @return The next Kmer in the sequence
     */
    Kmer next(HashIntoType& f, HashIntoType& r);

    Kmer first()
    {
        return first(_kmer_f, _kmer_r);
    }

    Kmer next()
    {
        return next(_kmer_f, _kmer_r);
    }

    /// @return Whether or not the iterator has completed.
    bool done()
    {
        return index >= length;
    }

    unsigned int get_start_pos() const
    {
        return index - _ksize;
    }

    unsigned int get_end_pos() const
    {
        return index;
    }
}; // class KmerIterator

}

#endif // KMER_HASH_HH
<|endoftext|>


<commit_before>//-----------------------------------------------
//
//	This file is part of the Siv3D Engine.
//
//	Copyright (c) 2008-2019 Ryo Suzuki
//	Copyright (c) 2016-2019 OpenSiv3D Project
//
//	Licensed under the MIT License.
//
//-----------------------------------------------

# include <cfloat>
# include <Siv3D/Ray.hpp>
# include <Siv3D/AABB.hpp>
# include <Siv3D/SIMD_Float4.hpp>
# include <Siv3D/SIMDMath.hpp>

namespace s3d
{
	///////////////////////////////////////////////////////////////
	//
	//

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

	namespace detail
	{
		inline constexpr __m128 m128_RayEpsilon{ 1e-20f, 1e-20f, 1e-20f, 1e-20f };
		inline constexpr __m128 m128_FltMin{ -FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX };
		inline constexpr __m128 m128_FltMax{ FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };

		//-----------------------------------------------------------------------------
		// Return true if any of the elements of a 3 vector are equal to 0xffffffff.
		// Slightly more efficient than using XMVector3EqualInt.
		//-----------------------------------------------------------------------------
		inline bool Vector3AnyTrue(__m128 V)
		{
			// Duplicate the fourth element from the first element.
			__m128 C = SIMD::Swizzle<SIMD::constants::SwizzleX, SIMD::constants::SwizzleY, SIMD::constants::SwizzleZ, SIMD::constants::SwizzleX>(V);

			return SIMD::ComparisonAnyTrue(SIMD::Vector4EqualIntR(C, SIMD::TrueInt()));
		}
	}

	Optional<float> Ray::intersects(const experimental::AABB& aabb) const
	{
		//assert(SIMD::Internal::Vector3IsUnit(Direction));

		const __m128 Origin = SIMD_Float4(origin, 0.0f);
		const __m128 Direction = SIMD_Float4(direction, 0.0f);

		// Load the box.
		__m128 vCenter = SIMD_Float4(aabb.center, 0.0f);
		__m128 vExtents = SIMD_Float4(aabb.size * 0.5f, 0.0f);

		// Adjust ray origin to be relative to center of the box.
		__m128 TOrigin = SIMD::Subtract(vCenter, Origin);

		// Compute the dot product againt each axis of the box.
		// Since the axii are (1,0,0), (0,1,0), (0,0,1) no computation is necessary.
		__m128 AxisDotOrigin = TOrigin;
		__m128 AxisDotDirection = Direction;

		// if (fabs(AxisDotDirection) <= Epsilon) the ray is nearly parallel to the slab.
		__m128 IsParallel = SIMD::LessOrEqual(SIMD::Abs(AxisDotDirection), detail::m128_RayEpsilon);

		// Test against all three axii simultaneously.
		__m128 InverseAxisDotDirection = SIMD::Reciprocal(AxisDotDirection);
		__m128 t1 = SIMD::Multiply(SIMD::Subtract(AxisDotOrigin, vExtents), InverseAxisDotDirection);
		__m128 t2 = SIMD::Multiply(SIMD::Add(AxisDotOrigin, vExtents), InverseAxisDotDirection);

		// Compute the max of min(t1,t2) and the min of max(t1,t2) ensuring we don't
		// use the results from any directions parallel to the slab.
		__m128 t_min = SIMD::Select(SIMD::Min(t1, t2), detail::m128_FltMin, IsParallel);
		__m128 t_max = SIMD::Select(SIMD::Max(t1, t2), detail::m128_FltMax, IsParallel);

		// t_min.x = maximum( t_min.x, t_min.y, t_min.z );
		// t_max.x = minimum( t_max.x, t_max.y, t_max.z );
		t_min = SIMD::Max(t_min, SIMD::SplatY(t_min));  // x = max(x,y)
		t_min = SIMD::Max(t_min, SIMD::SplatZ(t_min));  // x = max(max(x,y),z)
		t_max = SIMD::Min(t_max, SIMD::SplatY(t_max));  // x = min(x,y)
		t_max = SIMD::Min(t_max, SIMD::SplatZ(t_max));  // x = min(min(x,y),z)

		// if ( t_min > t_max ) return false;
		__m128 NoIntersection = SIMD::Greater(SIMD::SplatX(t_min), SIMD::SplatX(t_max));

		// if ( t_max < 0.0f ) return false;
		NoIntersection = SIMD::OrInt(NoIntersection, SIMD::Less(SIMD::SplatX(t_max), SIMD::Zero()));

		// if (IsParallel && (-Extents > AxisDotOrigin || Extents < AxisDotOrigin)) return false;
		__m128 ParallelOverlap = SIMD::InBounds(AxisDotOrigin, vExtents);
		NoIntersection = SIMD::OrInt(NoIntersection, SIMD::AndCInt(IsParallel, ParallelOverlap));

		if (!detail::Vector3AnyTrue(NoIntersection))
		{
			float distance = 0.0f;
			// Store the x-component to *pDist
			SIMD::StoreFloat(&distance, t_min);
			return distance;
		}

		return none;
	}

	//
	//
	///////////////////////////////////////////////////////////////
}
<commit_msg>Update SivRay.cpp<commit_after>//-----------------------------------------------
//
//	This file is part of the Siv3D Engine.
//
//	Copyright (c) 2008-2019 Ryo Suzuki
//	Copyright (c) 2016-2019 OpenSiv3D Project
//
//	Licensed under the MIT License.
//
//-----------------------------------------------

# include <cfloat>
# include <Siv3D/Ray.hpp>
# include <Siv3D/AABB.hpp>
# include <Siv3D/SIMD_Float4.hpp>
# include <Siv3D/SIMDMath.hpp>

namespace s3d
{
	///////////////////////////////////////////////////////////////
	//
	//

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

	namespace detail
	{
		inline constexpr __m128 m128_RayEpsilon{ 1e-20f, 1e-20f, 1e-20f, 1e-20f };
		inline constexpr __m128 m128_FltMin{ -FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX };
		inline constexpr __m128 m128_FltMax{ FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };

		//-----------------------------------------------------------------------------
		// Return true if any of the elements of a 3 vector are equal to 0xffffffff.
		// Slightly more efficient than using XMVector3EqualInt.
		//-----------------------------------------------------------------------------
		inline bool Vector3AnyTrue(__m128 V)
		{
			// Duplicate the fourth element from the first element.
			__m128 C = SIMD::Swizzle<SIMD::constants::SwizzleX, SIMD::constants::SwizzleY, SIMD::constants::SwizzleZ, SIMD::constants::SwizzleX>(V);

			return SIMD::ComparisonAnyTrue(SIMD::Vector4EqualIntR(C, SIMD::TrueInt()));
		}
	}

	Optional<float> Ray::intersects(const experimental::AABB& aabb) const
	{
		//assert(SIMD::Internal::Vector3IsUnit(Direction));

		const __m128 Origin = SIMD_Float4(origin, 0.0f);
		const __m128 Direction = SIMD_Float4(direction, 0.0f);

		// Load the box.
		__m128 vCenter = SIMD_Float4(aabb.center, 0.0f);
		__m128 vExtents = SIMD_Float4(aabb.size, 0.0f);
		vExtents = SIMD::Multiply(vExtents, SIMD::constants::m128_OneHalf);

		// Adjust ray origin to be relative to center of the box.
		__m128 TOrigin = SIMD::Subtract(vCenter, Origin);

		// Compute the dot product againt each axis of the box.
		// Since the axii are (1,0,0), (0,1,0), (0,0,1) no computation is necessary.
		__m128 AxisDotOrigin = TOrigin;
		__m128 AxisDotDirection = Direction;

		// if (fabs(AxisDotDirection) <= Epsilon) the ray is nearly parallel to the slab.
		__m128 IsParallel = SIMD::LessOrEqual(SIMD::Abs(AxisDotDirection), detail::m128_RayEpsilon);

		// Test against all three axii simultaneously.
		__m128 InverseAxisDotDirection = SIMD::Reciprocal(AxisDotDirection);
		__m128 t1 = SIMD::Multiply(SIMD::Subtract(AxisDotOrigin, vExtents), InverseAxisDotDirection);
		__m128 t2 = SIMD::Multiply(SIMD::Add(AxisDotOrigin, vExtents), InverseAxisDotDirection);

		// Compute the max of min(t1,t2) and the min of max(t1,t2) ensuring we don't
		// use the results from any directions parallel to the slab.
		__m128 t_min = SIMD::Select(SIMD::Min(t1, t2), detail::m128_FltMin, IsParallel);
		__m128 t_max = SIMD::Select(SIMD::Max(t1, t2), detail::m128_FltMax, IsParallel);

		// t_min.x = maximum( t_min.x, t_min.y, t_min.z );
		// t_max.x = minimum( t_max.x, t_max.y, t_max.z );
		t_min = SIMD::Max(t_min, SIMD::SplatY(t_min));  // x = max(x,y)
		t_min = SIMD::Max(t_min, SIMD::SplatZ(t_min));  // x = max(max(x,y),z)
		t_max = SIMD::Min(t_max, SIMD::SplatY(t_max));  // x = min(x,y)
		t_max = SIMD::Min(t_max, SIMD::SplatZ(t_max));  // x = min(min(x,y),z)

		// if ( t_min > t_max ) return false;
		__m128 NoIntersection = SIMD::Greater(SIMD::SplatX(t_min), SIMD::SplatX(t_max));

		// if ( t_max < 0.0f ) return false;
		NoIntersection = SIMD::OrInt(NoIntersection, SIMD::Less(SIMD::SplatX(t_max), SIMD::Zero()));

		// if (IsParallel && (-Extents > AxisDotOrigin || Extents < AxisDotOrigin)) return false;
		__m128 ParallelOverlap = SIMD::InBounds(AxisDotOrigin, vExtents);
		NoIntersection = SIMD::OrInt(NoIntersection, SIMD::AndCInt(IsParallel, ParallelOverlap));

		if (!detail::Vector3AnyTrue(NoIntersection))
		{
			float distance = 0.0f;
			// Store the x-component to *pDist
			SIMD::StoreFloat(&distance, t_min);
			return distance;
		}

		return none;
	}

	//
	//
	///////////////////////////////////////////////////////////////
}
<|endoftext|>


<commit_before>
#include "journal/player.hpp"

#include <list>
#include <string>
#include <vector>

#include "benchmark/benchmark.h"
#include "gtest/gtest.h"
#include "journal/method.hpp"
#include "journal/profiles.hpp"
#include "journal/recorder.hpp"
#include "ksp_plugin/interface.hpp"
#include "serialization/journal.pb.h"

namespace principia {
namespace journal {

// The benchmark is only run if --gtest_filter=PlayerTest.Benchmarks
void BM_PlayForReal(benchmark::State& state) {  // NOLINT(runtime/references)
  while (state.KeepRunning()) {
    Player player(R"(P:\Public Mockingbird\Principia\JOURNAL.20160207-192649)");
    int count = 0;
    while (player.Play()) {
      ++count;
      LOG_IF(ERROR, (count % 100'000) == 0)
          << count << " journal entries replayed";
    }
  }
}

BENCHMARK(BM_PlayForReal);

class PlayerTest : public ::testing::Test {
 protected:
  PlayerTest()
      : test_info_(testing::UnitTest::GetInstance()->current_test_info()),
        test_case_name_(test_info_->test_case_name()),
        test_name_(test_info_->name()),
        plugin_(interface::principia__NewPlugin(1, 2)),
        recorder_(new Recorder(test_name_ + ".journal.hex",
                               /*verbose=*/false)) {
    Recorder::Activate(recorder_);
  }

  ~PlayerTest() override {
    Recorder::Deactivate();
  }

  ::testing::TestInfo const* const test_info_;
  std::string const test_case_name_;
  std::string const test_name_;
  std::unique_ptr<ksp_plugin::Plugin> plugin_;
  Recorder* recorder_;
};

TEST_F(PlayerTest, PlayTiny) {
  {
    Method<NewPlugin> m({1, 2});
    m.Return(plugin_.get());
  }
  {
    const ksp_plugin::Plugin* plugin = plugin_.get();
    Method<DeletePlugin> m({&plugin}, {&plugin});
    m.Return();
  }

  Player player(test_name_ + ".journal.hex");

  // Replay the journal.  Note that the journal doesn't grow as we replay
  // because we didn't call principia__ActivateRecorder so there is no active
  // journal in the ksp_plugin assembly.
  int count = 0;
  while (player.Play()) {
    ++count;
  }
  EXPECT_EQ(2, count);
}

// This test (a.k.a. benchmark) is only run if the --gtest_filter flag names it
// explicitly.
TEST_F(PlayerTest, Benchmarks) {
  if (testing::FLAGS_gtest_filter == test_case_name_ + "." + test_name_) {
    benchmark::RunSpecifiedBenchmarks();
  }
}

#if 0
// This test is only run if the --gtest_filter flag names it explicitly.
TEST_F(PlayerTest, Debug) {
  if (testing::FLAGS_gtest_filter == test_case_name_ + "." + test_name_) {
    // An example of how journalling may be used for debugging.  You must set
    // |path| and fill the |m| protocol buffer.  This probably requires to make
    // RunIfAppropriate public.
    std::string path =
        R"(P:\Public Mockingbird\Principia\PrincipiaCrash2\JOURNAL.20160211-225301)";
    Player player(path);
    int count = 0;
    while (player.Play()) {
      ++count;
      LOG_IF(ERROR, (count % 100'000) == 0) << count
                                            << " journal entries replayed";
    }

    serialization::Method m;
    auto* extension = m.MutableExtension(
        serialization::FlightPlanRenderedSegment::extension);
    auto* in = extension->mutable_in();
    in->set_plugin(213537672);
    in->set_vessel_guid("6b68236e-6563-484b-a825-1598bfaed27a");
    in->mutable_sun_world_position()->set_x(-118919908386.17902);
    in->mutable_sun_world_position()->set_y(-56606248615.544792);
    in->mutable_sun_world_position()->set_z(-56606248615.544792);
    in->set_index(0);
    player.RunIfAppropriate<FlightPlanRenderedSegment>(m);
  }
}
#endif

}  // namespace journal
}  // namespace principia
<commit_msg>Lint.<commit_after>
#include "journal/player.hpp"

#include <list>
#include <string>
#include <vector>

#include "benchmark/benchmark.h"
#include "gtest/gtest.h"
#include "journal/method.hpp"
#include "journal/profiles.hpp"
#include "journal/recorder.hpp"
#include "ksp_plugin/interface.hpp"
#include "serialization/journal.pb.h"

namespace principia {
namespace journal {

// The benchmark is only run if --gtest_filter=PlayerTest.Benchmarks
void BM_PlayForReal(benchmark::State& state) {  // NOLINT(runtime/references)
  while (state.KeepRunning()) {
    Player player(R"(P:\Public Mockingbird\Principia\JOURNAL.20160207-192649)");
    int count = 0;
    while (player.Play()) {
      ++count;
      LOG_IF(ERROR, (count % 100'000) == 0)
          << count << " journal entries replayed";
    }
  }
}

BENCHMARK(BM_PlayForReal);

class PlayerTest : public ::testing::Test {
 protected:
  PlayerTest()
      : test_info_(testing::UnitTest::GetInstance()->current_test_info()),
        test_case_name_(test_info_->test_case_name()),
        test_name_(test_info_->name()),
        plugin_(interface::principia__NewPlugin(1, 2)),
        recorder_(new Recorder(test_name_ + ".journal.hex",
                               /*verbose=*/false)) {
    Recorder::Activate(recorder_);
  }

  ~PlayerTest() override {
    Recorder::Deactivate();
  }

  ::testing::TestInfo const* const test_info_;
  std::string const test_case_name_;
  std::string const test_name_;
  std::unique_ptr<ksp_plugin::Plugin> plugin_;
  Recorder* recorder_;
};

TEST_F(PlayerTest, PlayTiny) {
  {
    Method<NewPlugin> m({1, 2});
    m.Return(plugin_.get());
  }
  {
    const ksp_plugin::Plugin* plugin = plugin_.get();
    Method<DeletePlugin> m({&plugin}, {&plugin});
    m.Return();
  }

  Player player(test_name_ + ".journal.hex");

  // Replay the journal.  Note that the journal doesn't grow as we replay
  // because we didn't call principia__ActivateRecorder so there is no active
  // journal in the ksp_plugin assembly.
  int count = 0;
  while (player.Play()) {
    ++count;
  }
  EXPECT_EQ(2, count);
}

// This test (a.k.a. benchmark) is only run if the --gtest_filter flag names it
// explicitly.
TEST_F(PlayerTest, Benchmarks) {
  if (testing::FLAGS_gtest_filter == test_case_name_ + "." + test_name_) {
    benchmark::RunSpecifiedBenchmarks();
  }
}

#if 0
// This test is only run if the --gtest_filter flag names it explicitly.
TEST_F(PlayerTest, Debug) {
  if (testing::FLAGS_gtest_filter == test_case_name_ + "." + test_name_) {
    // An example of how journalling may be used for debugging.  You must set
    // |path| and fill the |m| protocol buffer.  This probably requires to make
    // RunIfAppropriate public.
    std::string path =
        R"(P:\Public Mockingbird\Principia\PrincipiaCrash2\JOURNAL.20160211-225301)";  // NOLINT
    Player player(path);
    int count = 0;
    while (player.Play()) {
      ++count;
      LOG_IF(ERROR, (count % 100'000) == 0) << count
                                            << " journal entries replayed";
    }

    serialization::Method m;
    auto* extension = m.MutableExtension(
        serialization::FlightPlanRenderedSegment::extension);
    auto* in = extension->mutable_in();
    in->set_plugin(213537672);
    in->set_vessel_guid("6b68236e-6563-484b-a825-1598bfaed27a");
    in->mutable_sun_world_position()->set_x(-118919908386.17902);
    in->mutable_sun_world_position()->set_y(-56606248615.544792);
    in->mutable_sun_world_position()->set_z(-56606248615.544792);
    in->set_index(0);
    player.RunIfAppropriate<FlightPlanRenderedSegment>(m);
  }
}
#endif

}  // namespace journal
}  // namespace principia
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2015, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */
#include "bistro/bistro/nodes/ScriptFetcher.h"

#include "bistro/bistro/config/Config.h"
#include "bistro/bistro/config/Node.h"
#include "bistro/bistro/nodes/Nodes.h"
#include "bistro/bistro/nodes/utils.h"
#include <folly/Subprocess.h>
#include <folly/gen/File.h>

namespace facebook { namespace bistro {

using namespace folly;
using namespace std;

void ScriptFetcher::fetch(
    const Config& config,
    const NodeConfig& node_config,
    Nodes *all_nodes) const {

  // Use the "parent_level" pref to get my parents and my level ID.
  auto my_level_and_parents =
    getMyLevelAndParents(config, node_config, all_nodes);
  for (const auto& parent : my_level_and_parents.second) {
    Subprocess p(
      vector<string>{
        node_config.prefs.requireConvert<string>("script"),
        parent->name()
      },
      Subprocess::pipeStdout()
    );
    gen::byLine(p.stdout()) | [&](StringPiece line) {
      all_nodes->add(
        line.str(),
        my_level_and_parents.first,
        true,
        parent.get()
      );
      std::cout << line << std::endl;
    };
    p.wait();
  }
}

}}
<commit_msg>Fix compile error<commit_after>/*
 *  Copyright (c) 2016, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */
#include "bistro/bistro/nodes/ScriptFetcher.h"

#include <iostream>

#include "bistro/bistro/config/Config.h"
#include "bistro/bistro/config/Node.h"
#include "bistro/bistro/nodes/Nodes.h"
#include "bistro/bistro/nodes/utils.h"
#include <folly/Subprocess.h>
#include <folly/gen/File.h>

namespace facebook { namespace bistro {

using namespace folly;
using namespace std;

void ScriptFetcher::fetch(
    const Config& config,
    const NodeConfig& node_config,
    Nodes *all_nodes) const {

  // Use the "parent_level" pref to get my parents and my level ID.
  auto my_level_and_parents =
    getMyLevelAndParents(config, node_config, all_nodes);
  for (const auto& parent : my_level_and_parents.second) {
    Subprocess p(
      vector<string>{
        node_config.prefs.requireConvert<string>("script"),
        parent->name()
      },
      Subprocess::pipeStdout()
    );
    gen::byLine(p.stdout()) | [&](StringPiece line) {
      all_nodes->add(
        line.str(),
        my_level_and_parents.first,
        true,
        parent.get()
      );
      std::cout << line << std::endl;
    };
    p.wait();
  }
}

}}
<|endoftext|>