<commit_before>#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/TestCaller.h>
#include <cppunit/TestCase.h>
#include <cppunit/extensions/HelperMacros.h>
#include <iostream>
#include "Vertex.cpp"

class VertexTest : public CppUnit::TestCase
{
	private:

	public:
		void testCreateVertex()
		{//Basic test of creating a vertex.
			//Set up the vertex.
			Graph::Vertex<int> v(1, 2);

			//Verify the values.
			CPPUNIT_ASSERT( v.getID() == 1 );
			CPPUNIT_ASSERT( v.getValue() == 2 );
			CPPUNIT_ASSERT( v.getNumEdges() == 0 );
		}

		void testChangeVertex()
		{//Basic test of changing vertex values and IDs.
			//Set up the vertex.
			Graph::Vertex<int> v(1, 2);

			//Verify the values.
			CPPUNIT_ASSERT( v.getID() == 1 );
			CPPUNIT_ASSERT( v.getValue() == 2 );
			CPPUNIT_ASSERT( v.getNumEdges() == 0 );

			//Change the values
			v.setID( 3 );
			v.setValue( 4 );

			//Verify the new values.
			CPPUNIT_ASSERT( v.getID() == 3 );
			CPPUNIT_ASSERT( v.getValue() == 4 );
			CPPUNIT_ASSERT( v.getNumEdges() == 0 );
		}

		void testVertexWithEdge()
		{//Basic test of create a vertex with an edge.
			//Set up the vertex and the edge.
			Graph::Edge ed(1, 1, 2);
			Graph::Vertex<int> v(1, 2);

			//Verify the vertex has no edges yet.
			CPPUNIT_ASSERT( v.getNumEdges() == 0 );

			//Add the edge.
			v.addEdge( ed );

			//Verfiy the edge has been added.
			CPPUNIT_ASSERT( v.getNumEdges() == 1 );
			CPPUNIT_ASSERT( v.getEdge(0).getWeight() == 1 );
			CPPUNIT_ASSERT( v.getEdge(0).getStartVertex() == 1 );
			CPPUNIT_ASSERT( v.getEdge(0).getEndVertex() == 2 );
		}

		void testChangeVertexEdge()
		{//Basic test of create a vertex with an edge.
			//Set up the vertex and the edge.
			Graph::Edge ed(1, 1, 2);
			Graph::Vertex<int> v(1, 2);

			//Verify the vertex has no edges yet.
			CPPUNIT_ASSERT( v.getNumEdges() == 0 );

			//Add the edge.
			v.addEdge( ed );

			//Verfiy the edge has been added.
			CPPUNIT_ASSERT( v.getNumEdges() == 1 );
			CPPUNIT_ASSERT( v.getEdge(0).getWeight() == 1 );

			//Change the edge.
			//v.getEdge(0).setWeight(2);
			v.changeEdgeWeight( 0, 2 );

			//Verfiy the edge has been changed.
			CPPUNIT_ASSERT( v.getNumEdges() == 1 );
			CPPUNIT_ASSERT( v.getEdge(0).getWeight() == 2 );
			CPPUNIT_ASSERT( v.getEdge(0).getStartVertex() == 1 );
			CPPUNIT_ASSERT( v.getEdge(0).getEndVertex() == 2 );
		}

		//Create the test suite using CPPUnit macros.
		CPPUNIT_TEST_SUITE( VertexTest );
		CPPUNIT_TEST( testCreateVertex );
		CPPUNIT_TEST( testChangeVertex );
		CPPUNIT_TEST( testVertexWithEdge );
		CPPUNIT_TEST( testChangeVertexEdge );
		CPPUNIT_TEST_SUITE_END( );
};

int main()
{
	CPPUNIT_TEST_SUITE_REGISTRATION( VertexTest );
	CppUnit::TextUi::TestRunner runner;
	CppUnit::TestFactoryRegistry &registry = CppUnit::TestFactoryRegistry::getRegistry( );
	runner.addTest( registry.makeTest( ) );
	if ( runner.run( ) )
	{//Runner had success.
		return 0;
	}
	else
	{//Runner failed.
		return 1;
	}
}
<commit_msg>Fixed an edit collision.<commit_after>#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/TestCaller.h>
#include <cppunit/TestCase.h>
#include <cppunit/extensions/HelperMacros.h>
#include <iostream>
#include "Vertex.cpp"

class VertexTest : public CppUnit::TestCase
{
	private:

	public:
		void testCreateVertex()
		{//Basic test of creating a vertex.
			//Set up the vertex.
			Graph::Vertex<int> v(1, 2);

			//Verify the values.
			CPPUNIT_ASSERT( v.getID() == 1 );
			CPPUNIT_ASSERT( v.getValue() == 2 );
			CPPUNIT_ASSERT( v.getNumEdges() == 0 );
		}

		void testChangeVertex()
		{//Basic test of changing vertex values and IDs.
			//Set up the vertex.
			Graph::Vertex<int> v(1, 2);

			//Verify the values.
			CPPUNIT_ASSERT( v.getID() == 1 );
			CPPUNIT_ASSERT( v.getValue() == 2 );
			CPPUNIT_ASSERT( v.getNumEdges() == 0 );

			//Change the values
			v.setID( 3 );
			v.setValue( 4 );

			//Verify the new values.
			CPPUNIT_ASSERT( v.getID() == 3 );
			CPPUNIT_ASSERT( v.getValue() == 4 );
			CPPUNIT_ASSERT( v.getNumEdges() == 0 );
		}

		void testVertexWithEdge()
		{//Basic test of create a vertex with an edge.
			//Set up the vertex and the edge.
			Graph::Edge ed(1, 1, 2);
			Graph::Vertex<int> v(1, 2);

			//Verify the vertex has no edges yet.
			CPPUNIT_ASSERT( v.getNumEdges() == 0 );

			//Add the edge.
			v.addEdge( ed );

			//Verfiy the edge has been added.
			CPPUNIT_ASSERT( v.getNumEdges() == 1 );
			CPPUNIT_ASSERT( v.getEdge(0).getWeight() == 1 );
			CPPUNIT_ASSERT( v.getEdge(0).getStartVertex() == 1 );
			CPPUNIT_ASSERT( v.getEdge(0).getEndVertex() == 2 );
		}

		void testChangeVertexEdge()
		{//Basic test of chanign a vertex's edge.
			//Set up the vertex and the edge.
			Graph::Edge ed(1, 1, 2);
			Graph::Vertex<int> v(1, 2);

			//Verify the vertex has no edges yet.
			CPPUNIT_ASSERT( v.getNumEdges() == 0 );

			//Add the edge.
			v.addEdge( ed );

			//Verfiy the edge has been added.
			CPPUNIT_ASSERT( v.getNumEdges() == 1 );
			CPPUNIT_ASSERT( v.getEdge(0).getWeight() == 1 );

			//Change the edge.
			//v.getEdge(0).setWeight(2);
			v.changeEdgeWeight( 0, 2 );

			//Verfiy the edge has been changed.
			CPPUNIT_ASSERT( v.getNumEdges() == 1 );
			CPPUNIT_ASSERT( v.getEdge(0).getWeight() == 2 );
			CPPUNIT_ASSERT( v.getEdge(0).getStartVertex() == 1 );
			CPPUNIT_ASSERT( v.getEdge(0).getEndVertex() == 2 );
		}

		void testClearVertexEdges()
		{//Basic test of clearing a vertex's edge.
			//Set up the vertex and the edge.
			Graph::Edge ed1(1, 1, 2);
			Graph::Edge ed2(2, 1, 2);
			Graph::Vertex<int> v(1, 2);

			//Verify the vertex has no edges yet.
			CPPUNIT_ASSERT( v.getNumEdges() == 0 );

			//Add the edges.
			v.addEdge( ed1 );
			v.addEdge( ed2 );

			//Verfiy the edge has been added.
			CPPUNIT_ASSERT( v.getNumEdges() == 2 );
			CPPUNIT_ASSERT( v.getEdge(0).getWeight() == 1 );
			CPPUNIT_ASSERT( v.getEdge(1).getWeight() == 2 );

			//Clear the edges.
			v.clearEdges();

			//Verfiy the edges have been cleared.
			CPPUNIT_ASSERT( v.getNumEdges() == 0 );
		}

		//Create the test suite using CPPUnit macros.
		CPPUNIT_TEST_SUITE( VertexTest );
		CPPUNIT_TEST( testCreateVertex );
		CPPUNIT_TEST( testChangeVertex );
		CPPUNIT_TEST( testVertexWithEdge );
		CPPUNIT_TEST( testChangeVertexEdge );
		CPPUNIT_TEST( testClearVertexEdges );
		CPPUNIT_TEST_SUITE_END( );
};

int main()
{
	CPPUNIT_TEST_SUITE_REGISTRATION( VertexTest );
	CppUnit::TextUi::TestRunner runner;
	CppUnit::TestFactoryRegistry &registry = CppUnit::TestFactoryRegistry::getRegistry( );
	runner.addTest( registry.makeTest( ) );
	if ( runner.run( ) )
	{//Runner had success.
		return 0;
	}
	else
	{//Runner failed.
		return 1;
	}
}
<|endoftext|>


<commit_before>#ifndef AMGCL_ADAPTER_ZERO_COPY_HPP
#define AMGCL_ADAPTER_ZERO_COPY_HPP

/*
The MIT License

Copyright (c) 2012-2021 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/adapter/zero_copy.hpp
\author  Denis Demidov <dennis.demidov@gmail.com>
\brief   Zero-copy adapter for input matrix in CRS format.
\ingroup adapters
*/

#include <type_traits>

#include <amgcl/util.hpp>
#include <amgcl/backend/builtin.hpp>

namespace amgcl {
namespace adapter {

template <typename Ptr, typename Col, typename Val>
std::shared_ptr< backend::crs<Val> >
zero_copy(size_t n, const Ptr *ptr, const Col *col, const Val *val) {
    return zero_copy(n, n, ptr, col, val);
}

template <typename Ptr, typename Col, typename Val>
std::shared_ptr< backend::crs<Val> >
zero_copy(size_t nrows, size_t ncols, const Ptr *ptr, const Col *col, const Val *val) {
    // Check that Ptr and Col types are binary-compatible with ptrdiff_t:
    static_assert(std::is_integral<Ptr>::value, "Unsupported Ptr type");
    static_assert(std::is_integral<Col>::value, "Unsupported Col type");
    static_assert(sizeof(Ptr) == sizeof(ptrdiff_t), "Unsupported Ptr type");
    static_assert(sizeof(Col) == sizeof(ptrdiff_t), "Unsupported Col type");

    auto A = std::make_shared< backend::crs<Val> >();
    A->nrows = nrows;
    A->ncols = ncols;
    A->nnz   = nrows ? ptr[nrows] : 0;

    A->ptr = (ptrdiff_t*)ptr;
    A->col = (ptrdiff_t*)col;
    A->val = (Val*)val;

    A->own_data = false;

    return A;
}

} // namespace adapter
} // namespace amgcl

#endif
<commit_msg>Fix the order of zero_copy overloads<commit_after>#ifndef AMGCL_ADAPTER_ZERO_COPY_HPP
#define AMGCL_ADAPTER_ZERO_COPY_HPP

