<commit_before>#include "catch.hpp"

#include <iostream>
#include <exception> // std::bad_function_call, std::runtime_error
#include <thread> // std::thread, std::this_thread::yield
#include <mutex> // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable
#include <functional> // std::function

class EventThreader {
public:
    std::condition_variable event_waiter;
    std::condition_variable calling_waiter;
    std::unique_lock<std::mutex>* event_lock = nullptr;
    std::unique_lock<std::mutex>* calling_lock = nullptr;
    std::mutex mtx;
    std::mutex allocation_mtx;
    std::thread event_thread;
    void switchToCallingThread();
    bool require_switch_from_event = false;
    std::function<void(void)> event_cleanup;
    std::runtime_error* exception_from_the_event_thread = nullptr;
    void deallocate();
public:
    EventThreader(std::function<void (std::function<void (void)>)> func);
    ~EventThreader();
    void switchToEventThread();
    void join();
    void setEventCleanup(std::function<void(void)>);
};

EventThreader::EventThreader(std::function<void (std::function<void (void)>)> func) {
	allocation_mtx.lock();
    calling_lock = new std::unique_lock<std::mutex>(mtx);
    allocation_mtx.unlock();
    event_cleanup = [](){}; // empty function
    auto event = [&](){
        /* mtx force switch to calling - blocked by the mutex */
        this->allocation_mtx.lock();
        this->event_lock = new std::unique_lock<std::mutex>(this->mtx);
        this->allocation_mtx.unlock();

        this->calling_waiter.notify_one();
        this->event_waiter.wait(*(this->event_lock));
        std::this_thread::yield();
        try {
            func([&](){this->switchToCallingThread();});
            if (this->require_switch_from_event) { // the event has ended, but not ready to join
                // rejoin the calling thread after dealing with this exception
                throw std::runtime_error("switch to event not matched with a switch to calling");
            }
        } catch (const std::runtime_error &e) {
            /* report the exception to the calling thread */
            this->allocation_mtx.lock();
            this->exception_from_the_event_thread = new std::runtime_error(e);
            this->allocation_mtx.unlock();
            this->calling_waiter.notify_one();
            std::this_thread::yield();
        }
        this->allocation_mtx.lock();
        delete this->event_lock;
        this->event_lock = nullptr;
        this->allocation_mtx.unlock();
        this->event_cleanup();
    };

    event_thread = std::thread(event);
}

EventThreader::~EventThreader() {
	deallocate();
}

void EventThreader::deallocate() {
	allocation_mtx.lock();
	if (exception_from_the_event_thread != nullptr) {
		delete exception_from_the_event_thread;
		exception_from_the_event_thread = nullptr;
	}
	if (calling_lock != nullptr) {
		delete calling_lock;
		calling_lock = nullptr;
	}
	if (event_lock != nullptr) {
		delete event_lock;
		event_lock = nullptr;
	}
	allocation_mtx.unlock();
}

void EventThreader::switchToCallingThread() {
	if (!require_switch_from_event) {
        throw std::runtime_error("switch to calling not matched with a switch to event");
    }
    require_switch_from_event = false;
    /* switch to calling */
    calling_waiter.notify_one();
    std::this_thread::yield();
    event_waiter.wait(*(event_lock));
    std::this_thread::yield();
    /* back from calling */
}

void EventThreader::switchToEventThread() {
}

void EventThreader::join() {
	allocation_mtx.lock();
    delete calling_lock; // remove lock on this thread, allow event to run
    calling_lock = nullptr;
    allocation_mtx.unlock();
    if (event_lock != nullptr) {
        event_waiter.notify_one();
        std::this_thread::yield();
    }
    event_thread.join();
    if (exception_from_the_event_thread != nullptr) {
        /* an exception occured */
        std::runtime_error e_copy(exception_from_the_event_thread->what());
        allocation_mtx.lock();
        delete exception_from_the_event_thread;
        exception_from_the_event_thread = nullptr;
        allocation_mtx.unlock();
        throw e_copy;
    }
    deallocate();
}

void EventThreader::setEventCleanup(std::function<void(void)> cleanup) {
    event_cleanup = cleanup;
}

TEST_CASE( "EventThreader", "[EventThreader]" ) {
	std::stringstream ss;

	SECTION("Finding the error") {

		/* Example of most basic use */
		auto f = [&ss](std::function<void(void)> switchToMainThread){
			for(int i = 0; i < 100; i++) { ss << "*"; }
			switchToMainThread();
			for(int i = 0; i < 50; i++) { ss << "*"; }
			switchToMainThread();
		};

		EventThreader et(f);

	    // class functions

		auto switchToEventThread= [&]() {
		    if (et.require_switch_from_event) {
		        throw std::runtime_error("switch to event not matched with a switch to calling");
		    }
		    et.require_switch_from_event = true;
		    /* switch to event */
		    et.event_waiter.notify_one();
		    std::this_thread::yield();
		    et.calling_waiter.wait(*et.calling_lock);
		    std::this_thread::yield();
		    /* back from event */
		    if (et.require_switch_from_event) {
		        /* this exception is thrown if switchToCallingThread() was not used, which means the thread ended */
		        et.join();
		    }
		};
		std::function<void (std::function<void (void)>)> func = f;

		// Start construction

	    std::this_thread::yield();
	    et.calling_waiter.wait(*(et.calling_lock));
	    std::this_thread::yield();
		// End constuction
		//EventThreader et(f);
		switchToEventThread();
		for(int i = 0; i < 75; i++) { ss << "$"; }
		switchToEventThread();
		for(int i = 0; i < 25; i++) { ss << "$"; }
		et.join();

		/* Generate what the result should look like */
		std::string requirement;
		for(int i = 0; i < 100; i++) { requirement += "*"; }
		for(int i = 0; i < 75; i++) { requirement += "$"; }
		for(int i = 0; i < 50; i++) { requirement += "*"; }
		for(int i = 0; i < 25; i++) { requirement += "$"; }
		REQUIRE( requirement == ss.str());

	}

	/* SECTION("Abitrary use") {
		// Example of most basic use
		auto f = [&ss](std::function<void(void)> switchToMainThread){
			for(int i = 0; i < 100; i++) { ss << "*"; }
			switchToMainThread();
			for(int i = 0; i < 50; i++) { ss << "*"; }
			switchToMainThread();
		};
		EventThreader et(f);
		switchToEventThread();
		for(int i = 0; i < 75; i++) { ss << "$"; }
		switchToEventThread();
		for(int i = 0; i < 25; i++) { ss << "$"; }
		join();

		// Generate what the result should look like
		std::string requirement;
		for(int i = 0; i < 100; i++) { requirement += "*"; }
		for(int i = 0; i < 75; i++) { requirement += "$"; }
		for(int i = 0; i < 50; i++) { requirement += "*"; }
		for(int i = 0; i < 25; i++) { requirement += "$"; }
		REQUIRE( requirement == ss.str());

	} */
}
<commit_msg>constructor<commit_after>#include "catch.hpp"

#include <iostream>
#include <exception> // std::bad_function_call, std::runtime_error
#include <thread> // std::thread, std::this_thread::yield
#include <mutex> // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable
#include <functional> // std::function

class EventThreader {
public:
    std::condition_variable event_waiter;
    std::condition_variable calling_waiter;
    std::unique_lock<std::mutex>* event_lock = nullptr;
    std::unique_lock<std::mutex>* calling_lock = nullptr;
    std::mutex mtx;
    std::mutex allocation_mtx;
    std::thread event_thread;
    void switchToCallingThread();
    bool require_switch_from_event = false;
    std::function<void(void)> event_cleanup;
    std::runtime_error* exception_from_the_event_thread = nullptr;
    void deallocate();
public:
    EventThreader(std::function<void (std::function<void (void)>)> func);
    ~EventThreader();
    void switchToEventThread();
    void join();
    void setEventCleanup(std::function<void(void)>);
};

EventThreader::EventThreader(std::function<void (std::function<void (void)>)> func) {
	allocation_mtx.lock();
    calling_lock = new std::unique_lock<std::mutex>(mtx);
    allocation_mtx.unlock();
    event_cleanup = [](){}; // empty function
}

EventThreader::~EventThreader() {
	deallocate();
}

void EventThreader::deallocate() {
	allocation_mtx.lock();
	if (exception_from_the_event_thread != nullptr) {
		delete exception_from_the_event_thread;
		exception_from_the_event_thread = nullptr;
	}
	if (calling_lock != nullptr) {
		delete calling_lock;
		calling_lock = nullptr;
	}
	if (event_lock != nullptr) {
		delete event_lock;
		event_lock = nullptr;
	}
	allocation_mtx.unlock();
}

void EventThreader::switchToCallingThread() {
	if (!require_switch_from_event) {
        throw std::runtime_error("switch to calling not matched with a switch to event");
    }
    require_switch_from_event = false;
    /* switch to calling */
    calling_waiter.notify_one();
    std::this_thread::yield();
    event_waiter.wait(*(event_lock));
    std::this_thread::yield();
    /* back from calling */
}

void EventThreader::switchToEventThread() {
}

void EventThreader::join() {
	allocation_mtx.lock();
    delete calling_lock; // remove lock on this thread, allow event to run
    calling_lock = nullptr;
    allocation_mtx.unlock();
    if (event_lock != nullptr) {
        event_waiter.notify_one();
        std::this_thread::yield();
    }
    event_thread.join();
    if (exception_from_the_event_thread != nullptr) {
        /* an exception occured */
        std::runtime_error e_copy(exception_from_the_event_thread->what());
        allocation_mtx.lock();
        delete exception_from_the_event_thread;
        exception_from_the_event_thread = nullptr;
        allocation_mtx.unlock();
        throw e_copy;
    }
    deallocate();
}

void EventThreader::setEventCleanup(std::function<void(void)> cleanup) {
    event_cleanup = cleanup;
}

TEST_CASE( "EventThreader", "[EventThreader]" ) {
	std::stringstream ss;

	SECTION("Finding the error") {

		/* Example of most basic use */
		auto f = [&ss](std::function<void(void)> switchToMainThread){
			for(int i = 0; i < 100; i++) { ss << "*"; }
			switchToMainThread();
			for(int i = 0; i < 50; i++) { ss << "*"; }
			switchToMainThread();
		};

		EventThreader et(f);

	    // class functions

		auto switchToEventThread= [&]() {
		    if (et.require_switch_from_event) {
		        throw std::runtime_error("switch to event not matched with a switch to calling");
		    }
		    et.require_switch_from_event = true;
		    /* switch to event */
		    et.event_waiter.notify_one();
		    std::this_thread::yield();
		    et.calling_waiter.wait(*et.calling_lock);
		    std::this_thread::yield();
		    /* back from event */
		    if (et.require_switch_from_event) {
		        /* this exception is thrown if switchToCallingThread() was not used, which means the thread ended */
		        et.join();
		    }
		};
		std::function<void (std::function<void (void)>)> func = f;

		// Start construction

	    auto event = [&](){
	        /* mtx force switch to calling - blocked by the mutex */
	        et.allocation_mtx.lock();
	        et.event_lock = new std::unique_lock<std::mutex>(et.mtx);
	        et.allocation_mtx.unlock();

	        et.calling_waiter.notify_one();
	        et.event_waiter.wait(*(et.event_lock));
	        std::this_thread::yield();
	        try {
	            func([&](){et.switchToCallingThread();});
	            if (et.require_switch_from_event) { // the event has ended, but not ready to join
	                // rejoin the calling thread after dealing with this exception
	                throw std::runtime_error("switch to event not matched with a switch to calling");
	            }
	        } catch (const std::runtime_error &e) {
	            /* report the exception to the calling thread */
	            et.allocation_mtx.lock();
	            et.exception_from_the_event_thread = new std::runtime_error(e);
	            et.allocation_mtx.unlock();
	            et.calling_waiter.notify_one();
	            std::this_thread::yield();
	        }
	        et.allocation_mtx.lock();
	        delete et.event_lock;
	        et.event_lock = nullptr;
	        et.allocation_mtx.unlock();
	        et.event_cleanup();
	    };

	    et.event_thread = std::thread(event);
	    std::this_thread::yield();
	    et.calling_waiter.wait(*(et.calling_lock));
	    std::this_thread::yield();
		// End constuction
		//EventThreader et(f);
		switchToEventThread();
		for(int i = 0; i < 75; i++) { ss << "$"; }
		switchToEventThread();
		for(int i = 0; i < 25; i++) { ss << "$"; }
		et.join();

		/* Generate what the result should look like */
		std::string requirement;
		for(int i = 0; i < 100; i++) { requirement += "*"; }
		for(int i = 0; i < 75; i++) { requirement += "$"; }
		for(int i = 0; i < 50; i++) { requirement += "*"; }
		for(int i = 0; i < 25; i++) { requirement += "$"; }
		REQUIRE( requirement == ss.str());

	}

	/* SECTION("Abitrary use") {
		// Example of most basic use
		auto f = [&ss](std::function<void(void)> switchToMainThread){
			for(int i = 0; i < 100; i++) { ss << "*"; }
			switchToMainThread();
			for(int i = 0; i < 50; i++) { ss << "*"; }
			switchToMainThread();
		};
		EventThreader et(f);
		switchToEventThread();
		for(int i = 0; i < 75; i++) { ss << "$"; }
		switchToEventThread();
		for(int i = 0; i < 25; i++) { ss << "$"; }
		join();

		// Generate what the result should look like
		std::string requirement;
		for(int i = 0; i < 100; i++) { requirement += "*"; }
		for(int i = 0; i < 75; i++) { requirement += "$"; }
		for(int i = 0; i < 50; i++) { requirement += "*"; }
		for(int i = 0; i < 25; i++) { requirement += "$"; }
		REQUIRE( requirement == ss.str());

	} */
}
<|endoftext|>


