<commit_before>//
// config.hpp
// **********
//
// Copyright (c) 2018 Sharon W (sharon at aegis dot gg)
//
// Distributed under the MIT License. (See accompanying file LICENSE)
//

#pragma once

#include "aegis/version.hpp"
#include "aegis/fwd.hpp"

#if !defined(ASIO_NO_DEPRECATED)
#define ASIO_NO_DEPRECATED
#endif

#if !defined(ASIO_STANDALONE)
#define ASIO_STANDALONE
#endif

#if !defined(ASIO_HEADER_ONLY) && !defined(ASIO_DYN_LINK) && !defined(ASIO_SEPARATE_COMPILATION)
#define ASIO_HEADER_ONLY
#endif

#if !defined(_WEBSOCKETPP_CPP11_STL_)
#define _WEBSOCKETPP_CPP11_STL_
#endif

// Shamelessly make use of ASIO's config-style

// Default to a header-only implementation. The user must specifically request
// separate compilation by defining either AEGIS_SEPARATE_COMPILATION or
// AEGIS_DYN_LINK (as a DLL/shared library implies separate compilation).
#if !defined(AEGIS_HEADER_ONLY)
# if !defined(AEGIS_SEPARATE_COMPILATION)
#  if !defined(AEGIS_DYN_LINK)
#   define AEGIS_HEADER_ONLY 1
#  endif // !defined(AEGIS_DYN_LINK)
# endif // !defined(AEGIS_SEPARATE_COMPILATION)
#endif // !defined(AEGIS_HEADER_ONLY)

#if defined(AEGIS_HEADER_ONLY)
# define AEGIS_DECL inline
#else // defined(AEGIS_HEADER_ONLY)
# if defined(_MSC_VER)
// We need to import/export our code only if the user has specifically asked
// for it by defining AEGIS_DYN_LINK.
#  if defined(AEGIS_DYN_LINK)
// Export if this is our own source, otherwise import.
#   if defined(AEGIS_SOURCE)
#    define AEGIS_DECL __declspec(dllexport)
#   else // defined(AEGIS_SOURCE)
#    define AEGIS_DECL __declspec(dllimport)
#   endif // defined(AEGIS_SOURCE)
#  endif // defined(AEGIS_DYN_LINK)
# endif // defined(_MSC_VER)
#endif // defined(AEGIS_HEADER_ONLY)

// If AEGIS_DECL isn't defined yet define it now.
#if !defined(AEGIS_DECL)
# define AEGIS_DECL
#endif // !defined(AEGIS_DECL)

// Microsoft Visual C++ detection.
#if !defined(AEGIS_MSVC)
# if defined(_MSC_VER) && (defined(__INTELLISENSE__) \
      || (!defined(__MWERKS__) && !defined(__EDG_VERSION__)))
#  define AEGIS_MSVC _MSC_VER
# endif // defined(_MSC_VER) && defined(__INTELLISENSE__)
        //|| (!defined(__MWERKS__) && !defined(__EDG_VERSION__)))
#endif // defined(AEGIS_MSVC)
#if defined(AEGIS_MSVC)
# include <ciso646> // Needed for _HAS_CXX17.
#endif // defined(AEGIS_MSVC)

// Workaround for Microsoft Visual C++ __cplusplus value
#if defined(AEGIS_MSVC)
# if (_MSVC_LANG < 201402)
#  error AegisLib requires C++14 or greater
# endif
#else
# if (__cplusplus < 201402)
#  error AegisLib requires C++14 or greater
# endif
#endif

// Support noexcept on compilers known to allow it.
#if !defined(AEGIS_NOEXCEPT)
# if !defined(AEGIS_DISABLE_NOEXCEPT)
#  if defined(__clang__)
#   if __has_feature(__cxx_noexcept__)
#    define AEGIS_NOEXCEPT noexcept(true)
#    define AEGIS_NOEXCEPT_OR_NOTHROW noexcept(true)
#   endif // __has_feature(__cxx_noexcept__)
#  elif defined(__GNUC__)
#   if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
#    if defined(__GXX_EXPERIMENTAL_CXX0X__)
#      define AEGIS_NOEXCEPT noexcept(true)
#      define AEGIS_NOEXCEPT_OR_NOTHROW noexcept(true)
#    endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
#   endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
#  elif defined(AEGIS_MSVC)
#   if (_MSC_VER >= 1900)
#    define AEGIS_NOEXCEPT noexcept(true)
#    define AEGIS_NOEXCEPT_OR_NOTHROW noexcept(true)
#   endif // (_MSC_VER >= 1900)
#  endif // defined(AEGIS_MSVC)
# endif // !defined(AEGIS_DISABLE_NOEXCEPT)
# if !defined(AEGIS_NOEXCEPT)
#  define AEGIS_NOEXCEPT
# endif // !defined(AEGIS_NOEXCEPT)
# if !defined(AEGIS_NOEXCEPT_OR_NOTHROW)
#  define AEGIS_NOEXCEPT_OR_NOTHROW throw()
# endif // !defined(AEGIS_NOEXCEPT_OR_NOTHROW)
#endif // !defined(AEGIS_NOEXCEPT)

// Support for std::optional over built-in
#if !defined(AEGIS_HAS_STD_OPTIONAL)
# if !defined(AEGIS_DISABLE_STD_OPTIONAL)
#  if (__cplusplus >= 201703)
#   if __has_include(<optional>)
#    include <optional>
namespace aegis
{
namespace lib
{
using namespace std::optional;
constexpr auto nullopt = std::nullopt;
using bad_optional_access = std::bad_optional_access;
}
}
#    define AEGIS_HAS_STD_OPTIONAL 1
#   elif __has_include(<experimental/optional>)
#    include <experimental/optional>
namespace aegis
{
namespace lib
{
template<typename T> using optional = std::experimental::optional<T>;
constexpr auto nullopt = std::experimental::nullopt;
using bad_optional_access = std::experimental::bad_optional_access;
}
}
#    define AEGIS_HAS_STD_OPTIONAL 1
#   endif // __has_include(<optional>)
#  elif (__cplusplus >= 201402) // c++14
#   include "aegis/optional.hpp"
namespace aegis
{
namespace lib
{
template<typename T> using optional = std::experimental::optional<T>;
constexpr auto nullopt = std::experimental::nullopt;
using bad_optional_access = std::experimental::bad_optional_access;
}
}
#  endif // (__cplusplus >= 201703)
#  if defined(AEGIS_MSVC)
#   if (_MSC_VER >= 1910 && defined(_HAS_CXX17))
#    include <optional>
namespace aegis
{
namespace lib
{
template<typename T> using optional = std::optional<T>;
constexpr auto nullopt = std::nullopt;
using bad_optional_access = std::bad_optional_access;
}
}
#    define AEGIS_HAS_STD_OPTIONAL
#  else
#   include "aegis/optional.hpp"
namespace aegis
{
namespace lib
{
template<typename T> using optional = std::experimental::optional<T>;
constexpr auto nullopt = std::experimental::nullopt;
using bad_optional_access = std::experimental::bad_optional_access;
}
}
#   endif // (_MSC_VER >= 1910 && _HAS_CXX17)
#  endif // defined(AEGIS_MSVC)
# endif // !defined(AEGIS_DISABLE_STD_OPTIONAL)
#endif // !defined(AEGIS_HAS_STD_OPTIONAL)

// use std::shared_timed_mutex on C++14 or shared_mutex on C++17
#if !defined(AEGIS_HAS_STD_SHARED_MUTEX)
# if !defined(AEGIS_DISABLE_STD_SHARED_MUTEX)
#  if (__cplusplus >= 201703) || (_MSVC_LANG >= 201703)
#   define AEGIS_HAS_STD_SHARED_MUTEX 1
#  endif // (__cplusplus >= 201703) || (_MSVC_LANG >= 201703)
# endif // !defined(AEGIS_DISABLE_STD_SHARED_MUTEX)
# if !defined(AEGIS_HAS_STD_SHARED_MUTEX)
#  define AEGIS_HAS_STD_SHARED_MUTEX 0
# endif // !defined(AEGIS_HAS_STD_SHARED_MUTEX)
#endif // !defined(AEGIS_HAS_STD_SHARED_MUTEX)

#if (__cplusplus >= 201703) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703) || (defined(_HAS_CXX17) && _HAS_CXX17 != 0)
# define AEGIS_CXX17
#endif // (__cplusplus >= 201703) || (_MSVC_LANG >= 201703)

#if !defined(NDEBUG)
#include <cassert>
#endif
<commit_msg>Fixed incorrect copy-paste<commit_after>//
// config.hpp
// **********
//
// Copyright (c) 2018 Sharon W (sharon at aegis dot gg)
//
// Distributed under the MIT License. (See accompanying file LICENSE)
//

#pragma once

#include "aegis/version.hpp"
#include "aegis/fwd.hpp"

#if !defined(ASIO_NO_DEPRECATED)
#define ASIO_NO_DEPRECATED
#endif

#if !defined(ASIO_STANDALONE)
#define ASIO_STANDALONE
#endif

#if !defined(ASIO_HEADER_ONLY) && !defined(ASIO_DYN_LINK) && !defined(ASIO_SEPARATE_COMPILATION)
#define ASIO_HEADER_ONLY
#endif

#if !defined(_WEBSOCKETPP_CPP11_STL_)
#define _WEBSOCKETPP_CPP11_STL_
#endif

// Shamelessly make use of ASIO's config-style

// Default to a header-only implementation. The user must specifically request
// separate compilation by defining either AEGIS_SEPARATE_COMPILATION or
// AEGIS_DYN_LINK (as a DLL/shared library implies separate compilation).
#if !defined(AEGIS_HEADER_ONLY)
# if !defined(AEGIS_SEPARATE_COMPILATION)
#  if !defined(AEGIS_DYN_LINK)
#   define AEGIS_HEADER_ONLY 1
#  endif // !defined(AEGIS_DYN_LINK)
# endif // !defined(AEGIS_SEPARATE_COMPILATION)
#endif // !defined(AEGIS_HEADER_ONLY)

#if defined(AEGIS_HEADER_ONLY)
# define AEGIS_DECL inline
#else // defined(AEGIS_HEADER_ONLY)
# if defined(_MSC_VER)
// We need to import/export our code only if the user has specifically asked
// for it by defining AEGIS_DYN_LINK.
#  if defined(AEGIS_DYN_LINK)
// Export if this is our own source, otherwise import.
#   if defined(AEGIS_SOURCE)
#    define AEGIS_DECL __declspec(dllexport)
#   else // defined(AEGIS_SOURCE)
#    define AEGIS_DECL __declspec(dllimport)
#   endif // defined(AEGIS_SOURCE)
#  endif // defined(AEGIS_DYN_LINK)
# endif // defined(_MSC_VER)
#endif // defined(AEGIS_HEADER_ONLY)

// If AEGIS_DECL isn't defined yet define it now.
#if !defined(AEGIS_DECL)
# define AEGIS_DECL
#endif // !defined(AEGIS_DECL)