/*
The MIT License

Copyright (c) 2012-2021 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/adapter/zero_copy.hpp
\author  Denis Demidov <dennis.demidov@gmail.com>
\brief   Zero-copy adapter for input matrix in CRS format.
\ingroup adapters
*/

#include <type_traits>

#include <amgcl/util.hpp>
#include <amgcl/backend/builtin.hpp>

namespace amgcl {
namespace adapter {

template <typename Ptr, typename Col, typename Val>
std::shared_ptr< backend::crs<Val> >
zero_copy(size_t nrows, size_t ncols, const Ptr *ptr, const Col *col, const Val *val) {
    // Check that Ptr and Col types are binary-compatible with ptrdiff_t:
    static_assert(std::is_integral<Ptr>::value, "Unsupported Ptr type");
    static_assert(std::is_integral<Col>::value, "Unsupported Col type");
    static_assert(sizeof(Ptr) == sizeof(ptrdiff_t), "Unsupported Ptr type");
    static_assert(sizeof(Col) == sizeof(ptrdiff_t), "Unsupported Col type");

    auto A = std::make_shared< backend::crs<Val> >();
    A->nrows = nrows;
    A->ncols = ncols;
    A->nnz   = nrows ? ptr[nrows] : 0;

    A->ptr = (ptrdiff_t*)ptr;
    A->col = (ptrdiff_t*)col;
    A->val = (Val*)val;

    A->own_data = false;

    return A;
}

template <typename Ptr, typename Col, typename Val>
std::shared_ptr< backend::crs<Val> >
zero_copy(size_t n, const Ptr *ptr, const Col *col, const Val *val) {
    return zero_copy(n, n, ptr, col, val);
}

} // namespace adapter
} // namespace amgcl

#endif
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (C) 2005-2017 by the FIFE team                              *
 *   http://www.fifengine.net                                              *
 *   This file is part of FIFE.                                            *
 *                                                                         *
 *   FIFE is free software; you can redistribute it and/or                 *
 *   modify it under the terms of the GNU Lesser General Public            *
 *   License as published by the Free Software Foundation; either          *
 *   version 2.1 of the License, or (at your option) any later version.    *
 *                                                                         *
 *   This library is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
 *   Lesser General Public License for more details.                       *
 *                                                                         *
 *   You should have received a copy of the GNU Lesser General Public      *
 *   License along with this library; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
 ***************************************************************************/

// Standard C++ library includes
#include <algorithm>
#include <list>

// 3rd party library includes
#include "zlib.h"
#include <boost/scoped_array.hpp>

// FIFE includes
// These includes are split up in two parts, separated by one empty line
// First block: files included from the FIFE root src directory
// Second block: files included from the same folder
#include "vfs/raw/rawdata.h"
#include "vfs/fife_boost_filesystem.h"
#include "util/base/exception.h"
#include "util/log/logger.h"

#include "zipsource.h"
#include "zipfilesource.h"
#include "zipnode.h"

namespace FIFE {

	static const uint32_t LF_HEADER = 0x04034b50;
	static const uint32_t DE_HEADER = 0x08064b50;
	static const uint32_t CF_HEADER = 0x02014b50;

	static Logger _log(LM_LOADERS);

    ZipSource::ZipSource(VFS* vfs, const std::string& zip_file) : VFSSource(vfs), m_zipfile(vfs->open(zip_file)) {
		readIndex();
	}

	ZipSource::~ZipSource() {
		delete m_zipfile;
	}

    bool ZipSource::fileExists(const std::string& file) const {
        bfs::path path(file);
        return (m_zipTree.getNode(path.string()) != 0);
	}

	RawData* ZipSource::open(const std::string& path) const {
        bfs::path filePath(path);
        ZipNode* node = m_zipTree.getNode(filePath.string());

        assert(node != 0);

        if (node) {
            const ZipEntryData& entryData = node->getZipEntryData();

		    m_zipfile->setIndex(entryData.offset);
		    uint8_t* data = new uint8_t[entryData.size_real]; // beware of me - one day i WILL cause memory leaks
		    if (entryData.comp == 8) { // compressed using deflate
			    FL_DBG(_log, LMsg("trying to uncompress file ") <<  path << " (compressed with method " << entryData.comp << ")");
			    boost::scoped_array<uint8_t> compdata(new uint8_t[entryData.size_comp]);
			    m_zipfile->readInto(compdata.get(), entryData.size_comp);

			    z_stream zstream;
			    zstream.next_in = compdata.get();
			    zstream.avail_in = entryData.size_comp;
			    zstream.zalloc = Z_NULL;
			    zstream.zfree = Z_NULL;
			    zstream.opaque = Z_NULL;
			    zstream.next_out = data;
			    zstream.avail_out = entryData.size_real;

			    if (inflateInit2(&zstream, -15) != Z_OK) {
				    FL_ERR(_log, LMsg("inflateInit2 failed"));
				    delete[] data;
				    return 0;
			    }

			    int32_t err = inflate(&zstream, Z_FINISH);
			    if (err != Z_STREAM_END) {
				    if (zstream.msg) {
					    FL_ERR(_log, LMsg("inflate failed: ") << zstream.msg);
				    } else {
					    FL_ERR(_log, LMsg("inflate failed without msg, err: ") << err);
				    }

				    inflateEnd(&zstream);
				    delete[] data;
				    return 0;
			    }

			    inflateEnd(&zstream);
		    } else if (entryData.comp == 0) { // uncompressed
			    m_zipfile->readInto(data, entryData.size_real);
		    } else {
			    FL_ERR(_log, LMsg("unsupported compression"));
				delete[] data;
			    return 0;
		    }

		    return new RawData(new ZipFileSource(data, entryData.size_real));
        }

        return 0;
	}

	void ZipSource::readIndex() {
		m_zipfile->setIndex(0);

		while (!readFileToIndex()) {}
	}

	bool ZipSource::readFileToIndex() {
		uint32_t header   = m_zipfile->read32Little();
		if (header == DE_HEADER || header == CF_HEADER) { // decryption header or central directory header - we are finished
			return true;
		}

		uint16_t vneeded  = m_zipfile->read16Little();
		uint16_t gflags   = m_zipfile->read16Little();
		uint16_t comp     = m_zipfile->read16Little();
		uint16_t lmodtime = m_zipfile->read16Little();
		uint16_t lmoddate = m_zipfile->read16Little();
		uint32_t crc      = m_zipfile->read32Little();
		uint32_t compsize = m_zipfile->read32Little();
		uint32_t realsize = m_zipfile->read32Little();
		uint16_t fnamelen = m_zipfile->read16Little();
		uint16_t extralen = m_zipfile->read16Little();

		if (header != LF_HEADER) {
			FL_ERR(_log, LMsg("invalid local file header: ") << header);
			return true;
		}

		if (vneeded > 20) {
			FL_ERR(_log, LMsg("only zip version 2 is supported, required: ") << vneeded);
			return true;
		}

        bfs::path filePath = bfs::path(m_zipfile->readString(fnamelen));

		m_zipfile->moveIndex(extralen);
		uint32_t offset = m_zipfile->getCurrentIndex();
		FL_DBG(_log, LMsg("found file: ") << filePath.string() << " (" << compsize << "/" << realsize << ") on offset " << offset);

		m_zipfile->moveIndex(compsize);
		if (gflags & (0x01 << 3)) {
			crc = m_zipfile->read32Little();
			compsize = m_zipfile->read32Little();
			realsize = m_zipfile->read32Little();
		}

		if (lmodtime || lmoddate) {} // shut up the compiler (warnings of unused variables)

        ZipEntryData data;
		data.comp = comp;
		data.size_real = realsize;
		data.size_comp = compsize;
		data.offset = offset;
		data.crc32 = crc;

        std::string filename = filePath.string();
        ZipNode* node = m_zipTree.addNode(filename);

        if (node) {
            // store the zip entry information in the node
            node->setZipEntryData(data);
        }

		return false;
	}

	std::set<std::string> ZipSource::listFiles(const std::string& path) const {
		std::set<std::string> result;

        bfs::path fixedPath(path);

        ZipNode* node = m_zipTree.getNode(fixedPath.string());

        if (node) {
            ZipNodeContainer files = node->getChildren(ZipContentType::File);
            ZipNodeContainer::iterator iter;
            for (iter = files.begin(); iter != files.end(); ++iter) {
                result.insert((*iter)->getFullName());
            }
        }

		return result;
	}

	// FIXME: quick&very dirty..
	std::set<std::string> ZipSource::listDirectories(const std::string& path) const {
		std::set<std::string> result;

        bfs::path fixedPath(path);

        ZipNode* node = m_zipTree.getNode(fixedPath.string());

        if (node) {
            ZipNodeContainer files = node->getChildren(ZipContentType::Directory);
            ZipNodeContainer::iterator iter;
            for (iter = files.begin(); iter != files.end(); ++iter) {
                result.insert((*iter)->getFullName());
            }
        }

		return result;
	}
}
<commit_msg>Fixed line indentation.<commit_after>/***************************************************************************
 *   Copyright (C) 2005-2017 by the FIFE team                              *
 *   http://www.fifengine.net                                              *
 *   This file is part of FIFE.                                            *
 *                                                                         *
 *   FIFE is free software; you can redistribute it and/or                 *
 *   modify it under the terms of the GNU Lesser General Public            *
 *   License as published by the Free Software Foundation; either          *
 *   version 2.1 of the License, or (at your option) any later version.    *
 *                                                                         *
 *   This library is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
 *   Lesser General Public License for more details.                       *
 *                                                                         *
 *   You should have received a copy of the GNU Lesser General Public      *
 *   License along with this library; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
 ***************************************************************************/

// Standard C++ library includes
#include <algorithm>
#include <list>

// 3rd party library includes
#include "zlib.h"
#include <boost/scoped_array.hpp>

// FIFE includes
// These includes are split up in two parts, separated by one empty line
// First block: files included from the FIFE root src directory
// Second block: files included from the same folder
#include "vfs/raw/rawdata.h"
#include "vfs/fife_boost_filesystem.h"
#include "util/base/exception.h"
#include "util/log/logger.h"

#include "zipsource.h"
#include "zipfilesource.h"
#include "zipnode.h"

namespace FIFE {

	static const uint32_t LF_HEADER = 0x04034b50;
	static const uint32_t DE_HEADER = 0x08064b50;
	static const uint32_t CF_HEADER = 0x02014b50;

	static Logger _log(LM_LOADERS);

	ZipSource::ZipSource(VFS* vfs, const std::string& zip_file) : VFSSource(vfs), m_zipfile(vfs->open(zip_file)) {
		readIndex();
	}

	ZipSource::~ZipSource() {
		delete m_zipfile;
	}

	bool ZipSource::fileExists(const std::string& file) const {
		bfs::path path(file);
		return (m_zipTree.getNode(path.string()) != 0);
	}