<commit_before>#include "cinder/app/AppNative.h"
#include "cinder/gl/gl.h"
#include "cinder/Rand.h"

#include "TriangleRenderer.h"
#include "SimpleRenderer.h"
#include "Locus2d.h"

#include <array>

using namespace ci;
using namespace ci::app;
using namespace std;
using namespace pockets;

/**
 Test for comparing performance of rendering strategies.
 Also demonstrates basic usage of the Renderer objects.

 Performance notes from testing on various devices (Release mode, 1k boxes):

 (Renderer/Device)        SimpleRenderer    TriangleRenderer
 iPhone 3GS               ~ 55ms             ~ 10ms
 iPhone 4S                ~ 25.5ms           ~  5.5ms
 iPad 2                   ~ 21.8ms           ~  6.6ms
 iPad 3 (Retina)          ~ 12.5ms           ~  4.6ms
 Macbook Pro              ~  2.7ms           ~  1.5ms

 Performance seems to increase much more on devices with limited GPUs, where
 GPU state switching is slow. This was all measured while plugged into XCode.

 SimpleRenderer, then, provides an easy interface for ordering custom rendering,
 while TriangleRenderer provides a high performance interface for rendering
 triangle strips.
 */

// Something we can render with either renderer for better comparison of methods
class Box : public TriangleRenderer::IRenderable, public SimpleRenderer::IRenderable
{
public:
  Box()
  { // build a box
    Rectf bounds{ -20.0f, -10.0f, 20.0f, 10.0f };
    mVertices[0].position = bounds.getUpperRight();
    mVertices[1].position = bounds.getUpperLeft();
    mVertices[2].position = bounds.getLowerRight();
    mVertices[3].position = bounds.getLowerLeft();
  }
  // accessors and mutators
  Vec2f getPos() const { return mLocus.getLoc(); }
  void setPos( const Vec2f &pos ){ mLocus.setLoc( pos ); }
  float getRotation() const { return mLocus.getRotation(); }
  void setRotation( float radians ){ mLocus.setRotation( radians ); }
  void setColor( const ColorA &color )
  {
    mColor = color;
    for( auto &v : mVertices )
    {
      v.color = color;
    }
  }
  // Interface for SimpleRenderer
  void render() override
  {
    glEnableClientState( GL_VERTEX_ARRAY );
    glVertexPointer( 2, GL_FLOAT, sizeof(Vertex), &mVertices[0].position.x );
    glEnableClientState( GL_TEXTURE_COORD_ARRAY );
    glTexCoordPointer( 2, GL_FLOAT, sizeof(Vertex), &mVertices[0].tex_coord.x );

    gl::pushModelView();
    gl::multModelView( mLocus );
    gl::color( mColor );
    glDrawArrays( GL_TRIANGLE_STRIP, 0, mVertices.size() );
    gl::popModelView();

    glDisableClientState( GL_VERTEX_ARRAY );
    glDisableClientState( GL_TEXTURE_COORD_ARRAY );
  }
  // Interface for TriangleRenderer
  vector<Vertex> getVertices() override
  {
    auto mat = mLocus.getTransform();
    vector<Vertex> ret;
    for( auto &v : mVertices )
    {
      ret.emplace_back( Vertex{ mat.transformPoint( v.position ), v.color, v.tex_coord } );
    }
    return ret;
  }
private:
  ci::ColorA                mColor;
  std::array<Vertex, 4>     mVertices;
  Locus2d                   mLocus;
};

typedef function<void ()> RenderFn;

class RendererTestApp : public AppNative {
public:
	void setup();
	void swapRenderer();
	void update();
	void draw();
private:
  RenderFn          mRenderFn;
  RenderFn          mRenderTriangle;
  RenderFn          mRenderSimple;
  TriangleRenderer  mTriangleRenderer;
  SimpleRenderer    mSimpleRenderer;
  array<Box, 1000>  mBoxes;
  bool              mRenderingSimple = true;
  double            mAverageRenderTime = 0;
};

void RendererTestApp::setup()
{
  mRenderTriangle = [=](){ mTriangleRenderer.render(); };
  mRenderSimple = [=](){ mSimpleRenderer.render(); };
  mRenderFn = mRenderSimple;

  for( auto &box : mBoxes )
  {
    box.setColor( ColorA{ CM_HSV, Rand::randFloat(), 0.9f, 0.9f, 1.0f } );
    box.setPos( Vec2f{ Rand::randFloat(getWindowWidth()), Rand::randFloat(getWindowHeight()) } );
    box.setRotation( Rand::randFloat( M_PI * 2 ) );
    mTriangleRenderer.add( &box );
    mSimpleRenderer.add( &box );
  }

  // We perform the cast since we know what type of things we stored in each renderer
  // A type-safe way could be to assign y to each objects layer and then sort by layer
  auto top_to_bottom_simple = []( const SimpleRenderer::IRenderable *lhs, const SimpleRenderer::IRenderable *rhs ) -> bool
  {
    return static_cast<const Box*>( lhs )->getPos().y < static_cast<const Box*>( rhs )->getPos().y;
  };
  auto top_to_bottom_triangle = []( const TriangleRenderer::IRenderable *lhs, const TriangleRenderer::IRenderable *rhs )
  {
    return static_cast<const Box*>( lhs )->getPos().y < static_cast<const Box*>( rhs )->getPos().y;
  };
  mSimpleRenderer.sort( top_to_bottom_simple );
  mTriangleRenderer.sort( top_to_bottom_triangle );

  getWindow()->getSignalKeyUp().connect( [this](KeyEvent &event){ swapRenderer(); } );
  getWindow()->getSignalTouchesEnded().connect( [this](TouchEvent &event){ swapRenderer(); } );
}

void RendererTestApp::swapRenderer()
{
  cout << (mRenderingSimple ? "SimpleRenderer " : "TriangleRenderer ")
  << "avg render time: " << mAverageRenderTime << "ms" << endl;
  cout << "Swapping renderer" << endl;
  mRenderingSimple = !mRenderingSimple;
  mRenderFn = mRenderingSimple ? mRenderSimple : mRenderTriangle;
}

void RendererTestApp::update()
{
  for( auto &box : mBoxes )
  {
    box.setRotation( fmodf( box.getRotation() + M_PI * 0.01f, M_PI * 2 ) );
  }
}

void RendererTestApp::draw()
{
	gl::clear( Color::black() );
  gl::color( Color::white() );
  auto t1 = getElapsedSeconds();
  mRenderFn();
  auto t2 = getElapsedSeconds();
  auto ms = (t2 - t1) * 1000;
  mAverageRenderTime = (mAverageRenderTime * 59 + ms) / 60;
  if( getElapsedFrames() % 120 == 0 )
  {
    cout << (mRenderingSimple ? "SimpleRenderer " : "TriangleRenderer ")
    << "avg render time: " << mAverageRenderTime << "ms" << endl;
  }
}

CINDER_APP_NATIVE( RendererTestApp, RendererGl( RendererGl::AA_NONE ) )
<commit_msg>More interesting sort order.<commit_after>#include "cinder/app/AppNative.h"
#include "cinder/gl/gl.h"
#include "cinder/Rand.h"

#include "TriangleRenderer.h"
#include "SimpleRenderer.h"
#include "Locus2d.h"

#include <array>

using namespace ci;
using namespace ci::app;
using namespace std;
using namespace pockets;

/**
 Test for comparing performance of rendering strategies.
 Also demonstrates basic usage of the Renderer objects.

 Performance notes from testing on various devices (Release mode, 1k boxes):

 (Renderer/Device)        SimpleRenderer    TriangleRenderer
 iPhone 3GS               ~ 55ms             ~ 10ms
 iPhone 4S                ~ 25.5ms           ~  5.5ms
 iPad 2                   ~ 21.8ms           ~  6.6ms
 iPad 3 (Retina)          ~ 12.5ms           ~  4.6ms
 Macbook Pro              ~  2.7ms           ~  1.5ms

 Performance seems to increase much more on devices with limited GPUs, where
 GPU state switching is slow. This was all measured while plugged into XCode.

 SimpleRenderer, then, provides an easy interface for ordering custom rendering,
 while TriangleRenderer provides a high performance interface for rendering
 triangle strips.
 */

// Something we can render with either renderer for better comparison of methods
class Box : public TriangleRenderer::IRenderable, public SimpleRenderer::IRenderable
{
public:
  Box()
  { // build a box
    Rectf bounds{ -20.0f, -10.0f, 20.0f, 10.0f };
    mVertices[0].position = bounds.getUpperRight();
    mVertices[1].position = bounds.getUpperLeft();
    mVertices[2].position = bounds.getLowerRight();
    mVertices[3].position = bounds.getLowerLeft();
  }
  // accessors and mutators
  Vec2f getPos() const { return mLocus.getLoc(); }
  void setPos( const Vec2f &pos ){ mLocus.setLoc( pos ); }
  float getRotation() const { return mLocus.getRotation(); }
  void setRotation( float radians ){ mLocus.setRotation( radians ); }
  void setColor( const ColorA &color )
  {
    mColor = color;
    for( auto &v : mVertices )
    {
      v.color = color;
    }
  }
  // Interface for SimpleRenderer
  void render() override
  {
    glEnableClientState( GL_VERTEX_ARRAY );
    glVertexPointer( 2, GL_FLOAT, sizeof(Vertex), &mVertices[0].position.x );
    glEnableClientState( GL_TEXTURE_COORD_ARRAY );
    glTexCoordPointer( 2, GL_FLOAT, sizeof(Vertex), &mVertices[0].tex_coord.x );

    gl::pushModelView();
    gl::multModelView( mLocus );
    gl::color( mColor );
    glDrawArrays( GL_TRIANGLE_STRIP, 0, mVertices.size() );
    gl::popModelView();

    glDisableClientState( GL_VERTEX_ARRAY );
    glDisableClientState( GL_TEXTURE_COORD_ARRAY );
  }
  // Interface for TriangleRenderer
  vector<Vertex> getVertices() override
  {
    auto mat = mLocus.getTransform();
    vector<Vertex> ret;
    for( auto &v : mVertices )
    {
      ret.emplace_back( Vertex{ mat.transformPoint( v.position ), v.color, v.tex_coord } );
    }
    return ret;
  }
private:
  ci::ColorA                mColor;
  std::array<Vertex, 4>     mVertices;
  Locus2d                   mLocus;
};

typedef function<void ()> RenderFn;

class RendererTestApp : public AppNative {
public:
	void setup();
	void swapRenderer();
	void update();
	void draw();
private:
  RenderFn          mRenderFn;
  RenderFn          mRenderTriangle;
  RenderFn          mRenderSimple;
  TriangleRenderer  mTriangleRenderer;
  SimpleRenderer    mSimpleRenderer;
  array<Box, 1000>  mBoxes;
  bool              mRenderingSimple = true;
  double            mAverageRenderTime = 0;
};