// Microsoft Visual C++ detection.
#if !defined(AEGIS_MSVC)
# if defined(_MSC_VER) && (defined(__INTELLISENSE__) \
      || (!defined(__MWERKS__) && !defined(__EDG_VERSION__)))
#  define AEGIS_MSVC _MSC_VER
# endif // defined(_MSC_VER) && defined(__INTELLISENSE__)
        //|| (!defined(__MWERKS__) && !defined(__EDG_VERSION__)))
#endif // defined(AEGIS_MSVC)
#if defined(AEGIS_MSVC)
# include <ciso646> // Needed for _HAS_CXX17.
#endif // defined(AEGIS_MSVC)

// Workaround for Microsoft Visual C++ __cplusplus value
#if defined(AEGIS_MSVC)
# if (_MSVC_LANG < 201402)
#  error AegisLib requires C++14 or greater
# endif
#else
# if (__cplusplus < 201402)
#  error AegisLib requires C++14 or greater
# endif
#endif

// Support noexcept on compilers known to allow it.
#if !defined(AEGIS_NOEXCEPT)
# if !defined(AEGIS_DISABLE_NOEXCEPT)
#  if defined(__clang__)
#   if __has_feature(__cxx_noexcept__)
#    define AEGIS_NOEXCEPT noexcept(true)
#    define AEGIS_NOEXCEPT_OR_NOTHROW noexcept(true)
#   endif // __has_feature(__cxx_noexcept__)
#  elif defined(__GNUC__)
#   if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
#    if defined(__GXX_EXPERIMENTAL_CXX0X__)
#      define AEGIS_NOEXCEPT noexcept(true)
#      define AEGIS_NOEXCEPT_OR_NOTHROW noexcept(true)
#    endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
#   endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
#  elif defined(AEGIS_MSVC)
#   if (_MSC_VER >= 1900)
#    define AEGIS_NOEXCEPT noexcept(true)
#    define AEGIS_NOEXCEPT_OR_NOTHROW noexcept(true)
#   endif // (_MSC_VER >= 1900)
#  endif // defined(AEGIS_MSVC)
# endif // !defined(AEGIS_DISABLE_NOEXCEPT)
# if !defined(AEGIS_NOEXCEPT)
#  define AEGIS_NOEXCEPT
# endif // !defined(AEGIS_NOEXCEPT)
# if !defined(AEGIS_NOEXCEPT_OR_NOTHROW)
#  define AEGIS_NOEXCEPT_OR_NOTHROW throw()
# endif // !defined(AEGIS_NOEXCEPT_OR_NOTHROW)
#endif // !defined(AEGIS_NOEXCEPT)

// Support for std::optional over built-in
#if !defined(AEGIS_HAS_STD_OPTIONAL)
# if !defined(AEGIS_DISABLE_STD_OPTIONAL)
#  if (__cplusplus >= 201703)
#   if __has_include(<optional>)
#    include <optional>
namespace aegis
{
namespace lib
{
template<typename T> using optional = std::optional<T>;
constexpr auto nullopt = std::nullopt;
using bad_optional_access = std::bad_optional_access;
}
}
#    define AEGIS_HAS_STD_OPTIONAL 1
#   elif __has_include(<experimental/optional>)
#    include <experimental/optional>
namespace aegis
{
namespace lib
{
template<typename T> using optional = std::experimental::optional<T>;
constexpr auto nullopt = std::experimental::nullopt;
using bad_optional_access = std::experimental::bad_optional_access;
}
}
#    define AEGIS_HAS_STD_OPTIONAL 1
#   endif // __has_include(<optional>)
#  elif (__cplusplus >= 201402) // c++14
#   include "aegis/optional.hpp"
namespace aegis
{
namespace lib
{
template<typename T> using optional = std::experimental::optional<T>;
constexpr auto nullopt = std::experimental::nullopt;
using bad_optional_access = std::experimental::bad_optional_access;
}
}
#  endif // (__cplusplus >= 201703)
#  if defined(AEGIS_MSVC)
#   if (_MSC_VER >= 1910 && defined(_HAS_CXX17))
#    include <optional>
namespace aegis
{
namespace lib
{
template<typename T> using optional = std::optional<T>;
constexpr auto nullopt = std::nullopt;
using bad_optional_access = std::bad_optional_access;
}
}
#    define AEGIS_HAS_STD_OPTIONAL
#  else
#   include "aegis/optional.hpp"
namespace aegis
{
namespace lib
{
template<typename T> using optional = std::experimental::optional<T>;
constexpr auto nullopt = std::experimental::nullopt;
using bad_optional_access = std::experimental::bad_optional_access;
}
}
#   endif // (_MSC_VER >= 1910 && _HAS_CXX17)
#  endif // defined(AEGIS_MSVC)
# endif // !defined(AEGIS_DISABLE_STD_OPTIONAL)
#endif // !defined(AEGIS_HAS_STD_OPTIONAL)

// use std::shared_timed_mutex on C++14 or shared_mutex on C++17
#if !defined(AEGIS_HAS_STD_SHARED_MUTEX)
# if !defined(AEGIS_DISABLE_STD_SHARED_MUTEX)
#  if (__cplusplus >= 201703) || (_MSVC_LANG >= 201703)
#   define AEGIS_HAS_STD_SHARED_MUTEX 1
#  endif // (__cplusplus >= 201703) || (_MSVC_LANG >= 201703)
# endif // !defined(AEGIS_DISABLE_STD_SHARED_MUTEX)
# if !defined(AEGIS_HAS_STD_SHARED_MUTEX)
#  define AEGIS_HAS_STD_SHARED_MUTEX 0
# endif // !defined(AEGIS_HAS_STD_SHARED_MUTEX)
#endif // !defined(AEGIS_HAS_STD_SHARED_MUTEX)

#if (__cplusplus >= 201703) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703) || (defined(_HAS_CXX17) && _HAS_CXX17 != 0)
# define AEGIS_CXX17
#endif // (__cplusplus >= 201703) || (_MSVC_LANG >= 201703)

#if !defined(NDEBUG)
#include <cassert>
#endif
<|endoftext|>


<commit_before>#ifndef BITES_THREAD_HPP_INCLUDED
#define BITES_THREAD_HPP_INCLUDED

#include <thread>

namespace bites {

/**
  Allows creating thread "objects"
  similarly to Python's Thread (or Process) class.
  For example, in Python you'd create your class this way:

  @code

  from threading import Thread

  class Foo(Thread):
     def __init__(self):
        super(Foo, self).__init__()
     def run(self):
        print('Hello!')

  bar = Foo()
  bar.start()
  bar.join()

  @endcode

  Using Thread class, the analogous C++ definition is:

  @code

  #include <iostream>
  #include <bites.hpp>

  class Foo : public bites::Thread {
  private:
     void run() { std::cout << "Hello!" << std::endl; }
  };

  int main (int argc, char** argv) {
     bar Foo;
     bar.start();
     bar.join();
  }

  @endcode
 */
class Thread {

public:
    /**
       Deallocate memory for internal thread object.
     */
    ~Thread()
    {
        if (m_thread)
        {
            delete m_thread;
        }
    }

    /**
       Allocate (and start) internal thread object.
    */
    void start ()
    {
        m_thread = new std::thread(&Thread::run, this);
    }

    /**
      Join internal thread.
    */
    void join ()
    {
        if (m_thread)
        {
            m_thread->join();
        }
    }

private:
    std::thread* m_thread = NULL;

    /**
       Implement this in subclass.
    */
    virtual void run() = 0;
};

}  // namespace sherlock.

#endif  // BITES_THREAD_HPP_INCLUDED
<commit_msg>Fix comment typo.<commit_after>#ifndef BITES_THREAD_HPP_INCLUDED
#define BITES_THREAD_HPP_INCLUDED

#include <thread>

namespace bites {

/**
  Allows creating thread "objects"
  similarly to Python's Thread (or Process) class.
  For example, in Python you'd create your class this way:

  @code

  from threading import Thread

  class Foo(Thread):
     def __init__(self):
        super(Foo, self).__init__()
     def run(self):
        print('Hello!')

  bar = Foo()
  bar.start()
  bar.join()

  @endcode

  Using Thread class, the analogous C++ definition is:

  @code

  #include <iostream>
  #include <bites.hpp>

  class Foo : public bites::Thread {
  private:
     void run() { std::cout << "Hello!" << std::endl; }
  };

  int main (int argc, char** argv) {
     bar Foo;
     bar.start();
     bar.join();
  }

  @endcode
 */
class Thread {

public:
    /**
       Deallocate memory for internal thread object.
     */
    ~Thread()
    {
        if (m_thread)
        {
            delete m_thread;
        }
    }

    /**
       Allocate (and start) internal thread object.
    */
    void start ()
    {
        m_thread = new std::thread(&Thread::run, this);
    }

    /**
      Join internal thread.
    */
    void join ()
    {
        if (m_thread)
        {
            m_thread->join();
        }
    }

private:
    std::thread* m_thread = NULL;

    /**
       Implement this in subclass.
    */
    virtual void run() = 0;
};

}  // namespace bites.

#endif  // BITES_THREAD_HPP_INCLUDED
<|endoftext|>


<commit_before>#include <iostream>
#include <cstring>
#include "Memory.hpp"
#include "registerAddr.hpp"

Memory::Memory(void) {}

Memory::~Memory(void) {}

void			Memory::reset(void)
{
	memset(this->_m_wram, 0xFF, sizeof(_m_wram));
	memset(this->_m_vram, 0xFF, sizeof(_m_vram));
	memset(this->_m_oam, 0xFF, sizeof(_m_oam));
	memset(this->_m_io, 0xFF, sizeof(_m_io));
	memset(this->_m_zp, 0xFF, sizeof(_m_zp));
	memset(this->_bcp, 0xFF, sizeof(_bcp));
	memset(this->_ocp, 0xFF, sizeof(_ocp));
	this->_inBios = true;
}

htype			Memory::getRomType(void)
{
	return this->_rom.getHardware();
}

htype			Memory::getTypeBios(void)
{
	return this->_typeBios;
}

int				Memory::loadRom(const char *file, htype hardware)
{
	int		ret;

	ret = this->_rom.load(file);
	hardware = (hardware == AUTO) ? this->_rom.getHardware() : hardware;
	this->_codeBios = this->_bios.load(hardware);
	this->_typeBios = hardware;
	return ret;
}

void			Memory::setInBios(bool inBios)
{
	this->_inBios = inBios;
}

void			Memory::transferData(uint16_t startAddr)
{
	int a = 0;

	for (uint16_t currAddr = startAddr ; currAddr <= (startAddr + 0x8c) ; currAddr++)
	{
		write_byte(0xfe00 + a, read_byte(currAddr));
		a++;
	}
}

void			Memory::handleInput()
{
	if ((read_byte(0xff00) & 0x30) == 0x10)
		write_byte(0xff00, 0x10 + key[1], true);
	else if ((read_byte(0xff00) & 0x30) == 0x20)
		write_byte(0xff00, 0x20 + key[0], true);
}

t_color15		Memory::getBgColor15(uint8_t palId, uint8_t colorId)
{
	return _bcp[palId][colorId];
}