	RawData* ZipSource::open(const std::string& path) const {
		bfs::path filePath(path);
		ZipNode* node = m_zipTree.getNode(filePath.string());

		assert(node != 0);

		if (node) {
			const ZipEntryData& entryData = node->getZipEntryData();

			m_zipfile->setIndex(entryData.offset);
			uint8_t* data = new uint8_t[entryData.size_real]; // beware of me - one day i WILL cause memory leaks
			if (entryData.comp == 8) { // compressed using deflate
				FL_DBG(_log, LMsg("trying to uncompress file ") <<  path << " (compressed with method " << entryData.comp << ")");
				boost::scoped_array<uint8_t> compdata(new uint8_t[entryData.size_comp]);
				m_zipfile->readInto(compdata.get(), entryData.size_comp);

				z_stream zstream;
				zstream.next_in = compdata.get();
				zstream.avail_in = entryData.size_comp;
				zstream.zalloc = Z_NULL;
				zstream.zfree = Z_NULL;
				zstream.opaque = Z_NULL;
				zstream.next_out = data;
				zstream.avail_out = entryData.size_real;

				if (inflateInit2(&zstream, -15) != Z_OK) {
					FL_ERR(_log, LMsg("inflateInit2 failed"));
					delete[] data;
					return 0;
				}

				int32_t err = inflate(&zstream, Z_FINISH);
				if (err != Z_STREAM_END) {
					if (zstream.msg) {
						FL_ERR(_log, LMsg("inflate failed: ") << zstream.msg);
					} else {
						FL_ERR(_log, LMsg("inflate failed without msg, err: ") << err);
					}

					inflateEnd(&zstream);
					delete[] data;
					return 0;
				}

				inflateEnd(&zstream);
			} else if (entryData.comp == 0) { // uncompressed
				m_zipfile->readInto(data, entryData.size_real);
			} else {
				FL_ERR(_log, LMsg("unsupported compression"));
				delete[] data;
				return 0;
			}

			return new RawData(new ZipFileSource(data, entryData.size_real));
		}

		return 0;
	}

	void ZipSource::readIndex() {
		m_zipfile->setIndex(0);

		while (!readFileToIndex()) {}
	}

	bool ZipSource::readFileToIndex() {
		uint32_t header   = m_zipfile->read32Little();
		if (header == DE_HEADER || header == CF_HEADER) { // decryption header or central directory header - we are finished
			return true;
		}

		uint16_t vneeded  = m_zipfile->read16Little();
		uint16_t gflags   = m_zipfile->read16Little();
		uint16_t comp     = m_zipfile->read16Little();
		uint16_t lmodtime = m_zipfile->read16Little();
		uint16_t lmoddate = m_zipfile->read16Little();
		uint32_t crc      = m_zipfile->read32Little();
		uint32_t compsize = m_zipfile->read32Little();
		uint32_t realsize = m_zipfile->read32Little();
		uint16_t fnamelen = m_zipfile->read16Little();
		uint16_t extralen = m_zipfile->read16Little();

		if (header != LF_HEADER) {
			FL_ERR(_log, LMsg("invalid local file header: ") << header);
			return true;
		}

		if (vneeded > 20) {
			FL_ERR(_log, LMsg("only zip version 2 is supported, required: ") << vneeded);
			return true;
		}

		bfs::path filePath = bfs::path(m_zipfile->readString(fnamelen));

		m_zipfile->moveIndex(extralen);
		uint32_t offset = m_zipfile->getCurrentIndex();
		FL_DBG(_log, LMsg("found file: ") << filePath.string() << " (" << compsize << "/" << realsize << ") on offset " << offset);

		m_zipfile->moveIndex(compsize);
		if (gflags & (0x01 << 3)) {
			crc = m_zipfile->read32Little();
			compsize = m_zipfile->read32Little();
			realsize = m_zipfile->read32Little();
		}

		if (lmodtime || lmoddate) {} // shut up the compiler (warnings of unused variables)

		ZipEntryData data;
		data.comp = comp;
		data.size_real = realsize;
		data.size_comp = compsize;
		data.offset = offset;
		data.crc32 = crc;

		std::string filename = filePath.string();
		ZipNode* node = m_zipTree.addNode(filename);

		if (node) {
			// store the zip entry information in the node
			node->setZipEntryData(data);
		}

		return false;
	}

	std::set<std::string> ZipSource::listFiles(const std::string& path) const {
		std::set<std::string> result;

		bfs::path fixedPath(path);

		ZipNode* node = m_zipTree.getNode(fixedPath.string());

		if (node) {
			ZipNodeContainer files = node->getChildren(ZipContentType::File);
			ZipNodeContainer::iterator iter;
			for (iter = files.begin(); iter != files.end(); ++iter) {
				result.insert((*iter)->getFullName());
			}
		}

		return result;
	}

	// FIXME: quick&very dirty..
	std::set<std::string> ZipSource::listDirectories(const std::string& path) const {
		std::set<std::string> result;

		bfs::path fixedPath(path);

		ZipNode* node = m_zipTree.getNode(fixedPath.string());

		if (node) {
			ZipNodeContainer files = node->getChildren(ZipContentType::Directory);
			ZipNodeContainer::iterator iter;
			for (iter = files.begin(); iter != files.end(); ++iter) {
				result.insert((*iter)->getFullName());
			}
		}

		return result;
	}
}
<|endoftext|>


<commit_before>#pragma once

#include <mapbox/geojsonvt/types.hpp>

namespace mapbox {
namespace geojsonvt {
namespace detail {

template <uint8_t I>
class clipper {
public:
    const double k1;
    const double k2;

    vt_geometry operator()(const vt_point& point) const {
        return point;
    }

    vt_geometry operator()(const vt_multi_point& points) const {
        vt_multi_point part;
        for (const auto& p : points) {
            const double ak = get<I>(p);
            if (ak >= k1 && ak <= k2)
                part.push_back(p);
        }
        return part;
    }

    vt_geometry operator()(const vt_line_string& line) const {
        vt_multi_line_string parts;
        clipLine(line, parts);
        if (parts.size() == 1)
            return parts[0];
        else
            return parts;
    }

    vt_geometry operator()(const vt_multi_line_string& lines) const {
        vt_multi_line_string parts;
        for (const auto& line : lines) {
            clipLine(line, parts);
        }
        if (parts.size() == 1)
            return parts[0];
        else
            return parts;
    }

    vt_geometry operator()(const vt_polygon& polygon) const {
        vt_polygon result;
        for (const auto& ring : polygon) {
            const auto new_ring = clipRing(ring);
            if (!new_ring.empty())
                result.push_back(new_ring);
        }
        return result;
    }

    vt_geometry operator()(const vt_multi_polygon& polygons) const {
        vt_multi_polygon result;
        for (const auto& polygon : polygons) {
            vt_polygon p;
            for (const auto& ring : polygon) {
                const auto new_ring = clipRing(ring);
                if (!new_ring.empty())
                    p.push_back(new_ring);
            }
            if (!p.empty())
                result.push_back(p);
        }
        return result;
    }

    vt_geometry operator()(const vt_geometry_collection& geometries) const {
        vt_geometry_collection result;
        for (const auto& geometry : geometries) {
            vt_geometry::visit(geometry,
                               [&](const auto& g) { result.push_back(this->operator()(g)); });
        }
        return result;
    }

private:
    vt_line_string newSlice(vt_multi_line_string& parts, vt_line_string& slice, double dist) const {
        if (!slice.empty()) {
            slice.dist = dist;
            parts.push_back(std::move(slice));
        }
        return {};
    }

    void clipLine(const vt_line_string& line, vt_multi_line_string& slices) const {

        const double dist = line.dist;
        const size_t len = line.size();

        if (len < 2)
            return;

        vt_line_string slice;

        for (size_t i = 0; i < (len - 1); ++i) {
            const auto& a = line[i];
            const auto& b = line[i + 1];
            const double ak = get<I>(a);
            const double bk = get<I>(b);

            if (ak < k1) {
                if (bk > k2) { // ---|-----|-->
                    slice.push_back(intersect<I>(a, b, k1));
                    slice.push_back(intersect<I>(a, b, k2));
                    slice = newSlice(slices, slice, dist);

                } else if (bk >= k1) { // ---|-->  |
                    slice.push_back(intersect<I>(a, b, k1));
                    if (i == len - 2)
                        slice.push_back(b); // last point
                }
            } else if (ak > k2) {
                if (bk < k1) { // <--|-----|---
                    slice.push_back(intersect<I>(a, b, k2));
                    slice.push_back(intersect<I>(a, b, k1));
                    slice = newSlice(slices, slice, dist);

                } else if (bk <= k2) { // |  <--|---
                    slice.push_back(intersect<I>(a, b, k2));
                    if (i == len - 2)
                        slice.push_back(b); // last point
                }
            } else {
                slice.push_back(a);

                if (bk < k1) { // <--|---  |
                    slice.push_back(intersect<I>(a, b, k1));
                    slice = newSlice(slices, slice, dist);

                } else if (bk > k2) { // |  ---|-->
                    slice.push_back(intersect<I>(a, b, k2));
                    slice = newSlice(slices, slice, dist);

                } else if (i == len - 2) { // | --> |
                    slice.push_back(b);
                }
            }
        }

        // add the final slice
        newSlice(slices, slice, dist);
    }

    vt_linear_ring clipRing(const vt_linear_ring& ring) const {
        const size_t len = ring.size();

        vt_linear_ring slice;
        slice.area = ring.area;

        if (len < 2)
            return slice;

        for (size_t i = 0; i < (len - 1); ++i) {
            const auto& a = ring[i];
            const auto& b = ring[i + 1];
            const double ak = get<I>(a);
            const double bk = get<I>(b);

            if (ak < k1) {
                if (bk >= k1) {
                    slice.push_back(intersect<I>(a, b, k1)); // ---|-->  |
                    if (bk > k2)                             // ---|-----|-->
                        slice.push_back(intersect<I>(a, b, k2));
                    else if (i == len - 2)
                        slice.push_back(b); // last point
                }
            } else if (ak > k2) {
                if (bk <= k2) { // |  <--|---
                    slice.push_back(intersect<I>(a, b, k2));
                    if (bk < k1) // <--|-----|---
                        slice.push_back(intersect<I>(a, b, k1));
                    else if (i == len - 2)
                        slice.push_back(b); // last point
                }
            } else {
                slice.push_back(a);
                if (bk < k1) // <--|---  |
                    slice.push_back(intersect<I>(a, b, k1));
                else if (bk > k2) // |  ---|-->
                    slice.push_back(intersect<I>(a, b, k2));
                // | --> |
            }
        }

        // close the polygon if its endpoints are not the same after clipping
        if (!slice.empty()) {
            const auto& first = slice.front();
            const auto& last = slice.back();
            if (first != last) {
                slice.push_back(first);
            }
        }

        return slice;
    }
};

/* clip features between two axis-parallel lines:
 *     |        |
 *  ___|___     |     /
 * /   |   \____|____/
 *     |        |
 */

template <uint8_t I>
inline vt_features clip(const vt_features& features,
                        const double k1,
                        const double k2,
                        const double minAll,
                        const double maxAll) {

    if (minAll >= k1 && maxAll <= k2) // trivial accept
        return features;

    if (minAll > k2 || maxAll < k1) // trivial reject
        return {};

    vt_features clipped;

    for (const auto& feature : features) {
        const auto& geom = feature.geometry;
        const auto& props = feature.properties;
        const auto& id = feature.id;

        const double min = get<I>(feature.bbox.min);
        const double max = get<I>(feature.bbox.max);

        if (min >= k1 && max <= k2) { // trivial accept
            clipped.push_back(feature);

        } else if (min > k2 || max < k1) { // trivial reject
            continue;

        } else {
            clipped.emplace_back(vt_geometry::visit(geom, clipper<I>{ k1, k2 }), props, id);
        }
    }

    return clipped;
}

} // namespace detail
} // namespace geojsonvt
} // namespace mapbox
<commit_msg>more consistent clipping on bbufer=0 (JS parity)<commit_after>#pragma once