void RendererTestApp::setup()
{
  mRenderTriangle = [=](){ mTriangleRenderer.render(); };
  mRenderSimple = [=](){ mSimpleRenderer.render(); };
  mRenderFn = mRenderSimple;

  for( auto &box : mBoxes )
  {
    box.setColor( ColorA{ CM_HSV, Rand::randFloat(), 0.9f, 0.9f, 1.0f } );
    box.setPos( Vec2f{ Rand::randFloat(getWindowWidth()), Rand::randFloat(getWindowHeight()) } );
    box.setRotation( Rand::randFloat( M_PI * 2 ) );
    mTriangleRenderer.add( &box );
    mSimpleRenderer.add( &box );
  }

  // We perform the cast since we know what type of things we stored in each renderer
  // A type-safe way could be to assign y to each objects layer and then sort by layer
  Vec2f center = getWindowCenter();
  auto vortex_simple = [center]( const SimpleRenderer::IRenderable *lhs, const SimpleRenderer::IRenderable *rhs )
  {
    return static_cast<const Box*>( lhs )->getPos().distance(center) <
    static_cast<const Box*>( rhs )->getPos().distance(center);
  };
  auto vortex_triangle = [center]( const TriangleRenderer::IRenderable *lhs, const TriangleRenderer::IRenderable *rhs )
  {
    return  static_cast<const Box*>( lhs )->getPos().distance(center) <
    static_cast<const Box*>( rhs )->getPos().distance(center);
  };
  mSimpleRenderer.sort( vortex_simple );
  mTriangleRenderer.sort( vortex_triangle );

  getWindow()->getSignalKeyUp().connect( [this](KeyEvent &event){ swapRenderer(); } );
  getWindow()->getSignalTouchesEnded().connect( [this](TouchEvent &event){ swapRenderer(); } );
}

void RendererTestApp::swapRenderer()
{
  cout << (mRenderingSimple ? "SimpleRenderer " : "TriangleRenderer ")
  << "avg render time: " << mAverageRenderTime << "ms" << endl;
  cout << "Swapping renderer" << endl;
  mRenderingSimple = !mRenderingSimple;
  mRenderFn = mRenderingSimple ? mRenderSimple : mRenderTriangle;
}

void RendererTestApp::update()
{
  for( auto &box : mBoxes )
  {
    box.setRotation( fmodf( box.getRotation() + M_PI * 0.01f, M_PI * 2 ) );
  }
}

void RendererTestApp::draw()
{
	gl::clear( Color::black() );
  gl::color( Color::white() );
  auto t1 = getElapsedSeconds();
  mRenderFn();
  auto t2 = getElapsedSeconds();
  auto ms = (t2 - t1) * 1000;
  mAverageRenderTime = (mAverageRenderTime * 59 + ms) / 60;
  if( getElapsedFrames() % 120 == 0 )
  {
    cout << (mRenderingSimple ? "SimpleRenderer " : "TriangleRenderer ")
    << "avg render time: " << mAverageRenderTime << "ms" << endl;
  }
}

CINDER_APP_NATIVE( RendererTestApp, RendererGl( RendererGl::AA_NONE ) )
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*! @file
    @brief  CSV クラス
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2018 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include <vector>
#include <string>
#include <boost/format.hpp>

#include "utils/string_utils.hpp"

namespace app {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  CSV 出力クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	class csv {

		typedef std::vector<utils::strings> CELL;

		CELL	form_;

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		csv() { }