t_color15		Memory::getObjColor15(uint8_t palId, uint8_t colorId)
{
	return _ocp[palId][colorId];
}

uint8_t			Memory::force_read_vram(uint16_t addr, uint8_t bank)
{
	return this->_m_vram[bank & 0x1][addr & 0x1FFF];
}

uint8_t			Memory::read_byte(uint16_t addr)
{
	switch (addr & 0xF000){
		case 0x0000:
			if (this->_inBios)
			{
				if (addr <= 0xFF)
					return this->_codeBios[addr];
				else if (addr >= 0x200 && addr < 0x900 && getTypeBios() == GBC)
					return this->_codeBios[addr - 0x100];
				else
					return this->_rom.read(addr);
			}
			else
			{
				return this->_rom.read(addr);
			}
			break;
		case 0x1000:
		case 0x2000:
		case 0x3000:
		case 0x4000:
		case 0x5000:
		case 0x6000:
		case 0x7000:
			// ROM
			return this->_rom.read(addr);
			break;
		case 0x8000:
		case 0x9000:
			// VRAM
			return this->_m_vram[(this->_m_io[(VBK & 0xFF)] & 0x01)][(addr & 0x1FFF)];
			break;
		case 0xA000:
		case 0xB000:
			// ERAM
			return this->_rom.read(addr);
			break;
		case 0xC000:
		case 0xD000:
			// WRAM
			if ((addr & 0xF000) < 0xD000)
				return this->_m_wram[0][(addr & 0x1FFF)];
			else
				return this->_m_wram
					[(this->_m_io[(SVBK & 0xFF)] & 0x07)]
					[(addr & 0x1FFF)];
			break;
		case 0xF000:
			switch (addr & 0x0F00){
				case 0x0E00:
					if ((addr & 0xFF) <= 0x9F)
					{
						// SPRITE
						return this->_m_oam[(addr & 0xFF)];
					}
					break;
				case 0x0F00:
					if ((addr & 0xFF) <= 0x7F)
					{
						// I/O
						return this->_m_io[(addr & 0xFF)];
					}
					else
					{
						// Zero page
						return this->_m_zp[(addr & 0xFF) - 0x80];
					}
					break;
			}
			break;
	}
	return 0;
}

void			Memory::write_byte(uint16_t addr, uint8_t val, bool super)
{
	switch (addr & 0xF000){
		case 0x0000:
		case 0x1000:
		case 0x2000:
		case 0x3000:
		case 0x4000:
		case 0x5000:
		case 0x6000:
		case 0x7000:
			// ROM
			this->_rom.write(addr, val);
			break;
		case 0x8000:
		case 0x9000:
			// VRAM
			this->_m_vram[(this->_m_io[(VBK & 0xFF)] & 0x01)][(addr & 0x1FFF)] = val;
			break;
		case 0xA000:
		case 0xB000:
			// ERAM
			this->_rom.write(addr, val);
			break;
		case 0xC000:
		case 0xD000:
			// WRAM
			if ((addr & 0xF000) < 0xD000)
				this->_m_wram[0][(addr & 0x1FFF)] = val;
			else
				this->_m_wram[(this->_m_io[(SVBK & 0xFF)] & 0x03)][(addr & 0x1FFF)] = val;
			break;
		case 0xF000:
			switch (addr & 0x0F00){
				case 0x0E00:
					if ((addr & 0xFF) <= 0x9F)
					{
						// SPRITE
						this->_m_oam[(addr & 0xFF)] = val;
					}
					break;
				case 0x0F00:
					if (!super && addr == 0xFF00)
					{
						// P1
						this->_m_io[(addr & 0xFF)] = (val & 0xF0) | (this->_m_io[(addr & 0xFF)] & 0x0F);
						handleInput();
					}
					else if (!super && addr == 0xFF04)
					{
						// DIV
						this->_m_io[(addr & 0xFF)] = 0x00;
					}
					else if ((addr & 0xFF) <= 0x7F)
					{
						// I/O

						// if Stat is overwritten
						if (addr == 0xFF41)
						{
							//protect 3 first byte form overwritting
							if (!super)
							{
								val &= 0xF8;
								val |= read_byte(0xFF41) & 0x07;
							}
							// Check coincidence
							if (val & 0x44)
								write_byte(0xFF0F, read_byte(0xFF0F) | 0x02);
						}
						if ((addr == 0xFF44 || addr == 0xFF45) && read_byte(0xFF40) & 0x80)
						{
							if (read_byte(0xFF44) == read_byte(0xFF45))
								this->_m_io[0x41] |= 0x04;// Coincidence
							else
								this->_m_io[0x41] &= 0xfb;
						}
						else if (addr == 0xFF40 && (val & 0x80))
						{
							if (read_byte(0xFF44) == read_byte(0xFF45))
								this->_m_io[0x41] |= 0x04;
							else
								this->_m_io[0x41] &= 0xfb;
						}
						//DMA
						if (addr == REGISTER_DMA)
							transferData(val << 8);
						// BCPS / BCPD
						if (addr == REGISTER_BCPS) {
							this->_m_io[REGISTER_BCPD & 0xFF] = ((uint8_t*)_bcp)[val & 0x3F];
						}
						if (addr == REGISTER_BCPD) {
							((uint8_t*)_bcp)[read_byte(REGISTER_BCPS) & 0x3F] = val;
							if (read_byte(REGISTER_BCPS) & 0x80)
								write_byte(REGISTER_BCPS, ((((read_byte(REGISTER_BCPS) << 2) + 4) & 0xFF) >> 2) | 0x80);
						}
						// OCPS / OCPD
						if (addr == REGISTER_OCPS) {
							this->_m_io[REGISTER_OCPD & 0xFF] = ((uint8_t*)_ocp)[val & 0x3F];
						}
						if (addr == REGISTER_OCPD) {
							((uint8_t*)_ocp)[read_byte(REGISTER_OCPS) & 0x3F] = val;
							if (read_byte(REGISTER_OCPS) & 0x80)
								write_byte(REGISTER_OCPS, ((((read_byte(REGISTER_OCPS) << 2) + 4) & 0xFF) >> 2) | 0x80);
						}
						this->_m_io[(addr & 0xFF)] = val;
					}
					else
					{
						// Zero page
						this->_m_zp[(addr & 0xFF) - 0x80] = val;
					}
					break;
			}
			break;
	}
}

uint16_t		Memory::read_word(uint16_t addr)
{
	return this->read_byte(addr) + (this->read_byte(addr + 1) << 8);
}

void			Memory::write_word(uint16_t addr, uint16_t val, bool super)
{
	this->write_byte(addr, (val & 0xFF), super);
	this->write_byte(addr + 1, ((val & 0xFF00) >> 8), super);
}
<commit_msg>fix du fix dans la branch fix<commit_after>#include <iostream>
#include <cstring>
#include "Memory.hpp"
#include "registerAddr.hpp"

Memory::Memory(void) {}

Memory::~Memory(void) {}

void			Memory::reset(void)
{
	memset(this->_m_wram, 0xFF, sizeof(_m_wram));
	memset(this->_m_vram, 0xFF, sizeof(_m_vram));
	memset(this->_m_oam, 0xFF, sizeof(_m_oam));
	memset(this->_m_io, 0xFF, sizeof(_m_io));
	memset(this->_m_zp, 0xFF, sizeof(_m_zp));
	memset(this->_bcp, 0xFF, sizeof(_bcp));
	memset(this->_ocp, 0xFF, sizeof(_ocp));
	this->_inBios = true;
}

htype			Memory::getRomType(void)
{
	return this->_rom.getHardware();
}

htype			Memory::getTypeBios(void)
{
	return this->_typeBios;
}

int				Memory::loadRom(const char *file, htype hardware)
{
	int		ret;

	ret = this->_rom.load(file);
	hardware = (hardware == AUTO) ? this->_rom.getHardware() : hardware;
	this->_codeBios = this->_bios.load(hardware);
	this->_typeBios = hardware;
	return ret;
}

void			Memory::setInBios(bool inBios)
{
	this->_inBios = inBios;
}

void			Memory::transferData(uint16_t startAddr)
{
	int a = 0;

	for (uint16_t currAddr = startAddr ; currAddr <= (startAddr + 0x8c) ; currAddr++)
	{
		write_byte(0xfe00 + a, read_byte(currAddr));
		a++;
	}
}

void			Memory::handleInput()
{
	if ((read_byte(0xff00) & 0x30) == 0x10)
		write_byte(0xff00, 0x10 + key[1], true);
	else if ((read_byte(0xff00) & 0x30) == 0x20)
		write_byte(0xff00, 0x20 + key[0], true);
}

t_color15		Memory::getBgColor15(uint8_t palId, uint8_t colorId)
{
	return _bcp[palId][colorId];
}

t_color15		Memory::getObjColor15(uint8_t palId, uint8_t colorId)
{
	return _ocp[palId][colorId];
}

uint8_t			Memory::force_read_vram(uint16_t addr, uint8_t bank)
{
	return this->_m_vram[bank & 0x1][addr & 0x1FFF];
}

uint8_t			Memory::read_byte(uint16_t addr)
{
	switch (addr & 0xF000){
		case 0x0000:
			if (this->_inBios)
			{
				if (addr <= 0xFF)
					return this->_codeBios[addr];
				else if (addr >= 0x200 && addr < 0x900 && getTypeBios() == GBC)
					return this->_codeBios[addr - 0x100];
				else
					return this->_rom.read(addr);
			}
			else
			{
				return this->_rom.read(addr);
			}
			break;
		case 0x1000:
		case 0x2000:
		case 0x3000:
		case 0x4000:
		case 0x5000:
		case 0x6000:
		case 0x7000:
			// ROM
			return this->_rom.read(addr);
			break;
		case 0x8000:
		case 0x9000:
			// VRAM
			return this->_m_vram[(this->_m_io[(VBK & 0xFF)] & 0x01)][(addr & 0x1FFF)];
			break;
		case 0xA000:
		case 0xB000:
			// ERAM
			return this->_rom.read(addr);
			break;
		case 0xC000:
		case 0xD000:
			// WRAM
			if ((addr & 0xF000) < 0xD000)
				return this->_m_wram[0][(addr & 0x1FFF)];
			else
				return this->_m_wram
					[(this->_m_io[(SVBK & 0xFF)] & 0x07)]
					[(addr & 0x1FFF)];
			break;
		case 0xF000:
			switch (addr & 0x0F00){
				case 0x0E00:
					if ((addr & 0xFF) <= 0x9F)
					{
						// SPRITE
						return this->_m_oam[(addr & 0xFF)];
					}
					break;
				case 0x0F00:
					if ((addr & 0xFF) <= 0x7F)
					{
						// I/O
						return this->_m_io[(addr & 0xFF)];
					}
					else
					{
						// Zero page
						return this->_m_zp[(addr & 0xFF) - 0x80];
					}
					break;
			}
			break;
	}
	return 0;
}