#include <mapbox/geojsonvt/types.hpp>

namespace mapbox {
namespace geojsonvt {
namespace detail {

template <uint8_t I>
class clipper {
public:
    const double k1;
    const double k2;

    vt_geometry operator()(const vt_point& point) const {
        return point;
    }

    vt_geometry operator()(const vt_multi_point& points) const {
        vt_multi_point part;
        for (const auto& p : points) {
            const double ak = get<I>(p);
            if (ak >= k1 && ak <= k2)
                part.push_back(p);
        }
        return part;
    }

    vt_geometry operator()(const vt_line_string& line) const {
        vt_multi_line_string parts;
        clipLine(line, parts);
        if (parts.size() == 1)
            return parts[0];
        else
            return parts;
    }

    vt_geometry operator()(const vt_multi_line_string& lines) const {
        vt_multi_line_string parts;
        for (const auto& line : lines) {
            clipLine(line, parts);
        }
        if (parts.size() == 1)
            return parts[0];
        else
            return parts;
    }

    vt_geometry operator()(const vt_polygon& polygon) const {
        vt_polygon result;
        for (const auto& ring : polygon) {
            const auto new_ring = clipRing(ring);
            if (!new_ring.empty())
                result.push_back(new_ring);
        }
        return result;
    }

    vt_geometry operator()(const vt_multi_polygon& polygons) const {
        vt_multi_polygon result;
        for (const auto& polygon : polygons) {
            vt_polygon p;
            for (const auto& ring : polygon) {
                const auto new_ring = clipRing(ring);
                if (!new_ring.empty())
                    p.push_back(new_ring);
            }
            if (!p.empty())
                result.push_back(p);
        }
        return result;
    }

    vt_geometry operator()(const vt_geometry_collection& geometries) const {
        vt_geometry_collection result;
        for (const auto& geometry : geometries) {
            vt_geometry::visit(geometry,
                               [&](const auto& g) { result.push_back(this->operator()(g)); });
        }
        return result;
    }

private:
    vt_line_string newSlice(vt_multi_line_string& parts, vt_line_string& slice, double dist) const {
        if (!slice.empty()) {
            slice.dist = dist;
            parts.push_back(std::move(slice));
        }
        return {};
    }

    void clipLine(const vt_line_string& line, vt_multi_line_string& slices) const {

        const double dist = line.dist;
        const size_t len = line.size();

        if (len < 2)
            return;

        vt_line_string slice;

        for (size_t i = 0; i < (len - 1); ++i) {
            const auto& a = line[i];
            const auto& b = line[i + 1];
            const double ak = get<I>(a);
            const double bk = get<I>(b);

            if (ak < k1) {
                if (bk > k2) { // ---|-----|-->
                    slice.push_back(intersect<I>(a, b, k1));
                    slice.push_back(intersect<I>(a, b, k2));
                    slice = newSlice(slices, slice, dist);

                } else if (bk >= k1) { // ---|-->  |
                    slice.push_back(intersect<I>(a, b, k1));
                    if (i == len - 2)
                        slice.push_back(b); // last point
                }
            } else if (ak >= k2) {
                if (bk < k1) { // <--|-----|---
                    slice.push_back(intersect<I>(a, b, k2));
                    slice.push_back(intersect<I>(a, b, k1));
                    slice = newSlice(slices, slice, dist);

                } else if (bk < k2) { // |  <--|---
                    slice.push_back(intersect<I>(a, b, k2));
                    if (i == len - 2)
                        slice.push_back(b); // last point
                }
            } else {
                slice.push_back(a);

                if (bk < k1) { // <--|---  |
                    slice.push_back(intersect<I>(a, b, k1));
                    slice = newSlice(slices, slice, dist);

                } else if (bk > k2) { // |  ---|-->
                    slice.push_back(intersect<I>(a, b, k2));
                    slice = newSlice(slices, slice, dist);

                } else if (i == len - 2) { // | --> |
                    slice.push_back(b);
                }
            }
        }

        // add the final slice
        newSlice(slices, slice, dist);
    }

    vt_linear_ring clipRing(const vt_linear_ring& ring) const {
        const size_t len = ring.size();

        vt_linear_ring slice;
        slice.area = ring.area;

        if (len < 2)
            return slice;

        for (size_t i = 0; i < (len - 1); ++i) {
            const auto& a = ring[i];
            const auto& b = ring[i + 1];
            const double ak = get<I>(a);
            const double bk = get<I>(b);

            if (ak < k1) {
                if (bk >= k1) {
                    slice.push_back(intersect<I>(a, b, k1)); // ---|-->  |
                    if (bk > k2)                             // ---|-----|-->
                        slice.push_back(intersect<I>(a, b, k2));
                    else if (i == len - 2)
                        slice.push_back(b); // last point
                }
            } else if (ak >= k2) {
                if (bk < k2) { // |  <--|---
                    slice.push_back(intersect<I>(a, b, k2));
                    if (bk < k1) // <--|-----|---
                        slice.push_back(intersect<I>(a, b, k1));
                    else if (i == len - 2)
                        slice.push_back(b); // last point
                }
            } else {
                slice.push_back(a);
                if (bk < k1) // <--|---  |
                    slice.push_back(intersect<I>(a, b, k1));
                else if (bk > k2) // |  ---|-->
                    slice.push_back(intersect<I>(a, b, k2));
                // | --> |
            }
        }

        // close the polygon if its endpoints are not the same after clipping
        if (!slice.empty()) {
            const auto& first = slice.front();
            const auto& last = slice.back();
            if (first != last) {
                slice.push_back(first);
            }
        }

        return slice;
    }
};

/* clip features between two axis-parallel lines:
 *     |        |
 *  ___|___     |     /
 * /   |   \____|____/
 *     |        |
 */

template <uint8_t I>
inline vt_features clip(const vt_features& features,
                        const double k1,
                        const double k2,
                        const double minAll,
                        const double maxAll) {

    if (minAll >= k1 && maxAll < k2) // trivial accept
        return features;

    if (maxAll < k1 || minAll >= k2) // trivial reject
        return {};

    vt_features clipped;

    for (const auto& feature : features) {
        const auto& geom = feature.geometry;
        const auto& props = feature.properties;
        const auto& id = feature.id;

        const double min = get<I>(feature.bbox.min);
        const double max = get<I>(feature.bbox.max);

        if (min >= k1 && max < k2) { // trivial accept
            clipped.push_back(feature);

        } else if (max < k1 || min >= k2) { // trivial reject
            continue;

        } else {
            clipped.emplace_back(vt_geometry::visit(geom, clipper<I>{ k1, k2 }), props, id);
        }
    }

    return clipped;
}

} // namespace detail
} // namespace geojsonvt
} // namespace mapbox
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */

#include <iostream>
#include <iomanip>
#include <errno.h>
#include <sys/ptrace.h>
#include <stdint.h>

#include "tracechild_amd64.hh"

using namespace std;

char * AMD64TraceChild::regNames[numregs] = {
                //GPRs
                "rax", "rbx", "rcx", "rdx",
                //Index registers
                "rsi", "rdi",
                //Base pointer and stack pointer
                "rbp", "rsp",
                //New 64 bit mode registers
                "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
                //Segmentation registers
                "cs", "ds", "es", "fs", "gs", "ss", "fs_base", "gs_base",
                //PC
                "rip",
                //Flags
                "eflags"};

bool AMD64TraceChild::sendState(int socket)
{
    uint64_t regVal = 0;
    for(int x = 0; x <= R15; x++)
    {
        regVal = getRegVal(x);
        if(write(socket, &regVal, sizeof(regVal)) == -1)
        {
            cerr << "Write failed! " << strerror(errno) << endl;
            tracing = false;
            return false;
        }
    }
    regVal = getRegVal(RIP);
    if(write(socket, &regVal, sizeof(regVal)) == -1)
    {
        cerr << "Write failed! " << strerror(errno) << endl;
        tracing = false;
        return false;
    }
    return true;
}

int64_t AMD64TraceChild::getRegs(user_regs_struct & myregs, int num)
{
        assert(num < numregs && num >= 0);
        switch(num)
        {
                //GPRs
                case RAX: return myregs.rax;
                case RBX: return myregs.rbx;
                case RCX: return myregs.rcx;
                case RDX: return myregs.rdx;
                //Index registers
                case RSI: return myregs.rsi;
                case RDI: return myregs.rdi;
                //Base pointer and stack pointer
                case RBP: return myregs.rbp;
                case RSP: return myregs.rsp;
                //New 64 bit mode registers
                case R8: return myregs.r8;
                case R9: return myregs.r9;
                case R10: return myregs.r10;
                case R11: return myregs.r11;
                case R12: return myregs.r12;
                case R13: return myregs.r13;
                case R14: return myregs.r14;
                case R15: return myregs.r15;
                //Segmentation registers
                case CS: return myregs.cs;
                case DS: return myregs.ds;
                case ES: return myregs.es;
                case FS: return myregs.fs;
                case GS: return myregs.gs;
                case SS: return myregs.ss;
                case FS_BASE: return myregs.fs_base;
                case GS_BASE: return myregs.gs_base;
                //PC
                case RIP: return myregs.rip;
                //Flags
                case EFLAGS: return myregs.eflags;
                default:
                        assert(0);
                        return 0;
        }
}

bool AMD64TraceChild::update(int pid)
{
    oldregs = regs;
    if(ptrace(PTRACE_GETREGS, pid, 0, &regs) != 0)
    {
        cerr << "update: " << strerror(errno) << endl;
        return false;
    }
    for(unsigned int x = 0; x < numregs; x++)
        regDiffSinceUpdate[x] = (getRegVal(x) != getOldRegVal(x));
    return true;
}

AMD64TraceChild::AMD64TraceChild()
{
    for(unsigned int x = 0; x < numregs; x++)
        regDiffSinceUpdate[x] = false;
}

int64_t AMD64TraceChild::getRegVal(int num)
{
        return getRegs(regs, num);
}

int64_t AMD64TraceChild::getOldRegVal(int num)
{
        return getRegs(oldregs, num);
}

char * AMD64TraceChild::printReg(int num)
{
        sprintf(printBuffer, "0x%08X", getRegVal(num));
        return printBuffer;
}