		//-----------------------------------------------------------------//
		/*!
			@brief  クリア
		*/
		//-----------------------------------------------------------------//
		void clear()
		{
		}

	};
}
<commit_msg>update: CSV save<commit_after>#pragma once
//=====================================================================//
/*! @file
    @brief  CSV クラス
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2018 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include <vector>
#include <string>
#include <boost/format.hpp>

#include "utils/string_utils.hpp"

namespace app {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  CSV 出力クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	class csv {

		typedef std::vector<utils::strings> CELL;

		CELL	cell_;

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		csv() { }

		//-----------------------------------------------------------------//
		/*!
			@brief  作成
			@param[in]	columns	列
			@param[in]	rows	行
		*/
		//-----------------------------------------------------------------//
		void create(uint32_t columns, uint32_t rows)
		{
			cell_.clear();
			for(uint32_t r = 0; r < rows; ++r) {
				utils::strings line;
				for(uint32_t c = 0; c < columns; ++c) {
					line.push_back("");
				}
				cell_.push_back(line);
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  クリア
		*/
		//-----------------------------------------------------------------//
		void clear()
		{
			cell_.clear();
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  設定
			@param[in]	columns	列
			@param[in]	rows	行
			@param[in]	str		文字列
			@return 設定不可なら「false」
		*/
		//-----------------------------------------------------------------//
		bool set(uint32_t columns, uint32_t rows, const std::string& str)
		{
			if(cell_.size() <= rows) return false;

			utils::strings& ss = cell_[rows];
			if(ss.size() <= columns) return false;
			ss[columns] = str;
			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  セーブ
			@param[in]	path	セーブ・パス
			@return 成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool save(const std::string& path)
		{
			utils::file_io fio;
			if(!fio.open(path, "wb")) {
				return false;
			}

			for(uint32_t r = 0; r < cell_.size(); ++r) {
				utils::strings& line = cell_[r];
				for(uint32_t c = 0; c < line.size(); ++c) {
					const std::string& s = line[c];
					fio.put(s);
					if(c < (line.size() - 1)) fio.put(",");
					else if(c == (line.size() - 1)) fio.put("\n");
				}
			}
			fio.close();

			return true;
		}

	};
}
<|endoftext|>


<commit_before>#include <catch.hpp>
#include <msgpack/msgpack.hpp>

#include <vector>
#include <map>
#include <system_error>

namespace msgpack = tarigo::msgpack;

using std::vector;
using std::map;
using std::string;
using std::error_code;

TEST_CASE("Check nil value", "[pack/unpack]") {
    msgpack::package nil, nil_explicit(nullptr);

    REQUIRE(nil == nil_explicit);
    REQUIRE(nil.type() == msgpack::type::NIL);
    REQUIRE(nil.format() == msgpack::format::NIL);

    vector<uint8_t> raw_msgpack;
    nil.pack(raw_msgpack);
    REQUIRE(raw_msgpack.size() == 1);
    REQUIRE(raw_msgpack.at(0) == 0xc0);

    error_code ec;
    auto unpacked = msgpack::package::unpack(raw_msgpack, ec);
    REQUIRE(!ec);
    REQUIRE(nil == unpacked);
    REQUIRE(nil_explicit == unpacked);
}

TEST_CASE("Check boolean values", "[pack/unpack]") {
    msgpack::package f(false), t(true);

    REQUIRE(f.type() == msgpack::type::BOOLEAN);
    REQUIRE(f.type() == t.type());

    REQUIRE(f.format() == msgpack::format::FALSE);
    REQUIRE(t.format() == msgpack::format::TRUE);

    REQUIRE(f != t);
    REQUIRE(t > f);

    vector<uint8_t> raw_msgpack;
    f.pack(raw_msgpack);
    REQUIRE(raw_msgpack.size() == 1);
    REQUIRE(raw_msgpack.at(0) == 0xc2);

    error_code ec;
    auto unpacked_f = msgpack::unpacker::unpack(raw_msgpack, ec);
    REQUIRE(!ec);
    REQUIRE(f == unpacked_f);

    raw_msgpack.clear();

    t.pack(raw_msgpack);
    REQUIRE(raw_msgpack.size() == 1);
    REQUIRE(raw_msgpack.at(0) == 0xc3);

    auto unpacked_t = msgpack::unpacker::unpack(raw_msgpack, ec);
    REQUIRE(!ec);
    REQUIRE(t == unpacked_t);
}

TEST_CASE("Check fixed string", "[pack/unpack]") {
    map<string, vector<uint8_t>> sample {
        { "", {0xa0} },
        { "f", {0xa1, 0x66} },
        { "foo", {0xa3, 0x66, 0x6f, 0x6f} },
        { "fooo",  {0xa4, 0x66, 0x6f, 0x6f, 0x6f} },
        { "foooo", {0xa5, 0x66, 0x6f, 0x6f, 0x6f, 0x6f} },
        { "fooooo", {0xa6, 0x66, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f} }
        //TODO: ...
    };

    for (auto entry : sample) {
        msgpack::package package(entry.first);

        REQUIRE(package.type() == msgpack::type::RAW_STRING);
        REQUIRE(package.format() == msgpack::format::FIXSTR);

        vector<uint8_t > raw_msgpack;
        package.pack(raw_msgpack);

        REQUIRE(entry.second == raw_msgpack);
    }

    //TODO: Range tests for fixed values.
    map<string, vector<uint8_t>> one_byte_more_than_fixstr {
        {
            "this_is_not_a_fixed_string_32byt",
            {0xbe, 0x74, 0x68, 0x69, 0x73, 0x5f, 0x69, 0x73, 0x5f, 0x6e, 0x6f,
             0x74, 0x5f, 0x61, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x73,
             0x74, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x33, 0x32, 0x62}
        }
    };

    for(auto entry : one_byte_more_than_fixstr) {
        msgpack::package package(entry.first);
        REQUIRE(package.type() == msgpack::type::RAW_STRING);
        REQUIRE(package.format() != msgpack::format::FIXSTR);
        REQUIRE(package.format() == msgpack::format::STR8);
    }
}
<commit_msg>Unit tests: pack/unpack map.<commit_after>#include <catch.hpp>
#include <msgpack/msgpack.hpp>

#include <vector>
#include <map>
#include <system_error>

namespace msgpack = tarigo::msgpack;

using std::vector;
using std::map;
using std::string;
using std::error_code;

TEST_CASE("Check nil value", "[pack/unpack]") {
    msgpack::package nil, nil_explicit(nullptr);

    REQUIRE(nil == nil_explicit);
    REQUIRE(nil.type() == msgpack::type::NIL);
    REQUIRE(nil.format() == msgpack::format::NIL);

    vector<uint8_t> raw_msgpack;
    nil.pack(raw_msgpack);
    REQUIRE(raw_msgpack.size() == 1);
    REQUIRE(raw_msgpack.at(0) == 0xc0);

    error_code ec;
    auto unpacked = msgpack::package::unpack(raw_msgpack, ec);
    REQUIRE(!ec);
    REQUIRE(nil == unpacked);
    REQUIRE(nil_explicit == unpacked);
}

TEST_CASE("Check boolean values", "[pack/unpack]") {
    msgpack::package f(false), t(true);

    REQUIRE(f.type() == msgpack::type::BOOLEAN);
    REQUIRE(f.type() == t.type());

    REQUIRE(f.format() == msgpack::format::FALSE);
    REQUIRE(t.format() == msgpack::format::TRUE);

    REQUIRE(f != t);
    REQUIRE(t > f);

    vector<uint8_t> raw_msgpack;
    f.pack(raw_msgpack);
    REQUIRE(raw_msgpack.size() == 1);
    REQUIRE(raw_msgpack.at(0) == 0xc2);

    error_code ec;
    auto unpacked_f = msgpack::unpacker::unpack(raw_msgpack, ec);
    REQUIRE(!ec);
    REQUIRE(f == unpacked_f);

    raw_msgpack.clear();

    t.pack(raw_msgpack);
    REQUIRE(raw_msgpack.size() == 1);
    REQUIRE(raw_msgpack.at(0) == 0xc3);

    auto unpacked_t = msgpack::unpacker::unpack(raw_msgpack, ec);
    REQUIRE(!ec);
    REQUIRE(t == unpacked_t);
}

TEST_CASE("Check fixed string", "[pack/unpack]") {
    map<string, vector<uint8_t>> sample {
        { "", {0xa0} },
        { "f", {0xa1, 0x66} },
        { "foo", {0xa3, 0x66, 0x6f, 0x6f} },
        { "fooo",  {0xa4, 0x66, 0x6f, 0x6f, 0x6f} },
        { "foooo", {0xa5, 0x66, 0x6f, 0x6f, 0x6f, 0x6f} },
        { "fooooo", {0xa6, 0x66, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f} }
        //TODO: ...
    };

    for (auto entry : sample) {
        msgpack::package package(entry.first);

        REQUIRE(package.type() == msgpack::type::RAW_STRING);
        REQUIRE(package.format() == msgpack::format::FIXSTR);

        vector<uint8_t > raw_msgpack;
        package.pack(raw_msgpack);

        REQUIRE(entry.second == raw_msgpack);
    }

    //TODO: Range tests for fixed values.
    map<string, vector<uint8_t>> one_byte_more_than_fixstr {
        {
            "this_is_not_a_fixed_string_32byt",
            {0xbe, 0x74, 0x68, 0x69, 0x73, 0x5f, 0x69, 0x73, 0x5f, 0x6e, 0x6f,
             0x74, 0x5f, 0x61, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x73,
             0x74, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x33, 0x32, 0x62}
        }
    };

    for(auto entry : one_byte_more_than_fixstr) {
        msgpack::package package(entry.first);
        REQUIRE(package.type() == msgpack::type::RAW_STRING);
        REQUIRE(package.format() != msgpack::format::FIXSTR);
        REQUIRE(package.format() == msgpack::format::STR8);
    }
}

TEST_CASE("Check fixed map", "[pack/unpack]") {
    const vector<uint8_t> expected { 0x82, 0xa7, 0x63, 0x6f, 0x6d, 0x70,
                                     0x61, 0x63, 0x74, 0xc3, 0xa6, 0x73,
                                     0x63, 0x68, 0x65, 0x6d, 0x61, 0x00 };
    msgpack::package::map map {
            {"compact", true },
            //FIXME: should not require explicit casting
            {"schema", static_cast<uint8_t >(0) }
    };

    vector<uint8_t> raw_msgpack;
    msgpack::package package { map };

    package.pack(raw_msgpack);
    REQUIRE(raw_msgpack == expected);

    error_code ec;
    auto unpacked = msgpack::unpacker::unpack(expected, ec);
    REQUIRE(unpacked.type() == msgpack::type::MAP);
    REQUIRE(unpacked.format() == msgpack::format::FIXMAP);

    REQUIRE(package == unpacked);
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: XMLDetectiveContext.hxx,v $
 * $Revision: 1.12 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _SC_XMLDETECTIVECONTEXT_HXX
#define _SC_XMLDETECTIVECONTEXT_HXX

#include <xmloff/xmlimp.hxx>
#include <com/sun/star/table/CellRangeAddress.hpp>
#include "detfunc.hxx"
#include "detdata.hxx"

#include <list>

class ScXMLImport;

//___________________________________________________________________

struct ScMyImpDetectiveObj
{
    ScRange                     aSourceRange;
    ScDetectiveObjType          eObjType;
    sal_Bool                    bHasError;

                                ScMyImpDetectiveObj();
};

typedef ::std::vector< ScMyImpDetectiveObj > ScMyImpDetectiveObjVec;

//___________________________________________________________________

struct ScMyImpDetectiveOp
{
    ScAddress                   aPosition;
    ScDetOpType                 eOpType;
    sal_Int32                   nIndex;

    inline                      ScMyImpDetectiveOp() : nIndex( -1 ) {}
    sal_Bool                    operator<(const ScMyImpDetectiveOp& rDetOp) const;
};

typedef ::std::list< ScMyImpDetectiveOp > ScMyImpDetectiveOpList;

class ScMyImpDetectiveOpArray
{
private:
    ScMyImpDetectiveOpList      aDetectiveOpList;

public:
    inline                      ScMyImpDetectiveOpArray() :
                                    aDetectiveOpList()  {}

    inline void                 AddDetectiveOp( const ScMyImpDetectiveOp& rDetOp )
                                    { aDetectiveOpList.push_back( rDetOp ); }

    void                        Sort();
    sal_Bool                    GetFirstOp( ScMyImpDetectiveOp& rDetOp );
};

//___________________________________________________________________

class ScXMLDetectiveContext : public SvXMLImportContext
{
private:
    ScMyImpDetectiveObjVec*     pDetectiveObjVec;

    const ScXMLImport&          GetScImport() const { return (const ScXMLImport&)GetImport(); }
    ScXMLImport&                GetScImport()       { return (ScXMLImport&)GetImport(); }

public:
                                ScXMLDetectiveContext(
                                    ScXMLImport& rImport,
                                    USHORT nPrfx,
                                    const ::rtl::OUString& rLName,
                                    ScMyImpDetectiveObjVec* pNewDetectiveObjVec
                                    );
    virtual                     ~ScXMLDetectiveContext();

    virtual SvXMLImportContext* CreateChildContext(
                                    USHORT nPrefix,
                                    const ::rtl::OUString& rLocalName,
                                    const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& xAttrList
                                    );
    virtual void                EndElement();
};

//___________________________________________________________________

class ScXMLDetectiveHighlightedContext : public SvXMLImportContext
{
private:
    ScMyImpDetectiveObjVec*     pDetectiveObjVec;
    ScMyImpDetectiveObj         aDetectiveObj;
    sal_Bool                    bValid;

    const ScXMLImport&          GetScImport() const { return (const ScXMLImport&)GetImport(); }
    ScXMLImport&                GetScImport()       { return (ScXMLImport&)GetImport(); }

public:
                                ScXMLDetectiveHighlightedContext(
                                    ScXMLImport& rImport,
                                    USHORT nPrfx,
                                    const ::rtl::OUString& rLName,
                                    const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& xAttrList,
                                    ScMyImpDetectiveObjVec* pNewDetectiveObjVec
                                    );
    virtual                     ~ScXMLDetectiveHighlightedContext();

    virtual SvXMLImportContext* CreateChildContext(
                                    USHORT nPrefix,
                                    const ::rtl::OUString& rLocalName,
                                    const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& xAttrList
                                    );
    virtual void                EndElement();
};

//___________________________________________________________________

class ScXMLDetectiveOperationContext : public SvXMLImportContext
{
private:
    ScMyImpDetectiveOp          aDetectiveOp;
    sal_Bool                    bHasType;

    const ScXMLImport&          GetScImport() const { return (const ScXMLImport&)GetImport(); }
    ScXMLImport&                GetScImport()       { return (ScXMLImport&)GetImport(); }

public:
                                ScXMLDetectiveOperationContext(
                                    ScXMLImport& rImport,
                                    USHORT nPrfx,
                                    const ::rtl::OUString& rLName,
                                    const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& xAttrList
                                    );
    virtual                     ~ScXMLDetectiveOperationContext();

    virtual SvXMLImportContext* CreateChildContext(
                                    USHORT nPrefix,
                                    const ::rtl::OUString& rLocalName,
                                    const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& xAttrList
                                    );
    virtual void                EndElement();
};

#endif

<commit_msg>INTEGRATION: CWS dr61 (1.12.16); FILE MERGED 2008/05/19 12:24:04 dr 1.12.16.1: #i10000# removed remaining include guards<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: XMLDetectiveContext.hxx,v $
 * $Revision: 1.13 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef SC_XMLDETECTIVECONTEXT_HXX
#define SC_XMLDETECTIVECONTEXT_HXX

#include <xmloff/xmlimp.hxx>
#include <com/sun/star/table/CellRangeAddress.hpp>
#include "detfunc.hxx"
#include "detdata.hxx"

#include <list>

class ScXMLImport;

//___________________________________________________________________

struct ScMyImpDetectiveObj
{
    ScRange                     aSourceRange;
    ScDetectiveObjType          eObjType;
    sal_Bool                    bHasError;

                                ScMyImpDetectiveObj();
};

typedef ::std::vector< ScMyImpDetectiveObj > ScMyImpDetectiveObjVec;

//___________________________________________________________________

struct ScMyImpDetectiveOp
{
    ScAddress                   aPosition;
    ScDetOpType                 eOpType;
    sal_Int32                   nIndex;

    inline                      ScMyImpDetectiveOp() : nIndex( -1 ) {}
    sal_Bool                    operator<(const ScMyImpDetectiveOp& rDetOp) const;
};

typedef ::std::list< ScMyImpDetectiveOp > ScMyImpDetectiveOpList;

class ScMyImpDetectiveOpArray
{
private:
    ScMyImpDetectiveOpList      aDetectiveOpList;

public:
    inline                      ScMyImpDetectiveOpArray() :
                                    aDetectiveOpList()  {}

    inline void                 AddDetectiveOp( const ScMyImpDetectiveOp& rDetOp )
                                    { aDetectiveOpList.push_back( rDetOp ); }

    void                        Sort();
    sal_Bool                    GetFirstOp( ScMyImpDetectiveOp& rDetOp );
};

//___________________________________________________________________

class ScXMLDetectiveContext : public SvXMLImportContext
{
private:
    ScMyImpDetectiveObjVec*     pDetectiveObjVec;

    const ScXMLImport&          GetScImport() const { return (const ScXMLImport&)GetImport(); }
    ScXMLImport&                GetScImport()       { return (ScXMLImport&)GetImport(); }

public:
                                ScXMLDetectiveContext(
                                    ScXMLImport& rImport,
                                    USHORT nPrfx,
                                    const ::rtl::OUString& rLName,
                                    ScMyImpDetectiveObjVec* pNewDetectiveObjVec
                                    );
    virtual                     ~ScXMLDetectiveContext();

    virtual SvXMLImportContext* CreateChildContext(
                                    USHORT nPrefix,
                                    const ::rtl::OUString& rLocalName,
                                    const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& xAttrList
                                    );
    virtual void                EndElement();
};

//___________________________________________________________________

class ScXMLDetectiveHighlightedContext : public SvXMLImportContext
{
private:
    ScMyImpDetectiveObjVec*     pDetectiveObjVec;
    ScMyImpDetectiveObj         aDetectiveObj;
    sal_Bool                    bValid;

    const ScXMLImport&          GetScImport() const { return (const ScXMLImport&)GetImport(); }
    ScXMLImport&                GetScImport()       { return (ScXMLImport&)GetImport(); }

public:
                                ScXMLDetectiveHighlightedContext(
                                    ScXMLImport& rImport,
                                    USHORT nPrfx,
                                    const ::rtl::OUString& rLName,
                                    const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& xAttrList,
                                    ScMyImpDetectiveObjVec* pNewDetectiveObjVec
                                    );
    virtual                     ~ScXMLDetectiveHighlightedContext();

    virtual SvXMLImportContext* CreateChildContext(
                                    USHORT nPrefix,
                                    const ::rtl::OUString& rLocalName,
                                    const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& xAttrList
                                    );
    virtual void                EndElement();
};

//___________________________________________________________________

class ScXMLDetectiveOperationContext : public SvXMLImportContext
{
private:
    ScMyImpDetectiveOp          aDetectiveOp;
    sal_Bool                    bHasType;

    const ScXMLImport&          GetScImport() const { return (const ScXMLImport&)GetImport(); }
    ScXMLImport&                GetScImport()       { return (ScXMLImport&)GetImport(); }

public:
                                ScXMLDetectiveOperationContext(
                                    ScXMLImport& rImport,
                                    USHORT nPrfx,
                                    const ::rtl::OUString& rLName,
                                    const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& xAttrList
                                    );
    virtual                     ~ScXMLDetectiveOperationContext();

    virtual SvXMLImportContext* CreateChildContext(
                                    USHORT nPrefix,
                                    const ::rtl::OUString& rLocalName,
                                    const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& xAttrList
                                    );
    virtual void                EndElement();
};

#endif

<|endoftext|>


<commit_before>#ifndef __RANGE__H__
#define __RANGE__H__

// range() for range-based loops with start, stop, and step.
//
// Acceptable forms are:
// for (auto i : range(stop)) { ... } // start = 0, step = 1
// for (auto i : range(start, stop)) { ... } // step = 1
// for (auto i : range(start, stop, step)) { ... }
//
// The start may be greater than the stop if the range is negative
// The range will effectively be empty if:
//   1) step is positive and start > stop
//   2) step is negative and start < stop
//
// If a step of 0 is provided, a RangeException will be thrown

#include <exception>

namespace iter {

    // Thrown when step 0 occurs
    class RangeException : public std::exception {
        virtual const char *what() const noexcept {
            return "range step must be non-zero";
        }
    };

    //Forward declarations of Enumerable and enumerate
    template <typename T>
    class Range;

    template <typename T>
    Range<T> range(T);
    template <typename T>
    Range<T> range(T, T);
    template <typename T>
    Range<T> range(T, T, T);

    template <typename T>
    class Range {
        friend Range range<T>(T);
        friend Range range<T>(T, T);
        friend Range range<T>(T, T, T);
        private:
            const T start;
            const T stop;
            const T step;

            Range(T stop) :
                start(0),
                stop(stop),
                step(1)
            { }

            Range(T start, T stop, T step=1) :
                start(start),
                stop(stop),
                step(step)
            { }

        public:
            Range() = delete;
            Range(const Range &) = default;
            class Iterator {
                private:
                    T value;
                    const T step;
                public:
                    Iterator(T val, T step) :
                        value(val),
                        step(step)
                    { }

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

                    Iterator & operator++() {
                        this->value += this->step;
                        return *this;
                    }

                    // This operator would more accurately read as "in bounds"
                    // or "incomplete" because exact comparison with the end
                    // isn't good enough for the purposes of this Iterator.
                    // There are two odd cases that need to be handled
                    //
                    // 1) The Range is infinite, such as
                    // Range (-1, 0, -1) which would go forever down toward
                    // infinitely (theoretically).  If this occurs, the Range
                    // will instead effectively be empty
                    //
                    // 2) (stop - start) % step != 0.  For
                    // example Range(1, 10, 2).  The iterator will never be
                    // exactly equal to the stop value.
                    bool operator!=(const Range::Iterator & other) const {
				         return not_equal_to(other, typename std::is_unsigned<T>::type());
			        }
			  private:
			        bool not_equal_to(const Range::Iterator& other, std::true_type /*unsigned*/) const{
					     return this->value < other.value;
			        }
			        bool not_equal_to(const Range::Iterator& other, std::false_type /*signed*/) const{
					     return !(this->step > 0 && this->value >= other.value)
						   && !(this->step < 0 && this->value <= other.value);
			        }
            };

            Iterator begin() const {
                return Iterator(start, step);
            }

            Iterator end() const {
                return Iterator(stop, step);
            }
    };

    template <typename T>
    Range<T> range(T stop) {
        return Range<T>(stop);
    }

    template <typename T>
    Range<T> range(T start, T stop) {
        return Range<T>(start, stop);
    }

    template <typename T>
    Range<T> range(T start, T stop, T step) {
        if (step == 0) {
            throw RangeException();
        }
        return Range<T>(start, stop, step);
    }
}

#endif //ifndef __RANGE__H__
<commit_msg>added include for type_traits<commit_after>#ifndef __RANGE__H__
#define __RANGE__H__

// range() for range-based loops with start, stop, and step.
//
// Acceptable forms are:
// for (auto i : range(stop)) { ... } // start = 0, step = 1
// for (auto i : range(start, stop)) { ... } // step = 1
// for (auto i : range(start, stop, step)) { ... }
//
// The start may be greater than the stop if the range is negative
// The range will effectively be empty if:
//   1) step is positive and start > stop
//   2) step is negative and start < stop
//
// If a step of 0 is provided, a RangeException will be thrown

#include <exception>
#include <type_traits>

namespace iter {

    // Thrown when step 0 occurs
    class RangeException : public std::exception {
        virtual const char *what() const noexcept {
            return "range step must be non-zero";
        }
    };

    //Forward declarations of Enumerable and enumerate
    template <typename T>
    class Range;

    template <typename T>
    Range<T> range(T);
    template <typename T>
    Range<T> range(T, T);
    template <typename T>
    Range<T> range(T, T, T);

    template <typename T>
    class Range {
        friend Range range<T>(T);
        friend Range range<T>(T, T);
        friend Range range<T>(T, T, T);
        private:
            const T start;
            const T stop;
            const T step;

            Range(T stop) :
                start(0),
                stop(stop),
                step(1)
            { }

            Range(T start, T stop, T step=1) :
                start(start),
                stop(stop),
                step(step)
            { }

        public:
            Range() = delete;
            Range(const Range &) = default;
            class Iterator {
                private:
                    T value;
                    const T step;
                public:
                    Iterator(T val, T step) :
                        value(val),
                        step(step)
                    { }

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

                    Iterator & operator++() {
                        this->value += this->step;
                        return *this;
                    }

                    // This operator would more accurately read as "in bounds"
                    // or "incomplete" because exact comparison with the end
                    // isn't good enough for the purposes of this Iterator.
                    // There are two odd cases that need to be handled
                    //
                    // 1) The Range is infinite, such as
                    // Range (-1, 0, -1) which would go forever down toward
                    // infinitely (theoretically).  If this occurs, the Range
                    // will instead effectively be empty
                    //
                    // 2) (stop - start) % step != 0.  For
                    // example Range(1, 10, 2).  The iterator will never be
                    // exactly equal to the stop value.
                    bool operator!=(const Range::Iterator & other) const {
				         return not_equal_to(other, typename std::is_unsigned<T>::type());
			        }
			  private:
			        bool not_equal_to(const Range::Iterator& other, std::true_type /*unsigned*/) const{
					     return this->value < other.value;
			        }
			        bool not_equal_to(const Range::Iterator& other, std::false_type /*signed*/) const{
					     return !(this->step > 0 && this->value >= other.value)
						   && !(this->step < 0 && this->value <= other.value);
			        }
            };

            Iterator begin() const {
                return Iterator(start, step);
            }

            Iterator end() const {
                return Iterator(stop, step);
            }
    };

    template <typename T>
    Range<T> range(T stop) {
        return Range<T>(stop);
    }

    template <typename T>
    Range<T> range(T start, T stop) {
        return Range<T>(start, stop);
    }

    template <typename T>
    Range<T> range(T start, T stop, T step) {
        if (step == 0) {
            throw RangeException();
        }
        return Range<T>(start, stop, step);
    }
}

#endif //ifndef __RANGE__H__
<|endoftext|>


<commit_before>#ifndef TEST_LINKED_LIST_H_
#define TEST_LINKED_LIST_H_

#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>

#include "types/linkedlist.hpp"

BOOST_AUTO_TEST_CASE(test_create_linkedlist)
{
    LinkedList<int> list;
    BOOST_TEST(true);
}

BOOST_AUTO_TEST_CASE(test_create_with_size)
{
    LinkedList<int> list(5, 42);
    BOOST_TEST(false == list.isEmpty());
    BOOST_TEST(5 == list.size());
    BOOST_TEST(42 == list.at(0));
    BOOST_TEST(42 == list.at(1));
    BOOST_TEST(42 == list.at(2));
    BOOST_TEST(42 == list.at(3));
    BOOST_TEST(42 == list.at(4));
}

BOOST_AUTO_TEST_CASE(test_add_elements)
{
    LinkedList<int> list;
    BOOST_TEST(list.isEmpty());

    list.addLast(1);
    list.addLast(2);
    list.addLast(3);
    list.addLast(4);

    BOOST_TEST(false == list.isEmpty());
    BOOST_TEST(4 == list.size());
    BOOST_TEST(1 == list.first());
    BOOST_TEST(4 == list.last());
}

BOOST_AUTO_TEST_CASE(test_clear)
{
    LinkedList<int> list;
    list.clear();
    BOOST_TEST(true == list.isEmpty());
    BOOST_TEST(0 == list.size());

    list.addLast(1);
    list.addLast(2);
    list.clear();

    BOOST_TEST(true == list.isEmpty());
    BOOST_TEST(0 == list.size());
}

BOOST_AUTO_TEST_CASE(test_first_last)
{
    LinkedList<unsigned int> list;

    BOOST_CHECK_THROW(list.first(), std::length_error);
    BOOST_CHECK_THROW(list.last(), std::length_error);

    list.addLast(186);
    list.addLast(187);
    list.addLast(28786);

    BOOST_TEST(186 == list.first());
    BOOST_TEST(28786 == list.last());
}

BOOST_AUTO_TEST_CASE(test_at)
{
    LinkedList<unsigned int> list;

    BOOST_CHECK_THROW(list.at(0), std::length_error);

    list.addLast(186);
    list.addLast(187);
    list.addLast(28786);

    BOOST_CHECK_THROW(list.at(-156), std::runtime_error);
    BOOST_CHECK_THROW(list.at(10), std::runtime_error);

    BOOST_TEST(186 == list.at(0));
    BOOST_TEST(187 == list.at(1));
    BOOST_TEST(28786 == list.at(2));
}

BOOST_AUTO_TEST_CASE(test_add_first)
{
    LinkedList<unsigned int> list;
    list.addFirst(186);
    list.addLast(187);
    list.addFirst(28786);

    BOOST_TEST(3 == list.size());
    BOOST_TEST(28786 == list.first());
    BOOST_TEST(186 == list.at(1));
    BOOST_TEST(187 == list.last());
}

BOOST_AUTO_TEST_CASE(test_add_last)
{
    LinkedList<unsigned int> list;
    list.addLast(186);
    list.addLast(187);

    BOOST_TEST(186 == list.first());
    BOOST_TEST(187 == list.last());
}

BOOST_AUTO_TEST_CASE(test_insert)
{
    LinkedList<unsigned int> list;
    list.insert(-100, 1);
    list.insert(1500, 2);
    list.insert(0, 3);
    list.insert(1, 4);

    BOOST_TEST(3 == list.at(0));
    BOOST_TEST(4 == list.at(1));
    BOOST_TEST(1 == list.at(2));
    BOOST_TEST(2 == list.at(3));
}

BOOST_AUTO_TEST_CASE(test_remove)
{
    LinkedList<int> list;
    list.remove(0);
    list.addLast(-100);
    list.addLast(1500);
    list.addLast(0);
    list.addLast(1);

    list.remove(-100);
    list.remove(1501);

    list.remove(1);
    BOOST_TEST(3 == list.size());
    BOOST_TEST(-100 == list.at(0));
    BOOST_TEST(0 == list.at(1));
    BOOST_TEST(1 == list.at(2));

    list.remove(2);
    BOOST_TEST(2 == list.size());
    BOOST_TEST(-100 == list.at(0));
    BOOST_TEST(0 == list.at(1));

    list.remove(0);
    BOOST_TEST(1 == list.size());
    BOOST_TEST(0 == list.at(0));

    list.remove(0);
    BOOST_TEST(0 == list.size());
    BOOST_TEST(true == list.isEmpty());
}

BOOST_AUTO_TEST_CASE(test_remove_first)
{
    BOOST_TEST(false);
}

BOOST_AUTO_TEST_CASE(test_remove_last)
{
    BOOST_TEST(false);
}

#endif /* TEST_LINKED_LIST_H_ */
<commit_msg>Test LinkedList removeFirst() and removeLast()<commit_after>#ifndef TEST_LINKED_LIST_H_
#define TEST_LINKED_LIST_H_

#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>

#include "types/linkedlist.hpp"

BOOST_AUTO_TEST_CASE(test_create_linkedlist)
{
    LinkedList<int> list;
    BOOST_TEST(true);
}

BOOST_AUTO_TEST_CASE(test_create_with_size)
{
    LinkedList<int> list(5, 42);
    BOOST_TEST(false == list.isEmpty());
    BOOST_TEST(5 == list.size());
    BOOST_TEST(42 == list.at(0));
    BOOST_TEST(42 == list.at(1));
    BOOST_TEST(42 == list.at(2));
    BOOST_TEST(42 == list.at(3));
    BOOST_TEST(42 == list.at(4));
}

BOOST_AUTO_TEST_CASE(test_add_elements)
{
    LinkedList<int> list;
    BOOST_TEST(list.isEmpty());

    list.addLast(1);
    list.addLast(2);
    list.addLast(3);
    list.addLast(4);

    BOOST_TEST(false == list.isEmpty());
    BOOST_TEST(4 == list.size());
    BOOST_TEST(1 == list.first());
    BOOST_TEST(4 == list.last());
}

BOOST_AUTO_TEST_CASE(test_clear)
{
    LinkedList<int> list;
    list.clear();
    BOOST_TEST(true == list.isEmpty());
    BOOST_TEST(0 == list.size());

    list.addLast(1);
    list.addLast(2);
    list.clear();

    BOOST_TEST(true == list.isEmpty());
    BOOST_TEST(0 == list.size());
}

BOOST_AUTO_TEST_CASE(test_first_last)
{
    LinkedList<unsigned int> list;

    BOOST_CHECK_THROW(list.first(), std::length_error);
    BOOST_CHECK_THROW(list.last(), std::length_error);

    list.addLast(186);
    list.addLast(187);
    list.addLast(28786);

    BOOST_TEST(186 == list.first());
    BOOST_TEST(28786 == list.last());
}

BOOST_AUTO_TEST_CASE(test_at)
{
    LinkedList<unsigned int> list;

    BOOST_CHECK_THROW(list.at(0), std::length_error);

    list.addLast(186);
    list.addLast(187);
    list.addLast(28786);

    BOOST_CHECK_THROW(list.at(-156), std::runtime_error);
    BOOST_CHECK_THROW(list.at(10), std::runtime_error);

    BOOST_TEST(186 == list.at(0));
    BOOST_TEST(187 == list.at(1));
    BOOST_TEST(28786 == list.at(2));
}

BOOST_AUTO_TEST_CASE(test_add_first)
{
    LinkedList<unsigned int> list;
    list.addFirst(186);
    list.addLast(187);
    list.addFirst(28786);

    BOOST_TEST(3 == list.size());
    BOOST_TEST(28786 == list.first());
    BOOST_TEST(186 == list.at(1));
    BOOST_TEST(187 == list.last());
}

BOOST_AUTO_TEST_CASE(test_add_last)
{
    LinkedList<unsigned int> list;
    list.addLast(186);
    list.addLast(187);

    BOOST_TEST(186 == list.first());
    BOOST_TEST(187 == list.last());
}

BOOST_AUTO_TEST_CASE(test_insert)
{
    LinkedList<unsigned int> list;
    list.insert(-100, 1);
    list.insert(1500, 2);
    list.insert(0, 3);
    list.insert(1, 4);

    BOOST_TEST(3 == list.at(0));
    BOOST_TEST(4 == list.at(1));
    BOOST_TEST(1 == list.at(2));
    BOOST_TEST(2 == list.at(3));
}

BOOST_AUTO_TEST_CASE(test_remove)
{
    LinkedList<int> list;
    list.remove(0);
    list.addLast(-100);
    list.addLast(1500);
    list.addLast(0);
    list.addLast(1);

    list.remove(-100);
    list.remove(1501);

    list.remove(1);
    BOOST_TEST(3 == list.size());
    BOOST_TEST(-100 == list.at(0));
    BOOST_TEST(0 == list.at(1));
    BOOST_TEST(1 == list.at(2));

    list.remove(2);
    BOOST_TEST(2 == list.size());
    BOOST_TEST(-100 == list.at(0));
    BOOST_TEST(0 == list.at(1));

    list.remove(0);
    BOOST_TEST(1 == list.size());
    BOOST_TEST(0 == list.at(0));

    list.remove(0);
    BOOST_TEST(0 == list.size());
    BOOST_TEST(true == list.isEmpty());
}

BOOST_AUTO_TEST_CASE(test_remove_first)
{
    LinkedList<unsigned int> list;
    list.addLast(1);
    list.addLast(2);
    list.addLast(3);
    list.addLast(4);

    list.removeFirst();
    BOOST_TEST(3 == list.size());
    BOOST_TEST(2 == list.at(0));
    BOOST_TEST(3 == list.at(1));
    BOOST_TEST(4 == list.at(2));

    list.removeFirst();
    BOOST_TEST(2 == list.size());
    BOOST_TEST(3 == list.at(0));
    BOOST_TEST(4 == list.at(1));

    list.removeFirst();
    BOOST_TEST(1 == list.size());
    BOOST_TEST(4 == list.at(0));

    list.removeFirst();
    BOOST_TEST(0 == list.size());
}

BOOST_AUTO_TEST_CASE(test_remove_last)
{
    LinkedList<unsigned int> list;
    list.addLast(1);
    list.addLast(2);
    list.addLast(3);
    list.addLast(4);

    list.removeLast();
    BOOST_TEST(3 == list.size());
    BOOST_TEST(1 == list.at(0));
    BOOST_TEST(2 == list.at(1));
    BOOST_TEST(3 == list.at(2));

    list.removeLast();
    BOOST_TEST(2 == list.size());
    BOOST_TEST(1 == list.at(0));
    BOOST_TEST(2 == list.at(1));

    list.removeLast();
    BOOST_TEST(1 == list.size());
    BOOST_TEST(1 == list.at(0));

    list.removeLast();
    BOOST_TEST(0 == list.size());
}

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


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#define LOK_USE_UNSTABLE_API
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
#include <com/sun/star/frame/Desktop.hpp>
#include <comphelper/processfactory.hxx>
#include <comphelper/string.hxx>
#include <test/bootstrapfixture.hxx>
#include <test/xmltesttools.hxx>
#include <unotest/macros_test.hxx>

#include <DrawDocShell.hxx>
#include <ViewShell.hxx>
#include <unomodel.hxx>

using namespace css;

static const char* DATA_DIRECTORY = "/sd/qa/unit/tiledrendering/data/";

class SdTiledRenderingTest : public test::BootstrapFixture, public unotest::MacrosTest, public XmlTestTools
{
public:
    virtual void setUp() SAL_OVERRIDE;
    virtual void tearDown() SAL_OVERRIDE;

    void testRegisterCallback();

    CPPUNIT_TEST_SUITE(SdTiledRenderingTest);
#if !defined(WNT) && !defined(MACOSX)
    CPPUNIT_TEST(testRegisterCallback);
#endif
    CPPUNIT_TEST_SUITE_END();

private:
    SdXImpressDocument* createDoc(const char* pName);
    static void callback(int nType, const char* pPayload, void* pData);
    void callbackImpl(int nType, const char* pPayload);

    uno::Reference<lang::XComponent> mxComponent;
    Rectangle m_aInvalidation;
};

void SdTiledRenderingTest::setUp()
{
    test::BootstrapFixture::setUp();

    mxDesktop.set(css::frame::Desktop::create(comphelper::getComponentContext(getMultiServiceFactory())));
}

void SdTiledRenderingTest::tearDown()
{
    if (mxComponent.is())
        mxComponent->dispose();

    test::BootstrapFixture::tearDown();
}

SdXImpressDocument* SdTiledRenderingTest::createDoc(const char* pName)
{
    if (mxComponent.is())
        mxComponent->dispose();
    mxComponent = loadFromDesktop(getURLFromSrc(DATA_DIRECTORY) + OUString::createFromAscii(pName), "com.sun.star.presentation.PresentationDocument");
    SdXImpressDocument* pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
    CPPUNIT_ASSERT(pImpressDocument);
    pImpressDocument->initializeForTiledRendering();
    return pImpressDocument;
}

void SdTiledRenderingTest::callback(int nType, const char* pPayload, void* pData)
{
    static_cast<SdTiledRenderingTest*>(pData)->callbackImpl(nType, pPayload);
}

void SdTiledRenderingTest::callbackImpl(int nType, const char* pPayload)
{
    switch (nType)
    {
    case LOK_CALLBACK_INVALIDATE_TILES:
    {
        OUString aPayload = OUString::createFromAscii(pPayload);
        if (aPayload != "EMPTY" && m_aInvalidation.IsEmpty())
        {
            uno::Sequence<OUString> aSeq = comphelper::string::convertCommaSeparated(aPayload);
            CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(4), aSeq.getLength());
            m_aInvalidation.setX(aSeq[0].toInt32());
            m_aInvalidation.setY(aSeq[1].toInt32());
            m_aInvalidation.setWidth(aSeq[2].toInt32());
            m_aInvalidation.setHeight(aSeq[3].toInt32());
        }
    }
    break;
    }
}

void SdTiledRenderingTest::testRegisterCallback()
{
    // Tests sd::Window::LogicInvalidate().
    SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp");
    pXImpressDocument->registerCallback(&SdTiledRenderingTest::callback, this);
    sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();

    // Append a character to the empty title shape.
    vcl::KeyCode aKeyCode(0, 0);
    KeyEvent aKeyEvent(static_cast<sal_Unicode>('x'), aKeyCode, 0);
    pViewShell->KeyInput(aKeyEvent, 0);
    mxComponent->dispose();

    // Check that the top left 256x256px tile would be invalidated.
    CPPUNIT_ASSERT(!m_aInvalidation.IsEmpty());
    Rectangle aTopLeft(0, 0, 256*15, 256*15); // 1 px = 15 twips, assuming 96 DPI.
    CPPUNIT_ASSERT(m_aInvalidation.IsOver(aTopLeft));
}

CPPUNIT_TEST_SUITE_REGISTRATION(SdTiledRenderingTest);

CPPUNIT_PLUGIN_IMPLEMENT();

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>Add SdXImpressDocument::postMouseEvent() testcase.<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#define LOK_USE_UNSTABLE_API
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
#include <com/sun/star/frame/Desktop.hpp>
#include <comphelper/processfactory.hxx>
#include <comphelper/string.hxx>
#include <editeng/editids.hrc>
#include <editeng/editview.hxx>
#include <editeng/outliner.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/viewfrm.hxx>
#include <test/bootstrapfixture.hxx>
#include <test/xmltesttools.hxx>
#include <unotest/macros_test.hxx>

#include <DrawDocShell.hxx>
#include <ViewShell.hxx>
#include <sdpage.hxx>
#include <unomodel.hxx>

using namespace css;

static const char* DATA_DIRECTORY = "/sd/qa/unit/tiledrendering/data/";

class SdTiledRenderingTest : public test::BootstrapFixture, public unotest::MacrosTest, public XmlTestTools
{
public:
    virtual void setUp() SAL_OVERRIDE;
    virtual void tearDown() SAL_OVERRIDE;

    void testRegisterCallback();
    void testPostMouseEvent();

    CPPUNIT_TEST_SUITE(SdTiledRenderingTest);
#if !defined(WNT) && !defined(MACOSX)
    CPPUNIT_TEST(testRegisterCallback);
    CPPUNIT_TEST(testPostMouseEvent);
#endif
    CPPUNIT_TEST_SUITE_END();

private:
    SdXImpressDocument* createDoc(const char* pName);
    static void callback(int nType, const char* pPayload, void* pData);
    void callbackImpl(int nType, const char* pPayload);

    uno::Reference<lang::XComponent> mxComponent;
    Rectangle m_aInvalidation;
};

void SdTiledRenderingTest::setUp()
{
    test::BootstrapFixture::setUp();

    mxDesktop.set(css::frame::Desktop::create(comphelper::getComponentContext(getMultiServiceFactory())));
}

void SdTiledRenderingTest::tearDown()
{
    if (mxComponent.is())
        mxComponent->dispose();

    test::BootstrapFixture::tearDown();
}

SdXImpressDocument* SdTiledRenderingTest::createDoc(const char* pName)
{
    if (mxComponent.is())
        mxComponent->dispose();
    mxComponent = loadFromDesktop(getURLFromSrc(DATA_DIRECTORY) + OUString::createFromAscii(pName), "com.sun.star.presentation.PresentationDocument");
    SdXImpressDocument* pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get());
    CPPUNIT_ASSERT(pImpressDocument);
    pImpressDocument->initializeForTiledRendering();
    return pImpressDocument;
}

void SdTiledRenderingTest::callback(int nType, const char* pPayload, void* pData)
{
    static_cast<SdTiledRenderingTest*>(pData)->callbackImpl(nType, pPayload);
}

void SdTiledRenderingTest::callbackImpl(int nType, const char* pPayload)
{
    switch (nType)
    {
    case LOK_CALLBACK_INVALIDATE_TILES:
    {
        OUString aPayload = OUString::createFromAscii(pPayload);
        if (aPayload != "EMPTY" && m_aInvalidation.IsEmpty())
        {
            uno::Sequence<OUString> aSeq = comphelper::string::convertCommaSeparated(aPayload);
            CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(4), aSeq.getLength());
            m_aInvalidation.setX(aSeq[0].toInt32());
            m_aInvalidation.setY(aSeq[1].toInt32());
            m_aInvalidation.setWidth(aSeq[2].toInt32());
            m_aInvalidation.setHeight(aSeq[3].toInt32());
        }
    }
    break;
    }
}