void			Memory::write_byte(uint16_t addr, uint8_t val, bool super)
{
	switch (addr & 0xF000){
		case 0x0000:
		case 0x1000:
		case 0x2000:
		case 0x3000:
		case 0x4000:
		case 0x5000:
		case 0x6000:
		case 0x7000:
			// ROM
			this->_rom.write(addr, val);
			break;
		case 0x8000:
		case 0x9000:
			// VRAM
			this->_m_vram[(this->_m_io[(VBK & 0xFF)] & 0x01)][(addr & 0x1FFF)] = val;
			break;
		case 0xA000:
		case 0xB000:
			// ERAM
			this->_rom.write(addr, val);
			break;
		case 0xC000:
		case 0xD000:
			// WRAM
			if ((addr & 0xF000) < 0xD000)
				this->_m_wram[0][(addr & 0x1FFF)] = val;
			else
				this->_m_wram[(this->_m_io[(SVBK & 0xFF)] & 0x03)][(addr & 0x1FFF)] = val;
			break;
		case 0xF000:
			switch (addr & 0x0F00){
				case 0x0E00:
					if ((addr & 0xFF) <= 0x9F)
					{
						// SPRITE
						this->_m_oam[(addr & 0xFF)] = val;
					}
					break;
				case 0x0F00:
					if (!super && addr == 0xFF00)
					{
						// P1
						this->_m_io[(addr & 0xFF)] = (val & 0xF0) | (this->_m_io[(addr & 0xFF)] & 0x0F);
						handleInput();
					}
					else if (!super && addr == 0xFF04)
					{
						// DIV
						this->_m_io[(addr & 0xFF)] = 0x00;
					}
					else if ((addr & 0xFF) <= 0x7F)
					{
						// I/O

						//protect 3 first byte of register STAT form overwritting
						if (addr == REGISTER_STAT && !super)
						{
							val &= 0xF8;
							val |= read_byte(REGISTER_STAT) & 0x07;
						}
						if ((addr == 0xFF44 || addr == 0xFF45) && read_byte(0xFF40) & 0x80)
						{
							if (read_byte(0xFF44) == read_byte(0xFF45))
								this->_m_io[0x41] |= 0x04;// Coincidence
							else
								this->_m_io[0x41] &= 0xfb;
						}
						else if (addr == 0xFF40 && (val & 0x80))
						{
							if (read_byte(0xFF44) == read_byte(0xFF45))
								this->_m_io[0x41] |= 0x04;
							else
								this->_m_io[0x41] &= 0xfb;
						}
						//DMA
						if (addr == REGISTER_DMA)
							transferData(val << 8);
						// BCPS / BCPD
						if (addr == REGISTER_BCPS) {
							this->_m_io[REGISTER_BCPD & 0xFF] = ((uint8_t*)_bcp)[val & 0x3F];
						}
						if (addr == REGISTER_BCPD) {
							((uint8_t*)_bcp)[read_byte(REGISTER_BCPS) & 0x3F] = val;
							if (read_byte(REGISTER_BCPS) & 0x80)
								write_byte(REGISTER_BCPS, ((((read_byte(REGISTER_BCPS) << 2) + 4) & 0xFF) >> 2) | 0x80);
						}
						// OCPS / OCPD
						if (addr == REGISTER_OCPS) {
							this->_m_io[REGISTER_OCPD & 0xFF] = ((uint8_t*)_ocp)[val & 0x3F];
						}
						if (addr == REGISTER_OCPD) {
							((uint8_t*)_ocp)[read_byte(REGISTER_OCPS) & 0x3F] = val;
							if (read_byte(REGISTER_OCPS) & 0x80)
								write_byte(REGISTER_OCPS, ((((read_byte(REGISTER_OCPS) << 2) + 4) & 0xFF) >> 2) | 0x80);
						}
						this->_m_io[(addr & 0xFF)] = val;
					}
					else
					{
						// Zero page
						this->_m_zp[(addr & 0xFF) - 0x80] = val;
					}
					break;
			}
			break;
	}
}

uint16_t		Memory::read_word(uint16_t addr)
{
	return this->read_byte(addr) + (this->read_byte(addr + 1) << 8);
}

void			Memory::write_word(uint16_t addr, uint16_t val, bool super)
{
	this->write_byte(addr, (val & 0xFF), super);
	this->write_byte(addr + 1, ((val & 0xFF00) >> 8), super);
}
<|endoftext|>


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

//$Id$

#ifndef QUERY_HPP
#define QUERY_HPP

//mapnik
#include <mapnik/box2d.hpp>
#include <mapnik/feature.hpp>

// boost
#include <boost/tuple/tuple.hpp>

// stl
#include <set>
#include <limits>

namespace mapnik {

class query
{
public:
    typedef boost::tuple<double,double> resolution_type;
private:
    box2d<double> bbox_;
    resolution_type resolution_;
    double scale_denominator_;
    std::set<std::string> names_;
public:

    explicit query(box2d<double> const& bbox, resolution_type const& resolution, double scale_denominator)
	: bbox_(bbox),
	  resolution_(resolution),
	  scale_denominator_(scale_denominator)
    {}

    explicit query(box2d<double> const& bbox, resolution_type const& resolution)
	: bbox_(bbox),
	  resolution_(resolution),
	  scale_denominator_(0.0)
    {}

    query(query const& other)
	: bbox_(other.bbox_),
	  resolution_(other.resolution_),
	  scale_denominator_(other.scale_denominator_),
	  names_(other.names_)
    {}

    query& operator=(query const& other)
    {
	if (this == &other) return *this;
	bbox_=other.bbox_;
	resolution_=other.resolution_;
	scale_denominator_=other.scale_denominator_;
	names_=other.names_;
	return *this;
    }

    query::resolution_type const& resolution() const
    {
	return resolution_;
    }

    double scale_denominator() const
    {
	return scale_denominator_;
    }

    box2d<double> const& get_bbox() const
    {
	return bbox_;
    }

    void add_property_name(std::string const& name)
    {
	names_.insert(name);
    }

    std::set<std::string> const& property_names() const
    {
	return names_;
    }
};
}

#endif //QUERY_HPP
<commit_msg>+ merge ctors<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id$

#ifndef QUERY_HPP
#define QUERY_HPP

//mapnik
#include <mapnik/box2d.hpp>
#include <mapnik/feature.hpp>

// boost
#include <boost/tuple/tuple.hpp>

// stl
#include <set>
#include <limits>

namespace mapnik {

class query
{
public:
    typedef boost::tuple<double,double> resolution_type;
private:
    box2d<double> bbox_;
    resolution_type resolution_;
    double scale_denominator_;
    std::set<std::string> names_;
public:

    query(box2d<double> const& bbox, resolution_type const& resolution, double scale_denominator = 1.0)
	: bbox_(bbox),
	  resolution_(resolution),
	  scale_denominator_(scale_denominator)
    {}

    query(query const& other)
	: bbox_(other.bbox_),
	  resolution_(other.resolution_),
	  scale_denominator_(other.scale_denominator_),
	  names_(other.names_)
    {}

    query& operator=(query const& other)
    {
	if (this == &other) return *this;
	bbox_=other.bbox_;
	resolution_=other.resolution_;
	scale_denominator_=other.scale_denominator_;
	names_=other.names_;
	return *this;
    }

    query::resolution_type const& resolution() const
    {
	return resolution_;
    }

    double scale_denominator() const
    {
	return scale_denominator_;
    }

    box2d<double> const& get_bbox() const
    {
	return bbox_;
    }

    void add_property_name(std::string const& name)
    {
	names_.insert(name);
    }

    std::set<std::string> const& property_names() const
    {
	return names_;
    }
};
}

#endif //QUERY_HPP
<|endoftext|>