ostream & AMD64TraceChild::outputStartState(ostream & os)
{
    uint64_t sp = getSP();
    uint64_t pc = getPC();
    char obuf[1024];
    sprintf(obuf, "Initial stack pointer = 0x%016llx\n", sp);
    os << obuf;
    sprintf(obuf, "Initial program counter = 0x%016llx\n", pc);
    os << obuf;

    //Output the argument count
    uint64_t cargc = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
    sprintf(obuf, "0x%016llx: Argc = 0x%016llx\n", sp, cargc);
    os << obuf;
    sp += 8;

    //Output argv pointers
    int argCount = 0;
    uint64_t cargv;
    do
    {
        cargv = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
        sprintf(obuf, "0x%016llx: argv[%d] = 0x%016llx\n",
                sp, argCount++, cargv);
        os << obuf;
        sp += 8;
    } while(cargv);

    //Output the envp pointers
    int envCount = 0;
    uint64_t cenvp;
    do
    {
        cenvp = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
        sprintf(obuf, "0x%016llx: envp[%d] = 0x%016llx\n",
                sp, envCount++, cenvp);
        os << obuf;
        sp += 8;
    } while(cenvp);
    uint64_t auxType, auxVal;
    do
    {
        auxType = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
        sp += 8;
        auxVal = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
        sp += 8;
        sprintf(obuf, "0x%016llx: Auxiliary vector = {0x%016llx, 0x%016llx}\n",
                sp - 16, auxType, auxVal);
        os << obuf;
    } while(auxType != 0 || auxVal != 0);
    //Print out the argument strings, environment strings, and file name.
    string current;
    uint64_t buf;
    uint64_t currentStart = sp;
    bool clearedInitialPadding = false;
    do
    {
        buf = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
        char * cbuf = (char *)&buf;
        for(int x = 0; x < sizeof(uint64_t); x++)
        {
            if(cbuf[x])
                current += cbuf[x];
            else
            {
                sprintf(obuf, "0x%016llx: \"%s\"\n",
                        currentStart, current.c_str());
                os << obuf;
                current = "";
                currentStart = sp + x + 1;
            }
        }
        sp += 8;
        clearedInitialPadding = clearedInitialPadding || buf != 0;
    } while(!clearedInitialPadding || buf != 0);
    return os;
}

uint64_t AMD64TraceChild::findSyscall()
{
    uint64_t rip = getPC();
    bool foundOpcode = false;
    bool twoByteOpcode = false;
    for(;;)
    {
        uint64_t buf = ptrace(PTRACE_PEEKDATA, pid, rip, 0);
        for(int i = 0; i < sizeof(uint64_t); i++)
        {
            unsigned char byte = buf & 0xFF;
            if(!foundOpcode)
            {
                if(!(byte == 0x66 || //operand override
                     byte == 0x67 || //address override
                     byte == 0x2E || //cs
                     byte == 0x3E || //ds
                     byte == 0x26 || //es
                     byte == 0x64 || //fs
                     byte == 0x65 || //gs
                     byte == 0x36 || //ss
                     byte == 0xF0 || //lock
                     byte == 0xF2 || //repe
                     byte == 0xF3 || //repne
                     (byte >= 0x40 && byte <= 0x4F) // REX
                    ))
                {
                    foundOpcode = true;
                }
            }
            if(foundOpcode)
            {
                if(twoByteOpcode)
                {
                    //SYSCALL or SYSENTER
                    if(byte == 0x05 || byte == 0x34)
                        return rip + 1;
                    else
                        return 0;
                }
                if(!twoByteOpcode)
                {
                    if(byte == 0xCC) // INT3
                        return rip + 1;
                    else if(byte == 0xCD) // INT with byte immediate
                        return rip + 2;
                    else if(byte == 0x0F) // two byte opcode prefix
                        twoByteOpcode = true;
                    else
                        return 0;
                }
            }
            buf >>= 8;
            rip++;
        }
    }
}

bool AMD64TraceChild::step()
{
    uint64_t ripAfterSyscall = findSyscall();
    if(ripAfterSyscall)
    {
        //Get the original contents of memory
        uint64_t buf = ptrace(PTRACE_PEEKDATA, pid, ripAfterSyscall, 0);
        //Patch the first two bytes of the memory immediately after this with
        //jmp -2. Either single stepping will take over before this
        //instruction, leaving the rip where it should be, or it will take
        //over after this instruction, -still- leaving the rip where it should
        //be.
        uint64_t newBuf = (buf & ~0xFFFF) | 0xFEEB;
        //Write the patched memory to the processes address space
        ptrace(PTRACE_POKEDATA, pid, ripAfterSyscall, newBuf);
        //Step and hit it
        ptraceSingleStep();
        //Put things back to the way they started
        ptrace(PTRACE_POKEDATA, pid, ripAfterSyscall, buf);
    }
    else
        ptraceSingleStep();
}

TraceChild * genTraceChild()
{
        return new AMD64TraceChild;
}
<commit_msg>Statetrace: Make sure all the info block strings are printed.<commit_after>/*
 * Copyright (c) 2007 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */

#include <iostream>
#include <iomanip>
#include <errno.h>
#include <sys/ptrace.h>
#include <stdint.h>

#include "tracechild_amd64.hh"

using namespace std;

char * AMD64TraceChild::regNames[numregs] = {
                //GPRs
                "rax", "rbx", "rcx", "rdx",
                //Index registers
                "rsi", "rdi",
                //Base pointer and stack pointer
                "rbp", "rsp",
                //New 64 bit mode registers
                "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
                //Segmentation registers
                "cs", "ds", "es", "fs", "gs", "ss", "fs_base", "gs_base",
                //PC
                "rip",
                //Flags
                "eflags"};

bool AMD64TraceChild::sendState(int socket)
{
    uint64_t regVal = 0;
    for(int x = 0; x <= R15; x++)
    {
        regVal = getRegVal(x);
        if(write(socket, &regVal, sizeof(regVal)) == -1)
        {
            cerr << "Write failed! " << strerror(errno) << endl;
            tracing = false;
            return false;
        }
    }
    regVal = getRegVal(RIP);
    if(write(socket, &regVal, sizeof(regVal)) == -1)
    {
        cerr << "Write failed! " << strerror(errno) << endl;
        tracing = false;
        return false;
    }
    return true;
}

int64_t AMD64TraceChild::getRegs(user_regs_struct & myregs, int num)
{
        assert(num < numregs && num >= 0);
        switch(num)
        {
                //GPRs
                case RAX: return myregs.rax;
                case RBX: return myregs.rbx;
                case RCX: return myregs.rcx;
                case RDX: return myregs.rdx;
                //Index registers
                case RSI: return myregs.rsi;
                case RDI: return myregs.rdi;
                //Base pointer and stack pointer
                case RBP: return myregs.rbp;
                case RSP: return myregs.rsp;
                //New 64 bit mode registers
                case R8: return myregs.r8;
                case R9: return myregs.r9;
                case R10: return myregs.r10;
                case R11: return myregs.r11;
                case R12: return myregs.r12;
                case R13: return myregs.r13;
                case R14: return myregs.r14;
                case R15: return myregs.r15;
                //Segmentation registers
                case CS: return myregs.cs;
                case DS: return myregs.ds;
                case ES: return myregs.es;
                case FS: return myregs.fs;
                case GS: return myregs.gs;
                case SS: return myregs.ss;
                case FS_BASE: return myregs.fs_base;
                case GS_BASE: return myregs.gs_base;
                //PC
                case RIP: return myregs.rip;
                //Flags
                case EFLAGS: return myregs.eflags;
                default:
                        assert(0);
                        return 0;
        }
}

bool AMD64TraceChild::update(int pid)
{
    oldregs = regs;
    if(ptrace(PTRACE_GETREGS, pid, 0, &regs) != 0)
    {
        cerr << "update: " << strerror(errno) << endl;
        return false;
    }
    for(unsigned int x = 0; x < numregs; x++)
        regDiffSinceUpdate[x] = (getRegVal(x) != getOldRegVal(x));
    return true;
}

AMD64TraceChild::AMD64TraceChild()
{
    for(unsigned int x = 0; x < numregs; x++)
        regDiffSinceUpdate[x] = false;
}

int64_t AMD64TraceChild::getRegVal(int num)
{
        return getRegs(regs, num);
}

int64_t AMD64TraceChild::getOldRegVal(int num)
{
        return getRegs(oldregs, num);
}

char * AMD64TraceChild::printReg(int num)
{
        sprintf(printBuffer, "0x%08X", getRegVal(num));
        return printBuffer;
}

ostream & AMD64TraceChild::outputStartState(ostream & os)
{
    uint64_t sp = getSP();
    uint64_t pc = getPC();
    uint64_t highestInfo = 0;
    char obuf[1024];
    sprintf(obuf, "Initial stack pointer = 0x%016llx\n", sp);
    os << obuf;
    sprintf(obuf, "Initial program counter = 0x%016llx\n", pc);
    os << obuf;

    //Output the argument count
    uint64_t cargc = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
    sprintf(obuf, "0x%016llx: Argc = 0x%016llx\n", sp, cargc);
    os << obuf;
    sp += 8;

    //Output argv pointers
    int argCount = 0;
    uint64_t cargv;
    do
    {
        cargv = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
        sprintf(obuf, "0x%016llx: argv[%d] = 0x%016llx\n",
                sp, argCount++, cargv);
        if(cargv)
            if(highestInfo < cargv)
                highestInfo = cargv;
        os << obuf;
        sp += 8;
    } while(cargv);

    //Output the envp pointers
    int envCount = 0;
    uint64_t cenvp;
    do
    {
        cenvp = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
        sprintf(obuf, "0x%016llx: envp[%d] = 0x%016llx\n",
                sp, envCount++, cenvp);
        os << obuf;
        sp += 8;
    } while(cenvp);
    uint64_t auxType, auxVal;
    do
    {
        auxType = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
        sp += 8;
        auxVal = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
        sp += 8;
        sprintf(obuf, "0x%016llx: Auxiliary vector = {0x%016llx, 0x%016llx}\n",
                sp - 16, auxType, auxVal);
        os << obuf;
    } while(auxType != 0 || auxVal != 0);
    //Print out the argument strings, environment strings, and file name.
    string current;
    uint64_t buf;
    uint64_t currentStart = sp;
    bool clearedInitialPadding = false;
    do
    {
        buf = ptrace(PTRACE_PEEKDATA, pid, sp, 0);
        char * cbuf = (char *)&buf;
        for(int x = 0; x < sizeof(uint64_t); x++)
        {
            if(cbuf[x])
                current += cbuf[x];
            else
            {
                sprintf(obuf, "0x%016llx: \"%s\"\n",
                        currentStart, current.c_str());
                os << obuf;
                current = "";
                currentStart = sp + x + 1;
            }
        }
        sp += 8;
        clearedInitialPadding = clearedInitialPadding || buf != 0;
    } while(!clearedInitialPadding || buf != 0 || sp <= highestInfo);
    return os;
}

uint64_t AMD64TraceChild::findSyscall()
{
    uint64_t rip = getPC();
    bool foundOpcode = false;
    bool twoByteOpcode = false;
    for(;;)
    {
        uint64_t buf = ptrace(PTRACE_PEEKDATA, pid, rip, 0);
        for(int i = 0; i < sizeof(uint64_t); i++)
        {
            unsigned char byte = buf & 0xFF;
            if(!foundOpcode)
            {
                if(!(byte == 0x66 || //operand override
                     byte == 0x67 || //address override
                     byte == 0x2E || //cs
                     byte == 0x3E || //ds
                     byte == 0x26 || //es
                     byte == 0x64 || //fs
                     byte == 0x65 || //gs
                     byte == 0x36 || //ss
                     byte == 0xF0 || //lock
                     byte == 0xF2 || //repe
                     byte == 0xF3 || //repne
                     (byte >= 0x40 && byte <= 0x4F) // REX
                    ))
                {
                    foundOpcode = true;
                }
            }
            if(foundOpcode)
            {
                if(twoByteOpcode)
                {
                    //SYSCALL or SYSENTER
                    if(byte == 0x05 || byte == 0x34)
                        return rip + 1;
                    else
                        return 0;
                }
                if(!twoByteOpcode)
                {
                    if(byte == 0xCC) // INT3
                        return rip + 1;
                    else if(byte == 0xCD) // INT with byte immediate
                        return rip + 2;
                    else if(byte == 0x0F) // two byte opcode prefix
                        twoByteOpcode = true;
                    else
                        return 0;
                }
            }
            buf >>= 8;
            rip++;
        }
    }
}