void SdTiledRenderingTest::testRegisterCallback()
{
    // Tests sd::Window::LogicInvalidate().
    SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp");
    pXImpressDocument->registerCallback(&SdTiledRenderingTest::callback, this);
    sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();

    // Append a character to the empty title shape.
    vcl::KeyCode aKeyCode(0, 0);
    KeyEvent aKeyEvent(static_cast<sal_Unicode>('x'), aKeyCode, 0);
    pViewShell->KeyInput(aKeyEvent, 0);
    mxComponent->dispose();

    // Check that the top left 256x256px tile would be invalidated.
    CPPUNIT_ASSERT(!m_aInvalidation.IsEmpty());
    Rectangle aTopLeft(0, 0, 256*15, 256*15); // 1 px = 15 twips, assuming 96 DPI.
    CPPUNIT_ASSERT(m_aInvalidation.IsOver(aTopLeft));
}

void SdTiledRenderingTest::testPostMouseEvent()
{
    SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp");
    sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
    SdPage* pActualPage = pViewShell->GetActualPage();
    SdrObject* pObject = pActualPage->GetObj(0);
    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(OBJ_TITLETEXT), pObject->GetObjIdentifier());
    SdrTextObj* pTextObj = static_cast<SdrTextObj*>(pObject);
    SdrView* pView = pViewShell->GetView();
    pView->MarkObj(pTextObj, pView->GetSdrPageView());
    SfxStringItem aInputString(SID_ATTR_CHAR, "x");
    pViewShell->GetViewFrame()->GetDispatcher()->Execute(SID_ATTR_CHAR, SfxCallMode::SYNCHRON, &aInputString, 0);
    CPPUNIT_ASSERT(pView->GetTextEditObject());
    EditView& rEditView = pView->GetTextEditOutlinerView()->GetEditView();
    // Did we manage to go after the first character?
    CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), rEditView.GetSelection().nStartPos);

    vcl::Cursor* pCursor = rEditView.GetCursor();
    Point aPosition = pCursor->GetPos();
    aPosition.setX(aPosition.getX() - 1000);
    pXImpressDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONDOWN, convertMm100ToTwip(aPosition.getX()), convertMm100ToTwip(aPosition.getY()), 1);
    pXImpressDocument->postMouseEvent(LOK_MOUSEEVENT_MOUSEBUTTONUP, convertMm100ToTwip(aPosition.getX()), convertMm100ToTwip(aPosition.getY()), 1);
    CPPUNIT_ASSERT(pView->GetTextEditObject());
    // The new cursor position must be before the first word.
    CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), rEditView.GetSelection().nStartPos);
}