<commit_before>/*
 *  Copyright 2008-2010 NVIDIA Corporation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#include <thrust/random/uniform_real_distribution.h>
#include <math.h>

namespace thrust
{

namespace random
{

template<typename RealType>
  uniform_real_distribution<RealType>
    ::uniform_real_distribution(RealType a, RealType b)
      :m_param(a,b)
{
} // end uniform_real_distribution::uniform_real_distribution()

template<typename RealType>
  uniform_real_distribution<RealType>
    ::uniform_real_distribution(const param_type &parm)
      :m_param(parm)
{
} // end uniform_real_distribution::uniform_real_distribution()

template<typename RealType>
  void uniform_real_distribution<RealType>
    ::reset(void)
{
} // end uniform_real_distribution::reset()

template<typename RealType>
  template<typename UniformRandomNumberGenerator>
    typename uniform_real_distribution<RealType>::result_type
      uniform_real_distribution<RealType>
        ::operator()(UniformRandomNumberGenerator &urng)
{
  return operator()(urng, m_param);
} // end uniform_real::operator()()

namespace detail
{

__host__ __device__ __inline__
double nextafter(double x, double y)
{
  return ::nextafter(x,y);
}

__host__ __device__ __inline__
float nextafter(float x, float y)
{
  return ::nextafterf(x,y);
}

}

template<typename RealType>
  template<typename UniformRandomNumberGenerator>
    typename uniform_real_distribution<RealType>::result_type
      uniform_real_distribution<RealType>
        ::operator()(UniformRandomNumberGenerator &urng,
                     const param_type &parm)
{
  // call the urng & map its result to [0,1]
  result_type result = static_cast<result_type>(urng() - UniformRandomNumberGenerator::min);
  result /= static_cast<result_type>(UniformRandomNumberGenerator::max - UniformRandomNumberGenerator::min);

  // do not include parm.second in the result
  // get the next value after parm.second in the direction of parm.first
  // we need to do this because the range is half-open at parm.second

  return (result * (detail::nextafter(parm.second,parm.first) - parm.first)) + parm.first;
} // end uniform_real::operator()()

template<typename RealType>
  typename uniform_real_distribution<RealType>::result_type
    uniform_real_distribution<RealType>
      ::a(void) const
{
  return m_param.first;
} // end uniform_real::a()

template<typename RealType>
  typename uniform_real_distribution<RealType>::result_type
    uniform_real_distribution<RealType>
      ::b(void) const
{
  return m_param.second;
} // end uniform_real_distribution::b()

template<typename RealType>
  typename uniform_real_distribution<RealType>::param_type
    uniform_real_distribution<RealType>
      ::param(void) const
{
  return m_param;;
} // end uniform_real_distribution::param()

template<typename RealType>
  void uniform_real_distribution<RealType>
    ::param(const param_type &parm)
{
  m_param = parm;
} // end uniform_real_distribution::param()

template<typename RealType>
  typename uniform_real_distribution<RealType>::result_type
    uniform_real_distribution<RealType>
      ::min(void) const
{
  return a();
} // end uniform_real_distribution::min()

template<typename RealType>
  typename uniform_real_distribution<RealType>::result_type
    uniform_real_distribution<RealType>
      ::max(void) const
{
  return b();
} // end uniform_real_distribution::max()

template<typename RealType>
  bool uniform_real_distribution<RealType>
    ::equal(const uniform_real_distribution &rhs) const
{
  return m_param == rhs.param();
}

template<typename RealType>
  template<typename CharT, typename Traits>
    std::basic_ostream<CharT,Traits>&
      uniform_real_distribution<RealType>
        ::stream_out(std::basic_ostream<CharT,Traits> &os) const
{
  typedef std::basic_ostream<CharT,Traits> ostream_type;
  typedef typename ostream_type::ios_base  ios_base;

  // save old flags and fill character
  const typename ios_base::fmtflags flags = os.flags();
  const CharT fill = os.fill();

  const CharT space = os.widen(' ');
  os.flags(ios_base::dec | ios_base::fixed | ios_base::left);
  os.fill(space);

  os << a() << space << b();

  // restore old flags and fill character
  os.flags(flags);
  os.fill(fill);
  return os;
}

template<typename RealType>
  template<typename CharT, typename Traits>
    std::basic_istream<CharT,Traits>&
      uniform_real_distribution<RealType>
        ::stream_in(std::basic_istream<CharT,Traits> &is)
{
  typedef std::basic_istream<CharT,Traits> istream_type;
  typedef typename istream_type::ios_base  ios_base;

  // save old flags
  const typename ios_base::fmtflags flags = is.flags();

  is.flags(ios_base::skipws);

  is >> m_param.first >> m_param.second;

  // restore old flags
  is.flags(flags);
  return is;
}

template<typename RealType>
bool operator==(const uniform_real_distribution<RealType> &lhs,
                const uniform_real_distribution<RealType> &rhs)
{
  return thrust::random::detail::random_core_access::equal(lhs,rhs);
}

template<typename RealType>
bool operator!=(const uniform_real_distribution<RealType> &lhs,
                const uniform_real_distribution<RealType> &rhs)
{
  return !(lhs == rhs);
}

template<typename RealType,
         typename CharT, typename Traits>
std::basic_ostream<CharT,Traits>&
operator<<(std::basic_ostream<CharT,Traits> &os,
           const uniform_real_distribution<RealType> &d)
{
  return thrust::random::detail::random_core_access::stream_out(os,d);
}

template<typename RealType,
         typename CharT, typename Traits>
std::basic_istream<CharT,Traits>&
operator>>(std::basic_istream<CharT,Traits> &is,
           uniform_real_distribution<RealType> &d)
{
  return thrust::random::detail::random_core_access::stream_in(is,d);
}

} // end random

} // end thrust

<commit_msg>Add forward declarations for nextafter & nextafterf to uniform_real_distribution.inl to WAR missing definitions on MSVC.<commit_after>/*
 *  Copyright 2008-2010 NVIDIA Corporation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#include <thrust/random/uniform_real_distribution.h>
#include <math.h>

// XXX WAR missing definitions on MSVC
__host__ __device__
double nextafter(double, double);

__host__ __device__
float nextafterf(float, float);

namespace thrust
{

namespace random
{

template<typename RealType>
  uniform_real_distribution<RealType>
    ::uniform_real_distribution(RealType a, RealType b)
      :m_param(a,b)
{
} // end uniform_real_distribution::uniform_real_distribution()

template<typename RealType>
  uniform_real_distribution<RealType>
    ::uniform_real_distribution(const param_type &parm)
      :m_param(parm)
{
} // end uniform_real_distribution::uniform_real_distribution()

template<typename RealType>
  void uniform_real_distribution<RealType>
    ::reset(void)
{
} // end uniform_real_distribution::reset()

template<typename RealType>
  template<typename UniformRandomNumberGenerator>
    typename uniform_real_distribution<RealType>::result_type
      uniform_real_distribution<RealType>
        ::operator()(UniformRandomNumberGenerator &urng)
{
  return operator()(urng, m_param);
} // end uniform_real::operator()()

namespace detail
{

__host__ __device__ __inline__
double nextafter(double x, double y)
{
  return ::nextafter(x,y);
}

__host__ __device__ __inline__
float nextafter(float x, float y)
{
  return ::nextafterf(x,y);
}

}

template<typename RealType>
  template<typename UniformRandomNumberGenerator>
    typename uniform_real_distribution<RealType>::result_type
      uniform_real_distribution<RealType>
        ::operator()(UniformRandomNumberGenerator &urng,
                     const param_type &parm)
{
  // call the urng & map its result to [0,1]
  result_type result = static_cast<result_type>(urng() - UniformRandomNumberGenerator::min);
  result /= static_cast<result_type>(UniformRandomNumberGenerator::max - UniformRandomNumberGenerator::min);

  // do not include parm.second in the result
  // get the next value after parm.second in the direction of parm.first
  // we need to do this because the range is half-open at parm.second

  return (result * (detail::nextafter(parm.second,parm.first) - parm.first)) + parm.first;
} // end uniform_real::operator()()

template<typename RealType>
  typename uniform_real_distribution<RealType>::result_type
    uniform_real_distribution<RealType>
      ::a(void) const
{
  return m_param.first;
} // end uniform_real::a()

template<typename RealType>
  typename uniform_real_distribution<RealType>::result_type
    uniform_real_distribution<RealType>
      ::b(void) const
{
  return m_param.second;
} // end uniform_real_distribution::b()

template<typename RealType>
  typename uniform_real_distribution<RealType>::param_type
    uniform_real_distribution<RealType>
      ::param(void) const
{
  return m_param;;
} // end uniform_real_distribution::param()

template<typename RealType>
  void uniform_real_distribution<RealType>
    ::param(const param_type &parm)
{
  m_param = parm;
} // end uniform_real_distribution::param()

template<typename RealType>
  typename uniform_real_distribution<RealType>::result_type
    uniform_real_distribution<RealType>
      ::min(void) const
{
  return a();
} // end uniform_real_distribution::min()

template<typename RealType>
  typename uniform_real_distribution<RealType>::result_type
    uniform_real_distribution<RealType>
      ::max(void) const
{
  return b();
} // end uniform_real_distribution::max()

template<typename RealType>
  bool uniform_real_distribution<RealType>
    ::equal(const uniform_real_distribution &rhs) const
{
  return m_param == rhs.param();
}

template<typename RealType>
  template<typename CharT, typename Traits>
    std::basic_ostream<CharT,Traits>&
      uniform_real_distribution<RealType>
        ::stream_out(std::basic_ostream<CharT,Traits> &os) const
{
  typedef std::basic_ostream<CharT,Traits> ostream_type;
  typedef typename ostream_type::ios_base  ios_base;

  // save old flags and fill character
  const typename ios_base::fmtflags flags = os.flags();
  const CharT fill = os.fill();

  const CharT space = os.widen(' ');
  os.flags(ios_base::dec | ios_base::fixed | ios_base::left);
  os.fill(space);

  os << a() << space << b();

  // restore old flags and fill character
  os.flags(flags);
  os.fill(fill);
  return os;
}

template<typename RealType>
  template<typename CharT, typename Traits>
    std::basic_istream<CharT,Traits>&
      uniform_real_distribution<RealType>
        ::stream_in(std::basic_istream<CharT,Traits> &is)
{
  typedef std::basic_istream<CharT,Traits> istream_type;
  typedef typename istream_type::ios_base  ios_base;

  // save old flags
  const typename ios_base::fmtflags flags = is.flags();

  is.flags(ios_base::skipws);

  is >> m_param.first >> m_param.second;

  // restore old flags
  is.flags(flags);
  return is;
}

template<typename RealType>
bool operator==(const uniform_real_distribution<RealType> &lhs,
                const uniform_real_distribution<RealType> &rhs)
{
  return thrust::random::detail::random_core_access::equal(lhs,rhs);
}

template<typename RealType>
bool operator!=(const uniform_real_distribution<RealType> &lhs,
                const uniform_real_distribution<RealType> &rhs)
{
  return !(lhs == rhs);
}

template<typename RealType,
         typename CharT, typename Traits>
std::basic_ostream<CharT,Traits>&
operator<<(std::basic_ostream<CharT,Traits> &os,
           const uniform_real_distribution<RealType> &d)
{
  return thrust::random::detail::random_core_access::stream_out(os,d);
}

template<typename RealType,
         typename CharT, typename Traits>
std::basic_istream<CharT,Traits>&
operator>>(std::basic_istream<CharT,Traits> &is,
           uniform_real_distribution<RealType> &d)
{
  return thrust::random::detail::random_core_access::stream_in(is,d);
}

} // end random

} // end thrust

<|endoftext|>


<commit_before>#include "general.hpp"
using namespace std;

string tostring(int i) {
	ostringstream tmp;
	tmp << i;
	return tmp.str();
}

int stringToInt(string const& str) {
	istringstream i(str);
	int x;
	i >> x;
	return x;
}

float stringToFloat(string const& str) {
	istringstream i(str);
	float x;
	i >> x;
	return x;
}

vector<string> &split(const string &s, char delim, vector<string> &elems) {
	stringstream ss(s);
	string item;
	while (getline(ss, item, delim)) {
		elems.push_back(item);
	}
	return elems;
}

vector<string> split(const string &s, char delim) {
	// taken from http://stackoverflow.com/a/236803
	vector<string> elems;
	split(s, delim, elems);
	return elems;
}

string removeAllQuotes(string s) {
	s.erase(remove(s.begin(), s.end(), '\"'), s.end());
	return s;
}

string removeTrailingSlashes(string s) {
	if (s[s.length()-1] == '/')
		s = s.substr(0, s.length()-1);
	return s;
}

string removeTrailingText(string s, string toRemove) {
	if (s.find(toRemove) != s.npos)
		s.erase(s.find(toRemove));
	return s;
}

string removeStartingText(string s, string toRemove) {
	if (s.find(toRemove) != s.npos)
		s.erase(s.find_first_of(toRemove), s.find_first_of(toRemove)+toRemove.length());
	return s;
}

string deDoubleString(string s) {
	// Todo: write this.
	return s;
}

void printEntireRecord(vector<string> record) {
	for (vector<string>::iterator i = record.begin(); i != record.end(); ++i) {
		cout << *i;
		if (i!=record.end()-1)
			cout << ", ";
		else
			cout << endl;
	}
}

string getFileContents(string fn) {
	ifstream in(fn.c_str(), ios::in | ios::binary);
	if (in) {
		string contents;
		in.seekg(0, ios::end);
		contents.resize(in.tellg());
		in.seekg(0, ios::beg);
		in.read(&contents[0], contents.size());
		in.close();
		return(contents);
	}
	throw(errno);
}
<commit_msg>Might want to mention *which* file cannot be opened.<commit_after>#include "general.hpp"
using namespace std;

string tostring(int i) {
	ostringstream tmp;
	tmp << i;
	return tmp.str();
}

int stringToInt(string const& str) {
	istringstream i(str);
	int x;
	i >> x;
	return x;
}

float stringToFloat(string const& str) {
	istringstream i(str);
	float x;
	i >> x;
	return x;
}

vector<string> &split(const string &s, char delim, vector<string> &elems) {
	stringstream ss(s);
	string item;
	while (getline(ss, item, delim)) {
		elems.push_back(item);
	}
	return elems;
}

vector<string> split(const string &s, char delim) {
	// taken from http://stackoverflow.com/a/236803
	vector<string> elems;
	split(s, delim, elems);
	return elems;
}

string removeAllQuotes(string s) {
	s.erase(remove(s.begin(), s.end(), '\"'), s.end());
	return s;
}

string removeTrailingSlashes(string s) {
	if (s[s.length()-1] == '/')
		s = s.substr(0, s.length()-1);
	return s;
}

string removeTrailingText(string s, string toRemove) {
	if (s.find(toRemove) != s.npos)
		s.erase(s.find(toRemove));
	return s;
}

string removeStartingText(string s, string toRemove) {
	if (s.find(toRemove) != s.npos)
		s.erase(s.find_first_of(toRemove), s.find_first_of(toRemove)+toRemove.length());
	return s;
}

string deDoubleString(string s) {
	// Todo: write this.
	return s;
}

void printEntireRecord(vector<string> record) {
	for (vector<string>::iterator i = record.begin(); i != record.end(); ++i) {
		cout << *i;
		if (i!=record.end()-1)
			cout << ", ";
		else
			cout << endl;
	}
}

string getFileContents(string fn) {
	ifstream in(fn.c_str(), ios::in | ios::binary);
	if (in) {
		string contents;
		in.seekg(0, ios::end);
		contents.resize(in.tellg());
		in.seekg(0, ios::beg);
		in.read(&contents[0], contents.size());
		in.close();
		return(contents);
	}
	else {
		cout << "Could not open file: " << fn << endl;
		throw(errno);
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright 2014 Open Connectome Project (http://openconnecto.me)
 * Written by Da Zheng (zhengda1936@gmail.com)
 *
 * This file is part of FlashMatrix.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <pthread.h>

#include "sparse_matrix.h"
#include "matrix_io.h"
#include "matrix_config.h"

namespace fm
{

/*
 * This represents a collection of row blocks that we usually access with
 * a single I/O request. However, due to load balancing, we sometimes
 * need to access the collection of row blocks with many smaller I/O
 * requests. In this case, each row block is accessed by one I/O request.
 */