bool AMD64TraceChild::step()
{
    uint64_t ripAfterSyscall = findSyscall();
    if(ripAfterSyscall)
    {
        //Get the original contents of memory
        uint64_t buf = ptrace(PTRACE_PEEKDATA, pid, ripAfterSyscall, 0);
        //Patch the first two bytes of the memory immediately after this with
        //jmp -2. Either single stepping will take over before this
        //instruction, leaving the rip where it should be, or it will take
        //over after this instruction, -still- leaving the rip where it should
        //be.
        uint64_t newBuf = (buf & ~0xFFFF) | 0xFEEB;
        //Write the patched memory to the processes address space
        ptrace(PTRACE_POKEDATA, pid, ripAfterSyscall, newBuf);
        //Step and hit it
        ptraceSingleStep();
        //Put things back to the way they started
        ptrace(PTRACE_POKEDATA, pid, ripAfterSyscall, buf);
    }
    else
        ptraceSingleStep();
}

TraceChild * genTraceChild()
{
        return new AMD64TraceChild;
}
<|endoftext|>


<commit_before>/*******************************************************************************
 *
 * MIT License
 *
 * Copyright (c) 2017 Advanced Micro Devices, Inc.
 *
 * 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.
 *
 *******************************************************************************/

#include <algorithm>
#include <cassert>
#include <functional>

#include <miopen/each_args.hpp>
#include <sstream>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include <miopen/rank.hpp>
#include <miopen/type_name.hpp>