CPPUNIT_TEST_SUITE_REGISTRATION(SdTiledRenderingTest);

CPPUNIT_PLUGIN_IMPLEMENT();

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>#include <iostream>
#include <random>

#include "featurizer.h"
#include "fm.h"

using namespace lightfm;
using namespace std;

/* Some test code copied from Crow.
 * Should check the license later on.
 */

bool failed__ = false;
void error_print()
{
    cerr << endl;
}

template <typename A, typename ...Args>
void error_print(const A& a, Args...args)
{
    cerr<<a;
    error_print(args...);
}

template <typename ...Args>
void fail(Args...args) { error_print(args...);failed__ = true; }

#define ASSERT_TRUE(x) if (!(x)) fail(__FILE__ ":", __LINE__, ": Assert fail: expected ", #x, " is true, at " __FILE__ ":",__LINE__)
#define ASSERT_EQUAL(a, b) if ((a) != (b)) fail(__FILE__ ":", __LINE__, ": Assert fail: expected ", (a), " actual " , (b),  ", " #a " == " #b ", at " __FILE__ ":",__LINE__)
#define ASSERT_NOTEQUAL(a, b) if ((a) == (b)) fail(__FILE__ ":", __LINE__, ": Assert fail: not expected ", (a), ", " #a " != " #b ", at " __FILE__ ":",__LINE__)
#define ASSERT_FLOAT_EQUAL(a, b) if (((a) == (b)) || (fabs((a) - (b)) <= ( (fabs((a)) > fabs((b)) ? fabs((b)) : fabs((a))) * std::numeric_limits<double>::epsilon())) ) fail(__FILE__ ":", __LINE__, ": Assert fail: expected ", (a), " actual  ", (b), ", " #a " == " #b ", at " __FILE__ ":",__LINE__)