class large_row_io
{
	// A reference to the row block vector of the graph.
	const std::vector<row_block> *blocks;
	// The offset of the first row block in the row block vector.
	off_t first_row_block;
	size_t num_row_blocks;
	size_t tot_num_rows;
public:
	large_row_io(const std::vector<row_block> &_blocks, off_t first_row_block,
			size_t num_row_blocks, size_t tot_num_rows) {
		this->blocks = &_blocks;
		this->first_row_block = first_row_block;
		this->num_row_blocks = num_row_blocks;
		this->tot_num_rows = tot_num_rows;
	}

	/*
	 * Create an I/O request that access all row blocks in the collection.
	 */
	matrix_io get_io(size_t tot_num_cols, int file_id) {
		off_t first_row_id = first_row_block * matrix_conf.get_row_block_size();
		matrix_loc top_left(first_row_id, 0);
		size_t num_rows = tot_num_rows;
		off_t first_row_offset = blocks->at(first_row_block).get_offset();
		size_t size = blocks->at(first_row_block + num_row_blocks).get_offset()
			- first_row_offset;
		matrix_io ret(top_left, num_rows, tot_num_cols,
					safs::data_loc_t(file_id, first_row_offset), size);
		first_row_block += num_row_blocks;
		num_row_blocks = 0;
		tot_num_rows = 0;
		return ret;
	}

	/*
	 * Create an I/O request that accesses a single row block.
	 */
	matrix_io get_sub_io(size_t tot_num_cols, int file_id) {
		off_t first_row_id = first_row_block * matrix_conf.get_row_block_size();
		matrix_loc top_left(first_row_id, 0);
		size_t num_curr_row_blocks = std::min(num_row_blocks,
				(size_t) matrix_conf.get_rb_steal_io_size());
		size_t num_rows = std::min(tot_num_rows,
				(size_t) num_curr_row_blocks * matrix_conf.get_row_block_size());
		off_t first_row_offset = blocks->at(first_row_block).get_offset();
		size_t size = blocks->at(first_row_block + num_curr_row_blocks).get_offset()
			- first_row_offset;
		matrix_io ret(top_left, num_rows,
				tot_num_cols, safs::data_loc_t(file_id, first_row_offset), size);
		first_row_block += num_curr_row_blocks;
		num_row_blocks -= num_curr_row_blocks;
		tot_num_rows -= num_rows;
		return ret;
	}

	bool has_data() const {
		return num_row_blocks > 0;
	}
};

/*
 * The I/O generator that access a matrix on disks by rows.
 * It dynamically assigns a row block to a thread each time and thus balances
 * the load automatically.
 */
class dyn_row_iogen: public matrix_io_generator
{
	std::vector<large_row_io> ios;
	// The current offset in the row_block vector.
	volatile off_t curr_io_off;
	int file_id;
	size_t tot_num_cols;

	pthread_spinlock_t lock;
public:
	dyn_row_iogen(const std::vector<row_block> &_blocks, size_t tot_num_rows,
			size_t tot_num_cols, int file_id, const row_block_mapper &mapper);

	/*
	 * This method is called by the worker thread that owns the I/O generator
	 * to get I/O requests.
	 */
	virtual matrix_io get_next_io() {
		matrix_io ret;
		pthread_spin_lock(&lock);
		if ((size_t) curr_io_off < ios.size()) {
			assert(ios[curr_io_off].has_data());
			ret = ios[curr_io_off++].get_io(tot_num_cols, file_id);
			assert(ret.is_valid());
		}
		pthread_spin_unlock(&lock);
		return ret;
	}

	virtual bool has_next_io() {
		// The last entry in the row_block vector is the size of the matrix
		// file.
		return (size_t) curr_io_off < ios.size();
	}
};

dyn_row_iogen::dyn_row_iogen(const std::vector<row_block> &blocks,
		size_t tot_num_rows, size_t tot_num_cols, int file_id,
		const row_block_mapper &mapper)
{
	pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE);
	// blocks[blocks.size() - 1] is an empty block. It only indicates
	// the end of the matrix file.
	// blocks[blocks.size() - 2] is the last row block. It's possible that
	// it's smaller than the full-size row block.
	for (size_t i = 0; i < mapper.get_num_ranges(); i++) {
		size_t num_row_blocks = mapper.get_range(i).num;
		off_t rb_off = mapper.get_range(i).idx;
		size_t num_rows = std::min(num_row_blocks * matrix_conf.get_row_block_size(),
				tot_num_rows - rb_off * matrix_conf.get_row_block_size());
		ios.emplace_back(blocks, rb_off, num_row_blocks, num_rows);
	}
	curr_io_off = 0;
	this->tot_num_cols = tot_num_cols;
	this->file_id = file_id;
}

/*
 * The I/O generator that access a matrix on disks by rows.
 * This assigns a row block to a thread statically, so it can't balance the load.
 * This is for testing purpose only.
 */
class static_row_iogen: public matrix_io_generator
{
	std::vector<large_row_io> ios;
	int file_id;
	size_t tot_num_cols;
	size_t num_threads;
	// The current offset in the row_block vector for each thread.
	std::vector<size_t> curr_io_offs;
public:
	static_row_iogen(const std::vector<row_block> &_blocks, size_t tot_num_rows,
			size_t tot_num_cols, int file_id, const row_block_mapper &mapper);

	/*
	 * This method is called by the worker thread that owns the I/O generator
	 * to get I/O requests.
	 */
	virtual matrix_io get_next_io() {
		matrix_io ret;
		int thread_id = detail::mem_thread_pool::get_curr_thread_id();
		size_t curr_io_off = curr_io_offs[thread_id];
		if (curr_io_off < ios.size()) {
			assert(ios[curr_io_off].has_data());
			ret = ios[curr_io_off].get_io(tot_num_cols, file_id);
			// This is the easiest way of assign row blocks to threads.
			curr_io_offs[thread_id] += num_threads;
			assert(ret.is_valid());
		}
		return ret;
	}

	virtual bool has_next_io() {
		int thread_id = detail::mem_thread_pool::get_curr_thread_id();
		return curr_io_offs[thread_id] < ios.size();
	}
};

static_row_iogen::static_row_iogen(const std::vector<row_block> &blocks,
		size_t tot_num_rows, size_t tot_num_cols, int file_id,
		const row_block_mapper &mapper)
{
	// blocks[blocks.size() - 1] is an empty block. It only indicates
	// the end of the matrix file.
	// blocks[blocks.size() - 2] is the last row block. It's possible that
	// it's smaller than the full-size row block.
	for (size_t i = 0; i < mapper.get_num_ranges(); i++) {
		size_t num_row_blocks = mapper.get_range(i).num;
		off_t rb_off = mapper.get_range(i).idx;
		size_t num_rows = std::min(
				num_row_blocks * matrix_conf.get_row_block_size(),
				tot_num_rows - rb_off * matrix_conf.get_row_block_size());
		ios.emplace_back(blocks, rb_off, num_row_blocks, num_rows);
	}
	this->tot_num_cols = tot_num_cols;
	this->file_id = file_id;
	this->num_threads = detail::mem_thread_pool::get_global_num_threads();
	curr_io_offs.resize(num_threads);
	for (size_t i = 0; i < curr_io_offs.size(); i++)
		curr_io_offs[i] = i;
}

/*
 * The I/O generator for accessing 2D-partitioned blocks.
 * A generated I/O request may access multiple 2D-partitioned blocks.
 * Each I/O generator still accesses all blocks in a block row.
 */
class b2d_io_generator: public matrix_io_generator
{
	pthread_spinlock_t lock;
	size_t brow_idx;
	size_t min_num_brows;
	size_t io_num_brows;
	// This is the starting point where we give a single block row for
	// each assignment for load balancing. This points to a block row.
	size_t balance_point;

	SpM_2d_index::ptr idx;
	block_2d_size block_size;
	int file_id;
	size_t tot_num_cols;
public:
	b2d_io_generator(SpM_2d_index::ptr idx, int file_id, size_t io_num_brows,
			size_t min_num_brows);

	virtual matrix_io get_next_io();

	virtual bool has_next_io() {
		return brow_idx < idx->get_num_block_rows();
	}
};

b2d_io_generator::b2d_io_generator(SpM_2d_index::ptr idx, int file_id,
		size_t io_num_brows, size_t min_num_brows): block_size(
			idx->get_header().get_2d_block_size())
{
	this->idx = idx;
	this->io_num_brows = io_num_brows;
	this->min_num_brows = min_num_brows;
	if (io_num_brows > min_num_brows) {
		size_t num_threads = detail::mem_thread_pool::get_global_num_threads();
		// We reserve some block rows in the matrix that are assigned one blow
		// row at a time.
		if (idx->get_num_block_rows() > io_num_brows * num_threads)
			balance_point = idx->get_num_block_rows() - num_threads;
		else
			balance_point = 0;
	}
	else
		balance_point = idx->get_num_block_rows();
	this->tot_num_cols = idx->get_header().get_num_cols();
	this->file_id = file_id;
	this->brow_idx = 0;
	pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE);
}

