<commit_before>#define BOOST_TEST_MODULE TEST_IO

#include <iostream>
#include <fstream>
#include <chrono>
#include <stdexcept>

#include <boost/test/unit_test.hpp>

#include <dynet/dynet.h>
#include <dynet/expr.h>
#include <dynet/rnn.h>
#include <dynet/lstm.h>
#include <dynet/gru.h>
#include <dynet/io.h>

#include "test.h"

using namespace dynet;
using namespace dynet::expr;
using namespace std;

struct IOTest {
    IOTest() {
        // initialize if necessary
        if (default_device == nullptr) {
            for (auto x : {"IOTest", "--dynet-mem", "512"}) {
                av.push_back(strdup(x));
            }
            char **argv = &av[0];
            int argc = av.size();
            dynet::initialize(argc, argv);
        }
        filename = "io.dump";
    }
    ~IOTest() {
        for (auto x : av) free(x);
    }

    std::vector<char*> av;
    std::string filename;
};

class testModel {
 public:
  testModel(dynet::ParameterCollection &model) {
    lookup_param = model.add_lookup_parameters(1000, {128});
    affine_params = model.add_subcollection("affine");
    W_x = affine_params.add_parameters({40, 30});
    b_x = affine_params.add_parameters({40});
    lstm = LSTMBuilder(3, 40, 1, model);
  }
  std::string get_affine_model_name() { return affine_params.get_fullname(); }
  dynet::ParameterCollection get_affine_model() const { return affine_params; }
  dynet::ParameterCollection get_lstm_model() { return lstm.get_parameter_collection(); }
 private:
  dynet::LookupParameter lookup_param;
  dynet::Parameter W_x, b_x;
  dynet::ParameterCollection affine_params;
  dynet::LSTMBuilder lstm;
}; // class testModel

// define the test suite
BOOST_FIXTURE_TEST_SUITE(io_test, IOTest);

BOOST_AUTO_TEST_CASE ( test_save_populate_pc ) {
  ParameterCollection m, m2;
  m.add_parameters({10}, "a");
  m.add_parameters({3,7});
  m.add_lookup_parameters(10, {2});
  m2.add_parameters({10}, "a");
  m2.add_parameters({3,7});
  m2.add_lookup_parameters(10, {2});
  {
    dynet::TextFileSaver s("test.model");
    s.save(m);
  }
  {
    dynet::TextFileLoader s("test.model");
    s.populate(m2);
  }
  DYNET_CHECK_EQUAL(m2, m);
}

BOOST_AUTO_TEST_CASE ( test_save_populate_sub_pc ) {
  // Create a parameter collection with a sub collection
  ParameterCollection m, m2;
  m.add_parameters({10}, "a");
  m.add_parameters({3,7});
  m.add_lookup_parameters(10, {2});
  ParameterCollection m_sub = m.add_subcollection("model1");
  m_sub.add_parameters({5}, "x");
  m_sub.add_parameters({3,6});
  m_sub.add_lookup_parameters(5, {3});
  m.add_lookup_parameters(4, {2});
  // Create another parameter collection with the same size as the sub collection
  m2.add_parameters({5}, "x");
  m2.add_parameters({3,6});
  m2.add_lookup_parameters(5, {3});
  // Save the overall collection
  {
    dynet::TextFileSaver s("test.model");
    s.save(m);
  }
  // Load only the sub-collection
  {
    dynet::TextFileLoader s("test.model");
    s.populate(m2, m_sub.get_fullname());
  }
  // Check if the sub-collection is equal
  DYNET_CHECK_EQUAL(m2, m_sub);
}

BOOST_AUTO_TEST_CASE ( test_save_populate_parameter ) {
  ParameterCollection m, m2;
  Parameter ma = m.add_parameters({10}, "a");
  Parameter mb = m.add_parameters({3,7});
  LookupParameter mc = m.add_lookup_parameters(10, {2});
  Parameter m2a = m2.add_parameters({10}, "a");
  Parameter m2b = m2.add_parameters({3,7});
  LookupParameter m2c = m2.add_lookup_parameters(10, {2});
  {
    dynet::TextFileSaver s("test.model");
    s.save(m);
  }
  {
    dynet::TextFileLoader s("test.model");
    s.populate(m2a, ma.get_fullname());
    s.populate(m2b, mb.get_fullname());
    s.populate(m2c, mc.get_fullname());
  }
  DYNET_CHECK_EQUAL(m2a, ma);
  DYNET_CHECK_EQUAL(m2b, mb);
  DYNET_CHECK_EQUAL(m2c, mc);
}

BOOST_AUTO_TEST_CASE ( test_save_load_parameter ) {
  ParameterCollection m, m2;
  Parameter ma = m.add_parameters({10}, "a");
  Parameter mb = m.add_parameters({3,7});
  LookupParameter mc = m.add_lookup_parameters(10, {2});
  Parameter m2a, m2b;
  LookupParameter m2c;
  {
    dynet::TextFileSaver s("test.model");
    s.save(m);
  }
  {
    dynet::TextFileLoader s("test.model");
    m2a = s.load_param(m2, ma.get_fullname());
    m2b = s.load_param(m2, mb.get_fullname());
    m2c = s.load_lookup_param(m2, mc.get_fullname());
  }
  DYNET_CHECK_EQUAL(m2a, ma);
  DYNET_CHECK_EQUAL(m2b, mb);
  DYNET_CHECK_EQUAL(m2c, mc);
}

BOOST_AUTO_TEST_CASE ( test_save1_perf ) {
  ParameterCollection m;
  for (int l = 0; l < 256; ++l)
    auto param = m.add_parameters({1024, 1024});
  std::chrono::time_point<std::chrono::system_clock> start, end;
  start = std::chrono::system_clock::now();
  {
    dynet::TextFileSaver s("test.model");
    s.save(m);
  }
  end = std::chrono::system_clock::now();
  std::chrono::duration<double> elapsed_seconds = end-start;
  std::cout << "elapsed time: " << elapsed_seconds.count() << "ms" << std::endl;
}

BOOST_AUTO_TEST_CASE ( test_load1_perf ) {
  ParameterCollection m, m_l;
  Parameter param;
  Parameter param_l = m_l.add_parameters({1024, 1024});
  for (int l = 0; l < 256; ++l)
    param = m.add_parameters({1024, 1024});
  {
    dynet::TextFileSaver s("test.model");
    s.save(m);
  }
  std::chrono::time_point<std::chrono::system_clock> start, end;
  start = std::chrono::system_clock::now();
  {
    dynet::TextFileLoader l("test.model");
    l.populate(param_l, param.get_fullname());
  }
  end = std::chrono::system_clock::now();
  std::chrono::duration<double> elapsed_seconds = end-start;
  std::cout << "elapsed time: " << elapsed_seconds.count() << "ms" << std::endl;
  DYNET_CHECK_EQUAL(param, param_l);
}

BOOST_AUTO_TEST_CASE ( test_save2_perf ) {
  ParameterCollection m;
  for (int l = 0; l < 5120; ++l)
    auto param = m.add_parameters({128, 128});
  std::chrono::time_point<std::chrono::system_clock> start, end;
  start = std::chrono::system_clock::now();
  {
    dynet::TextFileSaver s("test.model");
    s.save(m);
  }
  end = std::chrono::system_clock::now();
  std::chrono::duration<double> elapsed_seconds = end-start;
  std::cout << "elapsed time: " << elapsed_seconds.count() << "ms" << std::endl;
}