int main() {
    Featurizer f = Featurizer();
    ASSERT_EQUAL(0, f.size());
    ASSERT_NOTEQUAL(1, f.size());

    vector<string> features = {"what", "i", "cannot", "create", "i", "do", "not", "understand"};
    for (auto const& x: features) {
        f.add_feature(x);
    }
    ASSERT_EQUAL(7, f.size());  // `i` is counted twice.

    vector<int> indices = f.get_feature_indices(vector<string>({"i", "cannot", "tell", "you", "what", "knowledge", "is" }));
    ASSERT_EQUAL(10, indices[indices.size() - 1]);

    // proper randomized algorithm should use random_device
    int seed = 44;
    int k = 3;

    default_random_engine e1(seed);
    FM fm = FM(k, e1);

    vector<int> guess_index({0, 1, 2});
    vector<double> guess_weights({1.5, 0.2, 2.0});
    double guess = fm.predict(guess_index, guess_weights);
    ASSERT_EQUAL(guess_index.size(), fm.vi.size());
    ASSERT_EQUAL(k, fm.vi[0].size());

    // Naive calculation. O(kn^2). Actual implementation takes O(kn).
    double result = fm.w0;
    for (int i = 0; i < fm.wi.size(); ++i) {
        result += fm.wi[i] * guess_weights[i];
    }
    double tmp = 0.0;
    for (int i = 0; i < guess_index.size(); ++i) {
        for (int j = 0; j < guess_index.size(); ++j) {
            double v_dot = 0.0;
            for (int l = 0; l < k; ++l) {
                v_dot += fm.vi[i][l] * fm.vi[j][l];
            }
            tmp += v_dot * guess_weights[i] * guess_weights[j];
        }
    }
    for (int i = 0; i < guess_index.size(); ++i) {
        double v_dot = 0.0;
        for (int l = 0; l < k; ++l) {
            v_dot += fm.vi[i][l] * fm.vi[i][l];
        }
        tmp -= v_dot * guess_weights[i] * guess_weights[i];
    }

    tmp /= 2.0;
    result += tmp;
    ASSERT_FLOAT_EQUAL(result, guess);

    // learning
    // I have no idea how I should check this.
    // Let's just check if the error goes down.

    // Seven features as in 3 users, 4 items.
    // user : array([[-1.33025759,  1.27872403],
    //               [ 0.2494233 , -0.11624764],
    //               [ 1.08083429, -1.16247639]])
    //
    // item : array([[ 0.0168526 , -1.35498234],
    //               [ 1.60099728, -0.45764304],
    //               [-1.06171398,  1.30114198],
    //               [-0.5561359 ,  0.5114834 ]])
    //
    //        array([[-1.75506677, -2.71493793,  3.07615459,  1.39385011],
    //               [ 0.16171693,  0.45252594, -0.41607089, -0.19817199],
    //               [ 1.59334984,  2.26241198, -2.66008371, -1.19567812]])

    // This matrix can be factorized into two rank 2 matrices.
    vector<vector<double>> targets = {
        {-1.75506677, -2.71493793,  3.07615459,  1.39385011},
        { 0.16171693,  0.45252594, -0.41607089, -0.19817199},
        { 1.59334984,  2.26241198, -2.66008371, -1.19567812}
    };

    k = 2;
    FM fm2 = FM(k, e1);

    double initial_error = 0.0;
    guess = fm2.predict({2, 6}, {1.0, 1.0});
    double target = -1.19567812;
    initial_error = guess - target;

    int epoch = 30000;
    for (int r = 0; r < epoch; ++r) {
        for (int i = 0; i < 3; ++i) {
            // each user
            for (int j = 0; j < 4; ++j) {
                // each item
                if (i == 2 && j == 3) {
                    // Don't let the algorithm peak at the answer.
                    continue;
                }
                fm2.learn({i, 3 + j}, {1.0, 1.0}, targets[i][j]);
            }
        }
    }

    double final_error = 0.0;
    guess = fm2.predict({2, 6}, {1.0, 1.0});
    target = -1.19567812;
    final_error = guess - target;
    ASSERT_TRUE((final_error) < (initial_error));

    return 0;
}
<commit_msg>Fixing float almost equal test in test suite.<commit_after>#include <iostream>
#include <random>

#include "featurizer.h"
#include "fm.h"

using namespace lightfm;
using namespace std;

/* Some test code copied from Crow.
 * Should check the license later on.
 */

bool failed__ = false;
void error_print()
{
    cerr << endl;
}

template <typename A, typename ...Args>
void error_print(const A& a, Args...args)
{
    cerr<<a;
    error_print(args...);
}

template <typename ...Args>
void fail(Args...args) { error_print(args...);failed__ = true; }

#define ASSERT_TRUE(x) if (!(x)) fail(__FILE__ ":", __LINE__, ": Assert fail: expected ", #x, " is true, at " __FILE__ ":",__LINE__)
#define ASSERT_EQUAL(a, b) if ((a) != (b)) fail(__FILE__ ":", __LINE__, ": Assert fail: expected ", (a), " actual " , (b),  ", " #a " == " #b ", at " __FILE__ ":",__LINE__)
#define ASSERT_NOTEQUAL(a, b) if ((a) == (b)) fail(__FILE__ ":", __LINE__, ": Assert fail: not expected ", (a), ", " #a " != " #b ", at " __FILE__ ":",__LINE__)
// Assuming 0.000001 has enough resolution.
#define ASSERT_FLOAT_EQUAL(a, b) if (((a) != (b)) && (fabs((a) - (b)) > ( (fabs((a)) > fabs((b)) ? fabs((b)) : fabs((a))) * 0.000001)) ) fail(__FILE__ ":", __LINE__, ": Assert fail: expected ", (a), " actual  ", (b), ", " #a " == " #b ", at " __FILE__ ":",__LINE__)
#define ASSERT_FLOAT_NOTEQUAL(a, b) if (((a) == (b)) || (fabs((a) - (b)) <= ( (fabs((a)) > fabs((b)) ? fabs((b)) : fabs((a))) * 0.000001)) ) fail(__FILE__ ":", __LINE__, ": Assert fail: expected ", (a), " actual  ", (b), ", " #a " != " #b ", at " __FILE__ ":",__LINE__)