namespace args {

using string_map = std::unordered_map<std::string, std::vector<std::string>>;

template <class IsKeyword>
string_map parse(std::vector<std::string> as, IsKeyword is_keyword)
{
    string_map result;

    std::string flag;
    for(auto&& x : as)
    {
        if(is_keyword(x))
        {
            flag = x;
            result[flag]; // Ensure the flag exists
        }
        else
        {
            result[flag].push_back(x);
        }
    }
    return result;
}

namespace detail {

template <class T>
auto is_container(miopen::rank<1>, T&& x)
    -> decltype(x.insert(x.end(), *x.begin()), std::true_type{});

template <class T>
std::false_type is_container(miopen::rank<0>, T&&);

template <class T, class U>
auto is_streamable(miopen::rank<1>, T&& x, U&& y) -> decltype((x >> y), std::true_type{});

template <class T, class U>
std::false_type is_streamable(miopen::rank<0>, T&&, U&&);

template <bool B>
struct requires_bool
{
    static const bool value = B;
};

template <class T, long N>
struct requires_unwrap : T
{
};
} // namespace detail

template <class T>
struct is_container : decltype(detail::is_container(miopen::rank<1>{}, std::declval<T>()))
{
};

template <class T>
struct is_streamable
    : decltype(detail::is_streamable(miopen::rank<1>{},
                                     std::declval<std::istream>(),
                                     std::declval<typename std::add_lvalue_reference<T>::type>()))
{
};

#ifdef _MSC_VER
#define ARGS_REQUIRES_BOOL(...)                                                           \
    args::detail::requires_unwrap<decltype(args::detail::requires_bool<(__VA_ARGS__)>{}), \
                                  __LINE__>::value
#else
#define ARGS_REQUIRES_BOOL(...) (__VA_ARGS__)
#endif

#define ARGS_REQUIRES(...)                                                                    \
    bool RequiresBool##__LINE__ = true,                                                       \
         typename std::enable_if<ARGS_REQUIRES_BOOL(RequiresBool##__LINE__ && (__VA_ARGS__)), \
                                 int>::type = 0

template <class T>
struct value_parser
{
    template <ARGS_REQUIRES(is_streamable<T>{} and not std::is_pointer<T>{})>
    static T apply(const std::string& x)
    {
        T result;
        std::stringstream ss;
        ss.str(x);
        ss >> result;
        return result;
    }
};

struct any_value
{
    std::string s;

    template <class T, class = decltype(value_parser<T>::apply(std::string{}))>
    operator T() const
    {
        return value_parser<T>::apply(s);
    }
};

template <class T, std::size_t... Ns, class Data>
auto any_construct_impl(miopen::rank<1>, miopen::detail::seq<Ns...>, const Data& d)
    -> decltype(T(any_value{d[Ns]}...))
{
    return T(any_value{d[Ns]}...);
}

template <class T, std::size_t... Ns, class Data>
T any_construct_impl(miopen::rank<0>, miopen::detail::seq<Ns...>, const Data&)
{
    throw std::runtime_error("Cannot construct: " + miopen::get_type_name<T>());
}

template <class T, std::size_t N, class Data>
T any_construct(const Data& d)
{
    return any_construct_impl<T>(miopen::rank<1>{}, typename miopen::detail::gens<N>::type{}, d);
}

struct write_value
{
    template <class T>
    using is_multi_value =
        std::integral_constant<bool,
                               (is_container<T>{} and not std::is_convertible<T, std::string>{})>;

    template <class Container, ARGS_REQUIRES(is_multi_value<Container>{})>
    void operator()(Container& result, std::vector<std::string> params) const
    {
        using value_type = typename Container::value_type;
        for(auto&& s : params)
        {
            result.insert(result.end(), value_parser<value_type>::apply(s));
        }
    }

    template <class T, ARGS_REQUIRES(not is_multi_value<T>{} and is_streamable<T>{})>
    void operator()(T& result, std::vector<std::string> params) const
    {
        if(params.empty())
            throw std::runtime_error("Missing argument");
        result = value_parser<T>::apply(params.back());
    }

    template <class T, ARGS_REQUIRES(not is_multi_value<T>{} and not is_streamable<T>{})>
    void operator()(T& result, std::vector<std::string> params) const
    {
        switch(params.size())
        {
        case 0:
        {
            result = any_construct<T, 0>(params);
            break;
        }
        case 1:
        {
            result = any_construct<T, 1>(params);
            break;
        }
        case 2:
        {
            result = any_construct<T, 2>(params);
            break;
        }
        case 3:
        {
            result = any_construct<T, 3>(params);
            break;
        }
        case 4:
        {
            result = any_construct<T, 4>(params);
            break;
        }
        case 5:
        {
            result = any_construct<T, 5>(params);
            break;
        }
        case 6:
        {
            result = any_construct<T, 6>(params);
            break;
        }
        case 7:
        {
            result = any_construct<T, 7>(params);
            break;
        }
        default: throw std::runtime_error("Cannot construct: " + miopen::get_type_name<T>());
        }
    }
};
} // namespace args
<commit_msg>Check for parser failure in cli arguments<commit_after>/*******************************************************************************
 *
 * MIT License
 *
 * Copyright (c) 2017 Advanced Micro Devices, Inc.
 *
 * 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.
 *
 *******************************************************************************/

#include <algorithm>
#include <cassert>
#include <functional>

#include <miopen/each_args.hpp>
#include <sstream>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include <miopen/rank.hpp>
#include <miopen/type_name.hpp>

namespace args {

using string_map = std::unordered_map<std::string, std::vector<std::string>>;

template <class IsKeyword>
string_map parse(std::vector<std::string> as, IsKeyword is_keyword)
{
    string_map result;

    std::string flag;
    for(auto&& x : as)
    {
        if(is_keyword(x))
        {
            flag = x;
            result[flag]; // Ensure the flag exists
        }
        else
        {
            result[flag].push_back(x);
        }
    }
    return result;
}

namespace detail {

template <class T>
auto is_container(miopen::rank<1>, T&& x)
    -> decltype(x.insert(x.end(), *x.begin()), std::true_type{});

template <class T>
std::false_type is_container(miopen::rank<0>, T&&);

template <class T, class U>
auto is_streamable(miopen::rank<1>, T&& x, U&& y) -> decltype((x >> y), std::true_type{});

template <class T, class U>
std::false_type is_streamable(miopen::rank<0>, T&&, U&&);

template <bool B>
struct requires_bool
{
    static const bool value = B;
};

template <class T, long N>
struct requires_unwrap : T
{
};
} // namespace detail

template <class T>
struct is_container : decltype(detail::is_container(miopen::rank<1>{}, std::declval<T>()))
{
};

template <class T>
struct is_streamable
    : decltype(detail::is_streamable(miopen::rank<1>{},
                                     std::declval<std::istream>(),
                                     std::declval<typename std::add_lvalue_reference<T>::type>()))
{
};

#ifdef _MSC_VER
#define ARGS_REQUIRES_BOOL(...)                                                           \
    args::detail::requires_unwrap<decltype(args::detail::requires_bool<(__VA_ARGS__)>{}), \
                                  __LINE__>::value
#else
#define ARGS_REQUIRES_BOOL(...) (__VA_ARGS__)
#endif

#define ARGS_REQUIRES(...)                                                                    \
    bool RequiresBool##__LINE__ = true,                                                       \
         typename std::enable_if<ARGS_REQUIRES_BOOL(RequiresBool##__LINE__ && (__VA_ARGS__)), \
                                 int>::type = 0

template <class T>
struct value_parser
{
    template <ARGS_REQUIRES(is_streamable<T>{} and not std::is_pointer<T>{})>
    static T apply(const std::string& x)
    {
        T result;
        std::stringstream ss;
        ss.str(x);
        ss >> result;
        if (ss.fail()) throw std::runtime_error("Failed to parse: " + x);
        return result;
    }
};

struct any_value
{
    std::string s;

    template <class T, class = decltype(value_parser<T>::apply(std::string{}))>
    operator T() const
    {
        return value_parser<T>::apply(s);
    }
};

template <class T, std::size_t... Ns, class Data>
auto any_construct_impl(miopen::rank<1>, miopen::detail::seq<Ns...>, const Data& d)
    -> decltype(T(any_value{d[Ns]}...))
{
    return T(any_value{d[Ns]}...);
}

template <class T, std::size_t... Ns, class Data>
T any_construct_impl(miopen::rank<0>, miopen::detail::seq<Ns...>, const Data&)
{
    throw std::runtime_error("Cannot construct: " + miopen::get_type_name<T>());
}

template <class T, std::size_t N, class Data>
T any_construct(const Data& d)
{
    return any_construct_impl<T>(miopen::rank<1>{}, typename miopen::detail::gens<N>::type{}, d);
}

struct write_value
{
    template <class T>
    using is_multi_value =
        std::integral_constant<bool,
                               (is_container<T>{} and not std::is_convertible<T, std::string>{})>;

    template <class Container, ARGS_REQUIRES(is_multi_value<Container>{})>
    void operator()(Container& result, std::vector<std::string> params) const
    {
        using value_type = typename Container::value_type;
        for(auto&& s : params)
        {
            result.insert(result.end(), value_parser<value_type>::apply(s));
        }
    }

    template <class T, ARGS_REQUIRES(not is_multi_value<T>{} and is_streamable<T>{})>
    void operator()(T& result, std::vector<std::string> params) const
    {
        if(params.empty())
            throw std::runtime_error("Missing argument");
        result = value_parser<T>::apply(params.back());
    }

    template <class T, ARGS_REQUIRES(not is_multi_value<T>{} and not is_streamable<T>{})>
    void operator()(T& result, std::vector<std::string> params) const
    {
        switch(params.size())
        {
        case 0:
        {
            result = any_construct<T, 0>(params);
            break;
        }
        case 1:
        {
            result = any_construct<T, 1>(params);
            break;
        }
        case 2:
        {
            result = any_construct<T, 2>(params);
            break;
        }
        case 3:
        {
            result = any_construct<T, 3>(params);
            break;
        }
        case 4:
        {
            result = any_construct<T, 4>(params);
            break;
        }
        case 5:
        {
            result = any_construct<T, 5>(params);
            break;
        }
        case 6:
        {
            result = any_construct<T, 6>(params);
            break;
        }
        case 7:
        {
            result = any_construct<T, 7>(params);
            break;
        }
        default: throw std::runtime_error("Cannot construct: " + miopen::get_type_name<T>());
        }
    }
};
} // namespace args
<|endoftext|>


<commit_before>/*
  * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License").
  * You may not use this file except in compliance with the License.
  * A copy of the License is located at
  *
  *  http://aws.amazon.com/apache2.0
  *
  * or in the "license" file accompanying this file. This file is distributed
  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
  * express or implied. See the License for the specific language governing
  * permissions and limitations under the License.
  */

#include <aws/core/auth/AWSCredentialsProviderChain.h>
#include <aws/core/platform/Environment.h>
#include <aws/core/utils/memory/AWSMemory.h>
#include <aws/core/utils/StringUtils.h>
#include <aws/core/utils/logging/LogMacros.h>

using namespace Aws::Auth;

static const char AWS_ECS_CONTAINER_CREDENTIALS_RELATIVE_URI[] = "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI";
static const char AWS_ECS_CONTAINER_CREDENTIALS_FULL_URI[] = "CONTAINER_CREDENTIALS_FULL_URI";
static const char AWS_ECS_CONTAINER_AUTHORIZATION_TOKEN[] = "CONTAINER_AUTHORIZATION_TOKEN";
static const char AWS_EC2_METADATA_DISABLED[] = "AWS_EC2_METADATA_DISABLED";
static const char DefaultCredentialsProviderChainTag[] = "DefaultAWSCredentialsProviderChain";

AWSCredentials AWSCredentialsProviderChain::GetAWSCredentials()
{
    for (auto credentialsProvider : m_providerChain)
    {
        AWSCredentials credentials = credentialsProvider->GetAWSCredentials();
        if (!credentials.GetAWSAccessKeyId().empty() && !credentials.GetAWSSecretKey().empty())
        {
            return credentials;
        }
    }

    return AWSCredentials("", "");
}

DefaultAWSCredentialsProviderChain::DefaultAWSCredentialsProviderChain() : AWSCredentialsProviderChain()
{
    AddProvider(Aws::MakeShared<EnvironmentAWSCredentialsProvider>(DefaultCredentialsProviderChainTag));
    AddProvider(Aws::MakeShared<ProfileConfigFileAWSCredentialsProvider>(DefaultCredentialsProviderChainTag));

    //ECS TaskRole Credentials only available when ENVIRONMENT VARIABLE is set
    const auto relativeUri = Aws::Environment::GetEnv(AWS_ECS_CONTAINER_CREDENTIALS_RELATIVE_URI);
    AWS_LOGSTREAM_DEBUG(DefaultCredentialsProviderChainTag, "The environment variable value " << AWS_ECS_CONTAINER_CREDENTIALS_RELATIVE_URI
            << " is " << relativeUri);

    const auto absoluteUri = Aws::Environment::GetEnv(AWS_ECS_CONTAINER_CREDENTIALS_FULL_URI);
    AWS_LOGSTREAM_DEBUG(DefaultCredentialsProviderChainTag, "The environment variable value " << AWS_ECS_CONTAINER_CREDENTIALS_FULL_URI
            << " is " << absoluteUri);

    const auto ec2MetadataDisabled = Aws::Environment::GetEnv(AWS_EC2_METADATA_DISABLED);
    AWS_LOGSTREAM_DEBUG(DefaultCredentialsProviderChainTag, "The environment variable value " << AWS_EC2_METADATA_DISABLED
            << " is " << ec2MetadataDisabled);

    if (!relativeUri.empty())
    {
        AddProvider(Aws::MakeShared<TaskRoleCredentialsProvider>(DefaultCredentialsProviderChainTag, relativeUri.c_str()));
        AWS_LOGSTREAM_INFO(DefaultCredentialsProviderChainTag, "Added ECS metadata service credentials provider with relative path: ["
                << relativeUri << "] to the provider chain.");
    }
    else if (!absoluteUri.empty())
    {
        const auto token = Aws::Environment::GetEnv(AWS_ECS_CONTAINER_AUTHORIZATION_TOKEN);
        AddProvider(Aws::MakeShared<TaskRoleCredentialsProvider>(DefaultCredentialsProviderChainTag,
                    absoluteUri.c_str(), token.c_str()));

        //DO NOT log the value of the authorization token for security purposes.
        AWS_LOGSTREAM_INFO(DefaultCredentialsProviderChainTag, "Added ECS credentials provider with URI: ["
                << absoluteUri << "] to the provider chain with a" << (token.empty() ? "n empty " : " non-empty ")
                << "authorization token.");
    }
    else if (Aws::Utils::StringUtils::ToLower(ec2MetadataDisabled.c_str()) != "true")
    {
        AddProvider(Aws::MakeShared<InstanceProfileCredentialsProvider>(DefaultCredentialsProviderChainTag));
        AWS_LOGSTREAM_INFO(DefaultCredentialsProviderChainTag, "Added EC2 metadata service credentials provider to the provider chain.");
    }
}
<commit_msg>Use the correct environment variable name for ECS creds<commit_after>/*
  * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License").
  * You may not use this file except in compliance with the License.
  * A copy of the License is located at
  *
  *  http://aws.amazon.com/apache2.0
  *
  * or in the "license" file accompanying this file. This file is distributed
  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
  * express or implied. See the License for the specific language governing
  * permissions and limitations under the License.
  */

#include <aws/core/auth/AWSCredentialsProviderChain.h>
#include <aws/core/platform/Environment.h>
#include <aws/core/utils/memory/AWSMemory.h>
#include <aws/core/utils/StringUtils.h>
#include <aws/core/utils/logging/LogMacros.h>

using namespace Aws::Auth;

static const char AWS_ECS_CONTAINER_CREDENTIALS_RELATIVE_URI[] = "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI";
static const char AWS_ECS_CONTAINER_CREDENTIALS_FULL_URI[] = "AWS_CONTAINER_CREDENTIALS_FULL_URI";
static const char AWS_ECS_CONTAINER_AUTHORIZATION_TOKEN[] = "AWS_CONTAINER_AUTHORIZATION_TOKEN";
static const char AWS_EC2_METADATA_DISABLED[] = "AWS_EC2_METADATA_DISABLED";
static const char DefaultCredentialsProviderChainTag[] = "DefaultAWSCredentialsProviderChain";

AWSCredentials AWSCredentialsProviderChain::GetAWSCredentials()
{
    for (auto credentialsProvider : m_providerChain)
    {
        AWSCredentials credentials = credentialsProvider->GetAWSCredentials();
        if (!credentials.GetAWSAccessKeyId().empty() && !credentials.GetAWSSecretKey().empty())
        {
            return credentials;
        }
    }

    return AWSCredentials("", "");
}

DefaultAWSCredentialsProviderChain::DefaultAWSCredentialsProviderChain() : AWSCredentialsProviderChain()
{
    AddProvider(Aws::MakeShared<EnvironmentAWSCredentialsProvider>(DefaultCredentialsProviderChainTag));
    AddProvider(Aws::MakeShared<ProfileConfigFileAWSCredentialsProvider>(DefaultCredentialsProviderChainTag));

    //ECS TaskRole Credentials only available when ENVIRONMENT VARIABLE is set
    const auto relativeUri = Aws::Environment::GetEnv(AWS_ECS_CONTAINER_CREDENTIALS_RELATIVE_URI);
    AWS_LOGSTREAM_DEBUG(DefaultCredentialsProviderChainTag, "The environment variable value " << AWS_ECS_CONTAINER_CREDENTIALS_RELATIVE_URI
            << " is " << relativeUri);

    const auto absoluteUri = Aws::Environment::GetEnv(AWS_ECS_CONTAINER_CREDENTIALS_FULL_URI);
    AWS_LOGSTREAM_DEBUG(DefaultCredentialsProviderChainTag, "The environment variable value " << AWS_ECS_CONTAINER_CREDENTIALS_FULL_URI
            << " is " << absoluteUri);

    const auto ec2MetadataDisabled = Aws::Environment::GetEnv(AWS_EC2_METADATA_DISABLED);
    AWS_LOGSTREAM_DEBUG(DefaultCredentialsProviderChainTag, "The environment variable value " << AWS_EC2_METADATA_DISABLED
            << " is " << ec2MetadataDisabled);

    if (!relativeUri.empty())
    {
        AddProvider(Aws::MakeShared<TaskRoleCredentialsProvider>(DefaultCredentialsProviderChainTag, relativeUri.c_str()));
        AWS_LOGSTREAM_INFO(DefaultCredentialsProviderChainTag, "Added ECS metadata service credentials provider with relative path: ["
                << relativeUri << "] to the provider chain.");
    }
    else if (!absoluteUri.empty())
    {
        const auto token = Aws::Environment::GetEnv(AWS_ECS_CONTAINER_AUTHORIZATION_TOKEN);
        AddProvider(Aws::MakeShared<TaskRoleCredentialsProvider>(DefaultCredentialsProviderChainTag,
                    absoluteUri.c_str(), token.c_str()));

        //DO NOT log the value of the authorization token for security purposes.
        AWS_LOGSTREAM_INFO(DefaultCredentialsProviderChainTag, "Added ECS credentials provider with URI: ["
                << absoluteUri << "] to the provider chain with a" << (token.empty() ? "n empty " : " non-empty ")
                << "authorization token.");
    }
    else if (Aws::Utils::StringUtils::ToLower(ec2MetadataDisabled.c_str()) != "true")
    {
        AddProvider(Aws::MakeShared<InstanceProfileCredentialsProvider>(DefaultCredentialsProviderChainTag));
        AWS_LOGSTREAM_INFO(DefaultCredentialsProviderChainTag, "Added EC2 metadata service credentials provider to the provider chain.");
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2012, Luis Pedro Coelho <luis@luispedro.org>
// License: MIT

#include <iostream>
#include <memory>
#include <cmath>
#include <random>
#include <cassert>
#include <queue>
#include <eigen3/Eigen/Dense>

using namespace Eigen;

extern "C" {
    #include <Python.h>
    #include <numpy/ndarrayobject.h>
}

namespace {

template <typename T>
int random_int(T& random, const int max) {
    std::uniform_int_distribution<int> dist(0, max - 1);
    return dist(random);
}
inline
float soft(const float val, const float lam) {
    return std::copysign(std::fdim(std::fabs(val), lam), val);
}
typedef Map<Matrix<float, Dynamic, Dynamic, RowMajor>, Aligned> MapXAf;
bool has_nans(const MapXAf& X) {
    for (int i = 0; i != X.rows(); ++i) {
        for (int j = 0; j != X.cols(); ++j) {
            if (std::isnan(X(i,j))) return true;
        }
    }
    return false;
}

struct lasso_solver {
    lasso_solver(const MapXAf& X, const MapXAf& Y, const MapXAf& W, MapXAf& B, const int max_iter, const float lam, const float eps)
        :X(X)
        ,Y(Y)
        ,W(W)
        ,B(B)
        ,max_iter(max_iter)
        ,lam(lam)
        ,eps(eps)
        { }

    void next_coords(int& i, int& j) {
        ++j;
        if (j == B.cols()) {
            j = 0;
            ++i;
            if (i == B.rows()) {
                i = 0;
            }
        }
    }

    int solve() {
        Matrix<float, Dynamic, Dynamic, RowMajor> residuals;
        int i = 0;
        int j = -1;
        // sweep is whether we are doing a whole-B sweep (i.e., even looking at
        // non-zero Bs)
        // changed is whether something has changed
        // We set this up to trigger computation of residuals and a sweep on
        // the first iteration
        bool sweep = false;
        bool changed = false;
        assert(!has_nans(X));
        assert(!has_nans(Y));
        assert(!has_nans(B));
        for (int it = 0; it != max_iter; ++it) {
            this->next_coords(i, j);
            if (i == 0 && j == 0) {
                if (sweep && !changed) {
                    return it;
                }
                if (!changed) {
                    sweep = true;
                    // Reset the residuals matrix to the best values to avoid
                    // drift due to successive rounding:
                    residuals = Y - B*X;
                } else {
                    sweep = false;
                }
                changed = false;
            }
            if (!sweep && B(i,j) == 0.0) continue;

            // We now set βᵢⱼ holding everything else fixed.  This comes down
            // to a very simple 1-dimensional problem.
            // We remember the current value in order to compute update below
            const float prev = B(i,j);
            float x2 = 0.0;
            float xy = 0.0;
            for (int k = 0, cols = Y.cols(); k != cols; ++k) {
                x2 += W(i,k)*X(j,k)*X(j,k);
                xy += W(i,k)*X(j,k)*residuals(i,k);
            }
            const float raw_step = (x2 == 0.0 ? 0.0 : xy/x2);
            const float best = soft(prev + raw_step, lam);
            const float step = best - prev;
            if (std::fabs(step) > eps) {
                assert(!std::isnan(best));
                B(i,j) = best;
                residuals.row(i) -= step*X.row(j);
                changed = true;
            }
        }
        return max_iter;
    }
    std::mt19937 r;
    const MapXAf& X;
    const MapXAf& Y;
    const MapXAf& W;
    MapXAf& B;
    const int max_iter;
    const float lam;
    const float eps;
};

MapXAf as_eigen(PyArrayObject* arr) {
    assert(PyArray_EquivTypenums(PyArray_TYPE(arr), NPY_FLOAT32));
    assert(PyArray_ISCARRAY_RO(arr));
    return MapXAf(
                static_cast<float*>(PyArray_DATA(arr)),
                PyArray_DIM(arr, 0),
                PyArray_DIM(arr, 1));
}

const char* errmsg = "INTERNAL ERROR";
PyObject* py_lasso(PyObject* self, PyObject* args) {
    PyArrayObject* X;
    PyArrayObject* Y;
    PyArrayObject* W;
    PyArrayObject* B;
    int max_iter;
    float lam;
    float eps;
    if (!PyArg_ParseTuple(args, "OOOOiff", &X, &Y, &W, &B, &max_iter, &lam, &eps)) return NULL;
    if (!PyArray_Check(X) || !PyArray_ISCARRAY_RO(X) ||
        !PyArray_Check(Y) || !PyArray_ISCARRAY_RO(Y) ||
        !PyArray_Check(W) || !PyArray_ISCARRAY_RO(W) ||
        !PyArray_Check(B) || !PyArray_ISCARRAY(B) ||
        !PyArray_EquivTypenums(PyArray_TYPE(X), NPY_FLOAT32) ||
        !PyArray_EquivTypenums(PyArray_TYPE(Y), NPY_FLOAT32) ||
        !PyArray_EquivTypenums(PyArray_TYPE(W), NPY_FLOAT32) ||
        !PyArray_EquivTypenums(PyArray_TYPE(B), NPY_FLOAT32)) {
        PyErr_SetString(PyExc_RuntimeError,errmsg);
        return 0;
    }
    MapXAf mX = as_eigen(X);
    MapXAf mY = as_eigen(Y);
    MapXAf mW = as_eigen(W);
    MapXAf mB = as_eigen(B);
    max_iter *= mB.size();
    lasso_solver solver(mX, mY, mW, mB, max_iter, lam, eps);
    const int iters = solver.solve();

    return Py_BuildValue("i", iters);
}

PyMethodDef methods[] = {
  {"lasso", py_lasso, METH_VARARGS , "Do NOT call directly.\n" },
  {NULL, NULL,0,NULL},
};

const char  * module_doc =
    "Internal Module.\n"
    "\n"
    "Do NOT use directly!\n";

} // namespace

extern "C"
void init_lasso()
  {
    import_array();
    (void)Py_InitModule3("_lasso", methods, module_doc);
  }

<commit_msg>ENH Faster lasso<commit_after>// Copyright (C) 2012, Luis Pedro Coelho <luis@luispedro.org>
// License: MIT

#include <iostream>
#include <memory>
#include <cmath>
#include <random>
#include <cassert>
#include <queue>
#include <eigen3/Eigen/Dense>

using namespace Eigen;

extern "C" {
    #include <Python.h>
    #include <numpy/ndarrayobject.h>
}

namespace {

template <typename T>
int random_int(T& random, const int max) {
    std::uniform_int_distribution<int> dist(0, max - 1);
    return dist(random);
}
inline
float soft(const float val, const float lam) {
    return std::copysign(std::fdim(std::fabs(val), lam), val);
}
typedef Map<Matrix<float, Dynamic, Dynamic, RowMajor>, Aligned> MapXAf;
bool has_nans(const MapXAf& X) {
    for (int i = 0; i != X.rows(); ++i) {
        for (int j = 0; j != X.cols(); ++j) {
            if (std::isnan(X(i,j))) return true;
        }
    }
    return false;
}

struct lasso_solver {
    lasso_solver(const MapXAf& X, const MapXAf& Y, const MapXAf& W, MapXAf& B, const int max_iter, const float lam, const float eps)
        :X(X)
        ,Y(Y)
        ,W(W)
        ,B(B)
        ,max_iter(max_iter)
        ,lam(lam)
        ,eps(eps)
        { }

    void next_coords(int& i, int& j) {
        ++j;
        if (j == B.cols()) {
            j = 0;
            ++i;
            if (i == B.rows()) {
                i = 0;
            }
        }
    }

    int solve() {
        Matrix<float, Dynamic, Dynamic, RowMajor> residuals;
        int i = 0;
        int j = -1;
        // sweep is whether we are doing a whole-B sweep (i.e., even looking at
        // non-zero Bs)
        // changed is whether something has changed
        // We set this up to trigger computation of residuals and a sweep on
        // the first iteration
        bool sweep = false;
        bool changed = false;
        assert(!has_nans(X));
        assert(!has_nans(Y));
        assert(!has_nans(B));
        for (int it = 0; it != max_iter; ++it) {
            this->next_coords(i, j);
            if (i == 0 && j == 0) {
                if (sweep && !changed) {
                    return it;
                }
                if (!changed) {
                    sweep = true;
                    // Reset the residuals matrix to the best values to avoid
                    // drift due to successive rounding:
                    residuals = Y - B*X;
                } else {
                    sweep = false;
                }
                changed = false;
            }
            if (!sweep && B(i,j) == 0.0) continue;

            // We now set βᵢⱼ holding everything else fixed.  This comes down
            // to a very simple 1-dimensional problem.
            // We remember the current value in order to compute update below
            const float prev = B(i,j);
            const float x2 = (W.row(i).array()*X.row(j).array() * X.row(j).array()).sum();
            const float xy = (W.row(i).array()*X.row(j).array() * residuals.row(i).array()).sum();
            const float raw_step = (x2 == 0.0 ? 0.0 : xy/x2);
            const float best = soft(prev + raw_step, lam);
            const float step = best - prev;
            if (std::fabs(step) > eps) {
                assert(!std::isnan(best));
                B(i,j) = best;
                residuals.row(i) -= step*X.row(j);
                changed = true;
            }
        }
        return max_iter;
    }
    std::mt19937 r;
    const MapXAf& X;
    const MapXAf& Y;
    const MapXAf& W;
    MapXAf& B;
    const int max_iter;
    const float lam;
    const float eps;
};

MapXAf as_eigen(PyArrayObject* arr) {
    assert(PyArray_EquivTypenums(PyArray_TYPE(arr), NPY_FLOAT32));
    assert(PyArray_ISCARRAY_RO(arr));
    return MapXAf(
                static_cast<float*>(PyArray_DATA(arr)),
                PyArray_DIM(arr, 0),
                PyArray_DIM(arr, 1));
}

const char* errmsg = "INTERNAL ERROR";
PyObject* py_lasso(PyObject* self, PyObject* args) {
    PyArrayObject* X;
    PyArrayObject* Y;
    PyArrayObject* W;
    PyArrayObject* B;
    int max_iter;
    float lam;
    float eps;
    if (!PyArg_ParseTuple(args, "OOOOiff", &X, &Y, &W, &B, &max_iter, &lam, &eps)) return NULL;
    if (!PyArray_Check(X) || !PyArray_ISCARRAY_RO(X) ||
        !PyArray_Check(Y) || !PyArray_ISCARRAY_RO(Y) ||
        !PyArray_Check(W) || !PyArray_ISCARRAY_RO(W) ||
        !PyArray_Check(B) || !PyArray_ISCARRAY(B) ||
        !PyArray_EquivTypenums(PyArray_TYPE(X), NPY_FLOAT32) ||
        !PyArray_EquivTypenums(PyArray_TYPE(Y), NPY_FLOAT32) ||
        !PyArray_EquivTypenums(PyArray_TYPE(W), NPY_FLOAT32) ||
        !PyArray_EquivTypenums(PyArray_TYPE(B), NPY_FLOAT32)) {
        PyErr_SetString(PyExc_RuntimeError,errmsg);
        return 0;
    }
    MapXAf mX = as_eigen(X);
    MapXAf mY = as_eigen(Y);
    MapXAf mW = as_eigen(W);
    MapXAf mB = as_eigen(B);
    max_iter *= mB.size();
    lasso_solver solver(mX, mY, mW, mB, max_iter, lam, eps);
    const int iters = solver.solve();

    return Py_BuildValue("i", iters);
}

PyMethodDef methods[] = {
  {"lasso", py_lasso, METH_VARARGS , "Do NOT call directly.\n" },
  {NULL, NULL,0,NULL},
};

const char  * module_doc =
    "Internal Module.\n"
    "\n"
    "Do NOT use directly!\n";

} // namespace

extern "C"
void init_lasso()
  {
    import_array();
    (void)Py_InitModule3("_lasso", methods, module_doc);
  }

<|endoftext|>