BOOST_AUTO_TEST_CASE ( test_load2_perf ) {
  ParameterCollection m, m_l;
  Parameter param;
  Parameter param_l = m_l.add_parameters({128, 128});
  for (int l = 0; l < 5120; ++l)
    param = m.add_parameters({128, 128});
  {
    dynet::TextFileSaver s("test.model");
    s.save(m);
  }
  std::chrono::time_point<std::chrono::system_clock> start, end;
  start = std::chrono::system_clock::now();
  {
    dynet::TextFileLoader l("test.model");
    l.populate(param_l, param.get_fullname());
  }
  end = std::chrono::system_clock::now();
  std::chrono::duration<double> elapsed_seconds = end-start;
  std::cout << "elapsed time: " << elapsed_seconds.count() << "ms" << std::endl;
  DYNET_CHECK_EQUAL(param, param_l);
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>shorten test-io time<commit_after>#define BOOST_TEST_MODULE TEST_IO

#include <iostream>
#include <fstream>
#include <chrono>
#include <stdexcept>

#include <boost/test/unit_test.hpp>

#include <dynet/dynet.h>
#include <dynet/expr.h>
#include <dynet/rnn.h>
#include <dynet/lstm.h>
#include <dynet/gru.h>
#include <dynet/io.h>

#include "test.h"

using namespace dynet;
using namespace dynet::expr;
using namespace std;

struct IOTest {
    IOTest() {
        // initialize if necessary
        if (default_device == nullptr) {
            for (auto x : {"IOTest", "--dynet-mem", "512"}) {
                av.push_back(strdup(x));
            }
            char **argv = &av[0];
            int argc = av.size();
            dynet::initialize(argc, argv);
        }
        filename = "io.dump";
    }
    ~IOTest() {
        for (auto x : av) free(x);
    }

    std::vector<char*> av;
    std::string filename;
};

class testModel {
 public:
  testModel(dynet::ParameterCollection &model) {
    lookup_param = model.add_lookup_parameters(1000, {128});
    affine_params = model.add_subcollection("affine");
    W_x = affine_params.add_parameters({40, 30});
    b_x = affine_params.add_parameters({40});
    lstm = LSTMBuilder(3, 40, 1, model);
  }
  std::string get_affine_model_name() { return affine_params.get_fullname(); }
  dynet::ParameterCollection get_affine_model() const { return affine_params; }
  dynet::ParameterCollection get_lstm_model() { return lstm.get_parameter_collection(); }
 private:
  dynet::LookupParameter lookup_param;
  dynet::Parameter W_x, b_x;
  dynet::ParameterCollection affine_params;
  dynet::LSTMBuilder lstm;
}; // class testModel

// define the test suite
BOOST_FIXTURE_TEST_SUITE(io_test, IOTest);

BOOST_AUTO_TEST_CASE ( test_save_populate_pc ) {
  ParameterCollection m, m2;
  m.add_parameters({10}, "a");
  m.add_parameters({3,7});
  m.add_lookup_parameters(10, {2});
  m2.add_parameters({10}, "a");
  m2.add_parameters({3,7});
  m2.add_lookup_parameters(10, {2});
  {
    dynet::TextFileSaver s("test.model");
    s.save(m);
  }
  {
    dynet::TextFileLoader s("test.model");
    s.populate(m2);
  }
  DYNET_CHECK_EQUAL(m2, m);
}

BOOST_AUTO_TEST_CASE ( test_save_populate_sub_pc ) {
  // Create a parameter collection with a sub collection
  ParameterCollection m, m2;
  m.add_parameters({10}, "a");
  m.add_parameters({3,7});
  m.add_lookup_parameters(10, {2});
  ParameterCollection m_sub = m.add_subcollection("model1");
  m_sub.add_parameters({5}, "x");
  m_sub.add_parameters({3,6});
  m_sub.add_lookup_parameters(5, {3});
  m.add_lookup_parameters(4, {2});
  // Create another parameter collection with the same size as the sub collection
  m2.add_parameters({5}, "x");
  m2.add_parameters({3,6});
  m2.add_lookup_parameters(5, {3});
  // Save the overall collection
  {
    dynet::TextFileSaver s("test.model");
    s.save(m);
  }
  // Load only the sub-collection
  {
    dynet::TextFileLoader s("test.model");
    s.populate(m2, m_sub.get_fullname());
  }
  // Check if the sub-collection is equal
  DYNET_CHECK_EQUAL(m2, m_sub);
}

BOOST_AUTO_TEST_CASE ( test_save_populate_parameter ) {
  ParameterCollection m, m2;
  Parameter ma = m.add_parameters({10}, "a");
  Parameter mb = m.add_parameters({3,7});
  LookupParameter mc = m.add_lookup_parameters(10, {2});
  Parameter m2a = m2.add_parameters({10}, "a");
  Parameter m2b = m2.add_parameters({3,7});
  LookupParameter m2c = m2.add_lookup_parameters(10, {2});
  {
    dynet::TextFileSaver s("test.model");
    s.save(m);
  }
  {
    dynet::TextFileLoader s("test.model");
    s.populate(m2a, ma.get_fullname());
    s.populate(m2b, mb.get_fullname());
    s.populate(m2c, mc.get_fullname());
  }
  DYNET_CHECK_EQUAL(m2a, ma);
  DYNET_CHECK_EQUAL(m2b, mb);
  DYNET_CHECK_EQUAL(m2c, mc);
}

BOOST_AUTO_TEST_CASE ( test_save_load_parameter ) {
  ParameterCollection m, m2;
  Parameter ma = m.add_parameters({10}, "a");
  Parameter mb = m.add_parameters({3,7});
  LookupParameter mc = m.add_lookup_parameters(10, {2});
  Parameter m2a, m2b;
  LookupParameter m2c;
  {
    dynet::TextFileSaver s("test.model");
    s.save(m);
  }
  {
    dynet::TextFileLoader s("test.model");
    m2a = s.load_param(m2, ma.get_fullname());
    m2b = s.load_param(m2, mb.get_fullname());
    m2c = s.load_lookup_param(m2, mc.get_fullname());
  }
  DYNET_CHECK_EQUAL(m2a, ma);
  DYNET_CHECK_EQUAL(m2b, mb);
  DYNET_CHECK_EQUAL(m2c, mc);
}

BOOST_AUTO_TEST_CASE ( test_save1_perf ) {
  ParameterCollection m;
  for (int l = 0; l < 16; ++l)
    auto param = m.add_parameters({1024, 1024});
  std::chrono::time_point<std::chrono::system_clock> start, end;
  start = std::chrono::system_clock::now();
  {
    dynet::TextFileSaver s("test.model");
    s.save(m);
  }
  end = std::chrono::system_clock::now();
  std::chrono::duration<double> elapsed_seconds = end-start;
  std::cout << "elapsed time: " << elapsed_seconds.count() << "ms" << std::endl;
}

BOOST_AUTO_TEST_CASE ( test_load1_perf ) {
  ParameterCollection m, m_l;
  Parameter param;
  Parameter param_l = m_l.add_parameters({1024, 1024});
  for (int l = 0; l < 16; ++l)
    param = m.add_parameters({1024, 1024});
  {
    dynet::TextFileSaver s("test.model");
    s.save(m);
  }
  std::chrono::time_point<std::chrono::system_clock> start, end;
  start = std::chrono::system_clock::now();
  {
    dynet::TextFileLoader l("test.model");
    l.populate(param_l, param.get_fullname());
  }
  end = std::chrono::system_clock::now();
  std::chrono::duration<double> elapsed_seconds = end-start;
  std::cout << "elapsed time: " << elapsed_seconds.count() << "ms" << std::endl;
  DYNET_CHECK_EQUAL(param, param_l);
}

BOOST_AUTO_TEST_CASE ( test_save2_perf ) {
  ParameterCollection m;
  for (int l = 0; l < 512; ++l)
    auto param = m.add_parameters({128, 128});
  std::chrono::time_point<std::chrono::system_clock> start, end;
  start = std::chrono::system_clock::now();
  {
    dynet::TextFileSaver s("test.model");
    s.save(m);
  }
  end = std::chrono::system_clock::now();
  std::chrono::duration<double> elapsed_seconds = end-start;
  std::cout << "elapsed time: " << elapsed_seconds.count() << "ms" << std::endl;
}

BOOST_AUTO_TEST_CASE ( test_load2_perf ) {
  ParameterCollection m, m_l;
  Parameter param;
  Parameter param_l = m_l.add_parameters({128, 128});
  for (int l = 0; l < 512; ++l)
    param = m.add_parameters({128, 128});
  {
    dynet::TextFileSaver s("test.model");
    s.save(m);
  }
  std::chrono::time_point<std::chrono::system_clock> start, end;
  start = std::chrono::system_clock::now();
  {
    dynet::TextFileLoader l("test.model");
    l.populate(param_l, param.get_fullname());
  }
  end = std::chrono::system_clock::now();
  std::chrono::duration<double> elapsed_seconds = end-start;
  std::cout << "elapsed time: " << elapsed_seconds.count() << "ms" << std::endl;
  DYNET_CHECK_EQUAL(param, param_l);
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2016, Image Engine Design Inc. 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 Image Engine Design nor the names of
//        any other contributors to this software 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.
//
//////////////////////////////////////////////////////////////////////////

#include "OpenEXR/ImathFun.h"

#include "Gaffer/Context.h"

#include "GafferImage/ImageAlgo.h"
#include "GafferImage/UVWarp.h"

using namespace Imath;
using namespace IECore;
using namespace Gaffer;
using namespace GafferImage;

//////////////////////////////////////////////////////////////////////////
// Engine implementation
//////////////////////////////////////////////////////////////////////////

struct UVWarp::Engine : public Warp::Engine
{

	Engine( const Box2i &displayWindow, const Box2i &tileBound, const Box2i &validTileBound, ConstFloatVectorDataPtr uData, ConstFloatVectorDataPtr vData, ConstFloatVectorDataPtr aData )
		:	m_displayWindow( displayWindow ),
			m_tileBound( tileBound ),
			m_uData( uData ),
			m_vData( vData ),
			m_aData( aData ),
			m_u( uData->readable() ),
			m_v( vData->readable() ),
			m_a( aData->readable() )
	{
		V2i oP;
		for( oP.y = validTileBound.min.y; oP.y < validTileBound.max.y; ++oP.y )
		{
			size_t i = index( V2i( validTileBound.min.x, oP.y ), tileBound );
			for( oP.x = validTileBound.min.x; oP.x < validTileBound.max.x; ++oP.x, ++i )
			{
				if( m_a[i] == 0.0f )
				{
					continue;
				}
				const V2f iP = uvToPixel( V2f( m_u[i], m_v[i] ) );
				m_inputWindow.extendBy( iP );
			}
		}

		m_inputWindow.min -= V2i( 1 );
		m_inputWindow.max += V2i( 1 );
	}

	virtual void hash( IECore::MurmurHash &h ) const
	{
		m_uData->hash( h );
		m_vData->hash( h );
	}

	virtual Imath::Box2i inputWindow( const Imath::V2i &tileOrigin ) const
	{
		assert( tileOrigin == m_tileBound.min );
		return m_inputWindow;
	}

	virtual Imath::V2f inputPixel( const Imath::V2f &outputPixel ) const
	{
		const V2i outputPixelI( floorf( outputPixel.x ), floorf( outputPixel.y ) );
		const size_t i = index( outputPixelI, m_tileBound );
		if( m_a[i] == 0.0f )
		{
			return black;
		}
		else
		{
			return uvToPixel( V2f( m_u[i], m_v[i] ) );
		}
	}

	private :

		inline V2f uvToPixel( const V2f &uv ) const
		{
			return V2f(
				lerp<float>( m_displayWindow.min.x, m_displayWindow.max.x, uv.x ),
				lerp<float>( m_displayWindow.min.y, m_displayWindow.max.y, uv.y )
			);
		}

		const Box2i m_displayWindow;
		const Box2i m_tileBound;
		Box2i m_inputWindow;

		ConstFloatVectorDataPtr m_uData;
		ConstFloatVectorDataPtr m_vData;
		ConstFloatVectorDataPtr m_aData;

		const std::vector<float> &m_u;
		const std::vector<float> &m_v;
		const std::vector<float> &m_a;

};

//////////////////////////////////////////////////////////////////////////
// UVWarp implementation
//////////////////////////////////////////////////////////////////////////

IE_CORE_DEFINERUNTIMETYPED( UVWarp );

size_t UVWarp::g_firstPlugIndex = 0;

UVWarp::UVWarp( const std::string &name )
	:	Warp( name )
{
	storeIndexOfNextChild( g_firstPlugIndex );
	addChild( new ImagePlug( "uv" ) );

	outPlug()->formatPlug()->setInput( uvPlug()->formatPlug() );
	outPlug()->dataWindowPlug()->setInput( uvPlug()->dataWindowPlug() );
}

UVWarp::~UVWarp()
{
}

ImagePlug *UVWarp::uvPlug()
{
	return getChild<ImagePlug>( g_firstPlugIndex );
}

const ImagePlug *UVWarp::uvPlug() const
{
	return getChild<ImagePlug>( g_firstPlugIndex );
}

bool UVWarp::affectsEngine( const Gaffer::Plug *input ) const
{
	return
		Warp::affectsEngine( input ) ||
		input == inPlug()->formatPlug() ||
		input == uvPlug()->channelNamesPlug() ||
		input == uvPlug()->channelDataPlug();
}

void UVWarp::hashEngine( const std::string &channelName, const Imath::V2i &tileOrigin, const Gaffer::Context *context, IECore::MurmurHash &h ) const
{
	Warp::hashEngine( channelName, tileOrigin, context, h );

	h.append( tileOrigin );
	uvPlug()->dataWindowPlug()->hash( h );

	ConstStringVectorDataPtr channelNames = uvPlug()->channelNamesPlug()->getValue();

	ContextPtr tmpContext = new Context( *context, Context::Borrowed );
	Context::Scope scopedContext( tmpContext.get() );

	if( channelExists( channelNames->readable(), "R" ) )
	{
		tmpContext->set<std::string>( ImagePlug::channelNameContextName, "R" );
		uvPlug()->channelDataPlug()->hash( h );
	}

	if( channelExists( channelNames->readable(), "G" ) )
	{
		tmpContext->set<std::string>( ImagePlug::channelNameContextName, "G" );
		uvPlug()->channelDataPlug()->hash( h );
	}

	if( channelExists( channelNames->readable(), "A" ) )
	{
		tmpContext->set<std::string>( ImagePlug::channelNameContextName, "A" );
		uvPlug()->channelDataPlug()->hash( h );
	}

	inPlug()->formatPlug()->hash( h );
}

const Warp::Engine *UVWarp::computeEngine( const std::string &channelName, const Imath::V2i &tileOrigin, const Gaffer::Context *context ) const
{
	const Box2i tileBound( tileOrigin, tileOrigin + V2i( ImagePlug::tileSize() ) );
	const Box2i validTileBound = intersection( tileBound, uvPlug()->dataWindowPlug()->getValue() );

	ConstStringVectorDataPtr channelNames = uvPlug()->channelNamesPlug()->getValue();

	ContextPtr tmpContext = new Context( *context, Context::Borrowed );
	Context::Scope scopedContext( tmpContext.get() );

	ConstFloatVectorDataPtr uData = ImagePlug::blackTile();
	if( channelExists( channelNames->readable(), "R" ) )
	{
		tmpContext->set<std::string>( ImagePlug::channelNameContextName, "R" );
		uData = uvPlug()->channelDataPlug()->getValue();
	}

	ConstFloatVectorDataPtr vData = ImagePlug::blackTile();
	if( channelExists( channelNames->readable(), "G" ) )
	{
		tmpContext->set<std::string>( ImagePlug::channelNameContextName, "G" );
		vData = uvPlug()->channelDataPlug()->getValue();
	}

	ConstFloatVectorDataPtr aData = ImagePlug::whiteTile();
	if( channelExists( channelNames->readable(), "A" ) )
	{
		tmpContext->set<std::string>( ImagePlug::channelNameContextName, "A" );
		aData = uvPlug()->channelDataPlug()->getValue();
	}

	return new Engine(
		inPlug()->formatPlug()->getValue().getDisplayWindow(),
		tileBound,
		validTileBound,
		uData,
		vData,
		aData
	);
}
<commit_msg>UVWarp : Fix compilation with GCC 4.1.2.<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2016, Image Engine Design Inc. 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 Image Engine Design nor the names of
//        any other contributors to this software 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.
//
//////////////////////////////////////////////////////////////////////////

#include "OpenEXR/ImathFun.h"

#include "Gaffer/Context.h"

#include "GafferImage/ImageAlgo.h"
#include "GafferImage/UVWarp.h"

using namespace Imath;
using namespace IECore;
using namespace Gaffer;
using namespace GafferImage;

//////////////////////////////////////////////////////////////////////////
// Engine implementation
//////////////////////////////////////////////////////////////////////////

struct UVWarp::Engine : public Warp::Engine
{

	Engine( const Box2i &displayWindow, const Box2i &tileBound, const Box2i &validTileBound, ConstFloatVectorDataPtr uData, ConstFloatVectorDataPtr vData, ConstFloatVectorDataPtr aData )
		:	m_displayWindow( displayWindow ),
			m_tileBound( tileBound ),
			m_uData( uData ),
			m_vData( vData ),
			m_aData( aData ),
			m_u( uData->readable() ),
			m_v( vData->readable() ),
			m_a( aData->readable() )
	{
		V2i oP;
		for( oP.y = validTileBound.min.y; oP.y < validTileBound.max.y; ++oP.y )
		{
			size_t i = index( V2i( validTileBound.min.x, oP.y ), tileBound );
			for( oP.x = validTileBound.min.x; oP.x < validTileBound.max.x; ++oP.x, ++i )
			{
				if( m_a[i] == 0.0f )
				{
					continue;
				}
				const V2f iP = uvToPixel( V2f( m_u[i], m_v[i] ) );
				m_inputWindow.extendBy( iP );
			}
		}

		m_inputWindow.min -= V2i( 1 );
		m_inputWindow.max += V2i( 1 );
	}

	virtual void hash( IECore::MurmurHash &h ) const
	{
		m_uData->hash( h );
		m_vData->hash( h );
	}

	virtual Imath::Box2i inputWindow( const Imath::V2i &tileOrigin ) const
	{
		assert( tileOrigin == m_tileBound.min );
		return m_inputWindow;
	}

	virtual Imath::V2f inputPixel( const Imath::V2f &outputPixel ) const
	{
		const V2i outputPixelI( (int)floorf( outputPixel.x ), (int)floorf( outputPixel.y ) );
		const size_t i = index( outputPixelI, m_tileBound );
		if( m_a[i] == 0.0f )
		{
			return black;
		}
		else
		{
			return uvToPixel( V2f( m_u[i], m_v[i] ) );
		}
	}

	private :

		inline V2f uvToPixel( const V2f &uv ) const
		{
			return V2f(
				lerp<float>( m_displayWindow.min.x, m_displayWindow.max.x, uv.x ),
				lerp<float>( m_displayWindow.min.y, m_displayWindow.max.y, uv.y )
			);
		}

		const Box2i m_displayWindow;
		const Box2i m_tileBound;
		Box2i m_inputWindow;

		ConstFloatVectorDataPtr m_uData;
		ConstFloatVectorDataPtr m_vData;
		ConstFloatVectorDataPtr m_aData;

		const std::vector<float> &m_u;
		const std::vector<float> &m_v;
		const std::vector<float> &m_a;

};

//////////////////////////////////////////////////////////////////////////
// UVWarp implementation
//////////////////////////////////////////////////////////////////////////

IE_CORE_DEFINERUNTIMETYPED( UVWarp );

size_t UVWarp::g_firstPlugIndex = 0;

UVWarp::UVWarp( const std::string &name )
	:	Warp( name )
{
	storeIndexOfNextChild( g_firstPlugIndex );
	addChild( new ImagePlug( "uv" ) );

	outPlug()->formatPlug()->setInput( uvPlug()->formatPlug() );
	outPlug()->dataWindowPlug()->setInput( uvPlug()->dataWindowPlug() );
}

UVWarp::~UVWarp()
{
}

ImagePlug *UVWarp::uvPlug()
{
	return getChild<ImagePlug>( g_firstPlugIndex );
}

const ImagePlug *UVWarp::uvPlug() const
{
	return getChild<ImagePlug>( g_firstPlugIndex );
}

bool UVWarp::affectsEngine( const Gaffer::Plug *input ) const
{
	return
		Warp::affectsEngine( input ) ||
		input == inPlug()->formatPlug() ||
		input == uvPlug()->channelNamesPlug() ||
		input == uvPlug()->channelDataPlug();
}

void UVWarp::hashEngine( const std::string &channelName, const Imath::V2i &tileOrigin, const Gaffer::Context *context, IECore::MurmurHash &h ) const
{
	Warp::hashEngine( channelName, tileOrigin, context, h );

	h.append( tileOrigin );
	uvPlug()->dataWindowPlug()->hash( h );

	ConstStringVectorDataPtr channelNames = uvPlug()->channelNamesPlug()->getValue();

	ContextPtr tmpContext = new Context( *context, Context::Borrowed );
	Context::Scope scopedContext( tmpContext.get() );

	if( channelExists( channelNames->readable(), "R" ) )
	{
		tmpContext->set<std::string>( ImagePlug::channelNameContextName, "R" );
		uvPlug()->channelDataPlug()->hash( h );
	}

	if( channelExists( channelNames->readable(), "G" ) )
	{
		tmpContext->set<std::string>( ImagePlug::channelNameContextName, "G" );
		uvPlug()->channelDataPlug()->hash( h );
	}

	if( channelExists( channelNames->readable(), "A" ) )
	{
		tmpContext->set<std::string>( ImagePlug::channelNameContextName, "A" );
		uvPlug()->channelDataPlug()->hash( h );
	}

	inPlug()->formatPlug()->hash( h );
}

const Warp::Engine *UVWarp::computeEngine( const std::string &channelName, const Imath::V2i &tileOrigin, const Gaffer::Context *context ) const
{
	const Box2i tileBound( tileOrigin, tileOrigin + V2i( ImagePlug::tileSize() ) );
	const Box2i validTileBound = intersection( tileBound, uvPlug()->dataWindowPlug()->getValue() );

	ConstStringVectorDataPtr channelNames = uvPlug()->channelNamesPlug()->getValue();

	ContextPtr tmpContext = new Context( *context, Context::Borrowed );
	Context::Scope scopedContext( tmpContext.get() );

	ConstFloatVectorDataPtr uData = ImagePlug::blackTile();
	if( channelExists( channelNames->readable(), "R" ) )
	{
		tmpContext->set<std::string>( ImagePlug::channelNameContextName, "R" );
		uData = uvPlug()->channelDataPlug()->getValue();
	}

	ConstFloatVectorDataPtr vData = ImagePlug::blackTile();
	if( channelExists( channelNames->readable(), "G" ) )
	{
		tmpContext->set<std::string>( ImagePlug::channelNameContextName, "G" );
		vData = uvPlug()->channelDataPlug()->getValue();
	}

	ConstFloatVectorDataPtr aData = ImagePlug::whiteTile();
	if( channelExists( channelNames->readable(), "A" ) )
	{
		tmpContext->set<std::string>( ImagePlug::channelNameContextName, "A" );
		aData = uvPlug()->channelDataPlug()->getValue();
	}

	return new Engine(
		inPlug()->formatPlug()->getValue().getDisplayWindow(),
		tileBound,
		validTileBound,
		uData,
		vData,
		aData
	);
}
<|endoftext|>


<commit_before>// Copyright (C) 2010-2013 Joshua Boyce.
// See the file COPYING for copying permission.

#include <hadesmem/thread.hpp>

#include <locale>
#include <sstream>
#include <utility>

#define BOOST_TEST_MODULE process
#include <hadesmem/detail/warning_disable_prefix.hpp>
#include <boost/thread.hpp>
#include <boost/test/unit_test.hpp>
#include <hadesmem/detail/warning_disable_suffix.hpp>

#include <hadesmem/error.hpp>
#include <hadesmem/config.hpp>
#include <hadesmem/thread_helpers.hpp>
#include <hadesmem/detail/initialize.hpp>

// Boost.Test causes the following warning under GCC:
// error: base class 'struct boost::unit_test::ut_detail::nil_t' has a
// non-virtual destructor [-Werror=effc++]
#if defined(HADESMEM_GCC)
#pragma GCC diagnostic ignored "-Weffc++"
#endif // #if defined(HADESMEM_GCC)

// Boost.Test causes the following warning under Clang:
// error: declaration requires a global constructor
// [-Werror,-Wglobal-constructors]
#if defined(HADESMEM_CLANG)
#pragma GCC diagnostic ignored "-Wglobal-constructors"
#endif // #if defined(HADESMEM_CLANG)

BOOST_AUTO_TEST_CASE(initialize)
{
  hadesmem::detail::InitializeAll();
}

BOOST_AUTO_TEST_CASE(this_thread)
{
  hadesmem::Thread thread(::GetCurrentThreadId());
  BOOST_CHECK_EQUAL(thread, thread);
  hadesmem::Thread thread_new(::GetCurrentThreadId());
  BOOST_CHECK_EQUAL(thread, thread_new);
  hadesmem::Thread const thread_moved(std::move(thread_new));
  hadesmem::Thread thread_copy(thread);
  BOOST_CHECK_EQUAL(thread_copy, thread);
  thread = thread_copy;
  BOOST_CHECK_EQUAL(thread, thread_copy);
  thread_new = std::move(thread_copy);
  BOOST_CHECK_EQUAL(thread, thread_new);
  BOOST_CHECK_GE(thread, thread);
  BOOST_CHECK_LE(thread, thread);
  BOOST_CHECK_EQUAL(thread.GetId(), ::GetCurrentThreadId());
  std::stringstream thread_str_1;
  thread_str_1.imbue(std::locale::classic());
  thread_str_1 << thread;
  DWORD thread_id_1;
  thread_str_1 >> thread_id_1;
  BOOST_CHECK_EQUAL(thread.GetId(), thread_id_1);
  std::wstringstream thread_str_2;
  thread_str_2.imbue(std::locale::classic());
  thread_str_2 << thread;
  DWORD thread_id_2;
  thread_str_2 >> thread_id_2;
  BOOST_CHECK_EQUAL(thread.GetId(), thread_id_2);

  boost::thread other([]() { Sleep(INFINITE); });
  try
  {
    DWORD const other_id = ::GetThreadId(other.native_handle());
    hadesmem::Thread const other_thread(other_id);
    BOOST_CHECK_EQUAL(hadesmem::SuspendThread(other_thread), 0UL);
    BOOST_CHECK_EQUAL(hadesmem::SuspendThread(other_thread), 1UL);
    BOOST_CHECK_EQUAL(hadesmem::ResumeThread(other_thread), 2UL);
    BOOST_CHECK_EQUAL(hadesmem::ResumeThread(other_thread), 1UL);
    hadesmem::SuspendThread(other_thread);
    CONTEXT const full_context = hadesmem::GetThreadContext(
      other_thread, CONTEXT_FULL);
    CONTEXT const all_context = hadesmem::GetThreadContext(
      other_thread, CONTEXT_ALL);
    hadesmem::SetThreadContext(other_thread, full_context);
    hadesmem::SetThreadContext(other_thread, all_context);
    BOOST_CHECK_THROW(hadesmem::GetThreadContext(thread, CONTEXT_FULL),
      hadesmem::Error);
    {
      hadesmem::SuspendedThread const suspend_thread(other_thread.GetId());
    }
    {
      hadesmem::SuspendedProcess const suspend_process(
        ::GetCurrentProcessId());
    }
    other.detach();
  }
  catch (std::exception const& /*e*/)
  {
#if defined(HADESMEM_MSVC)
#pragma warning(push)
// warning C6258: Using TerminateThread does not allow proper thread clean up.
#pragma warning(disable: 6258)
    // TODO: Use an event or something else that's 'safe' instead of just
    // trashing the thread.
    (void)::TerminateThread(other.native_handle(), 0xDEADBEEF);
#pragma warning(pop)
#endif // #if defined(HADESMEM_MSVC)
    other.detach();
    throw;
  }
}
<commit_msg>* Fix thread tests.<commit_after>// Copyright (C) 2010-2013 Joshua Boyce.
// See the file COPYING for copying permission.

#include <hadesmem/thread.hpp>

#include <locale>
#include <sstream>
#include <utility>

#define BOOST_TEST_MODULE process
#include <hadesmem/detail/warning_disable_prefix.hpp>
#include <boost/thread.hpp>
#include <boost/test/unit_test.hpp>
#include <hadesmem/detail/warning_disable_suffix.hpp>

#include <hadesmem/error.hpp>
#include <hadesmem/config.hpp>
#include <hadesmem/thread_helpers.hpp>
#include <hadesmem/detail/initialize.hpp>

// Boost.Test causes the following warning under GCC:
// error: base class 'struct boost::unit_test::ut_detail::nil_t' has a
// non-virtual destructor [-Werror=effc++]
#if defined(HADESMEM_GCC)
#pragma GCC diagnostic ignored "-Weffc++"
#endif // #if defined(HADESMEM_GCC)

// Boost.Test causes the following warning under Clang:
// error: declaration requires a global constructor
// [-Werror,-Wglobal-constructors]
#if defined(HADESMEM_CLANG)
#pragma GCC diagnostic ignored "-Wglobal-constructors"
#endif // #if defined(HADESMEM_CLANG)

BOOST_AUTO_TEST_CASE(initialize)
{
  hadesmem::detail::InitializeAll();
}

BOOST_AUTO_TEST_CASE(this_thread)
{
  hadesmem::Thread thread(::GetCurrentThreadId());
  BOOST_CHECK_EQUAL(thread, thread);
  hadesmem::Thread thread_new(::GetCurrentThreadId());
  BOOST_CHECK_EQUAL(thread, thread_new);
  hadesmem::Thread const thread_moved(std::move(thread_new));
  hadesmem::Thread thread_copy(thread);
  BOOST_CHECK_EQUAL(thread_copy, thread);
  thread = thread_copy;
  BOOST_CHECK_EQUAL(thread, thread_copy);
  thread_new = std::move(thread_copy);
  BOOST_CHECK_EQUAL(thread, thread_new);
  BOOST_CHECK_GE(thread, thread);
  BOOST_CHECK_LE(thread, thread);
  BOOST_CHECK_EQUAL(thread.GetId(), ::GetCurrentThreadId());
  std::stringstream thread_str_1;
  thread_str_1.imbue(std::locale::classic());
  thread_str_1 << thread;
  DWORD thread_id_1;
  thread_str_1 >> thread_id_1;
  BOOST_CHECK_EQUAL(thread.GetId(), thread_id_1);
  std::wstringstream thread_str_2;
  thread_str_2.imbue(std::locale::classic());
  thread_str_2 << thread;
  DWORD thread_id_2;
  thread_str_2 >> thread_id_2;
  BOOST_CHECK_EQUAL(thread.GetId(), thread_id_2);

  hadesmem::detail::SmartHandle quit_event(::CreateEvent(
    nullptr,
    TRUE,
    FALSE,
    nullptr));
  boost::thread other(
    [&]()
    {
      BOOST_CHECK_EQUAL(::WaitForSingleObject(
        quit_event.GetHandle(),
        INFINITE),
        WAIT_OBJECT_0);
    });
  try
  {
    DWORD const other_id = ::GetThreadId(other.native_handle());
    hadesmem::Thread const other_thread(other_id);
    BOOST_CHECK_EQUAL(hadesmem::SuspendThread(other_thread), 0UL);
    BOOST_CHECK_EQUAL(hadesmem::SuspendThread(other_thread), 1UL);
    BOOST_CHECK_EQUAL(hadesmem::ResumeThread(other_thread), 2UL);
    BOOST_CHECK_EQUAL(hadesmem::ResumeThread(other_thread), 1UL);

    {
      hadesmem::SuspendedThread const suspend_thread(
        other_thread.GetId());

      CONTEXT const full_context = hadesmem::GetThreadContext(
        other_thread, CONTEXT_FULL);
      CONTEXT const all_context = hadesmem::GetThreadContext(
        other_thread, CONTEXT_ALL);
      hadesmem::SetThreadContext(other_thread, full_context);
      hadesmem::SetThreadContext(other_thread, all_context);
      BOOST_CHECK_THROW(hadesmem::GetThreadContext(thread, CONTEXT_FULL),
        hadesmem::Error);
    }

    {
      hadesmem::SuspendedProcess const suspend_process(
        ::GetCurrentProcessId());
    }
    BOOST_CHECK_NE(::SetEvent(quit_event.GetHandle()), 0);
    other.join();
  }
  catch (std::exception const& /*e*/)
  {
    BOOST_CHECK_NE(::SetEvent(quit_event.GetHandle()), 0);
    other.join();
    throw;
  }
}
<|endoftext|>


<commit_before>#include "Bitmap.hpp"

#include <zlib.h>

Bitmap::Bitmap(AVFrame *frame) {
	pix_fmt = static_cast<PixelFormat>(frame->format);
	width = frame->width;
	height = frame->height;

	avpicture_alloc(&picture, pix_fmt, frame->width, frame->height);
	av_image_copy(picture.data, picture.linesize, const_cast<const uint8_t**>(frame->data), frame->linesize, pix_fmt, width, height);
}

Bitmap::~Bitmap() {
	avpicture_free(&picture);
}

#define WS 8
#define WS2 64

double Bitmap::SSIM(Bitmap &other) {
	// FIXME: this should be resized
	if( width != other.width || height != other.height ) {
		throw "The bitmaps currently have to be of the same size";
	}

	double coef_1 = 6.5025;   // (0.01 * 255)^2
	double coef_2 = 58.5225;  // (0.03 * 255)^2

	int w_width = width / WS;
	int w_height = height / WS;

	int linesize = picture.linesize[0];
	uint8_t *data_this = picture.data[0];
	uint8_t *data_other = other.picture.data[0];

	double ssim = 0;
	for( int w_i = 0; w_i < w_height; w_i++ ) {
		for( int w_j = 0; w_j < w_width; w_j++ ) {
			int w_offset = linesize * w_i * WS + w_j * WS;
			int x = 0, xx = 0, y = 0, yy = 0, xy = 0;
			for( int i = 0; i < WS; i++ ) {
				int l_offset = w_offset + linesize*i;
				for( int j = 0; j < WS; j++ ) {
					int cur_this  = data_this [l_offset + j];
					int cur_other = data_other[l_offset + j];
					x += cur_this;
					xx += cur_this * cur_this;
					y += cur_other;
					yy += cur_other * cur_other;
					xy += cur_this * cur_other;
				}
			}

			double avg_this = (double) x / WS2;
			double avg_other = (double) y / WS2;
			double var_this = (double) (xx - x*x) / WS2;
			double var_other = (double) (yy - y*y) / WS2;
			double covar = (double) (xy - x*y) / WS2;

			ssim += (2 * avg_this * avg_other + coef_1) * (2 * covar + coef_2) / (avg_this * avg_this + avg_other * avg_other + coef_1) / (var_this + var_other + coef_2);
		}
	}

	return ssim / w_height / w_width;
}

uint32_t Bitmap::CRC32(bool include_chroma) {
	uint32_t crc = crc32(0, Z_NULL, 0);

	crc = crc32(crc, picture.data[0], picture.linesize[0] * height);

	if( include_chroma ) {
		crc = crc32(crc, picture.data[1], width * height / 4);
		crc = crc32(crc, picture.data[2], width * height / 4);
	}

	return crc;
}
<commit_msg>Check for the pixel format.<commit_after>#include "Bitmap.hpp"

#include <zlib.h>

Bitmap::Bitmap(AVFrame *frame) {
	pix_fmt = static_cast<PixelFormat>(frame->format);
	if( pix_fmt != PIX_FMT_YUV420P ) {
		throw "Formats other than YUV 4:2:0 are not supported";
	}
	width = frame->width;
	height = frame->height;

	avpicture_alloc(&picture, pix_fmt, frame->width, frame->height);
	av_image_copy(picture.data, picture.linesize, const_cast<const uint8_t**>(frame->data), frame->linesize, pix_fmt, width, height);
}

Bitmap::~Bitmap() {
	avpicture_free(&picture);
}

#define WS 8
#define WS2 64

double Bitmap::SSIM(Bitmap &other) {
	// FIXME: this should be resized
	if( width != other.width || height != other.height ) {
		throw "The bitmaps currently have to be of the same size";
	}

	double coef_1 = 6.5025;   // (0.01 * 255)^2
	double coef_2 = 58.5225;  // (0.03 * 255)^2

	int w_width = width / WS;
	int w_height = height / WS;

	int linesize = picture.linesize[0];
	uint8_t *data_this = picture.data[0];
	uint8_t *data_other = other.picture.data[0];

	double ssim = 0;
	for( int w_i = 0; w_i < w_height; w_i++ ) {
		for( int w_j = 0; w_j < w_width; w_j++ ) {
			int w_offset = linesize * w_i * WS + w_j * WS;
			int x = 0, xx = 0, y = 0, yy = 0, xy = 0;
			for( int i = 0; i < WS; i++ ) {
				int l_offset = w_offset + linesize*i;
				for( int j = 0; j < WS; j++ ) {
					int cur_this  = data_this [l_offset + j];
					int cur_other = data_other[l_offset + j];
					x += cur_this;
					xx += cur_this * cur_this;
					y += cur_other;
					yy += cur_other * cur_other;
					xy += cur_this * cur_other;
				}
			}

			double avg_this = (double) x / WS2;
			double avg_other = (double) y / WS2;
			double var_this = (double) (xx - x*x) / WS2;
			double var_other = (double) (yy - y*y) / WS2;
			double covar = (double) (xy - x*y) / WS2;

			ssim += (2 * avg_this * avg_other + coef_1) * (2 * covar + coef_2) / (avg_this * avg_this + avg_other * avg_other + coef_1) / (var_this + var_other + coef_2);
		}
	}

	return ssim / w_height / w_width;
}

uint32_t Bitmap::CRC32(bool include_chroma) {
	uint32_t crc = crc32(0, Z_NULL, 0);

	crc = crc32(crc, picture.data[0], picture.linesize[0] * height);

	if( include_chroma ) {
		crc = crc32(crc, picture.data[1], width * height / 4);
		crc = crc32(crc, picture.data[2], width * height / 4);
	}

	return crc;
}
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.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 St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id: wkb.cpp 19 2005-03-22 13:53:27Z pavlenko $

#include <mapnik/global.hpp>
#include <mapnik/wkb.hpp>
#include <mapnik/geom_util.hpp>
#include <mapnik/feature.hpp>

// boost
#include <boost/utility.hpp>
#include <boost/detail/endian.hpp>

namespace mapnik
{
    struct wkb_reader : boost::noncopyable
    {
    private:
        enum wkbByteOrder {
            wkbXDR=0,
            wkbNDR=1
        };
        const char* wkb_;
        unsigned size_;
        unsigned pos_;
        wkbByteOrder byteOrder_;
        bool needSwap_;
        wkbFormat format_;

    public:

        enum wkbGeometryType {
            wkbPoint=1,
            wkbLineString=2,
            wkbPolygon=3,
            wkbMultiPoint=4,
            wkbMultiLineString=5,
            wkbMultiPolygon=6,
            wkbGeometryCollection=7
        };

        wkb_reader(const char* wkb,unsigned size,wkbFormat format)
            : wkb_(wkb),
              size_(size),
              pos_(0),
              format_(format)
        {
            switch (format_)
            {
            case wkbSpatiaLite:
                byteOrder_ = (wkbByteOrder) wkb_[1];
                pos_ = 39;
                break;

            case wkbGeneric:
            default:
                byteOrder_ = (wkbByteOrder) wkb_[0];
                pos_ = 1;
                break;
            }

#ifndef BOOST_BIG_ENDIAN
            needSwap_=byteOrder_?wkbXDR:wkbNDR;
#else
            needSwap_=byteOrder_?wkbNDR:wkbXDR;
#endif
        }

        ~wkb_reader() {}

        void read_multi(Feature & feature)
        {
            int type=read_integer();
            switch (type)
            {
            case wkbPoint:
                read_point(feature);
                break;
            case wkbLineString:
                read_linestring(feature);
                break;
            case wkbPolygon:
                read_polygon(feature);
                break;
            case wkbMultiPoint:
                read_multipoint(feature);
                break;
            case wkbMultiLineString:
                read_multilinestring(feature);
                break;
            case wkbMultiPolygon:
                read_multipolygon(feature);
                break;
            case wkbGeometryCollection:
                break;
            default:
                break;
            }
        }

        void read(Feature & feature)
        {
            int type=read_integer();
            switch (type)
            {
            case wkbPoint:
                read_point(feature);
                break;
            case wkbLineString:
                read_linestring(feature);
                break;
            case wkbPolygon:
                read_polygon(feature);
                break;
            case wkbMultiPoint:
                read_multipoint_2(feature);
                break;
            case wkbMultiLineString:
                read_multilinestring_2(feature);
                break;
            case wkbMultiPolygon:
                read_multipolygon_2(feature);
                break;
            case wkbGeometryCollection:
                break;
            default:
                break;
            }
        }

    private:

        int read_integer()
        {
            int n;
            if (needSwap_)
            {
                read_int_xdr(wkb_+pos_,n);
            }
            else
            {
                read_int_ndr(wkb_+pos_,n);
            }
            pos_+=4;

            return n;
        }

        double read_double()
        {
            double d;
            if (needSwap_)
            {
                read_double_xdr(wkb_ + pos_, d);
            }
            else
            {
                read_double_ndr(wkb_ + pos_, d);
            }
            pos_+=8;

            return d;
        }

        void read_coords(CoordinateArray& ar)
        {
            int size=sizeof(coord<double,2>)*ar.size();
            if (!needSwap_)
            {
                std::memcpy(&ar[0],wkb_+pos_,size);
                pos_+=size;
            }
            else
            {
                for (unsigned i=0;i<ar.size();++i)
                {
                    read_double_ndr(wkb_ + pos_,ar[i].x);
                    read_double_ndr(wkb_ + pos_ + 8,ar[i].y);
                    pos_ += 16;
                }
            }

        }

        void read_point(Feature & feature)
        {
            geometry2d * pt = new point<vertex2d>;
            double x = read_double();
            double y = read_double();
            pt->move_to(x,y);
            feature.add_geometry(pt);
        }

        void read_multipoint(Feature & feature)
        {
            int num_points = read_integer();
            for (int i=0;i<num_points;++i)
            {
                pos_+=5;
                read_point(feature);
            }
        }

        void read_multipoint_2(Feature & feature)
        {
            geometry2d * pt = new point<vertex2d>;
            int num_points = read_integer();
            for (int i=0;i<num_points;++i)
            {
                pos_+=5;
                double x = read_double();
                double y = read_double();
                pt->move_to(x,y);
            }
            feature.add_geometry(pt);
        }

        void read_linestring(Feature & feature)
        {
            geometry2d * line = new line_string<vertex2d>;
            int num_points=read_integer();
            CoordinateArray ar(num_points);
            read_coords(ar);
            line->set_capacity(num_points);
            line->move_to(ar[0].x,ar[0].y);
            for (int i=1;i<num_points;++i)
            {
                line->line_to(ar[i].x,ar[i].y);
            }
            feature.add_geometry(line);
        }

        void read_multilinestring(Feature & feature)
        {
            int num_lines=read_integer();
            for (int i=0;i<num_lines;++i)
            {
                pos_+=5;
                read_linestring(feature);
            }
        }

        void read_multilinestring_2(Feature & feature)
        {
            geometry2d * line = new line_string<vertex2d>;
            int num_lines=read_integer();
            unsigned capacity = 0;
            for (int i=0;i<num_lines;++i)
            {
                pos_+=5;
                int num_points=read_integer();
                capacity+=num_points;
                CoordinateArray ar(num_points);
                read_coords(ar);
                line->set_capacity(capacity);
                line->move_to(ar[0].x,ar[0].y);
                for (int i=1;i<num_points;++i)
                {
                    line->line_to(ar[i].x,ar[i].y);
                }
            }
            feature.add_geometry(line);
        }

        void read_polygon(Feature & feature)
        {
            geometry2d * poly = new polygon<vertex2d>;
            int num_rings=read_integer();
            unsigned capacity = 0;
            for (int i=0;i<num_rings;++i)
            {
                int num_points=read_integer();
                capacity+=num_points;
                CoordinateArray ar(num_points);
                read_coords(ar);
                poly->set_capacity(capacity);
                poly->move_to(ar[0].x,ar[0].y);
                for (int j=1;j<num_points;++j)
                {
                    poly->line_to(ar[j].x,ar[j].y);
                }
            }
            feature.add_geometry(poly);
        }

        void read_multipolygon(Feature & feature)
        {
            int num_polys=read_integer();
            for (int i=0;i<num_polys;++i)
            {
                pos_+=5;
                read_polygon(feature);
            }
        }

        void read_multipolygon_2(Feature & feature)
        {
            geometry2d * poly = new polygon<vertex2d>;
            int num_polys=read_integer();
            unsigned capacity = 0;
            for (int i=0;i<num_polys;++i)
            {
                pos_+=5;
                int num_rings=read_integer();
                for (int i=0;i<num_rings;++i)
                {
                    int num_points=read_integer();
                    capacity += num_points;
                    CoordinateArray ar(num_points);
                    read_coords(ar);
                    poly->set_capacity(capacity);
                    poly->move_to(ar[0].x,ar[0].y);

                    for (int j=1;j<num_points;++j)
                    {
                        poly->line_to(ar[j].x,ar[j].y);
                    }
                    poly->line_to(ar[0].x,ar[0].y);
                }
            }
            feature.add_geometry(poly);
        }
    };

    void geometry_utils::from_wkb (Feature & feature,
                                   const char* wkb,
                                   unsigned size,
                                   bool multiple_geometries,
                                   wkbFormat format)
    {
        wkb_reader reader(wkb,size,format);
        if (multiple_geometries)
            return reader.read_multi(feature);
        else
            return reader.read(feature);
    }
}
<commit_msg>+ fixed read_coord method<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.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 St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id: wkb.cpp 19 2005-03-22 13:53:27Z pavlenko $

#include <mapnik/global.hpp>
#include <mapnik/wkb.hpp>
#include <mapnik/geom_util.hpp>
#include <mapnik/feature.hpp>

// boost
#include <boost/utility.hpp>
#include <boost/detail/endian.hpp>

namespace mapnik
{
    struct wkb_reader : boost::noncopyable
    {
    private:
        enum wkbByteOrder {
            wkbXDR=0,
            wkbNDR=1
        };
        const char* wkb_;
        unsigned size_;
        unsigned pos_;
        wkbByteOrder byteOrder_;
        bool needSwap_;
        wkbFormat format_;

    public:

        enum wkbGeometryType {
            wkbPoint=1,
            wkbLineString=2,
            wkbPolygon=3,
            wkbMultiPoint=4,
            wkbMultiLineString=5,
            wkbMultiPolygon=6,
            wkbGeometryCollection=7
        };

        wkb_reader(const char* wkb,unsigned size,wkbFormat format)
            : wkb_(wkb),
              size_(size),
              pos_(0),
              format_(format)
        {
            switch (format_)
            {
            case wkbSpatiaLite:
                byteOrder_ = (wkbByteOrder) wkb_[1];
                pos_ = 39;
                break;

            case wkbGeneric:
            default:
                byteOrder_ = (wkbByteOrder) wkb_[0];
                pos_ = 1;
                break;
            }

#ifndef BOOST_BIG_ENDIAN
            needSwap_=byteOrder_?wkbXDR:wkbNDR;
#else
            needSwap_=byteOrder_?wkbNDR:wkbXDR;
#endif
        }

        ~wkb_reader() {}

        void read_multi(Feature & feature)
        {
            int type=read_integer();
            switch (type)
            {
            case wkbPoint:
                read_point(feature);
                break;
            case wkbLineString:
                read_linestring(feature);
                break;
            case wkbPolygon:
                read_polygon(feature);
                break;
            case wkbMultiPoint:
                read_multipoint(feature);
                break;
            case wkbMultiLineString:
                read_multilinestring(feature);
                break;
            case wkbMultiPolygon:
                read_multipolygon(feature);
                break;
            case wkbGeometryCollection:
                break;
            default:
                break;
            }
        }

        void read(Feature & feature)
        {
            int type=read_integer();
            switch (type)
            {
            case wkbPoint:
                read_point(feature);
                break;
            case wkbLineString:
                read_linestring(feature);
                break;
            case wkbPolygon:
                read_polygon(feature);
                break;
            case wkbMultiPoint:
                read_multipoint_2(feature);
                break;
            case wkbMultiLineString:
                read_multilinestring_2(feature);
                break;
            case wkbMultiPolygon:
                read_multipolygon_2(feature);
                break;
            case wkbGeometryCollection:
                break;
            default:
                break;
            }
        }

    private:

        int read_integer()
        {
            int n;
            if (needSwap_)
            {
                read_int_xdr(wkb_+pos_,n);
            }
            else
            {
                read_int_ndr(wkb_+pos_,n);
            }
            pos_+=4;

            return n;
        }

        double read_double()
        {
            double d;
            if (needSwap_)
            {
                read_double_xdr(wkb_ + pos_, d);
            }
            else
            {
                read_double_ndr(wkb_ + pos_, d);
            }
            pos_+=8;

            return d;
        }

        void read_coords(CoordinateArray& ar)
        {
            int size=sizeof(coord<double,2>)*ar.size();
            if (!needSwap_)
            {
                std::memcpy(&ar[0],wkb_+pos_,size);
                pos_+=size;
            }
            else
            {
                for (unsigned i=0;i<ar.size();++i)
                {
                    read_double_xdr(wkb_ + pos_,ar[i].x);
                    read_double_xdr(wkb_ + pos_ + 8,ar[i].y);
                    pos_ += 16;
                }
            }

        }

        void read_point(Feature & feature)
        {
            geometry2d * pt = new point<vertex2d>;
            double x = read_double();
            double y = read_double();
            pt->move_to(x,y);
            feature.add_geometry(pt);
        }

        void read_multipoint(Feature & feature)
        {
            int num_points = read_integer();
            for (int i=0;i<num_points;++i)
            {
                pos_+=5;
                read_point(feature);
            }
        }

        void read_multipoint_2(Feature & feature)
        {
            geometry2d * pt = new point<vertex2d>;
            int num_points = read_integer();
            for (int i=0;i<num_points;++i)
            {
                pos_+=5;
                double x = read_double();
                double y = read_double();
                pt->move_to(x,y);
            }
            feature.add_geometry(pt);
        }

        void read_linestring(Feature & feature)
        {
            geometry2d * line = new line_string<vertex2d>;
            int num_points=read_integer();
            CoordinateArray ar(num_points);
            read_coords(ar);
            line->set_capacity(num_points);
            line->move_to(ar[0].x,ar[0].y);
            for (int i=1;i<num_points;++i)
            {
                line->line_to(ar[i].x,ar[i].y);
            }
            feature.add_geometry(line);
        }

        void read_multilinestring(Feature & feature)
        {
            int num_lines=read_integer();
            for (int i=0;i<num_lines;++i)
            {
                pos_+=5;
                read_linestring(feature);
            }
        }

        void read_multilinestring_2(Feature & feature)
        {
            geometry2d * line = new line_string<vertex2d>;
            int num_lines=read_integer();
            unsigned capacity = 0;
            for (int i=0;i<num_lines;++i)
            {
                pos_+=5;
                int num_points=read_integer();
                capacity+=num_points;
                CoordinateArray ar(num_points);
                read_coords(ar);
                line->set_capacity(capacity);
                line->move_to(ar[0].x,ar[0].y);
                for (int i=1;i<num_points;++i)
                {
                    line->line_to(ar[i].x,ar[i].y);
                }
            }
            feature.add_geometry(line);
        }

        void read_polygon(Feature & feature)
        {
            geometry2d * poly = new polygon<vertex2d>;
            int num_rings=read_integer();
            unsigned capacity = 0;
            for (int i=0;i<num_rings;++i)
            {
                int num_points=read_integer();
                capacity+=num_points;
                CoordinateArray ar(num_points);
                read_coords(ar);
                poly->set_capacity(capacity);
                poly->move_to(ar[0].x,ar[0].y);
                for (int j=1;j<num_points;++j)
                {
                    poly->line_to(ar[j].x,ar[j].y);
                }
            }
            feature.add_geometry(poly);
        }

        void read_multipolygon(Feature & feature)
        {
            int num_polys=read_integer();
            for (int i=0;i<num_polys;++i)
            {
                pos_+=5;
                read_polygon(feature);
            }
        }

        void read_multipolygon_2(Feature & feature)
        {
            geometry2d * poly = new polygon<vertex2d>;
            int num_polys=read_integer();
            unsigned capacity = 0;
            for (int i=0;i<num_polys;++i)
            {
                pos_+=5;
                int num_rings=read_integer();
                for (int i=0;i<num_rings;++i)
                {
                    int num_points=read_integer();
                    capacity += num_points;
                    CoordinateArray ar(num_points);
                    read_coords(ar);
                    poly->set_capacity(capacity);
                    poly->move_to(ar[0].x,ar[0].y);

                    for (int j=1;j<num_points;++j)
                    {
                        poly->line_to(ar[j].x,ar[j].y);
                    }
                    poly->line_to(ar[0].x,ar[0].y);
                }
            }
            feature.add_geometry(poly);
        }
    };

    void geometry_utils::from_wkb (Feature & feature,
                                   const char* wkb,
                                   unsigned size,
                                   bool multiple_geometries,
                                   wkbFormat format)
    {
        wkb_reader reader(wkb,size,format);
        if (multiple_geometries)
            return reader.read_multi(feature);
        else
            return reader.read(feature);
    }
}
<|endoftext|>


<commit_before>#include <boost/test/unit_test.hpp>

#include "../src/n_vector.hpp"

#include "test_utils.hpp"

template <position_t DIMENSIONS,typename T>
void test_vector_coordinates_equal(Vector<DIMENSIONS,T> const &values,Vector<DIMENSIONS,T> const &expected)
{
    std::string number;
    for(position_t i = 0; i < values.dimensions(); ++i)
    {
        number = std::to_string(i);

        BOOST_CHECK_CLOSE( values.get_coordinate(i), expected.get_coordinate(i), 0.00001 );
    }
}

BOOST_AUTO_TEST_SUITE( VECTOR_TEST_SUITE )

    BOOST_AUTO_TEST_CASE( unidimensional_vector_size_test )
    {
        Vector<1> vec;

        test_uint_value(   vec.dimensions(),
                            1,
                            "vec.dimensions()");
    }

    BOOST_AUTO_TEST_CASE( bidimensional_vector_size_test )
    {
        Vector<2> vec;

        test_uint_value(   vec.dimensions(),
                            2,
                            "vec.dimensions()");
    }

    BOOST_AUTO_TEST_CASE( multidimensional_vector_size_test )
    {
        Vector<37> vec;

        test_uint_value(   vec.dimensions(),
                            37,
                            "vec.dimensions()");
    }

    BOOST_AUTO_TEST_CASE( set_coordinate_test )
    {
        Vector<2> vec;

        vec.set_coordinate(0,1.0);

        BOOST_CHECK_CLOSE( vec.get_coordinate(0), 1.0, 0.00001 );

        vec.set_coordinate(0,5.5);

        BOOST_CHECK_CLOSE( vec.get_coordinate(0), 5.5, 0.00001 );

        vec.set_coordinate(1,3.3);

        BOOST_CHECK_CLOSE( vec.get_coordinate(1), 3.3, 0.00001 );

        vec.set_coordinate(1,9.2);

        BOOST_CHECK_CLOSE( vec.get_coordinate(1), 9.2, 0.00001 );
    }

    BOOST_AUTO_TEST_CASE( get_coordinate_throws_out_of_range_exception_test )
    {
        Vector<2> vec;

        BOOST_REQUIRE_THROW(vec.get_coordinate(300), std::out_of_range);
    }

    BOOST_AUTO_TEST_CASE( set_coordinate_throws_out_of_range_exception_test )
    {
        Vector<2> vec;

        BOOST_REQUIRE_THROW(vec.set_coordinate(300,0), std::out_of_range);
    }

    BOOST_AUTO_TEST_CASE( calculate_vector_distance_test )
    {
        Vector<2> vec1;
        Vector<2> vec2;

        vec1.set_coordinate(0,0);
        vec1.set_coordinate(1,0);

        vec2.set_coordinate(0,3);
        vec2.set_coordinate(1,4);

        BOOST_CHECK_CLOSE( vec1.distance_to(vec2), 5.0, 0.00001 );
    }

    BOOST_AUTO_TEST_CASE( calculate_dot_product_test )
    {
        Vector<2> vec1;
        Vector<2> vec2;

        vec1.set_coordinate(0,0);
        vec1.set_coordinate(1,1);

        vec2.set_coordinate(0,3);
        vec2.set_coordinate(1,4);

        BOOST_CHECK_CLOSE( vec1.dot(vec2), 4.0, 0.00001 );

        vec2.set_coordinate(1,7);
        BOOST_CHECK_CLOSE( vec1.dot(vec2), 7.0, 0.00001 );
    }

    BOOST_AUTO_TEST_CASE( vector_multiplication_should_return_dot_product_test )
    {
        Vector<2> vec1;
        Vector<2> vec2;

        vec1.set_coordinate(0,0);
        vec1.set_coordinate(1,1);

        vec2.set_coordinate(0,4);
        vec2.set_coordinate(1,5);

        BOOST_CHECK_CLOSE( vec1 * vec2, 5.0, 0.00001 );

        vec2.set_coordinate(1,14);

        BOOST_CHECK_CLOSE( vec1 * vec2, 14.0, 0.00001 );
    }

    BOOST_AUTO_TEST_CASE( assignment_operator_test )
    {
        Vector<2> vec1;
        Vector<2> vec2;

        vec1.set_coordinate(0,0);
        vec1.set_coordinate(1,1);

        vec2.set_coordinate(0,23);
        vec2.set_coordinate(1,89);

        vec2 = vec1;

        test_vector_coordinates_equal(vec2,vec1);
    }

    BOOST_AUTO_TEST_CASE( calculate_bidimensional_cross_product_test )
    {
        Vector<2> vec1;
        Vector<2> vec2;

        vec1.set_coordinate(0,1);
        vec1.set_coordinate(1,1);

        vec2.set_coordinate(0,4);
        vec2.set_coordinate(1,5);

        scalar_t product = vec1.cross(vec2);

        BOOST_CHECK_CLOSE( product, 1, 0.00001 );

        vec2.set_coordinate(0,3);
        vec2.set_coordinate(1,17);

        product = vec1.cross(vec2);

        BOOST_CHECK_CLOSE( product, 14, 0.00001 );
    }

    BOOST_AUTO_TEST_CASE( initializer_list_set_test )
    {
        Vector<2> vec1;
        Vector<2> expected1;

        vec1.set({2,6});

        expected1.set_coordinate(0,2);
        expected1.set_coordinate(1,6);

        test_vector_coordinates_equal(vec1,expected1);

        Vector<3> vec2;
        Vector<3> expected2;

        vec2.set({11,35,27});

        expected2.set_coordinate(0,11);
        expected2.set_coordinate(1,35);
        expected2.set_coordinate(2,27);

        test_vector_coordinates_equal(vec2,expected2);
    }

    BOOST_AUTO_TEST_CASE( initializer_list_set_should_ignore_excess_values_test )
    {
        Vector<2> vec1;
        Vector<2> expected1;

        vec1.set({2,6,8,15,23,30});

        expected1.set_coordinate(0,2);
        expected1.set_coordinate(1,6);

        test_vector_coordinates_equal(vec1,expected1);

        Vector<3> vec2;
        Vector<3> expected2;

        vec2.set({11,35,27,21,33,675,1292,4545,1221,111,1});

        expected2.set_coordinate(0,11);
        expected2.set_coordinate(1,35);
        expected2.set_coordinate(2,27);

        test_vector_coordinates_equal(vec2,expected2);
    }

    BOOST_AUTO_TEST_CASE( initializer_list_constructor_test )
    {
        Vector<2> vec1({2,6});
        Vector<2> expected1;

        expected1.set_coordinate(0,2);
        expected1.set_coordinate(1,6);

        test_vector_coordinates_equal(vec1,expected1);

        Vector<3> vec2({11,35,27});
        Vector<3> expected2;

        expected2.set_coordinate(0,11);
        expected2.set_coordinate(1,35);
        expected2.set_coordinate(2,27);

        test_vector_coordinates_equal(vec2,expected2);
    }

    BOOST_AUTO_TEST_CASE( empty_constructor_should_fill_with_zero_test )
    {
        Vector<3> vec1;

        const Vector<3> expected({0,0,0});

        test_vector_coordinates_equal(vec1,expected);
    }

    BOOST_AUTO_TEST_CASE( calculate_threedimensional_cross_product_test )
    {
        Vector<3> vec1({0,1,1});
        Vector<3> vec2({1,-1,3});

        Vector<3> product1 = vec1.cross(vec2);

        const Vector<3> expected1({4,1,-1});

        test_vector_coordinates_equal(product1,expected1);

        Vector<3> vec3({3,-3,1});
        Vector<3> vec4({4,9,2});

        Vector<3> product2 = vec3.cross(vec4);

        const Vector<3> expected2({-15,-2,39});

        test_vector_coordinates_equal(product2,expected2);
    }

BOOST_AUTO_TEST_SUITE_END()
/* src/Vector test suite end */<commit_msg>Changing test suite name<commit_after>#include <boost/test/unit_test.hpp>

#include "../src/n_vector.hpp"

#include "test_utils.hpp"

template <position_t DIMENSIONS,typename T>
void test_vector_coordinates_equal(Vector<DIMENSIONS,T> const &values,Vector<DIMENSIONS,T> const &expected)
{
    std::string number;
    for(position_t i = 0; i < values.dimensions(); ++i)
    {
        number = std::to_string(i);

        BOOST_CHECK_CLOSE( values.get_coordinate(i), expected.get_coordinate(i), 0.00001 );
    }
}

BOOST_AUTO_TEST_SUITE( VECTOR_CLASS_TEST_SUITE )

    BOOST_AUTO_TEST_CASE( unidimensional_vector_size_test )
    {
        Vector<1> vec;

        test_uint_value(   vec.dimensions(),
                            1,
                            "vec.dimensions()");
    }

    BOOST_AUTO_TEST_CASE( bidimensional_vector_size_test )
    {
        Vector<2> vec;

        test_uint_value(   vec.dimensions(),
                            2,
                            "vec.dimensions()");
    }

    BOOST_AUTO_TEST_CASE( multidimensional_vector_size_test )
    {
        Vector<37> vec;

        test_uint_value(   vec.dimensions(),
                            37,
                            "vec.dimensions()");
    }

    BOOST_AUTO_TEST_CASE( set_coordinate_test )
    {
        Vector<2> vec;

        vec.set_coordinate(0,1.0);

        BOOST_CHECK_CLOSE( vec.get_coordinate(0), 1.0, 0.00001 );

        vec.set_coordinate(0,5.5);

        BOOST_CHECK_CLOSE( vec.get_coordinate(0), 5.5, 0.00001 );

        vec.set_coordinate(1,3.3);

        BOOST_CHECK_CLOSE( vec.get_coordinate(1), 3.3, 0.00001 );

        vec.set_coordinate(1,9.2);

        BOOST_CHECK_CLOSE( vec.get_coordinate(1), 9.2, 0.00001 );
    }

    BOOST_AUTO_TEST_CASE( get_coordinate_throws_out_of_range_exception_test )
    {
        Vector<2> vec;

        BOOST_REQUIRE_THROW(vec.get_coordinate(300), std::out_of_range);
    }

    BOOST_AUTO_TEST_CASE( set_coordinate_throws_out_of_range_exception_test )
    {
        Vector<2> vec;

        BOOST_REQUIRE_THROW(vec.set_coordinate(300,0), std::out_of_range);
    }

    BOOST_AUTO_TEST_CASE( calculate_vector_distance_test )
    {
        Vector<2> vec1;
        Vector<2> vec2;

        vec1.set_coordinate(0,0);
        vec1.set_coordinate(1,0);

        vec2.set_coordinate(0,3);
        vec2.set_coordinate(1,4);

        BOOST_CHECK_CLOSE( vec1.distance_to(vec2), 5.0, 0.00001 );
    }

    BOOST_AUTO_TEST_CASE( calculate_dot_product_test )
    {
        Vector<2> vec1;
        Vector<2> vec2;

        vec1.set_coordinate(0,0);
        vec1.set_coordinate(1,1);

        vec2.set_coordinate(0,3);
        vec2.set_coordinate(1,4);

        BOOST_CHECK_CLOSE( vec1.dot(vec2), 4.0, 0.00001 );

        vec2.set_coordinate(1,7);
        BOOST_CHECK_CLOSE( vec1.dot(vec2), 7.0, 0.00001 );
    }

    BOOST_AUTO_TEST_CASE( vector_multiplication_should_return_dot_product_test )
    {
        Vector<2> vec1;
        Vector<2> vec2;

        vec1.set_coordinate(0,0);
        vec1.set_coordinate(1,1);

        vec2.set_coordinate(0,4);
        vec2.set_coordinate(1,5);

        BOOST_CHECK_CLOSE( vec1 * vec2, 5.0, 0.00001 );

        vec2.set_coordinate(1,14);

        BOOST_CHECK_CLOSE( vec1 * vec2, 14.0, 0.00001 );
    }

    BOOST_AUTO_TEST_CASE( assignment_operator_test )
    {
        Vector<2> vec1;
        Vector<2> vec2;

        vec1.set_coordinate(0,0);
        vec1.set_coordinate(1,1);

        vec2.set_coordinate(0,23);
        vec2.set_coordinate(1,89);

        vec2 = vec1;

        test_vector_coordinates_equal(vec2,vec1);
    }

    BOOST_AUTO_TEST_CASE( calculate_bidimensional_cross_product_test )
    {
        Vector<2> vec1;
        Vector<2> vec2;

        vec1.set_coordinate(0,1);
        vec1.set_coordinate(1,1);

        vec2.set_coordinate(0,4);
        vec2.set_coordinate(1,5);

        scalar_t product = vec1.cross(vec2);

        BOOST_CHECK_CLOSE( product, 1, 0.00001 );

        vec2.set_coordinate(0,3);
        vec2.set_coordinate(1,17);

        product = vec1.cross(vec2);

        BOOST_CHECK_CLOSE( product, 14, 0.00001 );
    }

    BOOST_AUTO_TEST_CASE( initializer_list_set_test )
    {
        Vector<2> vec1;
        Vector<2> expected1;

        vec1.set({2,6});

        expected1.set_coordinate(0,2);
        expected1.set_coordinate(1,6);

        test_vector_coordinates_equal(vec1,expected1);

        Vector<3> vec2;
        Vector<3> expected2;

        vec2.set({11,35,27});

        expected2.set_coordinate(0,11);
        expected2.set_coordinate(1,35);
        expected2.set_coordinate(2,27);

        test_vector_coordinates_equal(vec2,expected2);
    }

    BOOST_AUTO_TEST_CASE( initializer_list_set_should_ignore_excess_values_test )
    {
        Vector<2> vec1;
        Vector<2> expected1;

        vec1.set({2,6,8,15,23,30});

        expected1.set_coordinate(0,2);
        expected1.set_coordinate(1,6);

        test_vector_coordinates_equal(vec1,expected1);

        Vector<3> vec2;
        Vector<3> expected2;

        vec2.set({11,35,27,21,33,675,1292,4545,1221,111,1});

        expected2.set_coordinate(0,11);
        expected2.set_coordinate(1,35);
        expected2.set_coordinate(2,27);

        test_vector_coordinates_equal(vec2,expected2);
    }

    BOOST_AUTO_TEST_CASE( initializer_list_constructor_test )
    {
        Vector<2> vec1({2,6});
        Vector<2> expected1;

        expected1.set_coordinate(0,2);
        expected1.set_coordinate(1,6);

        test_vector_coordinates_equal(vec1,expected1);

        Vector<3> vec2({11,35,27});
        Vector<3> expected2;

        expected2.set_coordinate(0,11);
        expected2.set_coordinate(1,35);
        expected2.set_coordinate(2,27);

        test_vector_coordinates_equal(vec2,expected2);
    }

    BOOST_AUTO_TEST_CASE( empty_constructor_should_fill_with_zero_test )
    {
        Vector<3> vec1;

        const Vector<3> expected({0,0,0});

        test_vector_coordinates_equal(vec1,expected);
    }

    BOOST_AUTO_TEST_CASE( calculate_threedimensional_cross_product_test )
    {
        Vector<3> vec1({0,1,1});
        Vector<3> vec2({1,-1,3});

        Vector<3> product1 = vec1.cross(vec2);

        const Vector<3> expected1({4,1,-1});

        test_vector_coordinates_equal(product1,expected1);

        Vector<3> vec3({3,-3,1});
        Vector<3> vec4({4,9,2});

        Vector<3> product2 = vec3.cross(vec4);

        const Vector<3> expected2({-15,-2,39});

        test_vector_coordinates_equal(product2,expected2);
    }

BOOST_AUTO_TEST_SUITE_END()
/* src/Vector test suite end */<|endoftext|>


<commit_before>#include "Client.h"

#include <iostream>

#include "Logger.h"
#include "Common.h"
#include "../gen/ConnectionMessage.pb.h"
#include "PCLUtil.h"

int Client::leader_id = -1;

Client::Client(int id, int tcp_socket)
	: _tcp_con(tcp_socket)
	, _sensor_data()
	, _data_available(0)
	, _running(1)
	, _data_mutex()
	, _client_thread(&Client::_threadHandle, this)
	, _use_point_cloud(false)
	, _video_height(0)
	, _video_width(0)
	, _depth_height(0)
	, _depth_width(0)
	, _message_size(0)
	, _recv_buf(0)
	, _id(id) {}

Client::~Client(){
	_running = 0;
	_tcp_con.closeConnection();
	_client_thread.join();
}

void Client::setInfo(struct sockaddr_in* info){
	_tcp_con.setInfo(info);
}

int Client::getVideo(char** video, int size){
	if (!_data_available){
		return -1;
	}

	_data_mutex.lock();

	int size_new = _sensor_data.fvideo_data().capacity();

	if (size < size_new && size > 0){
		free(*video);
	}

	if (*video == NULL){
		*video = (char*) malloc(size_new);
	}

	memcpy(*video, _sensor_data.fvideo_data().c_str(), size_new);

	_data_mutex.unlock();

	return size_new;
}

int Client::getDepth(char** depth, int size){
	if (_use_point_cloud){
		return -2;
	}

	if (!_data_available){
		return -1;
	}

	_data_mutex.lock();

	int size_new = _sensor_data.fdepth_data().capacity();

	if (size < size_new && size > 0){
		free(*depth);
	}

	if (*depth == NULL){
		*depth = (char*) malloc(size_new);
	}

	memcpy(*depth, _sensor_data.fdepth_data().c_str(), size_new);

	_data_mutex.unlock();

	return size_new;
}

int Client::getCloud(float** cloud, int size){
	if (!_use_point_cloud){
		return -1;
	}

	if (!_data_available){
		return -2;
	}

	_data_mutex.lock();

#ifdef PROCESS_CLOUD_DISTRIBUTED
	int size_new = _sensor_data.cloud_size();
#else
	int size_new = _sensor_data.fdepth_data().capacity() * 3;
#endif

	if (size != size_new && size > 0){
		free(*cloud);
	}

	if (*cloud == NULL && size_new > 0){
		*cloud = (float*) malloc(size_new * sizeof(float));
	}

#ifdef PROCESS_CLOUD_DISTRIBUTED
	for (int i = 0; i < size_new; i++){
		(*cloud)[i] = _sensor_data.cloud(i);
	}
#else
	PCLUtil::convertToXYZPointCloud(*cloud, (uint16_t*) _sensor_data.fdepth_data().c_str(), _depth_height, _depth_width);
#endif

	_data_mutex.unlock();

	return size_new;
}

/*int Client::getData(char** video, char** depth, float** cloud){
	if (!_data_available){
		return -1;
	}

	_data_mutex.lock();

	int size = _sensor_data.fvideo_data().capacity();
	if (*video == NULL){
		*video = (char*) malloc(size);
	}
	memcpy(*video, _sensor_data.fvideo_data().c_str(), size);

	if (!_use_point_cloud && _sensor_data.fdepth_data() != ""){
		size = _sensor_data.fdepth_data().capacity();
		if (*depth == NULL){
			*depth = (char*) malloc(size);
		}
		memcpy(*depth, _sensor_data.fdepth_data().c_str(), size);
	} else if (_use_point_cloud){
		if (*cloud == NULL){
			cout << "DEBUG malloc pointer with cloud size = " << _sensor_data.cloud_size() << endl;
			*cloud = (float*) malloc(_sensor_data.cloud_size() * sizeof(float));
		}
		cout << "DEBUG enter data with cloud size = " << _sensor_data.cloud_size() << endl;
		for (int i = 0; i < _sensor_data.cloud_size(); i++){
			(*cloud)[i] = _sensor_data.cloud(i);
		}
	} else {
		_data_mutex.unlock();
		return -1;
	}

	_data_available = 0;

	_data_mutex.unlock();

	return 0;
}*/

void Client::_handleFrameMessage(){
	_tcp_con.recvData((void *) _recv_buf, _message_size);

	_data_mutex.lock();
	_sensor_data.ParseFromArray(_recv_buf, _message_size);

	if (_sensor_data.fvideo_data() == "" || _sensor_data.timestamp() == 0){
		LOG_ERROR << "message does not contain at least one required field"
			<< endl;
	} else {
		_data_available = 1;
	}

	_data_mutex.unlock();
}

void Client::_recvConnectionMessage(){
	ConnectionMessage m;
	uint32_t size = 0;
	uint32_t size_nw = 0;

	_tcp_con.recvData((void*) &size_nw, 4);

	size = ntohl(size_nw);
	char* buf[size] = {0};
	_tcp_con.recvData((void*) buf, size);

	m.ParseFromArray(buf, size);

	_use_point_cloud = m.use_point_cloud();
	_video_height = m.video_height();
	_video_width = m.video_width();
	_depth_height = m.depth_height();
	_depth_width = m.depth_width();

	if (m.is_leader()){
		Client::leader_id = _id;
	}

	_message_size = m.message_size();
	_recv_buf = (char*) malloc(_message_size);
}

void Client::_threadHandle(){
	int timestamp = 0;

	_recvConnectionMessage();

	while (_running){
		if (_tcp_con.isClosed()){
			_running = 0;
			break;
		}

		_handleFrameMessage();

		_data_mutex.lock();
		timestamp = _sensor_data.timestamp();
		_data_mutex.unlock();

		if (timestamp > 0) {
			LOG_DEBUG << "Timestamp = " << timestamp << endl;
		}
	}

	LOG_DEBUG << "leaving _threadHandle" << endl;
}
<commit_msg>add debug messages<commit_after>#include "Client.h"

#include <iostream>

#include "Logger.h"
#include "Common.h"
#include "../gen/ConnectionMessage.pb.h"
#include "PCLUtil.h"

int Client::leader_id = -1;

Client::Client(int id, int tcp_socket)
	: _tcp_con(tcp_socket)
	, _sensor_data()
	, _data_available(0)
	, _running(1)
	, _data_mutex()
	, _client_thread(&Client::_threadHandle, this)
	, _use_point_cloud(false)
	, _video_height(0)
	, _video_width(0)
	, _depth_height(0)
	, _depth_width(0)
	, _message_size(0)
	, _recv_buf(0)
	, _id(id) {}

Client::~Client(){
	_running = 0;
	_tcp_con.closeConnection();
	_client_thread.join();
}

void Client::setInfo(struct sockaddr_in* info){
	_tcp_con.setInfo(info);
}

int Client::getVideo(char** video, int size){
	if (!_data_available){
		return -1;
	}

	_data_mutex.lock();

	int size_new = _sensor_data.fvideo_data().capacity();

	if (size < size_new && size > 0){
		free(*video);
	}

	if (*video == NULL){
		*video = (char*) malloc(size_new);
	}

	memcpy(*video, _sensor_data.fvideo_data().c_str(), size_new);

	_data_mutex.unlock();

	return size_new;
}

int Client::getDepth(char** depth, int size){
	if (_use_point_cloud){
		return -2;
	}

	if (!_data_available){
		return -1;
	}

	_data_mutex.lock();

	int size_new = _sensor_data.fdepth_data().capacity();

	if (size < size_new && size > 0){
		free(*depth);
	}

	if (*depth == NULL){
		*depth = (char*) malloc(size_new);
	}

	memcpy(*depth, _sensor_data.fdepth_data().c_str(), size_new);

	_data_mutex.unlock();

	return size_new;
}

int Client::getCloud(float** cloud, int size){
	if (!_use_point_cloud){
		return -1;
	}

	if (!_data_available){
		return -2;
	}

	_data_mutex.lock();

#ifdef PROCESS_CLOUD_DISTRIBUTED
	int size_new = _sensor_data.cloud_size();
	LOG_DEBUG << "processing cloud on server" << endl;
#else
	int size_new = _sensor_data.fdepth_data().capacity() * 3;
	LOG_DEBUG << "rececived processed cloud" << endl;
#endif

	if (size != size_new && size > 0){
		free(*cloud);
	}

	if (*cloud == NULL && size_new > 0){
		*cloud = (float*) malloc(size_new * sizeof(float));
	}

#ifdef PROCESS_CLOUD_DISTRIBUTED
	LOG_DEBUG << "copying cloud" << endl;
	for (int i = 0; i < size_new; i++){
		(*cloud)[i] = _sensor_data.cloud(i);
	}
#else
	LOG_DEBUG << "converting cloud" << endl;
	PCLUtil::convertToXYZPointCloud(*cloud, (uint16_t*) _sensor_data.fdepth_data().c_str(), _depth_height, _depth_width);
#endif

	_data_mutex.unlock();

	LOG_DEBUG << "returning cloud with size " << size_new << endl;
	return size_new;
}

/*int Client::getData(char** video, char** depth, float** cloud){
	if (!_data_available){
		return -1;
	}

	_data_mutex.lock();

	int size = _sensor_data.fvideo_data().capacity();
	if (*video == NULL){
		*video = (char*) malloc(size);
	}
	memcpy(*video, _sensor_data.fvideo_data().c_str(), size);

	if (!_use_point_cloud && _sensor_data.fdepth_data() != ""){
		size = _sensor_data.fdepth_data().capacity();
		if (*depth == NULL){
			*depth = (char*) malloc(size);
		}
		memcpy(*depth, _sensor_data.fdepth_data().c_str(), size);
	} else if (_use_point_cloud){
		if (*cloud == NULL){
			cout << "DEBUG malloc pointer with cloud size = " << _sensor_data.cloud_size() << endl;
			*cloud = (float*) malloc(_sensor_data.cloud_size() * sizeof(float));
		}
		cout << "DEBUG enter data with cloud size = " << _sensor_data.cloud_size() << endl;
		for (int i = 0; i < _sensor_data.cloud_size(); i++){
			(*cloud)[i] = _sensor_data.cloud(i);
		}
	} else {
		_data_mutex.unlock();
		return -1;
	}

	_data_available = 0;

	_data_mutex.unlock();

	return 0;
}*/

void Client::_handleFrameMessage(){
	_tcp_con.recvData((void *) _recv_buf, _message_size);

	_data_mutex.lock();
	_sensor_data.ParseFromArray(_recv_buf, _message_size);

	if (_sensor_data.fvideo_data() == "" || _sensor_data.timestamp() == 0){
		LOG_ERROR << "message does not contain at least one required field"
			<< endl;
	} else {
		_data_available = 1;
	}

	_data_mutex.unlock();
}

void Client::_recvConnectionMessage(){
	ConnectionMessage m;
	uint32_t size = 0;
	uint32_t size_nw = 0;

	_tcp_con.recvData((void*) &size_nw, 4);

	size = ntohl(size_nw);
	char* buf[size] = {0};
	_tcp_con.recvData((void*) buf, size);

	m.ParseFromArray(buf, size);

	_use_point_cloud = m.use_point_cloud();
	_video_height = m.video_height();
	_video_width = m.video_width();
	_depth_height = m.depth_height();
	_depth_width = m.depth_width();

	if (m.is_leader()){
		Client::leader_id = _id;
	}

	_message_size = m.message_size();
	_recv_buf = (char*) malloc(_message_size);
}

void Client::_threadHandle(){
	int timestamp = 0;

	_recvConnectionMessage();

	while (_running){
		if (_tcp_con.isClosed()){
			_running = 0;
			break;
		}

		_handleFrameMessage();

		_data_mutex.lock();
		timestamp = _sensor_data.timestamp();
		_data_mutex.unlock();

		if (timestamp > 0) {
			LOG_DEBUG << "Timestamp = " << timestamp << endl;
		}
	}

	LOG_DEBUG << "leaving _threadHandle" << endl;
}
<|endoftext|>


<commit_before>// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.

#include "ustdxept.h"
#include "mistream.h"
#include "mostream.h"
#include "strmsize.h"
#include "uiosfunc.h"
#include "uspecial.h"

namespace ustl {

//----------------------------------------------------------------------

/// \p arg contains a description of the error.
error_message::error_message (const char* arg) noexcept
: exception()
,_arg()
{
    try { _arg = arg; } catch (...) {}
    set_format (xfmt_ErrorMessage);
}

/// Virtual destructor
error_message::~error_message (void) noexcept
{
}

/// Returns a descriptive error message. fmt="%s: %s"
void error_message::info (string& msgbuf, const char* fmt) const noexcept
{
    if (!fmt) fmt = "%s: %s";
    try { msgbuf.format (fmt, name(), _arg.c_str()); } catch (...) {}
}

/// Reads the object from stream \p is.
void error_message::read (istream& is)
{
    exception::read (is);
    is >> _arg >> ios::align();
}

/// Writes the object to stream \p os.
void error_message::write (ostream& os) const
{
    exception::write (os);
    os << _arg << ios::align();
}

/// Returns the size of the written object.
size_t error_message::stream_size (void) const noexcept
{
    return exception::stream_size() + Align (stream_size_of (_arg));
}

//----------------------------------------------------------------------

/// Initializes the empty object. \p operation is the function that returned the error code.
system_error::system_error (const char* operation) noexcept
#if HAVE_CPP14
: system_error (errno, system_category(), operation)
#else
: runtime_error (strerror (errno))
,_operation (operation)
,_errno (errno)
#endif
{
    set_format (xfmt_SystemError);
}

/// Reads the exception from stream \p is.
void system_error::read (istream& is)
{
    runtime_error::read (is);
    is >> _operation >> ios::align() >> _errno >> ios::align();
}

/// Writes the exception into stream \p os.
void system_error::write (ostream& os) const
{
    runtime_error::write (os);
    os << _operation << ios::align() << _errno << ios::align();
}

/// Returns the size of the written exception.
size_t system_error::stream_size (void) const noexcept
{
    return runtime_error::stream_size() +
	    Align (stream_size_of(_errno)) +
	    Align (stream_size_of(_operation));
}

//----------------------------------------------------------------------

/// Initializes the empty object. \p operation is the function that returned the error code.
file_exception::file_exception (const char* operation, const char* filename) noexcept
: system_error (operation)
{
    memset (_filename, 0, VectorSize(_filename));
    set_format (xfmt_FileException);
    if (filename) {
	strncpy (_filename, filename, VectorSize(_filename));
	_filename [VectorSize(_filename) - 1] = 0;
    }
}

/// Returns a descriptive error message. fmt="%s %s: %s"
void file_exception::info (string& msgbuf, const char* fmt) const noexcept
{
    if (!fmt) fmt = "%s %s: %s";
    try { msgbuf.format (fmt, Operation(), Filename(), _arg.c_str()); } catch (...) {}
}

/// Reads the exception from stream \p is.
void file_exception::read (istream& is)
{
    system_error::read (is);
    string filename;
    is >> filename;
    is.align();
    strncpy (_filename, filename.c_str(), VectorSize(_filename));
    _filename [VectorSize(_filename)-1] = 0;
}

/// Writes the exception into stream \p os.
void file_exception::write (ostream& os) const
{
    system_error::write (os);
    os << string (_filename);
    os.align();
}

/// Returns the size of the written exception.
size_t file_exception::stream_size (void) const noexcept
{
    return system_error::stream_size() +
	    Align (stream_size_of (string (_filename)));
}

//----------------------------------------------------------------------

/// Initializes the empty object. \p operation is the function that returned the error code.
stream_bounds_exception::stream_bounds_exception (const char* operation, const char* type, uoff_t offset, size_t expected, size_t remaining) noexcept
: system_error (operation)
,_typeName (type)
,_offset (offset)
,_expected (expected)
,_remaining (remaining)
{
    set_format (xfmt_StreamBoundsException);
}

/// Returns a descriptive error message. fmt="%s stream %s: @%u: expected %u, available %u";
void stream_bounds_exception::info (string& msgbuf, const char* fmt) const noexcept
{
    char typeName [256];
    strncpy (typeName, _typeName, VectorSize(typeName));
    typeName[VectorSize(typeName)-1] = 0;
    if (!fmt) fmt = "%s stream %s: @0x%X: need %u bytes, have %u";
    try { msgbuf.format (fmt, demangle_type_name (VectorBlock(typeName)), Operation(), _offset, _expected, _remaining); } catch (...) {}
}

/// Reads the exception from stream \p is.
void stream_bounds_exception::read (istream& is)
{
    system_error::read (is);
    is >> _typeName >> _offset >> _expected >> _remaining;
}

/// Writes the exception into stream \p os.
void stream_bounds_exception::write (ostream& os) const
{
    system_error::write (os);
    os << _typeName << _offset << _expected << _remaining;
}

/// Returns the size of the written exception.
size_t stream_bounds_exception::stream_size (void) const noexcept
{
    return system_error::stream_size() +
	    stream_size_of(_typeName) +
	    stream_size_of(_offset) +
	    stream_size_of(_expected) +
	    stream_size_of(_remaining);
}

} // namespace ustl
<commit_msg>Fix buffer size for strncpy in file_exception<commit_after>// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.

#include "ustdxept.h"
#include "mistream.h"
#include "mostream.h"
#include "strmsize.h"
#include "uiosfunc.h"
#include "uspecial.h"

namespace ustl {

//----------------------------------------------------------------------

/// \p arg contains a description of the error.
error_message::error_message (const char* arg) noexcept
: exception()
,_arg()
{
    try { _arg = arg; } catch (...) {}
    set_format (xfmt_ErrorMessage);
}

/// Virtual destructor
error_message::~error_message (void) noexcept
{
}

/// Returns a descriptive error message. fmt="%s: %s"
void error_message::info (string& msgbuf, const char* fmt) const noexcept
{
    if (!fmt) fmt = "%s: %s";
    try { msgbuf.format (fmt, name(), _arg.c_str()); } catch (...) {}
}

/// Reads the object from stream \p is.
void error_message::read (istream& is)
{
    exception::read (is);
    is >> _arg >> ios::align();
}

/// Writes the object to stream \p os.
void error_message::write (ostream& os) const
{
    exception::write (os);
    os << _arg << ios::align();
}

/// Returns the size of the written object.
size_t error_message::stream_size (void) const noexcept
{
    return exception::stream_size() + Align (stream_size_of (_arg));
}

//----------------------------------------------------------------------

/// Initializes the empty object. \p operation is the function that returned the error code.
system_error::system_error (const char* operation) noexcept
#if HAVE_CPP14
: system_error (errno, system_category(), operation)
#else
: runtime_error (strerror (errno))
,_operation (operation)
,_errno (errno)
#endif
{
    set_format (xfmt_SystemError);
}

/// Reads the exception from stream \p is.
void system_error::read (istream& is)
{
    runtime_error::read (is);
    is >> _operation >> ios::align() >> _errno >> ios::align();
}

/// Writes the exception into stream \p os.
void system_error::write (ostream& os) const
{
    runtime_error::write (os);
    os << _operation << ios::align() << _errno << ios::align();
}

/// Returns the size of the written exception.
size_t system_error::stream_size (void) const noexcept
{
    return runtime_error::stream_size() +
	    Align (stream_size_of(_errno)) +
	    Align (stream_size_of(_operation));
}

//----------------------------------------------------------------------

/// Initializes the empty object. \p operation is the function that returned the error code.
file_exception::file_exception (const char* operation, const char* filename) noexcept
: system_error (operation)
{
    memset (_filename, 0, VectorSize(_filename));
    set_format (xfmt_FileException);
    if (filename)
	strncpy (_filename, filename, VectorSize(_filename)-1);
}

/// Returns a descriptive error message. fmt="%s %s: %s"
void file_exception::info (string& msgbuf, const char* fmt) const noexcept
{
    if (!fmt) fmt = "%s %s: %s";
    try { msgbuf.format (fmt, Operation(), Filename(), _arg.c_str()); } catch (...) {}
}

/// Reads the exception from stream \p is.
void file_exception::read (istream& is)
{
    system_error::read (is);
    string filename;
    is >> filename;
    is.align();
    strncpy (_filename, filename.c_str(), VectorSize(_filename));
    _filename [VectorSize(_filename)-1] = 0;
}

/// Writes the exception into stream \p os.
void file_exception::write (ostream& os) const
{
    system_error::write (os);
    os << string (_filename);
    os.align();
}

/// Returns the size of the written exception.
size_t file_exception::stream_size (void) const noexcept
{
    return system_error::stream_size() +
	    Align (stream_size_of (string (_filename)));
}

//----------------------------------------------------------------------

/// Initializes the empty object. \p operation is the function that returned the error code.
stream_bounds_exception::stream_bounds_exception (const char* operation, const char* type, uoff_t offset, size_t expected, size_t remaining) noexcept
: system_error (operation)
,_typeName (type)
,_offset (offset)
,_expected (expected)
,_remaining (remaining)
{
    set_format (xfmt_StreamBoundsException);
}

/// Returns a descriptive error message. fmt="%s stream %s: @%u: expected %u, available %u";
void stream_bounds_exception::info (string& msgbuf, const char* fmt) const noexcept
{
    char typeName [256];
    strncpy (typeName, _typeName, VectorSize(typeName));
    typeName[VectorSize(typeName)-1] = 0;
    if (!fmt) fmt = "%s stream %s: @0x%X: need %u bytes, have %u";
    try { msgbuf.format (fmt, demangle_type_name (VectorBlock(typeName)), Operation(), _offset, _expected, _remaining); } catch (...) {}
}

/// Reads the exception from stream \p is.
void stream_bounds_exception::read (istream& is)
{
    system_error::read (is);
    is >> _typeName >> _offset >> _expected >> _remaining;
}

/// Writes the exception into stream \p os.
void stream_bounds_exception::write (ostream& os) const
{
    system_error::write (os);
    os << _typeName << _offset << _expected << _remaining;
}

/// Returns the size of the written exception.
size_t stream_bounds_exception::stream_size (void) const noexcept
{
    return system_error::stream_size() +
	    stream_size_of(_typeName) +
	    stream_size_of(_offset) +
	    stream_size_of(_expected) +
	    stream_size_of(_remaining);
}

} // namespace ustl
<|endoftext|>