matrix_io b2d_io_generator::get_next_io()
{
	matrix_io ret;
	pthread_spin_lock(&lock);
	// It's possible that all IOs have been stolen.
	// We have to check it.
	if (has_next_io()) {
		// If we have passed the balancing point, we now assign one block row
		// to a thread each time.
		if (brow_idx >= balance_point)
			io_num_brows = min_num_brows;

		matrix_loc mat_loc(brow_idx * block_size.get_num_rows(), 0);
		safs::data_loc_t data_loc(file_id, idx->get_block_row_off(brow_idx));
		size_t num_brows = std::min(io_num_brows,
				idx->get_num_block_rows() - brow_idx);
		size_t brow_size = idx->get_block_row_off(brow_idx
				+ num_brows) - idx->get_block_row_off(brow_idx);
		ret = matrix_io(mat_loc, block_size.get_num_rows() * num_brows,
				tot_num_cols, data_loc, brow_size);
		brow_idx += num_brows;
	}
	pthread_spin_unlock(&lock);
	return ret;
}

matrix_io_generator::ptr matrix_io_generator::create(
		const std::vector<row_block> &_blocks, size_t tot_num_rows,
		size_t tot_num_cols, int file_id, const row_block_mapper &mapper)
{
	return matrix_io_generator::ptr(new dyn_row_iogen(_blocks,
				tot_num_rows, tot_num_cols, file_id, mapper));
}

matrix_io_generator::ptr matrix_io_generator::create(SpM_2d_index::ptr idx,
		int file_id, size_t io_num_brows, size_t min_num_brows)
{
	return matrix_io_generator::ptr(new b2d_io_generator(idx, file_id,
				io_num_brows, min_num_brows));
}

void row_block_mapper::init(size_t num_rbs, size_t range_size)
{
	// We now need to jump to the next row block that belongs to
	// the current I/O generator.
	for (size_t i = 0; i < num_rbs; i += range_size) {
		struct rb_range range;
		range.idx = i;
		range.num = std::min(range_size, num_rbs - i);
		ranges.push_back(range);
	}
}

row_block_mapper::row_block_mapper(const SpM_2d_index &index, size_t range_size)
{
	init(index.get_num_block_rows(), range_size);
}

}
<commit_msg>[Matrix]: remove static_row_iogen.<commit_after>/*
 * Copyright 2014 Open Connectome Project (http://openconnecto.me)
 * Written by Da Zheng (zhengda1936@gmail.com)
 *
 * This file is part of FlashMatrix.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <pthread.h>

#include "sparse_matrix.h"
#include "matrix_io.h"
#include "matrix_config.h"

namespace fm
{

/*
 * This represents a collection of row blocks that we usually access with
 * a single I/O request. However, due to load balancing, we sometimes
 * need to access the collection of row blocks with many smaller I/O
 * requests. In this case, each row block is accessed by one I/O request.
 */
class large_row_io
{
	// A reference to the row block vector of the graph.
	const std::vector<row_block> *blocks;
	// The offset of the first row block in the row block vector.
	off_t first_row_block;
	size_t num_row_blocks;
	size_t tot_num_rows;
public:
	large_row_io(const std::vector<row_block> &_blocks, off_t first_row_block,
			size_t num_row_blocks, size_t tot_num_rows) {
		this->blocks = &_blocks;
		this->first_row_block = first_row_block;
		this->num_row_blocks = num_row_blocks;
		this->tot_num_rows = tot_num_rows;
	}

	/*
	 * Create an I/O request that access all row blocks in the collection.
	 */
	matrix_io get_io(size_t tot_num_cols, int file_id) {
		off_t first_row_id = first_row_block * matrix_conf.get_row_block_size();
		matrix_loc top_left(first_row_id, 0);
		size_t num_rows = tot_num_rows;
		off_t first_row_offset = blocks->at(first_row_block).get_offset();
		size_t size = blocks->at(first_row_block + num_row_blocks).get_offset()
			- first_row_offset;
		matrix_io ret(top_left, num_rows, tot_num_cols,
					safs::data_loc_t(file_id, first_row_offset), size);
		first_row_block += num_row_blocks;
		num_row_blocks = 0;
		tot_num_rows = 0;
		return ret;
	}

	/*
	 * Create an I/O request that accesses a single row block.
	 */
	matrix_io get_sub_io(size_t tot_num_cols, int file_id) {
		off_t first_row_id = first_row_block * matrix_conf.get_row_block_size();
		matrix_loc top_left(first_row_id, 0);
		size_t num_curr_row_blocks = std::min(num_row_blocks,
				(size_t) matrix_conf.get_rb_steal_io_size());
		size_t num_rows = std::min(tot_num_rows,
				(size_t) num_curr_row_blocks * matrix_conf.get_row_block_size());
		off_t first_row_offset = blocks->at(first_row_block).get_offset();
		size_t size = blocks->at(first_row_block + num_curr_row_blocks).get_offset()
			- first_row_offset;
		matrix_io ret(top_left, num_rows,
				tot_num_cols, safs::data_loc_t(file_id, first_row_offset), size);
		first_row_block += num_curr_row_blocks;
		num_row_blocks -= num_curr_row_blocks;
		tot_num_rows -= num_rows;
		return ret;
	}

	bool has_data() const {
		return num_row_blocks > 0;
	}
};

/*
 * The I/O generator that access a matrix on disks by rows.
 * It dynamically assigns a row block to a thread each time and thus balances
 * the load automatically.
 */
class dyn_row_iogen: public matrix_io_generator
{
	std::vector<large_row_io> ios;
	// The current offset in the row_block vector.
	volatile off_t curr_io_off;
	int file_id;
	size_t tot_num_cols;

	pthread_spinlock_t lock;
public:
	dyn_row_iogen(const std::vector<row_block> &_blocks, size_t tot_num_rows,
			size_t tot_num_cols, int file_id, const row_block_mapper &mapper);

	/*
	 * This method is called by the worker thread that owns the I/O generator
	 * to get I/O requests.
	 */
	virtual matrix_io get_next_io() {
		matrix_io ret;
		pthread_spin_lock(&lock);
		if ((size_t) curr_io_off < ios.size()) {
			assert(ios[curr_io_off].has_data());
			ret = ios[curr_io_off++].get_io(tot_num_cols, file_id);
			assert(ret.is_valid());
		}
		pthread_spin_unlock(&lock);
		return ret;
	}

	virtual bool has_next_io() {
		// The last entry in the row_block vector is the size of the matrix
		// file.
		return (size_t) curr_io_off < ios.size();
	}
};

dyn_row_iogen::dyn_row_iogen(const std::vector<row_block> &blocks,
		size_t tot_num_rows, size_t tot_num_cols, int file_id,
		const row_block_mapper &mapper)
{
	pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE);
	// blocks[blocks.size() - 1] is an empty block. It only indicates
	// the end of the matrix file.
	// blocks[blocks.size() - 2] is the last row block. It's possible that
	// it's smaller than the full-size row block.
	for (size_t i = 0; i < mapper.get_num_ranges(); i++) {
		size_t num_row_blocks = mapper.get_range(i).num;
		off_t rb_off = mapper.get_range(i).idx;
		size_t num_rows = std::min(num_row_blocks * matrix_conf.get_row_block_size(),
				tot_num_rows - rb_off * matrix_conf.get_row_block_size());
		ios.emplace_back(blocks, rb_off, num_row_blocks, num_rows);
	}
	curr_io_off = 0;
	this->tot_num_cols = tot_num_cols;
	this->file_id = file_id;
}

/*
 * The I/O generator for accessing 2D-partitioned blocks.
 * A generated I/O request may access multiple 2D-partitioned blocks.
 * Each I/O generator still accesses all blocks in a block row.
 */
class b2d_io_generator: public matrix_io_generator
{
	pthread_spinlock_t lock;
	size_t brow_idx;
	size_t min_num_brows;
	size_t io_num_brows;
	// This is the starting point where we give a single block row for
	// each assignment for load balancing. This points to a block row.
	size_t balance_point;

	SpM_2d_index::ptr idx;
	block_2d_size block_size;
	int file_id;
	size_t tot_num_cols;
public:
	b2d_io_generator(SpM_2d_index::ptr idx, int file_id, size_t io_num_brows,
			size_t min_num_brows);

	virtual matrix_io get_next_io();

	virtual bool has_next_io() {
		return brow_idx < idx->get_num_block_rows();
	}
};

b2d_io_generator::b2d_io_generator(SpM_2d_index::ptr idx, int file_id,
		size_t io_num_brows, size_t min_num_brows): block_size(
			idx->get_header().get_2d_block_size())
{
	this->idx = idx;
	this->io_num_brows = io_num_brows;
	this->min_num_brows = min_num_brows;
	if (io_num_brows > min_num_brows) {
		size_t num_threads = detail::mem_thread_pool::get_global_num_threads();
		// We reserve some block rows in the matrix that are assigned one blow
		// row at a time.
		if (idx->get_num_block_rows() > io_num_brows * num_threads)
			balance_point = idx->get_num_block_rows() - num_threads;
		else
			balance_point = 0;
	}
	else
		balance_point = idx->get_num_block_rows();
	this->tot_num_cols = idx->get_header().get_num_cols();
	this->file_id = file_id;
	this->brow_idx = 0;
	pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE);
}

matrix_io b2d_io_generator::get_next_io()
{
	matrix_io ret;
	pthread_spin_lock(&lock);
	// It's possible that all IOs have been stolen.
	// We have to check it.
	if (has_next_io()) {
		// If we have passed the balancing point, we now assign one block row
		// to a thread each time.
		if (brow_idx >= balance_point)
			io_num_brows = min_num_brows;

		matrix_loc mat_loc(brow_idx * block_size.get_num_rows(), 0);
		safs::data_loc_t data_loc(file_id, idx->get_block_row_off(brow_idx));
		size_t num_brows = std::min(io_num_brows,
				idx->get_num_block_rows() - brow_idx);
		size_t brow_size = idx->get_block_row_off(brow_idx
				+ num_brows) - idx->get_block_row_off(brow_idx);
		ret = matrix_io(mat_loc, block_size.get_num_rows() * num_brows,
				tot_num_cols, data_loc, brow_size);
		brow_idx += num_brows;
	}
	pthread_spin_unlock(&lock);
	return ret;
}

matrix_io_generator::ptr matrix_io_generator::create(
		const std::vector<row_block> &_blocks, size_t tot_num_rows,
		size_t tot_num_cols, int file_id, const row_block_mapper &mapper)
{
	return matrix_io_generator::ptr(new dyn_row_iogen(_blocks,
				tot_num_rows, tot_num_cols, file_id, mapper));
}

matrix_io_generator::ptr matrix_io_generator::create(SpM_2d_index::ptr idx,
		int file_id, size_t io_num_brows, size_t min_num_brows)
{
	return matrix_io_generator::ptr(new b2d_io_generator(idx, file_id,
				io_num_brows, min_num_brows));
}

void row_block_mapper::init(size_t num_rbs, size_t range_size)
{
	// We now need to jump to the next row block that belongs to
	// the current I/O generator.
	for (size_t i = 0; i < num_rbs; i += range_size) {
		struct rb_range range;
		range.idx = i;
		range.num = std::min(range_size, num_rbs - i);
		ranges.push_back(range);
	}
}