int main() {
    Featurizer f = Featurizer();
    ASSERT_EQUAL(0, f.size());
    ASSERT_NOTEQUAL(1, f.size());

    vector<string> features = {"what", "i", "cannot", "create", "i", "do", "not", "understand"};
    for (auto const& x: features) {
        f.add_feature(x);
    }
    ASSERT_EQUAL(7, f.size());  // `i` is counted twice.

    vector<int> indices = f.get_feature_indices(vector<string>({"i", "cannot", "tell", "you", "what", "knowledge", "is" }));
    ASSERT_EQUAL(10, indices[indices.size() - 1]);

    // proper randomized algorithm should use random_device
    int seed = 44;
    int k = 3;

    default_random_engine e1(seed);
    FM fm = FM(k, e1);

    vector<int> guess_index({0, 1, 2});
    vector<double> guess_weights({1.5, 0.2, 2.0});
    double guess = fm.predict(guess_index, guess_weights);
    ASSERT_EQUAL(guess_index.size(), fm.vi.size());
    ASSERT_EQUAL(k, fm.vi[0].size());

    // Naive calculation. O(kn^2). Actual implementation takes O(kn).
    double result = fm.w0;
    for (int i = 0; i < fm.wi.size(); ++i) {
        result += fm.wi[i] * guess_weights[i];
    }
    double tmp = 0.0;
    for (int i = 0; i < guess_index.size(); ++i) {
        for (int j = 0; j < guess_index.size(); ++j) {
            double v_dot = 0.0;
            for (int l = 0; l < k; ++l) {
                v_dot += fm.vi[i][l] * fm.vi[j][l];
            }
            tmp += v_dot * guess_weights[i] * guess_weights[j];
        }
    }
    for (int i = 0; i < guess_index.size(); ++i) {
        double v_dot = 0.0;
        for (int l = 0; l < k; ++l) {
            v_dot += fm.vi[i][l] * fm.vi[i][l];
        }
        tmp -= v_dot * guess_weights[i] * guess_weights[i];
    }

    tmp /= 2.0;
    result += tmp;
    ASSERT_FLOAT_EQUAL(3.0, 3.0000000000000000000000000001);
    ASSERT_FLOAT_EQUAL(result, guess);

    // learning
    // I have no idea how I should check this.
    // Let's just check if the error goes down.

    // Seven features as in 3 users, 4 items.
    // user : array([[-1.33025759,  1.27872403],
    //               [ 0.2494233 , -0.11624764],
    //               [ 1.08083429, -1.16247639]])
    //
    // item : array([[ 0.0168526 , -1.35498234],
    //               [ 1.60099728, -0.45764304],
    //               [-1.06171398,  1.30114198],
    //               [-0.5561359 ,  0.5114834 ]])
    //
    //        array([[-1.75506677, -2.71493793,  3.07615459,  1.39385011],
    //               [ 0.16171693,  0.45252594, -0.41607089, -0.19817199],
    //               [ 1.59334984,  2.26241198, -2.66008371, -1.19567812]])

    // This matrix can be factorized into two rank 2 matrices.
    vector<vector<double>> targets = {
        {-1.75506677, -2.71493793,  3.07615459,  1.39385011},
        { 0.16171693,  0.45252594, -0.41607089, -0.19817199},
        { 1.59334984,  2.26241198, -2.66008371, -1.19567812}
    };

    k = 2;
    FM fm2 = FM(k, e1);

    double initial_error = 0.0;
    guess = fm2.predict({2, 6}, {1.0, 1.0});
    double target = -1.19567812;
    initial_error = guess - target;

    int epoch = 30000;
    for (int r = 0; r < epoch; ++r) {
        for (int i = 0; i < 3; ++i) {
            // each user
            for (int j = 0; j < 4; ++j) {
                // each item
                if (i == 2 && j == 3) {
                    // Don't let the algorithm peak at the answer.
                    continue;
                }
                fm2.learn({i, 3 + j}, {1.0, 1.0}, targets[i][j]);
            }
        }
    }

    double final_error = 0.0;
    guess = fm2.predict({2, 6}, {1.0, 1.0});
    target = -1.19567812;
    final_error = guess - target;
    ASSERT_TRUE((final_error) < (initial_error));

    return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include <set>
#include <sstream>
#include <iterator>
#include "GameState.h"
#include "Constants.h"

using namespace std;

GameState::GameState(Map * canvas) {
	map = canvas;
	Map& m = *canvas;
	vector<vector<char> > * board = m.getOriginalMap();
	setBoxes(board);
}

/*
Create a new GameState from a previous GameState, assuming a box was moved
from box_move.start to box_move.end. Also updates player position to box_move.start.
*/
GameState::GameState(GameState * prev, struct boxMove * box_move) {
	boxes = prev->boxes;
	boxes.erase(box_move->start);
	boxes.insert(box_move->end);
	player = box_move->start;
	map = prev->map;
}

/*
Private method to set all boxes from a board, and also set player position.
Only called from constructor.
*/
void GameState::setBoxes(vector<vector<char> > * stringmap) {
	vector<vector<char> >& board = *stringmap;

	for(unsigned int i = 0; i < board.size(); i++) {
		for(unsigned int j = 0; j < board[i].size(); j++) {
			char c = board[i][j];
			if(c == BOX) {
				boxes.insert(pos(i,j));
				board[i][j] = ' '; // Overwrite dynamic entity.
			} else if(c == PLAYER || c == PLAYER_ON_GOAL) {
				player = pos(i,j);
				board[i][j] = ' '; // Overwrite dynamic entity.
			}
		}
	}
}

// Destructor.
GameState::~GameState(){}

// Returns the state that results from pushing a box.
/*
GameState GameState::pushBox(const struct boxMove & m){
    vector<vector<char> > stringmap = map;
    stringmap[m.startY][m.startX] = ' ';
    stringmap[m.endY][m.endX] = '$';
    return GameState(stringmap,0,0);

}*/

/* Just a way to sort the GameStates. */
bool GameState::operator<(GameState other) const {
    if(hash() < other.hash())
        return true;
    else
        return false;
}

/* Returns true iff it is possible to move a box in the way specified in the argument. */
bool GameState::isValid(const struct boxMove & m){
    vector<char> path = moveToPath(this,m);
    if(path[0] == 'X'){
        return false;
    }
    if(map->isDeadlock(m.end)){
        return false;
    }
    return true;
//    // Testing relative positions.
//    if(!(abs(m.start.x-m.end.x) == 1 && abs(m.start.y-m.end.y) == 0
//      || abs(m.start.x-m.end.x) == 0 && abs(m.start.y-m.end.y) == 1)){
//        return false;
//    }
//    // Testing bounds.
//    if(min(min(min(m.start.x,m.end.x),m.start.y),m.end.y) < 0
//    || max(m.start.y,m.end.y) > map->getHeight()
//    || max(m.start.x,m.end.x) > map[m.start.y].getHeight()){
//        return false;
//    }
//    // Testing starting position chars.
//    if(!(boxes.find(pos(m.start.y,m.start.x)) == '$' || map[m.start.y][m.start.x] == '*')){
//        return false;
//    }
//    // Testing destination position chars.
//    if(!(map[m.start.y][m.start.x] == ' ' || map[m.start.y][m.start.x] == '.')){
//        return false;
//    }
//    return true;
}

/* Enables you to do cout << gamestate;. */
ostream& operator<<(ostream &strm, const GameState &state) {
    std::ostream& stream = strm;
    vector<vector<char> > & m = *(state.map->getOriginalMap());
    for(int i = 0;i < state.map->getHeight();i++){
		for(int j = 0;j < state.map->getWidth();j++){
            stream << m[i][j];
        }
        stream << endl;
    }
    return stream;
}

/* Returns the set of moves possible to make for the box in position boxPos. */
set<boxMove> GameState::moves(pos boxPos){
    set<boxMove> moveSet;
    boxMove up; up.start = boxPos; up.end = boxPos+pos(0,-1);
    boxMove down; down.start = boxPos; down.end = boxPos+pos(0,1);
    boxMove left; left.start = boxPos; left.end = boxPos+pos(-1,0);
    boxMove right; right.start = boxPos; right.end = boxPos+pos(1,0);
    if(isValid(up)){
        moveSet.insert(up);
    }
    if(isValid(down)){
        moveSet.insert(down);
    }
    if(isValid(left)){
        moveSet.insert(left);
    }
    if(isValid(right)){
        moveSet.insert(right);
    }
    return moveSet;
}

/* Returns a set of all succeeding states. */
set<GameState> GameState::findNextMoves(){
    set<GameState> successors;
    set<pos>::iterator it;
    for(it = boxes.begin();it != boxes.end();++it){
        pos b = *it;
        set<boxMove> ms = moves(b);
        set<boxMove>::iterator it2;
        for(it2 = ms.begin();it2 != ms.end();++it2){
            boxMove m = *it2;
            GameState gs(this,&m);
            successors.insert(gs);
        }
    }
    return successors;
}

/* Slightly misleading name because it is meant to be used for sorting GameStates in a std::set, not
 * in a hash datastructure. */
//TODO: Ingen garanti för att alla GameStates har en unik hash.
unsigned long long GameState::hash() const{
    unsigned long long hash = 0;
    set<pos>::iterator it;
    int multiplier = 1;
    for(it = boxes.begin();it != boxes.end();++it){
        pos p = *it;
        int posHash = p.x*map->getOriginalMap()->size()+p.y;
        hash += multiplier*posHash;
        multiplier++;
    }
    return hash;
}

<commit_msg>Ändring i hash.<commit_after>#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include <set>
#include <sstream>
#include <iterator>
#include "GameState.h"
#include "Constants.h"

using namespace std;

GameState::GameState(Map * canvas) {
	map = canvas;
	Map& m = *canvas;
	vector<vector<char> > * board = m.getOriginalMap();
	setBoxes(board);
}

/*
Create a new GameState from a previous GameState, assuming a box was moved
from box_move.start to box_move.end. Also updates player position to box_move.start.
*/
GameState::GameState(GameState * prev, struct boxMove * box_move) {
	boxes = prev->boxes;
	boxes.erase(box_move->start);
	boxes.insert(box_move->end);
	player = box_move->start;
	map = prev->map;
}

/*
Private method to set all boxes from a board, and also set player position.
Only called from constructor.
*/
void GameState::setBoxes(vector<vector<char> > * stringmap) {
	vector<vector<char> >& board = *stringmap;

	for(unsigned int i = 0; i < board.size(); i++) {
		for(unsigned int j = 0; j < board[i].size(); j++) {
			char c = board[i][j];
			if(c == BOX) {
				boxes.insert(pos(i,j));
				board[i][j] = ' '; // Overwrite dynamic entity.
			} else if(c == PLAYER || c == PLAYER_ON_GOAL) {
				player = pos(i,j);
				board[i][j] = ' '; // Overwrite dynamic entity.
			}
		}
	}
}

// Destructor.
GameState::~GameState(){}

// Returns the state that results from pushing a box.
/*
GameState GameState::pushBox(const struct boxMove & m){
    vector<vector<char> > stringmap = map;
    stringmap[m.startY][m.startX] = ' ';
    stringmap[m.endY][m.endX] = '$';
    return GameState(stringmap,0,0);

}*/

/* Just a way to sort the GameStates. */
bool GameState::operator<(GameState other) const {
    if(hash() < other.hash())
        return true;
    else
        return false;
}

/* Returns true iff it is possible to move a box in the way specified in the argument. */
bool GameState::isValid(const struct boxMove & m){
    vector<char> path = moveToPath(this,m);
    if(path[0] == 'X'){
        return false;
    }
    if(map->isDeadlock(m.end)){
        return false;
    }
    return true;
//    // Testing relative positions.
//    if(!(abs(m.start.x-m.end.x) == 1 && abs(m.start.y-m.end.y) == 0
//      || abs(m.start.x-m.end.x) == 0 && abs(m.start.y-m.end.y) == 1)){
//        return false;
//    }
//    // Testing bounds.
//    if(min(min(min(m.start.x,m.end.x),m.start.y),m.end.y) < 0
//    || max(m.start.y,m.end.y) > map->getHeight()
//    || max(m.start.x,m.end.x) > map[m.start.y].getHeight()){
//        return false;
//    }
//    // Testing starting position chars.
//    if(!(boxes.find(pos(m.start.y,m.start.x)) == '$' || map[m.start.y][m.start.x] == '*')){
//        return false;
//    }
//    // Testing destination position chars.
//    if(!(map[m.start.y][m.start.x] == ' ' || map[m.start.y][m.start.x] == '.')){
//        return false;
//    }
//    return true;
}

/* Enables you to do cout << gamestate;. */
ostream& operator<<(ostream &strm, const GameState &state) {
    std::ostream& stream = strm;
    vector<vector<char> > & m = *(state.map->getOriginalMap());
    for(int i = 0;i < state.map->getHeight();i++){
		for(int j = 0;j < state.map->getWidth();j++){
            stream << m[i][j];
        }
        stream << endl;
    }
    return stream;
}

/* Returns the set of moves possible to make for the box in position boxPos. */
set<boxMove> GameState::moves(pos boxPos){
    set<boxMove> moveSet;
    boxMove up; up.start = boxPos; up.end = boxPos+pos(0,-1);
    boxMove down; down.start = boxPos; down.end = boxPos+pos(0,1);
    boxMove left; left.start = boxPos; left.end = boxPos+pos(-1,0);
    boxMove right; right.start = boxPos; right.end = boxPos+pos(1,0);
    if(isValid(up)){
        moveSet.insert(up);
    }
    if(isValid(down)){
        moveSet.insert(down);
    }
    if(isValid(left)){
        moveSet.insert(left);
    }
    if(isValid(right)){
        moveSet.insert(right);
    }
    return moveSet;
}

/* Returns a set of all succeeding states. */
set<GameState> GameState::findNextMoves(){
    set<GameState> successors;
    set<pos>::iterator it;
    for(it = boxes.begin();it != boxes.end();++it){
        pos b = *it;
        set<boxMove> ms = moves(b);
        set<boxMove>::iterator it2;
        for(it2 = ms.begin();it2 != ms.end();++it2){
            boxMove m = *it2;
            GameState gs(this,&m);
            successors.insert(gs);
        }
    }
    return successors;
}

/* Slightly misleading name because it is meant to be used for sorting GameStates in a std::set, not
 * in a hash datastructure. */
//TODO: Ingen garanti för att alla GameStates har en unik hash.
unsigned long long GameState::hash() const{
    unsigned long long hash = 0;
    set<pos>::iterator it;
    int multiplier = 1;
    for(it = boxes.begin();it != boxes.end();++it){
        pos p = *it;
        int posHash = p.x*map->getOriginalMap()->size()+p.y;
        hash += multiplier*posHash;
        multiplier *= 2;
    }
    return hash;
}

<|endoftext|>