row_block_mapper::row_block_mapper(const SpM_2d_index &index, size_t range_size)
{
	init(index.get_num_block_rows(), range_size);
}

}
<|endoftext|>


<commit_before><commit_msg>Avoid undefined computation of unaligned pointers to multi-byte objects<commit_after><|endoftext|>


<commit_before>#include "process.h"

// POSIX
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>

// POSIX++
#include <cerrno>
#include <cstdlib>
#include <climits>
#include <cstring>
#include <cassert>

// PDTK
#include <specialized/procstat.h>
#include <specialized/eventbackend.h>
#include <cxxutils/error_helpers.h>
#include <cxxutils/vterm.h>

static std::unordered_map<pid_t, Process*> process_map; // do not try to own Process memory

void Process::init_once(void) noexcept
{
  static bool first = true;
  if(first)
  {
    first = false;
    struct sigaction actions;
    actions.sa_handler = &handler;
    sigemptyset(&actions.sa_mask);
    actions.sa_flags = SA_RESTART | SA_NOCLDSTOP;

    flaw(::sigaction(SIGCHLD, &actions, nullptr) == posix::error_response,
         terminal::critical,
         std::exit(errno),,
         "Unable assign action to a signal: %s", std::strerror(errno))
  }
}

// in case of incomplete implementations
#if !defined(WCONTINUED)
#define WCONTINUED 0
#endif

void Process::handler(int signum) noexcept
{
  flaw(signum != SIGCHLD,
       terminal::warning,
       posix::error(std::errc::invalid_argument),,
       "Process::reaper() has been called improperly")

  pid_t pid = posix::error_response; // set value just in case
  int status = 0;
  while((pid = ::waitpid(pid_t(-1), &status, WNOHANG | WCONTINUED | WUNTRACED)) > 0) // get the next dead process (if there is one)... while the currently reaped process was valid
  {
    auto process_map_iter = process_map.find(pid); // find dead process
    if(process_map_iter != process_map.end()) // if the dead process exists...
    {
      Process* p = process_map_iter->second;
      if(WIFEXITED(status))
      {
        EventBackend::remove(p->getStdOut(), EventBackend::SimplePollReadFlags);
        EventBackend::remove(p->getStdErr(), EventBackend::SimplePollReadFlags);
        posix::close(p->getStdOut());
        posix::close(p->getStdErr());
        posix::close(p->getStdIn());

        p->m_state = Process::State::Finished;
#if defined(WIFSIGNALED)
        if(WIFSIGNALED(status))
          Object::enqueue_copy(p->killed, p->processId(), posix::signal::EId(WTERMSIG(status)));
        else
#endif
          Object::enqueue_copy(p->finished, p->processId(), posix::error_t(WEXITSTATUS(status)));
        process_map.erase(process_map_iter); // remove finished process from the process map
      }
#if defined(WIFSTOPPED)
      else if(WIFSTOPPED(status))
      {
        p->m_state = Process::State::Stopped;
        Object::enqueue_copy(p->stopped, p->processId());
      }
#endif
#if defined(WIFCONTINUED)
      else if(WIFCONTINUED(status))
      {
        p->m_state = Process::State::Running;
        Object::enqueue_copy(p->started, p->processId());
      }
#endif
    }
  }
}

Process::Process(void) noexcept
  : m_state(State::Initializing)
{
  init_once();
  process_map.emplace(processId(), this); // add self to process map
}

Process::~Process(void) noexcept
{
  EventBackend::remove(getStdOut(), EventBackend::SimplePollReadFlags);
  EventBackend::remove(getStdErr(), EventBackend::SimplePollReadFlags);
}

bool Process::setOption(const std::string& name, const std::string& value) noexcept
{
  m_iobuf.reset();
  return !(m_iobuf << name << value).hadError() && writeStdIn(m_iobuf);
}

bool Process::sendSignal(posix::signal::EId id, int value) const noexcept
{
  return posix::signal::send(processId(), id, value);
}

bool Process::invoke(void) noexcept
{
  posix::success();

  flaw(m_state != State::Initializing,
       terminal::severe,
       posix::error(std::errc::device_or_resource_busy),
       false,
       "Called Process::invoke() on an active process!");

  EventBackend::add(getStdOut(), EventBackend::SimplePollReadFlags,
                    [this](posix::fd_t lambda_fd, native_flags_t) noexcept
                      { Object::enqueue(stdoutMessage, lambda_fd); });

  EventBackend::add(getStdErr(), EventBackend::SimplePollReadFlags,
                    [this](posix::fd_t lambda_fd, native_flags_t) noexcept
                      { Object::enqueue(stderrMessage, lambda_fd); });

  m_iobuf.reset();
  if((m_iobuf << "Launch").hadError() ||
     !writeStdIn(m_iobuf))
    return false;

  m_state = State::Invalid;
  if(state() == State::Running)
    Object::enqueue_copy(started, processId());

  return errno == posix::success_response;
}

Process::State Process::state(void) noexcept
{
  switch(m_state)
  {
    case State::Finished:
    case State::Initializing:
      break;
    default:
      process_state_t data;
      flaw(::procstat(processId(), data) == posix::error_response && m_state != State::Finished,
           terminal::severe,
           m_state = State::Invalid,
           m_state,
           "Process %i does not exist.", processId()); // process must exist (rare case where process could exit durring this call is handled)
      switch (data.state)
      {
        case WaitingInterruptable:
        case WaitingUninterruptable:
          m_state = State::Waiting; break;
        case Zombie : m_state = State::Zombie ; break;
        case Stopped: m_state = State::Stopped; break;
        case Running: m_state = State::Running; break;
        default: break; // invalid state (process exited before it could be stat'd
      }
  }
  return m_state;
}
<commit_msg>remove two safetly that are part of POSIX Base<commit_after>#include "process.h"

// POSIX
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>

// POSIX++
#include <cerrno>
#include <cstdlib>
#include <climits>
#include <cstring>
#include <cassert>

// PDTK
#include <specialized/procstat.h>
#include <specialized/eventbackend.h>
#include <cxxutils/error_helpers.h>
#include <cxxutils/vterm.h>

static std::unordered_map<pid_t, Process*> process_map; // do not try to own Process memory

void Process::init_once(void) noexcept
{
  static bool first = true;
  if(first)
  {
    first = false;
    struct sigaction actions;
    actions.sa_handler = &handler;
    sigemptyset(&actions.sa_mask);
    actions.sa_flags = SA_RESTART | SA_NOCLDSTOP;

    flaw(::sigaction(SIGCHLD, &actions, nullptr) == posix::error_response,
         terminal::critical,
         std::exit(errno),,
         "Unable assign action to a signal: %s", std::strerror(errno))
  }
}

// in case of incomplete implementations
#if !defined(WCONTINUED)
#define WCONTINUED 0
#endif

void Process::handler(int signum) noexcept
{
  flaw(signum != SIGCHLD,
       terminal::warning,
       posix::error(std::errc::invalid_argument),,
       "Process::reaper() has been called improperly")

  pid_t pid = posix::error_response; // set value just in case
  int status = 0;
  while((pid = ::waitpid(pid_t(-1), &status, WNOHANG | WCONTINUED | WUNTRACED)) > 0) // get the next dead process (if there is one)... while the currently reaped process was valid
  {
    auto process_map_iter = process_map.find(pid); // find dead process
    if(process_map_iter != process_map.end()) // if the dead process exists...
    {
      Process* p = process_map_iter->second;
      if(WIFEXITED(status))
      {
        EventBackend::remove(p->getStdOut(), EventBackend::SimplePollReadFlags);
        EventBackend::remove(p->getStdErr(), EventBackend::SimplePollReadFlags);
        posix::close(p->getStdOut());
        posix::close(p->getStdErr());
        posix::close(p->getStdIn());

        p->m_state = Process::State::Finished;
        if(WIFSIGNALED(status))
          Object::enqueue_copy(p->killed, p->processId(), posix::signal::EId(WTERMSIG(status)));
        else
          Object::enqueue_copy(p->finished, p->processId(), posix::error_t(WEXITSTATUS(status)));
        process_map.erase(process_map_iter); // remove finished process from the process map
      }
      else if(WIFSTOPPED(status))
      {
        p->m_state = Process::State::Stopped;
        Object::enqueue_copy(p->stopped, p->processId());
      }
#if defined(WIFCONTINUED)
      else if(WIFCONTINUED(status))
      {
        p->m_state = Process::State::Running;
        Object::enqueue_copy(p->started, p->processId());
      }
#endif
    }
  }
}

Process::Process(void) noexcept
  : m_state(State::Initializing)
{
  init_once();
  process_map.emplace(processId(), this); // add self to process map
}

Process::~Process(void) noexcept
{
  EventBackend::remove(getStdOut(), EventBackend::SimplePollReadFlags);
  EventBackend::remove(getStdErr(), EventBackend::SimplePollReadFlags);
}

bool Process::setOption(const std::string& name, const std::string& value) noexcept
{
  m_iobuf.reset();
  return !(m_iobuf << name << value).hadError() && writeStdIn(m_iobuf);
}

bool Process::sendSignal(posix::signal::EId id, int value) const noexcept
{
  return posix::signal::send(processId(), id, value);
}

bool Process::invoke(void) noexcept
{
  posix::success();

  flaw(m_state != State::Initializing,
       terminal::severe,
       posix::error(std::errc::device_or_resource_busy),
       false,
       "Called Process::invoke() on an active process!");

  EventBackend::add(getStdOut(), EventBackend::SimplePollReadFlags,
                    [this](posix::fd_t lambda_fd, native_flags_t) noexcept
                      { Object::enqueue(stdoutMessage, lambda_fd); });

  EventBackend::add(getStdErr(), EventBackend::SimplePollReadFlags,
                    [this](posix::fd_t lambda_fd, native_flags_t) noexcept
                      { Object::enqueue(stderrMessage, lambda_fd); });

  m_iobuf.reset();
  if((m_iobuf << "Launch").hadError() ||
     !writeStdIn(m_iobuf))
    return false;

  m_state = State::Invalid;
  if(state() == State::Running)
    Object::enqueue_copy(started, processId());

  return errno == posix::success_response;
}

Process::State Process::state(void) noexcept
{
  switch(m_state)
  {
    case State::Finished:
    case State::Initializing:
      break;
    default:
      process_state_t data;
      flaw(::procstat(processId(), data) == posix::error_response && m_state != State::Finished,
           terminal::severe,
           m_state = State::Invalid,
           m_state,
           "Process %i does not exist.", processId()); // process must exist (rare case where process could exit durring this call is handled)
      switch (data.state)
      {
        case WaitingInterruptable:
        case WaitingUninterruptable:
          m_state = State::Waiting; break;
        case Zombie : m_state = State::Zombie ; break;
        case Stopped: m_state = State::Stopped; break;
        case Running: m_state = State::Running; break;
        default: break; // invalid state (process exited before it could be stat'd
      }
  }
  return m_state;
}
<|endoftext|>