<commit_before>#include <faunus/ensemble.h>

namespace Faunus {
  ensemble::ensemble() {};
  bool ensemble::metropolis(double du)
  {
    if (du > 0)
      if ( slp.random_one()>exp(-du) )
        return false;
    return true;
  }

  canonical::canonical() {};
  isobarical::isobarical() {};

  int grandcanonical::size() {};

  short grandcanonical::findgroup(unsigned int i) {
    for (unsigned int n=0; n<g.size(); n++)
      if (g[n].find(i)==true) return n;
    return -1;
  }

  void grandcanonical::addgroup(group &group) { g.push_back(group); }

  short grandcanonical::findgroup(string name) {
    for (int k=0; k<g.size(); k++)
      if (g[k].name==name) return k;
    return -1;
  }
  void grandcanonical::searchsalt(container &c, salt &salt) {
    particle ref = c.p[salt.beg];
    group w;
    w.beg=salt.beg;
    w.end=salt.beg-1;
    for (unsigned int i=salt.beg; i<=salt.end; i++)
      if (c.p[i].id==ref.id)
        w.end++;
      else {
        w.name=c.atom[ref.id].name;
        g.push_back(w);
        w.beg=w.end=i;
        ref.id=c.p[i].id;
      }
    w.name=c.atom[ref.id].name;
    g.push_back(w);
  }

  //\param p - particle vector to insert into.
  //\param i - We will insert at this position - the rest will be moved forward.
  //\param p - Particle to insert
  //\param num - Number of particles to insert.
  bool grandcanonical::insert(vector<particle> &p, unsigned int i, particle a, unsigned char num) {
    short n=findgroup(i);
    if (n>0) {
      for (unsigned short k=0; k<g.size(); k++)
        if (g[k].beg>i) {
          g[k].beg += num;
          g[k].end += num;
        }
      p.insert( p.begin()+i, num, a );
      g[n].end+=num;
      return true;
    }
    return false;
  }
  bool grandcanonical::erase(vector<particle> &p, unsigned int i, unsigned char num) {
    short n=findgroup(i);
    if (n>0) {
      for (unsigned short k=0; k<g.size(); k++)
        if (g[k].beg>i) {
          g[k].beg -= num;
          g[k].end -= num;
        }
      p.erase( p.begin()+i, p.begin()+i+num );
      g[n].end -= num;
      return true;
    }
    return false;
  }

  string grandcanonical::info() {
    std::ostringstream o;
    o << "Grand Canonical Master Class:\n"
      << "  Number of groups     = " << g.size() << endl
      << "  Number of particles  = " << size() << endl;
  }
}//namespace
<commit_msg>prettify (?), feel free to revert<commit_after>#include <faunus/ensemble.h>

namespace Faunus {

  //
  // class ensemble
  //

  ensemble::ensemble() {};

  bool ensemble::metropolis(double du)
  {
    if (du > 0)
      if ( slp.random_one()>exp(-du) )
        return false;
    return true;
  }

  //
  // class canonical
  //

  canonical::canonical() {};

  //
  // class isobarical
  //

  isobarical::isobarical() {};

  //
  // class grandcanonical
  //

  int grandcanonical::size() {};

  short grandcanonical::findgroup(unsigned int i) {
    for (unsigned int n=0; n<g.size(); n++)
      if (g[n].find(i)==true) return n;
    return -1;
  }

  void grandcanonical::addgroup(group &group) {
    g.push_back(group);
  }

  short grandcanonical::findgroup(string name) {
    for (int k=0; k<g.size(); k++)
      if (g[k].name==name) return k;
    return -1;
  }

  void grandcanonical::searchsalt(container &c, salt &salt) {
    particle ref = c.p[salt.beg];
    group w;
    w.beg=salt.beg;
    w.end=salt.beg-1;
    for (unsigned int i=salt.beg; i<=salt.end; i++)
      if (c.p[i].id==ref.id)
        w.end++;
      else {
        w.name=c.atom[ref.id].name;
        g.push_back(w);
        w.beg=w.end=i;
        ref.id=c.p[i].id;
      }
    w.name=c.atom[ref.id].name;
    g.push_back(w);
  }

  //\param p - particle vector to insert into.
  //\param i - We will insert at this position - the rest will be moved forward.
  //\param p - Particle to insert
  //\param num - Number of particles to insert.
  bool grandcanonical::insert(vector<particle> &p, unsigned int i, particle a, unsigned char num) {
    short n=findgroup(i);
    if (n>0) {
      for (unsigned short k=0; k<g.size(); k++)
        if (g[k].beg>i) {
          g[k].beg += num;
          g[k].end += num;
        }
      p.insert( p.begin()+i, num, a );
      g[n].end+=num;
      return true;
    }
    return false;
  }

  bool grandcanonical::erase(vector<particle> &p, unsigned int i, unsigned char num) {
    short n=findgroup(i);
    if (n>0) {
      for (unsigned short k=0; k<g.size(); k++)
        if (g[k].beg>i) {
          g[k].beg -= num;
          g[k].end -= num;
        }
      p.erase( p.begin()+i, p.begin()+i+num );
      g[n].end -= num;
      return true;
    }
    return false;
  }

  string grandcanonical::info() {
    std::ostringstream o;
    o << "Grand Canonical Master Class:\n"
      << "  Number of groups     = " << g.size() << endl
      << "  Number of particles  = " << size() << endl;
  }

} //namespace
<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#if defined __linux__ || (defined __APPLE__ && __MACH__) || defined __FreeBSD__ || defined __NetBSD__ \
	|| defined __OpenBSD__ || defined __bsdi__ || defined __DragonFly__
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <net/route.h>
#elif defined WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <iphlpapi.h>
#endif

#include "libtorrent/enum_net.hpp"
#include <asio/ip/host_name.hpp>

namespace libtorrent
{
	namespace
	{
		address sockaddr_to_address(sockaddr const* sin)
		{
			if (sin->sa_family == AF_INET)
			{
				typedef asio::ip::address_v4::bytes_type bytes_t;
				bytes_t b;
				memcpy(&b[0], &((sockaddr_in const*)sin)->sin_addr, b.size());
				return address_v4(b);
			}
			else if (sin->sa_family == AF_INET6)
			{
				typedef asio::ip::address_v6::bytes_type bytes_t;
				bytes_t b;
				memcpy(&b[0], &((sockaddr_in6 const*)sin)->sin6_addr, b.size());
				return address_v6(b);
			}
			return address();
		}

		bool verify_sockaddr(sockaddr_in* sin)
		{
			return (sin->sin_len == sizeof(sockaddr_in)
				&& sin->sin_family == AF_INET)
				|| (sin->sin_len == sizeof(sockaddr_in6)
				&& sin->sin_family == AF_INET6);
		}
	}

	bool in_subnet(address const& addr, ip_interface const& iface)
	{
		if (addr.is_v4() != iface.interface_address.is_v4()) return false;
		// since netmasks seems unreliable for IPv6 interfaces
		// (MacOS X returns AF_INET addresses as bitmasks) assume
		// that any IPv6 address belongs to the subnet of any
		// interface with an IPv6 address
		if (addr.is_v6()) return true;

		return (addr.to_v4().to_ulong() & iface.netmask.to_v4().to_ulong())
			== (iface.interface_address.to_v4().to_ulong() & iface.netmask.to_v4().to_ulong());
	}

	bool in_local_network(asio::io_service& ios, address const& addr, asio::error_code& ec)
	{
		std::vector<ip_interface> const& net = enum_net_interfaces(ios, ec);
		if (ec) return false;
		for (std::vector<ip_interface>::const_iterator i = net.begin()
			, end(net.end()); i != end; ++i)
		{
			if (in_subnet(addr, *i)) return true;
		}
		return false;
	}

	std::vector<ip_interface> enum_net_interfaces(asio::io_service& ios, asio::error_code& ec)
	{
		std::vector<ip_interface> ret;
// covers linux, MacOS X and BSD distributions
#if defined __linux__ || (defined __APPLE__ && __MACH__) || defined __FreeBSD__ || defined __NetBSD__ \
	|| defined __OpenBSD__ || defined __bsdi__ || defined __DragonFly__
		int s = socket(AF_INET, SOCK_DGRAM, 0);
		if (s < 0)
		{
			ec = asio::error::fault;
			return ret;
		}
		ifconf ifc;
		char buf[1024];
		ifc.ifc_len = sizeof(buf);
		ifc.ifc_buf = buf;
		if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
		{
			close(s);
			ec = asio::error_code(errno, asio::error::system_category);
			return ret;
		}

		char *ifr = (char*)ifc.ifc_req;
		int remaining = ifc.ifc_len;

		while (remaining)
		{
			ifreq const& item = *reinterpret_cast<ifreq*>(ifr);

			if (item.ifr_addr.sa_family == AF_INET
				|| item.ifr_addr.sa_family == AF_INET6)
			{
				ip_interface iface;
				iface.interface_address = sockaddr_to_address(&item.ifr_addr);

				ifreq netmask = item;
				if (ioctl(s, SIOCGIFNETMASK, &netmask) < 0)
				{
					if (iface.interface_address.is_v6())
					{
						// this is expected to fail (at least on MacOS X)
						iface.netmask = address_v6::any();
					}
					else
					{
						close(s);
						ec = asio::error_code(errno, asio::error::system_category);
						return ret;
					}
				}
				else
				{
					iface.netmask = sockaddr_to_address(&netmask.ifr_addr);
				}
				ret.push_back(iface);
			}

#if (defined __APPLE__ && __MACH__) || defined __FreeBSD__ || defined __NetBSD__ \
	|| defined __OpenBSD__ || defined __bsdi__ || defined __DragonFly__
			int current_size = item.ifr_addr.sa_len + IFNAMSIZ;
#elif defined __linux__
			int current_size = sizeof(ifreq);
#endif
			ifr += current_size;
			remaining -= current_size;
		}
		close(s);

#elif defined WIN32

		SOCKET s = socket(AF_INET, SOCK_DGRAM, 0);
		if (s == SOCKET_ERROR)
		{
			ec = asio::error_code(WSAGetLastError(), asio::error::system_category);
			return ret;
		}

		INTERFACE_INFO buffer[30];
		DWORD size;

		if (WSAIoctl(s, SIO_GET_INTERFACE_LIST, 0, 0, buffer,
			sizeof(buffer), &size, 0, 0) != 0)
		{
			ec = asio::error_code(WSAGetLastError(), asio::error::system_category);
			closesocket(s);
			return ret;
		}
		closesocket(s);

		int n = size / sizeof(INTERFACE_INFO);

		ip_interface iface;
		for (int i = 0; i < n; ++i)
		{
			iface.interface_address = sockaddr_to_address(&buffer[i].iiAddress.Address);
			iface.netmask = sockaddr_to_address(&buffer[i].iiNetmask.Address);
			if (iface.interface_address == address_v4::any()) continue;
			ret.push_back(iface);
		}

#else
#warning THIS OS IS NOT RECOGNIZED, enum_net_interfaces WILL PROBABLY NOT WORK
		// make a best guess of the interface we're using and its IP
		udp::resolver r(ios);
		udp::resolver::iterator i = r.resolve(udp::resolver::query(asio::ip::host_name(ec), "0"), ec);
		if (ec) return ret;
		ip_interface iface;
		for (;i != udp::resolver_iterator(); ++i)
		{
			iface.interface_address = i->endpoint().address();
			if (iface.interface_address.is_v4())
				iface.netmask = address_v4::netmask(iface.interface_address.to_v4());
			ret.push_back(iface);
		}
#endif
		return ret;
	}

	address get_default_gateway(asio::io_service& ios, address const& interface, asio::error_code& ec)
	{

#if defined __linux__ || (defined __APPLE__ && __MACH__) || defined __FreeBSD__ || defined __NetBSD__ \
	|| defined __OpenBSD__ || defined __bsdi__ || defined __DragonFly__

		struct rt_msg
		{
			rt_msghdr m_rtm;
			char buf[512];
		};

		rt_msg m;
		int len = sizeof(rt_msg);
		bzero(&m, len);
		m.m_rtm.rtm_type = RTM_GET;
		m.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY;
		m.m_rtm.rtm_version = RTM_VERSION;
		m.m_rtm.rtm_addrs = RTA_DST | RTA_GATEWAY;
		m.m_rtm.rtm_seq = 0;
		m.m_rtm.rtm_msglen = len;

		int s = socket(PF_ROUTE, SOCK_RAW, AF_INET);
		if (s == -1)
		{
			ec = asio::error_code(errno, asio::error::system_category);
			return address_v4::any();
		}

		int n = write(s, &m, len);
		if (n == -1)
		{
			ec = asio::error_code(errno, asio::error::system_category);
			close(s);
			return address_v4::any();
		}
		else if (n != len)
		{
			ec = asio::error::operation_not_supported;
			close(s);
			return address_v4::any();
		}
		bzero(&m, len);

		n = read(s, &m, len);
		if (n == -1)
		{
			ec = asio::error_code(errno, asio::error::system_category);
			close(s);
			return address_v4::any();
		}
		close(s);

		TORRENT_ASSERT(m.m_rtm.rtm_seq == 0);
		TORRENT_ASSERT(m.m_rtm.rtm_pid == getpid());
		if (m.m_rtm.rtm_errno)
		{
			ec = asio::error_code(m.m_rtm.rtm_errno, asio::error::system_category);
			return address_v4::any();
		}
		if (m.m_rtm.rtm_flags & RTF_UP == 0
			|| m.m_rtm.rtm_flags & RTF_GATEWAY == 0)
		{
			ec = asio::error::operation_not_supported;
			return address_v4::any();
		}
		if (m.m_rtm.rtm_addrs & RTA_DST == 0
			|| m.m_rtm.rtm_addrs & RTA_GATEWAY == 0)
		{
			ec = asio::error::operation_not_supported;
			return address_v4::any();
		}
		if (m.m_rtm.rtm_msglen > len)
		{
			ec = asio::error::operation_not_supported;
			return address_v4::any();
		}
		int min_len = sizeof(rt_msghdr) + 2 * sizeof(struct sockaddr_in);
		if (m.m_rtm.rtm_msglen < min_len)
		{
			ec = asio::error::operation_not_supported;
			return address_v4::any();
		}

		// default route
		char* p = m.buf;
		sockaddr_in* sin = (sockaddr_in*)p;
		if (!verify_sockaddr(sin))
		{
			ec = asio::error::operation_not_supported;
			return address_v4::any();
		}

		// default gateway
		p += sin->sin_len;
		sin = (sockaddr_in*)p;
		if (!verify_sockaddr(sin))
		{
			ec = asio::error::operation_not_supported;
			return address_v4::any();
		}

		return sockaddr_to_address((sockaddr*)sin);

#elif defined WIN32

		// Load Iphlpapi library
		HMODULE iphlp = LoadLibraryA("Iphlpapi.dll");
		if (!iphlp)
		{
			ec = asio::error::operation_not_supported;
			return address_v4::any();
		}

		// Get GetAdaptersInfo() pointer
		typedef DWORD (WINAPI *GetAdaptersInfo_t)(PIP_ADAPTER_INFO, PULONG);
		GetAdaptersInfo_t GetAdaptersInfo = (GetAdaptersInfo_t)GetProcAddress(iphlp, "GetAdaptersInfo");
		if (!GetAdaptersInfo)
		{
			FreeLibrary(iphlp);
			ec = asio::error::operation_not_supported;
			return address_v4::any();
		}

		PIP_ADAPTER_INFO adapter_info = 0;
		ULONG out_buf_size = 0;
		if (GetAdaptersInfo(adapter_info, &out_buf_size) != ERROR_BUFFER_OVERFLOW)
		{
			FreeLibrary(iphlp);
			ec = asio::error::operation_not_supported;
			return address_v4::any();
		}

		adapter_info = (IP_ADAPTER_INFO*)malloc(out_buf_size);
		if (!adapter_info)
		{
			FreeLibrary(iphlp);
			ec = asio::error::no_memory;
			return address_v4::any();
		}

		address ret;
		if (GetAdaptersInfo(adapter_info, &out_buf_size) == NO_ERROR)
		{

			for (PIP_ADAPTER_INFO adapter = adapter_info;
				adapter != 0; adapter = adapter->Next)
			{
				address iface = address::from_string(adapter->IpAddressList.IpAddress.String, ec);
				if (ec)
				{
					ec = asio::error_code();
					continue;
				}
				if (is_loopback(iface) || is_any(iface)) continue;
				if (interface == address() || interface == iface)
				{
					ret = address::from_string(adapter->GatewayList.IpAddress.String, ec);
					break;
				}
			}
		}

		// Free memory
		free(adapter_info);
		FreeLibrary(iphlp);

		return ret;

#else
		address interface = guess_local_address(ios);

		if (!interface.is_v4())
		{
			ec = asio::error::operation_not_supported;
			return address_v4::any();
		}
		return address_v4((interface.to_v4().to_ulong() & 0xffffff00) | 1);
#endif
	}

}

<commit_msg>made it build on linux. No linux implementation for getting default route yet<commit_after>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#if defined __linux__ || (defined __APPLE__ && __MACH__) || defined __FreeBSD__ || defined __NetBSD__ \
	|| defined __OpenBSD__ || defined __bsdi__ || defined __DragonFly__
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <net/route.h>
#elif defined WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <iphlpapi.h>
#endif

#include "libtorrent/enum_net.hpp"
#include "libtorrent/broadcast_socket.hpp"
#include <asio/ip/host_name.hpp>

namespace libtorrent
{
	namespace
	{
		address sockaddr_to_address(sockaddr const* sin)
		{
			if (sin->sa_family == AF_INET)
			{
				typedef asio::ip::address_v4::bytes_type bytes_t;
				bytes_t b;
				memcpy(&b[0], &((sockaddr_in const*)sin)->sin_addr, b.size());
				return address_v4(b);
			}
			else if (sin->sa_family == AF_INET6)
			{
				typedef asio::ip::address_v6::bytes_type bytes_t;
				bytes_t b;
				memcpy(&b[0], &((sockaddr_in6 const*)sin)->sin6_addr, b.size());
				return address_v6(b);
			}
			return address();
		}
	}

	bool in_subnet(address const& addr, ip_interface const& iface)
	{
		if (addr.is_v4() != iface.interface_address.is_v4()) return false;
		// since netmasks seems unreliable for IPv6 interfaces
		// (MacOS X returns AF_INET addresses as bitmasks) assume
		// that any IPv6 address belongs to the subnet of any
		// interface with an IPv6 address
		if (addr.is_v6()) return true;

		return (addr.to_v4().to_ulong() & iface.netmask.to_v4().to_ulong())
			== (iface.interface_address.to_v4().to_ulong() & iface.netmask.to_v4().to_ulong());
	}

	bool in_local_network(asio::io_service& ios, address const& addr, asio::error_code& ec)
	{
		std::vector<ip_interface> const& net = enum_net_interfaces(ios, ec);
		if (ec) return false;
		for (std::vector<ip_interface>::const_iterator i = net.begin()
			, end(net.end()); i != end; ++i)
		{
			if (in_subnet(addr, *i)) return true;
		}
		return false;
	}

	std::vector<ip_interface> enum_net_interfaces(asio::io_service& ios, asio::error_code& ec)
	{
		std::vector<ip_interface> ret;
// covers linux, MacOS X and BSD distributions
#if defined __linux__ || (defined __APPLE__ && __MACH__) || defined __FreeBSD__ || defined __NetBSD__ \
	|| defined __OpenBSD__ || defined __bsdi__ || defined __DragonFly__
		int s = socket(AF_INET, SOCK_DGRAM, 0);
		if (s < 0)
		{
			ec = asio::error::fault;
			return ret;
		}
		ifconf ifc;
		char buf[1024];
		ifc.ifc_len = sizeof(buf);
		ifc.ifc_buf = buf;
		if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
		{
			close(s);
			ec = asio::error_code(errno, asio::error::system_category);
			return ret;
		}

		char *ifr = (char*)ifc.ifc_req;
		int remaining = ifc.ifc_len;

		while (remaining)
		{
			ifreq const& item = *reinterpret_cast<ifreq*>(ifr);

			if (item.ifr_addr.sa_family == AF_INET
				|| item.ifr_addr.sa_family == AF_INET6)
			{
				ip_interface iface;
				iface.interface_address = sockaddr_to_address(&item.ifr_addr);

				ifreq netmask = item;
				if (ioctl(s, SIOCGIFNETMASK, &netmask) < 0)
				{
					if (iface.interface_address.is_v6())
					{
						// this is expected to fail (at least on MacOS X)
						iface.netmask = address_v6::any();
					}
					else
					{
						close(s);
						ec = asio::error_code(errno, asio::error::system_category);
						return ret;
					}
				}
				else
				{
					iface.netmask = sockaddr_to_address(&netmask.ifr_addr);
				}
				ret.push_back(iface);
			}

#if (defined __APPLE__ && __MACH__) || defined __FreeBSD__ || defined __NetBSD__ \
	|| defined __OpenBSD__ || defined __bsdi__ || defined __DragonFly__
			int current_size = item.ifr_addr.sa_len + IFNAMSIZ;
#elif defined __linux__
			int current_size = sizeof(ifreq);
#endif
			ifr += current_size;
			remaining -= current_size;
		}
		close(s);

#elif defined WIN32

		SOCKET s = socket(AF_INET, SOCK_DGRAM, 0);
		if (s == SOCKET_ERROR)
		{
			ec = asio::error_code(WSAGetLastError(), asio::error::system_category);
			return ret;
		}

		INTERFACE_INFO buffer[30];
		DWORD size;

		if (WSAIoctl(s, SIO_GET_INTERFACE_LIST, 0, 0, buffer,
			sizeof(buffer), &size, 0, 0) != 0)
		{
			ec = asio::error_code(WSAGetLastError(), asio::error::system_category);
			closesocket(s);
			return ret;
		}
		closesocket(s);

		int n = size / sizeof(INTERFACE_INFO);

		ip_interface iface;
		for (int i = 0; i < n; ++i)
		{
			iface.interface_address = sockaddr_to_address(&buffer[i].iiAddress.Address);
			iface.netmask = sockaddr_to_address(&buffer[i].iiNetmask.Address);
			if (iface.interface_address == address_v4::any()) continue;
			ret.push_back(iface);
		}

#else
#warning THIS OS IS NOT RECOGNIZED, enum_net_interfaces WILL PROBABLY NOT WORK
		// make a best guess of the interface we're using and its IP
		udp::resolver r(ios);
		udp::resolver::iterator i = r.resolve(udp::resolver::query(asio::ip::host_name(ec), "0"), ec);
		if (ec) return ret;
		ip_interface iface;
		for (;i != udp::resolver_iterator(); ++i)
		{
			iface.interface_address = i->endpoint().address();
			if (iface.interface_address.is_v4())
				iface.netmask = address_v4::netmask(iface.interface_address.to_v4());
			ret.push_back(iface);
		}
#endif
		return ret;
	}

	address get_default_gateway(asio::io_service& ios, address const& interface, asio::error_code& ec)
	{

#if (defined __APPLE__ && __MACH__) || defined __FreeBSD__ || defined __NetBSD__ \
	|| defined __OpenBSD__ || defined __bsdi__ || defined __DragonFly__

		bool verify_sockaddr(sockaddr_in* sin)
		{
			return (sin->sin_len == sizeof(sockaddr_in)
				&& sin->sin_family == AF_INET)
				|| (sin->sin_len == sizeof(sockaddr_in6)
				&& sin->sin_family == AF_INET6);
		}

		struct rt_msg
		{
			rt_msghdr m_rtm;
			char buf[512];
		};

		rt_msg m;
		int len = sizeof(rt_msg);
		bzero(&m, len);
		m.m_rtm.rtm_type = RTM_GET;
		m.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY;
		m.m_rtm.rtm_version = RTM_VERSION;
		m.m_rtm.rtm_addrs = RTA_DST | RTA_GATEWAY;
		m.m_rtm.rtm_seq = 0;
		m.m_rtm.rtm_msglen = len;

		int s = socket(PF_ROUTE, SOCK_RAW, AF_INET);
		if (s == -1)
		{
			ec = asio::error_code(errno, asio::error::system_category);
			return address_v4::any();
		}

		int n = write(s, &m, len);
		if (n == -1)
		{
			ec = asio::error_code(errno, asio::error::system_category);
			close(s);
			return address_v4::any();
		}
		else if (n != len)
		{
			ec = asio::error::operation_not_supported;
			close(s);
			return address_v4::any();
		}
		bzero(&m, len);

		n = read(s, &m, len);
		if (n == -1)
		{
			ec = asio::error_code(errno, asio::error::system_category);
			close(s);
			return address_v4::any();
		}
		close(s);

		TORRENT_ASSERT(m.m_rtm.rtm_seq == 0);
		TORRENT_ASSERT(m.m_rtm.rtm_pid == getpid());
		if (m.m_rtm.rtm_errno)
		{
			ec = asio::error_code(m.m_rtm.rtm_errno, asio::error::system_category);
			return address_v4::any();
		}
		if (m.m_rtm.rtm_flags & RTF_UP == 0
			|| m.m_rtm.rtm_flags & RTF_GATEWAY == 0)
		{
			ec = asio::error::operation_not_supported;
			return address_v4::any();
		}
		if (m.m_rtm.rtm_addrs & RTA_DST == 0
			|| m.m_rtm.rtm_addrs & RTA_GATEWAY == 0)
		{
			ec = asio::error::operation_not_supported;
			return address_v4::any();
		}
		if (m.m_rtm.rtm_msglen > len)
		{
			ec = asio::error::operation_not_supported;
			return address_v4::any();
		}
		int min_len = sizeof(rt_msghdr) + 2 * sizeof(struct sockaddr_in);
		if (m.m_rtm.rtm_msglen < min_len)
		{
			ec = asio::error::operation_not_supported;
			return address_v4::any();
		}

		// default route
		char* p = m.buf;
		sockaddr_in* sin = (sockaddr_in*)p;
		if (!verify_sockaddr(sin))
		{
			ec = asio::error::operation_not_supported;
			return address_v4::any();
		}

		// default gateway
		p += sin->sin_len;
		sin = (sockaddr_in*)p;
		if (!verify_sockaddr(sin))
		{
			ec = asio::error::operation_not_supported;
			return address_v4::any();
		}

		return sockaddr_to_address((sockaddr*)sin);

#elif defined WIN32

		// Load Iphlpapi library
		HMODULE iphlp = LoadLibraryA("Iphlpapi.dll");
		if (!iphlp)
		{
			ec = asio::error::operation_not_supported;
			return address_v4::any();
		}

		// Get GetAdaptersInfo() pointer
		typedef DWORD (WINAPI *GetAdaptersInfo_t)(PIP_ADAPTER_INFO, PULONG);
		GetAdaptersInfo_t GetAdaptersInfo = (GetAdaptersInfo_t)GetProcAddress(iphlp, "GetAdaptersInfo");
		if (!GetAdaptersInfo)
		{
			FreeLibrary(iphlp);
			ec = asio::error::operation_not_supported;
			return address_v4::any();
		}

		PIP_ADAPTER_INFO adapter_info = 0;
		ULONG out_buf_size = 0;
		if (GetAdaptersInfo(adapter_info, &out_buf_size) != ERROR_BUFFER_OVERFLOW)
		{
			FreeLibrary(iphlp);
			ec = asio::error::operation_not_supported;
			return address_v4::any();
		}

		adapter_info = (IP_ADAPTER_INFO*)malloc(out_buf_size);
		if (!adapter_info)
		{
			FreeLibrary(iphlp);
			ec = asio::error::no_memory;
			return address_v4::any();
		}

		address ret;
		if (GetAdaptersInfo(adapter_info, &out_buf_size) == NO_ERROR)
		{

			for (PIP_ADAPTER_INFO adapter = adapter_info;
				adapter != 0; adapter = adapter->Next)
			{
				address iface = address::from_string(adapter->IpAddressList.IpAddress.String, ec);
				if (ec)
				{
					ec = asio::error_code();
					continue;
				}
				if (is_loopback(iface) || is_any(iface)) continue;
				if (interface == address() || interface == iface)
				{
					ret = address::from_string(adapter->GatewayList.IpAddress.String, ec);
					break;
				}
			}
		}

		// Free memory
		free(adapter_info);
		FreeLibrary(iphlp);

		return ret;

//#elif defined __linux__
// No linux implementation yet
#else
		if (!interface.is_v4())
		{
			ec = asio::error::operation_not_supported;
			return address_v4::any();
		}
		return address_v4((interface.to_v4().to_ulong() & 0xffffff00) | 1);
#endif
	}

}

<|endoftext|>


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

#include "exception.h"

#include "config.h"           // for XAPIAND_TRACEBACKS

#include <cstdlib>            // for free
#include <cstring>            // for strtok_r
#include <cxxabi.h>           // for abi::__cxa_demangle
#include <dlfcn.h>            // for dladdr

#ifdef HAVE_EXECINFO_H
#include <execinfo.h>         // for backtrace
#else
static inline int backtrace(void**, int) { return 0; }
#endif

#include "likely.h"

#ifndef NDEBUG
#ifndef XAPIAND_TRACEBACKS
#define XAPIAND_TRACEBACKS 1
#endif
#endif

#define BUFFER_SIZE 1024

#ifdef __APPLE__
#include <util.h>             // for forkpty
#include <unistd.h>           // for execlp
#include <termios.h>          // for termios, cfmakeraw
#include <sys/select.h>       // for select
/* Use `atos` to do symbol lookup, can lookup non-dynamic symbols and also line
 * numbers. This function is more complicated than you'd expect because `atos`
 * doesn't flush after each line, so plain pipe() or socketpair() won't work
 * until we close the write side. But the whole point is we want to keep `atos`
 * around so we don't have to reprocess the symbol table over and over. What we
 * wind up doing is using `forkpty()` to make a new pseudoterminal for atos to
 * run in, and thus will use line-buffering for stdout, and then we can get
 * each line.
 */
static std::string
atos(const void* address)
{
	static std::mutex mtx;
	std::lock_guard lk(mtx);

	char tmp[20];
	static int fd = -1;
	if (fd == -1) {
		Dl_info info;
		memset(&info, 0, sizeof(Dl_info));
		if (dladdr(reinterpret_cast<const void*>(&atos), &info) == 0) {
			perror("Could not get base address for `atos`.");
			return "";
		}

		struct termios term_opts;
		cfmakeraw(&term_opts);  // have to set this first, otherwise queries echo until child kicks in
		pid_t childpid;
		if unlikely((childpid = forkpty(&fd, nullptr, &term_opts, nullptr)) < 0) {
			perror("Could not forkpty for `atos` call.");
			return "";
		}

		if (childpid == 0) {
			snprintf(tmp, sizeof(tmp), "%p", static_cast<const void *>(info.dli_fbase));
			execlp("/usr/bin/atos", "atos", "-o", info.dli_fname, "-l", tmp, nullptr);
			fprintf(stderr,"Could not exec `atos` for stack trace!\n");
			exit(1);
		}

		int size = snprintf(tmp, sizeof(tmp), "%p\n", address);
		write(fd, tmp, size);

		// atos can take a while to parse symbol table on first request, which
		// is why we leave it running if we see a delay, explain what's going on...
		fd_set fds;
		FD_ZERO(&fds);
		FD_SET(fd, &fds);
		struct timeval tv = {3, 0};
		int err = select(fd + 1, &fds, nullptr, nullptr, &tv);
		if unlikely(err < 0) {
			perror("Generating... first call takes some time for `atos` to cache the symbol table.");
		} else if (err == 0) {  // timeout
			fprintf(stderr, "Generating... first call takes some time for `atos` to cache the symbol table.\n");
		}
	} else {
		int size = snprintf(tmp, sizeof(tmp), "%p\n", address);
		write(fd, tmp, size);
	}

	const unsigned int MAXLINE = 1024;
	char line[MAXLINE];
	char c = '\0';
	size_t nread = 0;
	while (c != '\n' && nread < MAXLINE) {
		if unlikely(read(fd, &c, 1) <= 0) {
			perror("Lost `atos` connection.");
			close(fd);
			fd = -1;
			return "";
		}
		if (c != '\n') {
			line[nread++] = c;
		}
	}
	if (nread < MAXLINE) {
		return std::string(line, nread);
	}
	fprintf(stderr, "Line read from `atos` was too long.\n");
	return "";
}
#else
static inline std::string
atos(const void*)
{
	return "";
}
#endif

std::string
traceback(const char* function, const char* filename, int line, const std::vector<void*>& callstack, int skip = 1)
{
	char tmp[20];

	std::string tb = "\n== Traceback (most recent call first): ";
	tb.append(filename);
	tb.push_back(':');
	tb.append(std::to_string(line));
	tb.append(" at ");
	tb.append(function);

	int frames = callstack.size();

	if (frames == 0) {
		tb.append(":\n    <empty traceback>");
		return tb;
	}

	if (frames < 2) {
		tb.append(":\n    <no traceback>");
		return tb;
	}

	tb.push_back(':');

	// Iterate over the callstack. Skip the first, it is the address of this function.
	std::string result;
	for (int i = skip; i < frames; ++i) {
		auto address = callstack[i];

		result.assign(std::to_string(frames - i - 1));
		result.push_back(' ');

		auto address_string = atos(address);
		if (address_string.size() > 2 && address_string.compare(0, 2, "0x") != 0) {
			result.append(address_string);
		} else {
			Dl_info info;
			memset(&info, 0, sizeof(Dl_info));
			if (dladdr(address, &info) != 0) {
				// Address:
				snprintf(tmp, sizeof(tmp), "%p ", address);
				result.append(tmp);
				// Symbol name:
				if (info.dli_sname != nullptr) {
					int status = 0;
					char* unmangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status);
					if (status != 0) {
						result.append(info.dli_sname);
					} else {
						try {
							result.append(unmangled);
							free(unmangled);
						} catch(...) {
							free(unmangled);
							throw;
						}
					}
				} else {
					result.append("[unknown symbol]");
				}
				// Offset:
				snprintf(tmp, sizeof(tmp), " + %zu", static_cast<const char*>(address) - static_cast<const char*>(info.dli_saddr));
				result.append(tmp);
			} else {
				snprintf(tmp, sizeof(tmp), "%p [unknown symbol]", address);
				result.append(tmp);
			}
		}
		tb.append("\n    ");
		tb.append(result);
	}

	return tb;
}

std::string
traceback(const char* function, const char* filename, int line, int skip)
{
	std::vector<void*> callstack;

	// retrieve current stack addresses
	callstack.resize(128);
	callstack.resize(backtrace(callstack.data(), callstack.size()));
	callstack.shrink_to_fit();

	auto tb = traceback(function, filename, line, callstack, skip);

	return tb;
}

extern "C" void
__assert_tb(const char* function, const char* filename, unsigned int line, const char* expression)
{
#ifdef XAPIAND_TRACEBACKS
	(void)fprintf(stderr, "Assertion failed: %s in %s %s:%u%s\n",
		expression, function, filename, line, traceback(function, filename, line, 2).c_str());
#else
	(void)fprintf(stderr, "Assertion failed: %s in %s %s:%u\n",
		expression, function, filename, line);
#endif
	abort();
}

BaseException::BaseException()
	: line{0}
{ }

BaseException::BaseException(const BaseException& exc)
	: type{exc.type},
	  function{exc.function},
	  filename{exc.filename},
	  line{exc.line},
	  callstack{exc.callstack},
	  message{exc.message},
	  context{exc.context},
	  traceback{exc.traceback}
{
}

BaseException::BaseException(BaseException&& exc)
	: type{std::move(exc.type)},
	  function{std::move(exc.function)},
	  filename{std::move(exc.filename)},
	  line{std::move(exc.line)},
	  callstack{std::move(exc.callstack)},
	  message{std::move(exc.message)},
	  context{std::move(exc.context)},
	  traceback{std::move(exc.traceback)}
{ }

BaseException::BaseException(const BaseException* exc)
	: BaseException(exc != nullptr ? *exc : BaseException())
{ }

BaseException::BaseException(BaseException::private_ctor, const BaseException& exc, const char *function_, const char *filename_, int line_, const char* type, std::string_view format, VFPRINTF_ARGS args)
	: type(type),
	  function(function_),
	  filename(filename_),
	  line(line_),
	  message(VSPRINTF(format, args))
{
	if (!exc.type.empty()) {
		function = exc.function;
		filename = exc.filename;
		line = exc.line;
		callstack = exc.callstack;
	} else {
#ifdef XAPIAND_TRACEBACKS
		// retrieve current stack addresses
		callstack.resize(128);
		callstack.resize(backtrace(callstack.data(), callstack.size()));
		callstack.shrink_to_fit();
#endif
	}
}

const char*
BaseException::get_message() const
{
	if (message.empty()) {
		message.assign(type);
	}
	return message.c_str();
}

const char*
BaseException::get_context() const
{
	if (context.empty()) {
		context.append(filename);
		context.push_back(':');
		context.append(std::to_string(line));
		context.append(" at ");
		context.append(function);
		context.append(": ");
		context.append(get_message());
	}
	return context.c_str();
}

const char*
BaseException::get_traceback() const
{
	if (traceback.empty()) {
		traceback = ::traceback(function, filename, line, callstack);
	}
	return traceback.c_str();
}
<commit_msg>Exceptions: atos() uses poll when available<commit_after>/*
 * Copyright (C) 2015-2018 Dubalu LLC. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "exception.h"

#include "config.h"           // for XAPIAND_TRACEBACKS

#include <cstdlib>            // for free
#include <cstring>            // for strtok_r
#include <cxxabi.h>           // for abi::__cxa_demangle
#include <dlfcn.h>            // for dladdr

#ifdef HAVE_EXECINFO_H
#include <execinfo.h>         // for backtrace
#else
static inline int backtrace(void**, int) { return 0; }
#endif

#include "likely.h"

#ifndef NDEBUG
#ifndef XAPIAND_TRACEBACKS
#define XAPIAND_TRACEBACKS 1
#endif
#endif

#define BUFFER_SIZE 1024

#ifdef __APPLE__
#include <util.h>             // for forkpty
#include <unistd.h>           // for execlp
#include <termios.h>          // for termios, cfmakeraw
#ifdef HAVE_POLL
#include <poll.h>             // for poll
#else
#include <sys/select.h>       // for select
#endif
/* Use `atos` to do symbol lookup, can lookup non-dynamic symbols and also line
 * numbers. This function is more complicated than you'd expect because `atos`
 * doesn't flush after each line, so plain pipe() or socketpair() won't work
 * until we close the write side. But the whole point is we want to keep `atos`
 * around so we don't have to reprocess the symbol table over and over. What we
 * wind up doing is using `forkpty()` to make a new pseudoterminal for atos to
 * run in, and thus will use line-buffering for stdout, and then we can get
 * each line.
 */
static std::string
atos(const void* address)
{
	static std::mutex mtx;
	std::lock_guard lk(mtx);

	char tmp[20];
	static int fd = -1;
	if (fd == -1) {
		Dl_info info;
		memset(&info, 0, sizeof(Dl_info));
		if (dladdr(reinterpret_cast<const void*>(&atos), &info) == 0) {
			perror("Could not get base address for `atos`.");
			return "";
		}

		struct termios term_opts;
		cfmakeraw(&term_opts);  // have to set this first, otherwise queries echo until child kicks in
		pid_t childpid;
		if unlikely((childpid = forkpty(&fd, nullptr, &term_opts, nullptr)) < 0) {
			perror("Could not forkpty for `atos` call.");
			return "";
		}

		if (childpid == 0) {
			snprintf(tmp, sizeof(tmp), "%p", static_cast<const void *>(info.dli_fbase));
			execlp("/usr/bin/atos", "atos", "-o", info.dli_fname, "-l", tmp, nullptr);
			fprintf(stderr,"Could not exec `atos` for stack trace!\n");
			exit(1);
		}

		int size = snprintf(tmp, sizeof(tmp), "%p\n", address);
		write(fd, tmp, size);

		// atos can take a while to parse symbol table on first request, which
		// is why we leave it running if we see a delay, explain what's going on...
		int err = 0;

#ifdef HAVE_POLL
		struct pollfd fds;
		fds.fd = fd;
		fds.events = POLLIN;
		err = poll(&fds, 1, 3000);
#else
		if (fdin < FD_SETSIZE) {
			fd_set fds;
			FD_ZERO(&fds);
			FD_SET(fd, &fds);
			struct timeval tv = {3, 0};
			err = select(fd + 1, &fds, nullptr, nullptr, &tv);
		}
#endif
		if unlikely(err < 0) {
			perror("Generating... first call takes some time for `atos` to cache the symbol table.");
		} else if (err == 0) {  // timeout
			fprintf(stderr, "Generating... first call takes some time for `atos` to cache the symbol table.\n");
		}
	} else {
		int size = snprintf(tmp, sizeof(tmp), "%p\n", address);
		write(fd, tmp, size);
	}

	const unsigned int MAXLINE = 1024;
	char line[MAXLINE];
	char c = '\0';
	size_t nread = 0;
	while (c != '\n' && nread < MAXLINE) {
		if unlikely(read(fd, &c, 1) <= 0) {
			perror("Lost `atos` connection.");
			close(fd);
			fd = -1;
			return "";
		}
		if (c != '\n') {
			line[nread++] = c;
		}
	}
	if (nread < MAXLINE) {
		return std::string(line, nread);
	}
	fprintf(stderr, "Line read from `atos` was too long.\n");
	return "";
}
#else
static inline std::string
atos(const void*)
{
	return "";
}
#endif

std::string
traceback(const char* function, const char* filename, int line, const std::vector<void*>& callstack, int skip = 1)
{
	char tmp[20];

	std::string tb = "\n== Traceback (most recent call first): ";
	tb.append(filename);
	tb.push_back(':');
	tb.append(std::to_string(line));
	tb.append(" at ");
	tb.append(function);

	int frames = callstack.size();

	if (frames == 0) {
		tb.append(":\n    <empty traceback>");
		return tb;
	}

	if (frames < 2) {
		tb.append(":\n    <no traceback>");
		return tb;
	}

	tb.push_back(':');

	// Iterate over the callstack. Skip the first, it is the address of this function.
	std::string result;
	for (int i = skip; i < frames; ++i) {
		auto address = callstack[i];

		result.assign(std::to_string(frames - i - 1));
		result.push_back(' ');

		auto address_string = atos(address);
		if (address_string.size() > 2 && address_string.compare(0, 2, "0x") != 0) {
			result.append(address_string);
		} else {
			Dl_info info;
			memset(&info, 0, sizeof(Dl_info));
			if (dladdr(address, &info) != 0) {
				// Address:
				snprintf(tmp, sizeof(tmp), "%p ", address);
				result.append(tmp);
				// Symbol name:
				if (info.dli_sname != nullptr) {
					int status = 0;
					char* unmangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status);
					if (status != 0) {
						result.append(info.dli_sname);
					} else {
						try {
							result.append(unmangled);
							free(unmangled);
						} catch(...) {
							free(unmangled);
							throw;
						}
					}
				} else {
					result.append("[unknown symbol]");
				}
				// Offset:
				snprintf(tmp, sizeof(tmp), " + %zu", static_cast<const char*>(address) - static_cast<const char*>(info.dli_saddr));
				result.append(tmp);
			} else {
				snprintf(tmp, sizeof(tmp), "%p [unknown symbol]", address);
				result.append(tmp);
			}
		}
		tb.append("\n    ");
		tb.append(result);
	}

	return tb;
}

std::string
traceback(const char* function, const char* filename, int line, int skip)
{
	std::vector<void*> callstack;

	// retrieve current stack addresses
	callstack.resize(128);
	callstack.resize(backtrace(callstack.data(), callstack.size()));
	callstack.shrink_to_fit();

	auto tb = traceback(function, filename, line, callstack, skip);

	return tb;
}

extern "C" void
__assert_tb(const char* function, const char* filename, unsigned int line, const char* expression)
{
#ifdef XAPIAND_TRACEBACKS
	(void)fprintf(stderr, "Assertion failed: %s in %s %s:%u%s\n",
		expression, function, filename, line, traceback(function, filename, line, 2).c_str());
#else
	(void)fprintf(stderr, "Assertion failed: %s in %s %s:%u\n",
		expression, function, filename, line);
#endif
	abort();
}

BaseException::BaseException()
	: line{0}
{ }

BaseException::BaseException(const BaseException& exc)
	: type{exc.type},
	  function{exc.function},
	  filename{exc.filename},
	  line{exc.line},
	  callstack{exc.callstack},
	  message{exc.message},
	  context{exc.context},
	  traceback{exc.traceback}
{
}

BaseException::BaseException(BaseException&& exc)
	: type{std::move(exc.type)},
	  function{std::move(exc.function)},
	  filename{std::move(exc.filename)},
	  line{std::move(exc.line)},
	  callstack{std::move(exc.callstack)},
	  message{std::move(exc.message)},
	  context{std::move(exc.context)},
	  traceback{std::move(exc.traceback)}
{ }

BaseException::BaseException(const BaseException* exc)
	: BaseException(exc != nullptr ? *exc : BaseException())
{ }

BaseException::BaseException(BaseException::private_ctor, const BaseException& exc, const char *function_, const char *filename_, int line_, const char* type, std::string_view format, VFPRINTF_ARGS args)
	: type(type),
	  function(function_),
	  filename(filename_),
	  line(line_),
	  message(VSPRINTF(format, args))
{
	if (!exc.type.empty()) {
		function = exc.function;
		filename = exc.filename;
		line = exc.line;
		callstack = exc.callstack;
	} else {
#ifdef XAPIAND_TRACEBACKS
		// retrieve current stack addresses
		callstack.resize(128);
		callstack.resize(backtrace(callstack.data(), callstack.size()));
		callstack.shrink_to_fit();
#endif
	}
}

const char*
BaseException::get_message() const
{
	if (message.empty()) {
		message.assign(type);
	}
	return message.c_str();
}

const char*
BaseException::get_context() const
{
	if (context.empty()) {
		context.append(filename);
		context.push_back(':');
		context.append(std::to_string(line));
		context.append(" at ");
		context.append(function);
		context.append(": ");
		context.append(get_message());
	}
	return context.c_str();
}

const char*
BaseException::get_traceback() const
{
	if (traceback.empty()) {
		traceback = ::traceback(function, filename, line, callstack);
	}
	return traceback.c_str();
}
<|endoftext|>


<commit_before>#include "fileCache.h"
#include "logging.h"
#include "helpers/storageHelperFactory.h"

#define MAX_BLOCK_SIZE 10

namespace veil {
namespace helpers {

using namespace std;

FileCache::FileCache(uint32_t blockSize, bool isBuffer)
  : m_isBuffer(isBuffer),
    m_curBlockNo(1),
    m_blockSize(blockSize),
    m_byteSize(0)
{
}

FileCache::~FileCache()
{
}

bool FileCache::readData(off_t offset, size_t size, std::string &buff)
{
    boost::unique_lock<boost::recursive_mutex> guard(m_fileBlocksMutex);

    discardExpired();
    buff.resize(0);

    multiset<block_ptr>::const_iterator it = m_fileBlocks.upper_bound(block_ptr(new FileBlock(offset)));

    if(it == m_fileBlocks.begin())
        return false;

    for(--it; it != m_fileBlocks.end() && buff.size() < size; ++it)
    {
        if(static_cast<size_t>((*it)->offset) > offset + buff.size())
            break;

        size_t startFrom = offset + buff.size() - (*it)->offset;
        if(startFrom < (*it)->size()) {
            buff += (*it)->data.substr( startFrom ,  min( size - buff.size(), startFrom - (*it)->size() ));
        }
    }

    return buff.size() > 0;
}

bool FileCache::writeData(off_t offset, const std::string &buff)
{
    boost::unique_lock<boost::recursive_mutex> guard(m_fileBlocksMutex);

    discardExpired();

    FileBlock block(offset, buff);

    return insertBlock(block);
}

void FileCache::debugPrint()
{
    cout << "BlockList:" << endl;
    multiset<block_ptr>::iterator it = m_fileBlocks.begin();
    while(it != m_fileBlocks.end())
    {
        printf("\t Offset: %ld, Size: %lu, Data: %s, valid_to: %lu\n", (*it)->offset, (*it)->size(), (*it)->data.c_str(), (*it)->valid_to);
        ++it;
    }
}

block_ptr FileCache::removeOldestBlock()
{
    boost::unique_lock<boost::recursive_mutex> guard(m_fileBlocksMutex);

    if(m_blockExpire.empty())
        return block_ptr();

    discardExpired();

    block_ptr tmp = *m_blockExpire.begin();
    m_blockExpire.erase(m_blockExpire.begin());
    m_fileBlocks.erase(tmp);

    // Update current byte size
    m_byteSize -= tmp->size();

    return tmp;
}

bool FileCache::insertBlock(const FileBlock &block)
{
    boost::unique_lock<boost::recursive_mutex> guard(m_fileBlocksMutex);

    discardExpired();

    string cBuff = block.data;
    off_t offset = block.offset;

    // repeat while the is still data to save
    do
    {
        multiset<block_ptr>::iterator it = m_fileBlocks.upper_bound(block_ptr(new FileBlock(offset)));
        multiset<block_ptr>::iterator next;
        if(it != m_fileBlocks.begin())
            --it;

        while(it != m_fileBlocks.end() && cBuff.size() > 0)
        {
            next = it;
            if((*it)->offset <= offset)
                ++next;

            // At least one byte starting with 'offset' of the block (but not all of them) does not overlap others
            if( ((*it)->offset + (*it)->size() <= static_cast<size_t>(offset)) || ((*it)->offset > offset) )
            {
                size_t tmpSize = next == m_fileBlocks.end() ? cBuff.size() : min((size_t)((*next)->offset - offset ), cBuff.size());
                block_ptr tmp = block_ptr(new FileBlock(offset, cBuff.substr(0, tmpSize)));

                cBuff = cBuff.substr(tmpSize);
                offset += tmpSize;

                forceInsertBlock(tmp, next);
                break;
            }
            // At least one byte (starting with 'offset') overlaps with older blocks
            else if ( (*it)->offset <= offset && (*it)->offset + (*it)->size() > static_cast<size_t>(offset))
            {
                off_t tStart = offset - (*it)->offset;
                size_t toCpy = min( (size_t)((*it)->offset + (*it)->size() - offset), cBuff.size() );

                (*it)->data.replace(tStart, toCpy, cBuff.substr(0, toCpy));
                cBuff = cBuff.substr(toCpy);
                offset += toCpy;
            }

            ++it;
        }

        // Whole current data block does not overlap with older ones
        if(it == m_fileBlocks.end())
        {
            block_ptr tmp = block_ptr(new FileBlock(offset, cBuff));
            forceInsertBlock(tmp, it);

            cBuff = "";
        }

    } while (cBuff.size() > 0);

    return true;
}

void FileCache::forceInsertBlock(block_ptr block, std::multiset<block_ptr>::iterator whereTo)
{
    boost::unique_lock<boost::recursive_mutex> guard(m_fileBlocksMutex);

    // This method asumes that given block does not overlap at all with others
    // This is where block merging thakes place

    if(block->size() == 0)
        return;

    // Set expiration time if it isn't set yet
    if(block->valid_to == 0)
        block->valid_to = m_isBuffer ? ++m_curBlockNo : utils::mtime<uint64_t>() + 5000;

    multiset<block_ptr>::iterator it, next, origNext, tmp;
    it = next = origNext = m_fileBlocks.insert(whereTo, block);
    m_blockExpire.insert(block);
    m_byteSize += block->size();

    // If it was first block, there is nothing to megre
    if(m_blockExpire.size() == 1)
        return;

    if(it != m_fileBlocks.begin()) {
        --it;
    } else {
        ++next;
    }

    ++origNext;

    // Iterate from block before the given until merging is done
    do {
        if((*it)->offset + (*it)->size() == static_cast<size_t>((*next)->offset) && (*it)->size() < m_blockSize)
        {
            size_t toCpy = min(m_blockSize - (*it)->size(), (*next)->size());
            (*it)->data += (*next)->data.substr(0, toCpy);
            (*next)->data = (*next)->data.substr(toCpy);
            (*next)->offset += toCpy;

            // If merge process generates empty block, delete it
            if((*next)->size() == 0)
            {
                m_blockExpire.erase(*next);
                tmp = next, tmp++;
                m_fileBlocks.erase(next);
                next = tmp;
            }
        } else if(next != origNext) {
            break;
        } else {
            ++it, ++next;
        }

    } while(it != m_fileBlocks.end() && next != m_fileBlocks.end());
}

size_t FileCache::byteSize()
{
    boost::unique_lock<boost::recursive_mutex> guard(m_fileBlocksMutex);
    return m_byteSize;
}

size_t FileCache::blockCount()
{
    boost::unique_lock<boost::recursive_mutex> guard(m_fileBlocksMutex);
    return m_fileBlocks.size();
}

void FileCache::discardExpired()
{
    if(m_isBuffer)
        return;

    boost::unique_lock<boost::recursive_mutex> guard(m_fileBlocksMutex);
    while(!m_blockExpire.empty())
    {
        block_ptr tmp = *m_blockExpire.begin();

        if(tmp->valid_to > utils::mtime<uint64_t>())
            break;

        m_blockExpire.erase(tmp);
        m_fileBlocks.erase(tmp);

        m_byteSize -= tmp->size();

    }
}

} // namespace helpers
} // namespace veil
<commit_msg>VFS-689 Fix compile warning.<commit_after>#include "fileCache.h"
#include "logging.h"
#include "helpers/storageHelperFactory.h"

#define MAX_BLOCK_SIZE 10

namespace veil {
namespace helpers {

using namespace std;

FileCache::FileCache(uint32_t blockSize, bool isBuffer)
  : m_isBuffer(isBuffer),
    m_curBlockNo(1),
    m_blockSize(blockSize),
    m_byteSize(0)
{
}

FileCache::~FileCache()
{
}

bool FileCache::readData(off_t offset, size_t size, std::string &buff)
{
    boost::unique_lock<boost::recursive_mutex> guard(m_fileBlocksMutex);

    discardExpired();
    buff.resize(0);

    multiset<block_ptr>::const_iterator it = m_fileBlocks.upper_bound(block_ptr(new FileBlock(offset)));

    if(it == m_fileBlocks.begin())
        return false;

    for(--it; it != m_fileBlocks.end() && buff.size() < size; ++it)
    {
        if(static_cast<size_t>((*it)->offset) > offset + buff.size())
            break;

        size_t startFrom = offset + buff.size() - (*it)->offset;
        if(startFrom < (*it)->size()) {
            buff += (*it)->data.substr( startFrom ,  min( size - buff.size(), startFrom - (*it)->size() ));
        }
    }

    return buff.size() > 0;
}

bool FileCache::writeData(off_t offset, const std::string &buff)
{
    boost::unique_lock<boost::recursive_mutex> guard(m_fileBlocksMutex);

    discardExpired();

    FileBlock block(offset, buff);

    return insertBlock(block);
}

void FileCache::debugPrint()
{
    cout << "BlockList:" << endl;
    multiset<block_ptr>::iterator it = m_fileBlocks.begin();
    while(it != m_fileBlocks.end())
    {
        printf("\t Offset: %lld, Size: %lu, Data: %s, valid_to: %llu\n", (*it)->offset, (*it)->size(), (*it)->data.c_str(), (*it)->valid_to);
        ++it;
    }
}

block_ptr FileCache::removeOldestBlock()
{
    boost::unique_lock<boost::recursive_mutex> guard(m_fileBlocksMutex);

    if(m_blockExpire.empty())
        return block_ptr();

    discardExpired();

    block_ptr tmp = *m_blockExpire.begin();
    m_blockExpire.erase(m_blockExpire.begin());
    m_fileBlocks.erase(tmp);

    // Update current byte size
    m_byteSize -= tmp->size();

    return tmp;
}

bool FileCache::insertBlock(const FileBlock &block)
{
    boost::unique_lock<boost::recursive_mutex> guard(m_fileBlocksMutex);

    discardExpired();

    string cBuff = block.data;
    off_t offset = block.offset;

    // repeat while the is still data to save
    do
    {
        multiset<block_ptr>::iterator it = m_fileBlocks.upper_bound(block_ptr(new FileBlock(offset)));
        multiset<block_ptr>::iterator next;
        if(it != m_fileBlocks.begin())
            --it;

        while(it != m_fileBlocks.end() && cBuff.size() > 0)
        {
            next = it;
            if((*it)->offset <= offset)
                ++next;

            // At least one byte starting with 'offset' of the block (but not all of them) does not overlap others
            if( ((*it)->offset + (*it)->size() <= static_cast<size_t>(offset)) || ((*it)->offset > offset) )
            {
                size_t tmpSize = next == m_fileBlocks.end() ? cBuff.size() : min((size_t)((*next)->offset - offset ), cBuff.size());
                block_ptr tmp = block_ptr(new FileBlock(offset, cBuff.substr(0, tmpSize)));

                cBuff = cBuff.substr(tmpSize);
                offset += tmpSize;

                forceInsertBlock(tmp, next);
                break;
            }
            // At least one byte (starting with 'offset') overlaps with older blocks
            else if ( (*it)->offset <= offset && (*it)->offset + (*it)->size() > static_cast<size_t>(offset))
            {
                off_t tStart = offset - (*it)->offset;
                size_t toCpy = min( (size_t)((*it)->offset + (*it)->size() - offset), cBuff.size() );

                (*it)->data.replace(tStart, toCpy, cBuff.substr(0, toCpy));
                cBuff = cBuff.substr(toCpy);
                offset += toCpy;
            }

            ++it;
        }

        // Whole current data block does not overlap with older ones
        if(it == m_fileBlocks.end())
        {
            block_ptr tmp = block_ptr(new FileBlock(offset, cBuff));
            forceInsertBlock(tmp, it);

            cBuff = "";
        }

    } while (cBuff.size() > 0);

    return true;
}

void FileCache::forceInsertBlock(block_ptr block, std::multiset<block_ptr>::iterator whereTo)
{
    boost::unique_lock<boost::recursive_mutex> guard(m_fileBlocksMutex);

    // This method asumes that given block does not overlap at all with others
    // This is where block merging thakes place

    if(block->size() == 0)
        return;

    // Set expiration time if it isn't set yet
    if(block->valid_to == 0)
        block->valid_to = m_isBuffer ? ++m_curBlockNo : utils::mtime<uint64_t>() + 5000;

    multiset<block_ptr>::iterator it, next, origNext, tmp;
    it = next = origNext = m_fileBlocks.insert(whereTo, block);
    m_blockExpire.insert(block);
    m_byteSize += block->size();

    // If it was first block, there is nothing to megre
    if(m_blockExpire.size() == 1)
        return;

    if(it != m_fileBlocks.begin()) {
        --it;
    } else {
        ++next;
    }

    ++origNext;

    // Iterate from block before the given until merging is done
    do {
        if((*it)->offset + (*it)->size() == static_cast<size_t>((*next)->offset) && (*it)->size() < m_blockSize)
        {
            size_t toCpy = min(m_blockSize - (*it)->size(), (*next)->size());
            (*it)->data += (*next)->data.substr(0, toCpy);
            (*next)->data = (*next)->data.substr(toCpy);
            (*next)->offset += toCpy;

            // If merge process generates empty block, delete it
            if((*next)->size() == 0)
            {
                m_blockExpire.erase(*next);
                tmp = next, tmp++;
                m_fileBlocks.erase(next);
                next = tmp;
            }
        } else if(next != origNext) {
            break;
        } else {
            ++it, ++next;
        }

    } while(it != m_fileBlocks.end() && next != m_fileBlocks.end());
}

size_t FileCache::byteSize()
{
    boost::unique_lock<boost::recursive_mutex> guard(m_fileBlocksMutex);
    return m_byteSize;
}

size_t FileCache::blockCount()
{
    boost::unique_lock<boost::recursive_mutex> guard(m_fileBlocksMutex);
    return m_fileBlocks.size();
}

void FileCache::discardExpired()
{
    if(m_isBuffer)
        return;

    boost::unique_lock<boost::recursive_mutex> guard(m_fileBlocksMutex);
    while(!m_blockExpire.empty())
    {
        block_ptr tmp = *m_blockExpire.begin();

        if(tmp->valid_to > utils::mtime<uint64_t>())
            break;

        m_blockExpire.erase(tmp);
        m_fileBlocks.erase(tmp);

        m_byteSize -= tmp->size();

    }
}

} // namespace helpers
} // namespace veil
<|endoftext|>


<commit_before>#include "ThreadName.hpp"

#ifdef WIN32
void SetThreadName( DWORD dwThreadID, const char* threadName)
{
   THREADNAME_INFO info;
   info.dwType = 0x1000;
   info.szName = threadName;
   info.dwThreadID = dwThreadID;
   info.dwFlags = 0;

   __try
   {
      RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
   }
   __except(EXCEPTION_EXECUTE_HANDLER)
   {
   }
}
#endif<commit_msg>Microprofile on thread names<commit_after>#include "ThreadName.hpp"
#include <microprofile/microprofile.h>

#ifdef WIN32
void SetThreadName( DWORD dwThreadID, const char* threadName)
{
   THREADNAME_INFO info;
   info.dwType = 0x1000;
   info.szName = threadName;
   info.dwThreadID = dwThreadID;
   info.dwFlags = 0;

   MicroProfileOnThreadCreate(threadName);

   __try
   {
      RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
   }
   __except(EXCEPTION_EXECUTE_HANDLER)
   {
   }
}
#endif<|endoftext|>


<commit_before>#include <stdio.h>
#include <vector>
#include <cmath>

#include "ChSystemParallel.h"
#include "ChLcpSystemDescriptorParallel.h"

#include "utils/input_output.h"
#include "utils/generators.h"

using namespace chrono;

using std::cout;
using std::endl;

template <typename T>
void AddWall(T&                   body,
             const ChVector<>&    loc,
             const ChVector<>&    dim)
{
	// Append to collision geometry
	body->GetCollisionModel()->AddBox(dim.x, dim.y, dim.z, loc);

	// Append to assets
	ChSharedPtr<ChBoxShape> box_shape = ChSharedPtr<ChAsset>(new ChBoxShape);
	box_shape->SetColor(ChColor(1, 0, 0));
	box_shape->Pos = loc;
	box_shape->Rot = ChQuaternion<>(1,0,0,0);
	box_shape->GetBoxGeometry().Size = dim;

	body->GetAssets().push_back(box_shape);
}

void OutputFile(ChStreamOutAsciiFile& file,
                ChSystem&             sys,
                double                time)
{
	chrono::Vector bodyAngs;

	file << time << "     ";
	cout << time << "     ";

	for (int i = 0; i < sys.Get_bodylist()->size(); ++i) {
		ChBody* abody = (ChBody*) sys.Get_bodylist()->at(i);
		assert(typeid(*abody) == typeid(ChBodyDEM));

		const ChVector<>& bodypos = abody->GetPos();
		bodyAngs = abody->GetRot().Q_to_NasaAngles();
		file << bodypos.x  << "  " << bodypos.y  << "  " << bodypos.z  << "  ";
		file << bodyAngs.x << "  " << bodyAngs.y << "  " << bodyAngs.z << "       ";
		cout << bodypos.x << "  " << bodypos.y << "  " << bodypos.z << "   |   ";
	}

	file << "\n";
	cout << endl;
}

double FindLowest(ChSystem& sys)
{
	double lowest = 1000;

	for (int i = 0; i < sys.Get_bodylist()->size(); ++i) {
		ChBody* abody = (ChBody*) sys.Get_bodylist()->at(i);
		if (abody->GetBodyFixed())
			continue;
		if (abody->GetPos().z < lowest)
			lowest = abody->GetPos().z;
	}
	return lowest;
}

int main(int argc, char* argv[])
{
	int threads = 8;

	// Simulation parameters
	double gravity = -9.81;
	double time_step = 0.0001;
	double time_drop = 5;
	double time_end = 10;
	int    num_steps = std::ceil(time_end / time_step);

	int max_iteration = 20;

	// Output
	ChStreamOutAsciiFile sph_file("../soilbin_pos.txt");
	const char* data_folder = "../SOILBIN";
	double out_fps = 30;
	int out_steps = std::ceil((1 / time_step) / out_fps);

	// Parameters for the mixture balls
	double     radius = 0.1;
	double     density = 2000;
	double     volume = (4.0/3) * PI * radius * radius * radius;
	double     mass = density * volume;
	ChVector<> inertia = 0.4 * mass * radius * radius * ChVector<>(1,1,1);

	// Parameters for the falling ball
	double     dropHeight = 2.5;
	int        ballId = 100;
	double     radius1 = 0.5;
	double     density1 = 2000;
	double     volume1 = (4.0/3) * PI * radius1 * radius1 * radius1;
	double     mass1 = density1 * volume1;
	ChVector<> inertia1 = 0.4 * mass1 * radius1 * radius1 * ChVector<>(1,1,1);

	// Parameters for the containing bin
	int    binId = -200;
	double hDimX = 5;          // length in x direction
	double hDimY = 2;          // depth in y direction
	double hDimZ = 2;          // height in z direction
	double hThickness = 0.1;   // wall thickness

	// Create system
	ChSystemParallelDEM* msystem = new ChSystemParallelDEM();

	// Set number of threads.
	int max_threads = msystem->GetParallelThreadNumber();
	if (threads > max_threads)
		threads = max_threads;
	msystem->SetParallelThreadNumber(threads);
	omp_set_num_threads(threads);

	// Set gravitational acceleration
	msystem->Set_G_acc(ChVector<>(0, 0, gravity));

	// Edit system settings
	msystem->SetMaxiter(max_iteration);
	msystem->SetIterLCPmaxItersSpeed(max_iteration);
	msystem->SetTol(1e-3);
	msystem->SetTolSpeeds(1e-3);
	msystem->SetStep(time_step);

	((ChLcpSolverParallelDEM*) msystem->GetLcpSolverSpeed())->SetMaxIteration(max_iteration);
	((ChLcpSolverParallelDEM*) msystem->GetLcpSolverSpeed())->SetTolerance(0);
	((ChLcpSolverParallelDEM*) msystem->GetLcpSolverSpeed())->SetContactRecoverySpeed(1);

	((ChCollisionSystemParallel*) msystem->GetCollisionSystem())->setBinsPerAxis(I3(10, 10, 10));
	((ChCollisionSystemParallel*) msystem->GetCollisionSystem())->setBodyPerBin(100, 50);

	((ChCollisionSystemParallel*) msystem->GetCollisionSystem())->ChangeNarrowphase(new ChCNarrowphaseR);

	// Create a material for the ball mixture
	ChSharedPtr<ChMaterialSurfaceDEM> ballMixMat;
	ballMixMat = ChSharedPtr<ChMaterialSurfaceDEM>(new ChMaterialSurfaceDEM);
	ballMixMat->SetYoungModulus(2e6f);
	ballMixMat->SetFriction(0.4f);
	ballMixMat->SetDissipationFactor(0.6f);

	// Create a material for the falling ball
	ChSharedPtr<ChMaterialSurfaceDEM> ballMat;
	ballMat = ChSharedPtr<ChMaterialSurfaceDEM>(new ChMaterialSurfaceDEM);
	ballMat->SetYoungModulus(2e6f);
	ballMat->SetFriction(0.4f);
	ballMat->SetDissipationFactor(0.6f);

	// Create a material for the bin
	ChSharedPtr<ChMaterialSurfaceDEM> binMat;
	binMat = ChSharedPtr<ChMaterialSurfaceDEM>(new ChMaterialSurfaceDEM);
	binMat->SetYoungModulus(2e6f);
	binMat->SetFriction(0.4f);
	binMat->SetDissipationFactor(0.6f);

	// Create the falling balls (a mixture entirely made out of spheres)
	int numObjects;

	{
		utils::Generator gen(msystem);

		utils::MixtureIngredientPtr& m1 = gen.AddMixtureIngredient(utils::SPHERE, 1.0);
		m1->setDefaultMaterialDEM(ballMixMat);
		m1->setDefaultDensity(density);
		m1->setDefaultSize(radius);

		gen.createObjectsBox(utils::POISSON_DISK,
		                     2.01 * radius,
		                     ChVector<>(0, 0, 1.5),
		                     ChVector<>(0.8 * hDimX, 0.8 * hDimY, 1));

		numObjects = gen.getTotalNumBodies();
	}

	cout << "Number bodies: " << numObjects << endl;

	// Create the falling ball, but do not add it to the system
	ChSharedBodyDEMPtr ball(new ChBodyDEM(new ChCollisionModelParallel));

	ball->SetMaterialSurfaceDEM(binMat);

	ball->SetIdentifier(binId);
	ball->SetMass(mass1);
	ball->SetInertiaXX(inertia1);
	ball->SetPos(ChVector<>(0, 0, dropHeight));
	ball->SetRot(ChQuaternion<>(1, 0, 0, 0));
	ball->SetCollide(true);
	ball->SetBodyFixed(false);

	ball->GetCollisionModel()->ClearModel();
	ball->GetCollisionModel()->AddSphere(radius1);
	ball->GetCollisionModel()->BuildModel();

	ChSharedPtr<ChSphereShape> ball_shape = ChSharedPtr<ChAsset>(new ChSphereShape);
	ball_shape->SetColor(ChColor(0, 0, 1));
	ball_shape->GetSphereGeometry().rad = radius1;
	ball_shape->Pos = ChVector<>(0,0,0);
	ball_shape->Rot = ChQuaternion<>(1,0,0,0);
	ball->GetAssets().push_back(ball_shape);

	// Create the containing bin
	ChSharedBodyDEMPtr bin(new ChBodyDEM(new ChCollisionModelParallel));

	bin->SetMaterialSurfaceDEM(binMat);

	bin->SetIdentifier(binId);
	bin->SetMass(1);
	bin->SetPos(ChVector<>(0, 0, 0));
	bin->SetRot(ChQuaternion<>(1, 0, 0, 0));
	bin->SetCollide(true);
	bin->SetBodyFixed(true);

	bin->GetCollisionModel()->ClearModel();
	AddWall(bin, ChVector<>(0, 0, -hThickness), ChVector<>(hDimX, hDimY, hThickness));
	AddWall(bin, ChVector<>(-hDimX-hThickness, 0, hDimZ), ChVector<>(hThickness, hDimY, hDimZ));
	AddWall(bin, ChVector<>( hDimX+hThickness, 0, hDimZ), ChVector<>(hThickness, hDimY, hDimZ));
	AddWall(bin, ChVector<>(0, -hDimY-hThickness, hDimZ), ChVector<>(hDimX, hThickness, hDimZ));
	AddWall(bin, ChVector<>(0,  hDimY+hThickness, hDimZ), ChVector<>(hDimX, hThickness, hDimZ));
	bin->GetCollisionModel()->BuildModel();

	msystem->AddBody(bin);

	// Perform the simulation
	double time = 0;
	int out_frame = 0;
	char filename[100];

	bool dropped = false;
	double exec_time = 0;

	for (int i = 0; i < num_steps; i++) {
		if (!dropped && time >= time_drop) {
			cout << " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> DROP BALL" << endl;
			msystem->AddBody(ball);
			dropped = true;
		}

		if (i % out_steps == 0) {
			// Output for Renderman
			sprintf(filename, "%s/RENDERMAN/data_%03d.dat", data_folder, out_frame);
			utils::WriteShapesRender(msystem, filename);

			// Output for POV-Ray
			sprintf(filename, "%s/POVRAY/data_%03d.dat", data_folder, out_frame);
			utils::WriteShapesPovray(msystem, filename);

			// Stats
			cout << " --------------------------------- " << out_frame << "  " << time << "  " <<  endl;
			cout << "                                   " << FindLowest(*msystem) << endl;
			cout << "                                   " << exec_time << endl;

			//OutputFile(sph_file, *msystem, time);

			out_frame++;
		}

		msystem->DoStepDynamics(time_step);
		time += time_step;

		exec_time += msystem->mtimer_step();
	}

	// Final stats
	cout << "==================================" << endl;
	cout << "Number of objects: " << numObjects << endl;
	cout << "Lowest position: " << FindLowest(*msystem) << endl;
	cout << "Simulation time: " << exec_time << endl;
	cout << "Number of threads: " << threads << endl;

	return 0;
}

<commit_msg>Modified demo_soilbin to use checkpointing.<commit_after>#include <stdio.h>
#include <vector>
#include <cmath>

#include "ChSystemParallel.h"
#include "ChLcpSystemDescriptorParallel.h"

#include "utils/input_output.h"
#include "utils/generators.h"

using namespace chrono;

using std::cout;
using std::endl;

// =======================================================================
enum ProblemType {
	SETTLING,
	DROPPING,
	COMPLETE
};

ProblemType problem = SETTLING;

// =======================================================================
// Global problem definitions

int threads = 8;

// Simulation parameters
double gravity = -9.81;
double time_step = 0.0001;
double time_drop = 2;
double time_end = 4;

int max_iteration = 20;

// Output
const char* data_folder = "../SOILBIN";
const char* checkpoint_file = "../SOILBIN/settled.dat";
ChStreamOutAsciiFile sph_file("../SOILBIN/soilbin_pos.txt");
double out_fps = 30;

// Parameters for the mixture balls
double     radius = 0.1;
double     density = 2000;
double     vol = (4.0/3) * PI * radius * radius * radius;
double     mass = density * vol;
ChVector<> inertia = 0.4 * mass * radius * radius * ChVector<>(1,1,1);

// Parameters for the falling ball
double     dropHeight = 2.5;
int        ballId = 100;
double     radius1 = 0.5;
double     density1 = 2000;
double     volume1 = (4.0/3) * PI * radius1 * radius1 * radius1;
double     mass1 = density1 * volume1;
ChVector<> inertia1 = 0.4 * mass1 * radius1 * radius1 * ChVector<>(1,1,1);

// Parameters for the containing bin
int    binId = -200;
double hDimX = 1.5;          // length in x direction
double hDimY = 1;          // depth in y direction
double hDimZ = 2;          // height in z direction
double hThickness = 0.1;   // wall thickness

// =======================================================================

template <typename T>
void AddWall(T&                   body,
             const ChVector<>&    loc,
             const ChVector<>&    dim)
{
	// Append to collision geometry
	body->GetCollisionModel()->AddBox(dim.x, dim.y, dim.z, loc);

	// Append to assets
	ChSharedPtr<ChBoxShape> box_shape = ChSharedPtr<ChAsset>(new ChBoxShape);
	box_shape->SetColor(ChColor(1, 0, 0));
	box_shape->Pos = loc;
	box_shape->Rot = ChQuaternion<>(1,0,0,0);
	box_shape->GetBoxGeometry().Size = dim;

	body->GetAssets().push_back(box_shape);
}

void CreateObjects(ChSystemParallel* system)
{
	// Create a material for the ball mixture
	ChSharedPtr<ChMaterialSurfaceDEM> ballMixMat;
	ballMixMat = ChSharedPtr<ChMaterialSurfaceDEM>(new ChMaterialSurfaceDEM);
	ballMixMat->SetYoungModulus(2e6f);
	ballMixMat->SetFriction(0.4f);
	ballMixMat->SetDissipationFactor(0.6f);

	// Create a material for the bin
	ChSharedPtr<ChMaterialSurfaceDEM> binMat;
	binMat = ChSharedPtr<ChMaterialSurfaceDEM>(new ChMaterialSurfaceDEM);
	binMat->SetYoungModulus(2e6f);
	binMat->SetFriction(0.4f);
	binMat->SetDissipationFactor(0.6f);

	// Create a mixture entirely made out of spheres
	utils::Generator gen(system);

	utils::MixtureIngredientPtr& m1 = gen.AddMixtureIngredient(utils::SPHERE, 1.0);
	m1->setDefaultMaterialDEM(ballMixMat);
	m1->setDefaultDensity(density);
	m1->setDefaultSize(radius);

	gen.createObjectsBox(utils::POISSON_DISK,
	                     2.01 * radius,
	                     ChVector<>(0, 0, 1.5),
	                     ChVector<>(0.8 * hDimX, 0.8 * hDimY, 1));

	cout << "Number bodies generated: " << gen.getTotalNumBodies() << endl;

	// Create the containing bin
	ChSharedBodyDEMPtr bin(new ChBodyDEM(new ChCollisionModelParallel));

	bin->SetMaterialSurfaceDEM(binMat);

	bin->SetIdentifier(binId);
	bin->SetMass(1);
	bin->SetPos(ChVector<>(0, 0, 0));
	bin->SetRot(ChQuaternion<>(1, 0, 0, 0));
	bin->SetCollide(true);
	bin->SetBodyFixed(true);

	bin->GetCollisionModel()->ClearModel();
	AddWall(bin, ChVector<>(0, 0, -hThickness), ChVector<>(hDimX, hDimY, hThickness));
	AddWall(bin, ChVector<>(-hDimX-hThickness, 0, hDimZ), ChVector<>(hThickness, hDimY, hDimZ));
	AddWall(bin, ChVector<>( hDimX+hThickness, 0, hDimZ), ChVector<>(hThickness, hDimY, hDimZ));
	AddWall(bin, ChVector<>(0, -hDimY-hThickness, hDimZ), ChVector<>(hDimX, hThickness, hDimZ));
	AddWall(bin, ChVector<>(0,  hDimY+hThickness, hDimZ), ChVector<>(hDimX, hThickness, hDimZ));
	bin->GetCollisionModel()->BuildModel();

	system->AddBody(bin);
}

// =======================================================================

ChBody* CreateFallingBall()
{
	// Create a material for the falling ball
	ChSharedPtr<ChMaterialSurfaceDEM> ballMat;
	ballMat = ChSharedPtr<ChMaterialSurfaceDEM>(new ChMaterialSurfaceDEM);
	ballMat->SetYoungModulus(2e6f);
	ballMat->SetFriction(0.4f);
	ballMat->SetDissipationFactor(0.6f);

	// Create the falling ball, but do not add it to the system
	ChBodyDEM* ball = new ChBodyDEM(new ChCollisionModelParallel);

	ball->SetMaterialSurfaceDEM(ballMat);

	ball->SetIdentifier(binId);
	ball->SetMass(mass1);
	ball->SetInertiaXX(inertia1);
	ball->SetPos(ChVector<>(0, 0, dropHeight));
	ball->SetRot(ChQuaternion<>(1, 0, 0, 0));
	ball->SetCollide(true);
	ball->SetBodyFixed(false);

	ball->GetCollisionModel()->ClearModel();
	ball->GetCollisionModel()->AddSphere(radius1);
	ball->GetCollisionModel()->BuildModel();

	ChSharedPtr<ChSphereShape> ball_shape = ChSharedPtr<ChAsset>(new ChSphereShape);
	ball_shape->SetColor(ChColor(0, 0, 1));
	ball_shape->GetSphereGeometry().rad = radius1;
	ball_shape->Pos = ChVector<>(0,0,0);
	ball_shape->Rot = ChQuaternion<>(1,0,0,0);
	ball->GetAssets().push_back(ball_shape);

	return ball;
}

// =======================================================================

void OutputFile(ChStreamOutAsciiFile& file,
                ChSystem&             sys,
                double                time)
{
	chrono::Vector bodyAngs;

	file << time << "     ";
	cout << time << "     ";

	for (int i = 0; i < sys.Get_bodylist()->size(); ++i) {
		ChBody* abody = (ChBody*) sys.Get_bodylist()->at(i);
		assert(typeid(*abody) == typeid(ChBodyDEM));

		const ChVector<>& bodypos = abody->GetPos();
		bodyAngs = abody->GetRot().Q_to_NasaAngles();
		file << bodypos.x  << "  " << bodypos.y  << "  " << bodypos.z  << "  ";
		file << bodyAngs.x << "  " << bodyAngs.y << "  " << bodyAngs.z << "       ";
		cout << bodypos.x << "  " << bodypos.y << "  " << bodypos.z << "   |   ";
	}

	file << "\n";
	cout << endl;
}

double FindLowest(ChSystem& sys)
{
	double lowest = 1000;

	for (int i = 0; i < sys.Get_bodylist()->size(); ++i) {
		ChBody* abody = (ChBody*) sys.Get_bodylist()->at(i);
		if (abody->GetBodyFixed())
			continue;
		if (abody->GetPos().z < lowest)
			lowest = abody->GetPos().z;
	}
	return lowest;
}

int main(int argc, char* argv[])
{

	// Create system
	ChSystemParallelDEM* msystem = new ChSystemParallelDEM();

	// Set number of threads.
	int max_threads = msystem->GetParallelThreadNumber();
	if (threads > max_threads)
		threads = max_threads;
	msystem->SetParallelThreadNumber(threads);
	omp_set_num_threads(threads);

	// Set gravitational acceleration
	msystem->Set_G_acc(ChVector<>(0, 0, gravity));

	// Edit system settings
	msystem->SetMaxiter(max_iteration);
	msystem->SetIterLCPmaxItersSpeed(max_iteration);
	msystem->SetTol(1e-3);
	msystem->SetTolSpeeds(1e-3);
	msystem->SetStep(time_step);

	((ChLcpSolverParallelDEM*) msystem->GetLcpSolverSpeed())->SetMaxIteration(max_iteration);
	((ChLcpSolverParallelDEM*) msystem->GetLcpSolverSpeed())->SetTolerance(0);
	((ChLcpSolverParallelDEM*) msystem->GetLcpSolverSpeed())->SetContactRecoverySpeed(1);

	((ChCollisionSystemParallel*) msystem->GetCollisionSystem())->setBinsPerAxis(I3(10, 10, 10));
	((ChCollisionSystemParallel*) msystem->GetCollisionSystem())->setBodyPerBin(100, 50);

	((ChCollisionSystemParallel*) msystem->GetCollisionSystem())->ChangeNarrowphase(new ChCNarrowphaseR);

	// Always create the falling ball (not attached to system)
	ChBody* ball = CreateFallingBall();

	// Select start/end simulation times
	double Tstart;
	double Tend;
	bool dropped = false;

	switch (problem) {
	case SETTLING:
		Tstart = 0;
		Tend = time_drop;    // Simulate from 0 to time_drop
		dropped = true;      // Make sure we never drop the ball
		break;
	case DROPPING:
		Tstart = time_drop;
		Tend = time_end;     // Simulate from time_drop to time_end
		break;
	case COMPLETE:
		Tstart = 0;
		Tend = time_end;     // Simulate from 0 to time_end
		break;
	}

	// Create objects
	if (problem == DROPPING)
		utils::ReadCheckpoint(msystem, checkpoint_file);
	else
		CreateObjects(msystem);

	// Number of steps
	int num_steps = std::ceil((Tend - Tstart) / time_step);
	int out_steps = std::ceil((1 / time_step) / out_fps);

	// Perform the simulation
	double time = Tstart;
	int out_frame = 0;
	double exec_time = 0;

	for (int i = 0; i < num_steps; i++) {
		if (!dropped && time >= time_drop) {
			cout << " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> DROP BALL" << endl;
			msystem->AddBody(ChSharedPtr<ChBody>(ball));
			dropped = true;
		}

		if (i % out_steps == 0) {
			char filename[100];

			// Output for Renderman
			////sprintf(filename, "%s/RENDERMAN/data_%03d.dat", data_folder, out_frame);
			////utils::WriteShapesRender(msystem, filename);

			// Output for POV-Ray
			sprintf(filename, "%s/POVRAY/data_%03d.dat", data_folder, out_frame);
			utils::WriteShapesPovray(msystem, filename);

			// Stats
			cout << " --------------------------------- " << out_frame << "  " << time << "  " <<  endl;
			cout << "                                   " << FindLowest(*msystem) << endl;
			cout << "                                   " << exec_time << endl;

			//OutputFile(sph_file, *msystem, time);

			out_frame++;
		}

		msystem->DoStepDynamics(time_step);
		time += time_step;

		exec_time += msystem->mtimer_step();
	}

	// Create a checkpoint from the last state
	if (problem == SETTLING)
		utils::WriteCheckpoint(msystem, checkpoint_file);

	// Final stats
	cout << "==================================" << endl;
	cout << "Number of bodies: " << msystem->Get_bodylist()->size() << endl;
	cout << "Lowest position: " << FindLowest(*msystem) << endl;
	cout << "Simulation time: " << exec_time << endl;
	cout << "Number of threads: " << threads << endl;

	return 0;
}

<|endoftext|>


<commit_before>#include "gamemode.hpp"
#include "engine.hpp"
#include "debug.hpp"
#include "world.hpp"
#include "gridmap.hpp"
#include "fmv.hpp"

enum class ByteCodeInstruction : u8
{
    kNumberLiteral = 0x1
};

class InPlaceReadOnlyMemoryStream
{
public:
    bool AtEnd() { return false; }
    u8 ReadByte() { return 0; }
private:
    std::vector<u8> mData;
};

class VirtualMachine
{
public:
    void Execute()
    {
        while (!mByteCode.AtEnd())
        {
            ExecuteInstruction(mByteCode.ReadByte());
        }
    }

    void ExecuteInstruction(u8 instruction)
    {
        switch (instruction)
        {
        case ByteCodeInstruction::kNumberLiteral:
            Push(mByteCode.ReadByte());
            break;
        }
    }

    void Push(s32 value)
    {
        mStack[mStackPos++] = value;
    }

    s32 Pop()
    {
        return mStack[--mStackPos];
    }
private:
    s32 mStackPos = 0;
    s32 mStack[256] = {};

    InPlaceReadOnlyMemoryStream mByteCode;
};

class ByteCodeEmitter
{
public:
    ByteCodeEmitter()
    {

    }

    void StartingScreen(const std::string&)
    {

    }

    void ChangeScreen(const std::string&)
    {

    }

    void OnEnter()
    {

    }

    void OnExit()
    {

    }

    void Delay(s32)
    {

    }

    void IdleTimeOut(s32)
    {

    }

    void PlayFmv(const std::string&)
    {

    }

    void PlayAnimation(const std::string&)
    {

    }

    void BeginOnExit(const std::string&)
    {
        throw std::logic_error("The method or operation is not implemented.");
    }

    void EndOnExit()
    {
        throw std::logic_error("The method or operation is not implemented.");
    }

    void BeginOnEnter(const std::string&)
    {
        throw std::logic_error("The method or operation is not implemented.");
    }

    void EndOnEnter()
    {
        throw std::logic_error("The method or operation is not implemented.");
    }

    void DisableMenu()
    {
        throw std::logic_error("The method or operation is not implemented.");
    }

    void EnableMenu()
    {
        throw std::logic_error("The method or operation is not implemented.");
    }

private:
    void Write(s32)
    {

    }

    void Write(const std::string&)
    {

    }

    //Oddlib::MemoryStream mStream;
};

GameMode::GameMode(WorldState& mapState)
    : mWorldState(mapState)
{
    // hack/wip/test
    //mState = eMenu;

}

void Test()
{
    ByteCodeEmitter be;

    be.StartingScreen("STP01C25.CAM");
    be.Delay(100);

    be.BeginOnExit("STP01C25.CAM");
    be.DisableMenu();
    be.EndOnEnter();

    be.BeginOnExit("STP01C25.CAM");
    be.PlayFmv("AE_GTILogo");
    be.PlayFmv("AE_DigitalDialect");
    be.PlayFmv("AE_OWILogo");
    be.PlayFmv("AE_Intro");
    be.PlayFmv("AE_MainMenu");
    be.ChangeScreen("STP01C01.CAM");

    be.EndOnExit();

    be.BeginOnEnter("STP01C01.CAM");
    be.PlayAnimation("StDoorOpen");
    be.PlayAnimation("AbeHello");
    be.EnableMenu();

    be.EndOnEnter();
}

void GameMode::UpdateMenu(const InputState& /*input*/, CoordinateSpace& /*coords*/)
{
    switch (mMenuState)
    {
    case GameMode::MenuStates::eInit:
        mMenuState = MenuStates::eCameraRoll;
        mWorldState.SetCurrentCamera("STP01C25.CAM");
        mWorldState.SetGameCameraToCameraAt(mWorldState.CurrentCameraX(), mWorldState.CurrentCameraY());
        break;

    case GameMode::MenuStates::eCameraRoll:
        if ((mWorldState.mGlobalFrameCounter % 100) == 0)
        {
            mWorldState.mPlayFmvState->Play("AE_Intro");
            mWorldState.mReturnToState = mWorldState.mState;
            mWorldState.mState = WorldState::States::ePlayFmv;
        }
        break;

    case GameMode::MenuStates::eFmv:
        break;

    case GameMode::MenuStates::eUserMenu:
        break;

    default:
        break;
    }

}

void GameMode::Update(const InputState& input, CoordinateSpace& coords)
{
    coords.SetScreenSize(mWorldState.kVirtualScreenSize);

    if (mState == eMenu)
    {
        UpdateMenu(input, coords);
        coords.SetCameraPosition(mWorldState.mCameraPosition);
        return;
    }

    if (mState == eRunning)
    {
        if (input.mKeys[SDL_SCANCODE_ESCAPE].IsPressed())
        {
            // TODO: Stop or pause music? Check what real game does
            mState = ePaused;
        }
    }
    else if (mState == ePaused)
    {
        if (input.mKeys[SDL_SCANCODE_ESCAPE].IsPressed())
        {
            mState = eRunning;
        }
    }

    if (input.mKeys[SDL_SCANCODE_E].IsPressed() && mState != ePaused)
    {
        mWorldState.mState = WorldState::States::eToEditor;
        coords.mSmoothCameraPosition = true;

        mWorldState.mModeSwitchTimeout = SDL_GetTicks() + kSwitchTimeMs;

        //mCameraPosition.x = mPlayer.mXPos;
        //mCameraPosition.y = mPlayer.mYPos;
    }

    if (mState == eRunning)
    {
        for (auto& obj : mWorldState.mObjs)
        {
            obj->Update(input);
        }
    }

    if (mWorldState.mCameraSubject)
    {
        const s32 camX = static_cast<s32>(mWorldState.mCameraSubject->mXPos / mWorldState.kCameraBlockSize.x);
        const s32 camY = static_cast<s32>(mWorldState.mCameraSubject->mYPos / mWorldState.kCameraBlockSize.y);

        const glm::vec2 camPos = glm::vec2(
            (camX * mWorldState.kCameraBlockSize.x) + mWorldState.kCameraBlockImageOffset.x,
            (camY * mWorldState.kCameraBlockSize.y) + mWorldState.kCameraBlockImageOffset.y) + glm::vec2(mWorldState.kVirtualScreenSize.x / 2, mWorldState.kVirtualScreenSize.y / 2);

        if (mWorldState.mCameraPosition != camPos)
        {
            LOG_INFO("TODO: Screen change");
            coords.mSmoothCameraPosition = false;
            mWorldState.mCameraPosition = camPos;
        }

        coords.SetCameraPosition(mWorldState.mCameraPosition);
    }
}

// TODO: Add to common header with same func from fmv.cpp
static f32 Percent2(f32 max, f32 percent)
{
    return (max / 100.0f) * percent;
}

void GameMode::Render(AbstractRenderer& rend) const
{
    if (mWorldState.mCameraSubject && Debugging().mDrawCameras)
    {
        const s32 camX = mState == eMenu ? static_cast<s32>(mWorldState.CurrentCameraX()) : static_cast<s32>(mWorldState.mCameraSubject->mXPos / mWorldState.kCameraBlockSize.x);
        const s32 camY = mState == eMenu ? static_cast<s32>(mWorldState.CurrentCameraY()) : static_cast<s32>(mWorldState.mCameraSubject->mYPos / mWorldState.kCameraBlockSize.y);

        if (camX >= 0 && camY >= 0 &&
            camX < static_cast<s32>(mWorldState.mScreens.size()) &&
            camY < static_cast<s32>(mWorldState.mScreens[camX].size()))
        {
            GridScreen* screen = mWorldState.mScreens[camX][camY].get();
            if (screen)
            {
                if (screen->hasTexture())
                {
                    screen->Render(rend,
                        (camX * mWorldState.kCameraBlockSize.x) + mWorldState.kCameraBlockImageOffset.x,
                        (camY * mWorldState.kCameraBlockSize.y) + mWorldState.kCameraBlockImageOffset.y,
                        mWorldState.kVirtualScreenSize.x, mWorldState.kVirtualScreenSize.y);
                }
            }
        }
    }

    mWorldState.RenderDebug(rend);

    if (Debugging().mDrawObjects)
    {
        for (const auto& obj : mWorldState.mObjs)
        {
            obj->Render(rend, 0, 0, 1.0f, AbstractRenderer::eForegroundLayer0);
        }
    }

    if (mWorldState.mCameraSubject)
    {
        // Test raycasting for shadows
        mWorldState.DebugRayCast(rend,
            glm::vec2(mWorldState.mCameraSubject->mXPos, mWorldState.mCameraSubject->mYPos),
            glm::vec2(mWorldState.mCameraSubject->mXPos, mWorldState.mCameraSubject->mYPos + 500),
            0,
            glm::vec2(0, -10)); // -10 so when we are *ON* a line you can see something

        mWorldState.DebugRayCast(rend,
            glm::vec2(mWorldState.mCameraSubject->mXPos, mWorldState.mCameraSubject->mYPos - 2),
            glm::vec2(mWorldState.mCameraSubject->mXPos, mWorldState.mCameraSubject->mYPos - 60),
            3,
            glm::vec2(0, 0));

        if (mWorldState.mCameraSubject->mFlipX)
        {
            mWorldState.DebugRayCast(rend,
                glm::vec2(mWorldState.mCameraSubject->mXPos, mWorldState.mCameraSubject->mYPos - 20),
                glm::vec2(mWorldState.mCameraSubject->mXPos - 25, mWorldState.mCameraSubject->mYPos - 20), 1);

            mWorldState.DebugRayCast(rend,
                glm::vec2(mWorldState.mCameraSubject->mXPos, mWorldState.mCameraSubject->mYPos - 50),
                glm::vec2(mWorldState.mCameraSubject->mXPos - 25, mWorldState.mCameraSubject->mYPos - 50), 1);
        }
        else
        {
            mWorldState.DebugRayCast(rend,
                glm::vec2(mWorldState.mCameraSubject->mXPos, mWorldState.mCameraSubject->mYPos - 20),
                glm::vec2(mWorldState.mCameraSubject->mXPos + 25, mWorldState.mCameraSubject->mYPos - 20), 2);

            mWorldState.DebugRayCast(rend,
                glm::vec2(mWorldState.mCameraSubject->mXPos, mWorldState.mCameraSubject->mYPos - 50),
                glm::vec2(mWorldState.mCameraSubject->mXPos + 25, mWorldState.mCameraSubject->mYPos - 50), 2);
        }
    }

    if (mState == ePaused)
    {
        rend.PathBegin();
        f32 w = static_cast<f32>(rend.Width());
        f32 h = static_cast<f32>(rend.Height());

        rend.PathLineTo(0.0f, 0.0f);
        rend.PathLineTo(0.0f, h);
        rend.PathLineTo(w, h);
        rend.PathLineTo(w, 0.0f);
        rend.PathFill(ColourU8{ 0, 0, 0, 200 }, AbstractRenderer::eLayers::ePauseMenu, AbstractRenderer::eNormal, AbstractRenderer::eScreen);

        f32 textSize = Percent2(h, 8.0f);
        f32 bounds[4] = {};
        rend.TextBounds((w / 2.0f), (h / 2.0f), textSize, "Paused", bounds);
        rend.Text(
            (w / 2.0f) - ((bounds[2] - bounds[0]) / 2.0f),
            (h / 2.0f) - ((bounds[3] - bounds[1]) / 2.0f),
            textSize, "Paused", ColourU8{ 255, 255, 255, 255 }, AbstractRenderer::eLayers::ePauseMenu, AbstractRenderer::eNormal, AbstractRenderer::eScreen);
    }
}
<commit_msg>revert incomplete test code<commit_after>#include "gamemode.hpp"
#include "engine.hpp"
#include "debug.hpp"
#include "world.hpp"
#include "gridmap.hpp"
#include "fmv.hpp"

GameMode::GameMode(WorldState& mapState)
    : mWorldState(mapState)
{

}

void GameMode::UpdateMenu(const InputState& /*input*/, CoordinateSpace& /*coords*/)
{
    switch (mMenuState)
    {
    case GameMode::MenuStates::eInit:
        mMenuState = MenuStates::eCameraRoll;
        mWorldState.SetCurrentCamera("STP01C25.CAM");
        mWorldState.SetGameCameraToCameraAt(mWorldState.CurrentCameraX(), mWorldState.CurrentCameraY());
        break;

    case GameMode::MenuStates::eCameraRoll:
        if ((mWorldState.mGlobalFrameCounter % 100) == 0)
        {
            mWorldState.mPlayFmvState->Play("AE_Intro");
            mWorldState.mReturnToState = mWorldState.mState;
            mWorldState.mState = WorldState::States::ePlayFmv;
        }
        break;

    case GameMode::MenuStates::eFmv:
        break;

    case GameMode::MenuStates::eUserMenu:
        break;

    default:
        break;
    }

}

void GameMode::Update(const InputState& input, CoordinateSpace& coords)
{
    coords.SetScreenSize(mWorldState.kVirtualScreenSize);

    if (mState == eMenu)
    {
        UpdateMenu(input, coords);
        coords.SetCameraPosition(mWorldState.mCameraPosition);
        return;
    }

    if (mState == eRunning)
    {
        if (input.mKeys[SDL_SCANCODE_ESCAPE].IsPressed())
        {
            // TODO: Stop or pause music? Check what real game does
            mState = ePaused;
        }
    }
    else if (mState == ePaused)
    {
        if (input.mKeys[SDL_SCANCODE_ESCAPE].IsPressed())
        {
            mState = eRunning;
        }
    }

    if (input.mKeys[SDL_SCANCODE_E].IsPressed() && mState != ePaused)
    {
        mWorldState.mState = WorldState::States::eToEditor;
        coords.mSmoothCameraPosition = true;

        mWorldState.mModeSwitchTimeout = SDL_GetTicks() + kSwitchTimeMs;

        //mCameraPosition.x = mPlayer.mXPos;
        //mCameraPosition.y = mPlayer.mYPos;
    }

    if (mState == eRunning)
    {
        for (auto& obj : mWorldState.mObjs)
        {
            obj->Update(input);
        }
    }

    if (mWorldState.mCameraSubject)
    {
        const s32 camX = static_cast<s32>(mWorldState.mCameraSubject->mXPos / mWorldState.kCameraBlockSize.x);
        const s32 camY = static_cast<s32>(mWorldState.mCameraSubject->mYPos / mWorldState.kCameraBlockSize.y);

        const glm::vec2 camPos = glm::vec2(
            (camX * mWorldState.kCameraBlockSize.x) + mWorldState.kCameraBlockImageOffset.x,
            (camY * mWorldState.kCameraBlockSize.y) + mWorldState.kCameraBlockImageOffset.y) + glm::vec2(mWorldState.kVirtualScreenSize.x / 2, mWorldState.kVirtualScreenSize.y / 2);

        if (mWorldState.mCameraPosition != camPos)
        {
            LOG_INFO("TODO: Screen change");
            coords.mSmoothCameraPosition = false;
            mWorldState.mCameraPosition = camPos;
        }

        coords.SetCameraPosition(mWorldState.mCameraPosition);
    }
}

// TODO: Add to common header with same func from fmv.cpp
static f32 Percent2(f32 max, f32 percent)
{
    return (max / 100.0f) * percent;
}

void GameMode::Render(AbstractRenderer& rend) const
{
    if (mWorldState.mCameraSubject && Debugging().mDrawCameras)
    {
        const s32 camX = mState == eMenu ? static_cast<s32>(mWorldState.CurrentCameraX()) : static_cast<s32>(mWorldState.mCameraSubject->mXPos / mWorldState.kCameraBlockSize.x);
        const s32 camY = mState == eMenu ? static_cast<s32>(mWorldState.CurrentCameraY()) : static_cast<s32>(mWorldState.mCameraSubject->mYPos / mWorldState.kCameraBlockSize.y);

        if (camX >= 0 && camY >= 0 &&
            camX < static_cast<s32>(mWorldState.mScreens.size()) &&
            camY < static_cast<s32>(mWorldState.mScreens[camX].size()))
        {
            GridScreen* screen = mWorldState.mScreens[camX][camY].get();
            if (screen)
            {
                if (screen->hasTexture())
                {
                    screen->Render(rend,
                        (camX * mWorldState.kCameraBlockSize.x) + mWorldState.kCameraBlockImageOffset.x,
                        (camY * mWorldState.kCameraBlockSize.y) + mWorldState.kCameraBlockImageOffset.y,
                        mWorldState.kVirtualScreenSize.x, mWorldState.kVirtualScreenSize.y);
                }
            }
        }
    }

    mWorldState.RenderDebug(rend);

    if (Debugging().mDrawObjects)
    {
        for (const auto& obj : mWorldState.mObjs)
        {
            obj->Render(rend, 0, 0, 1.0f, AbstractRenderer::eForegroundLayer0);
        }
    }

    if (mWorldState.mCameraSubject)
    {
        // Test raycasting for shadows
        mWorldState.DebugRayCast(rend,
            glm::vec2(mWorldState.mCameraSubject->mXPos, mWorldState.mCameraSubject->mYPos),
            glm::vec2(mWorldState.mCameraSubject->mXPos, mWorldState.mCameraSubject->mYPos + 500),
            0,
            glm::vec2(0, -10)); // -10 so when we are *ON* a line you can see something

        mWorldState.DebugRayCast(rend,
            glm::vec2(mWorldState.mCameraSubject->mXPos, mWorldState.mCameraSubject->mYPos - 2),
            glm::vec2(mWorldState.mCameraSubject->mXPos, mWorldState.mCameraSubject->mYPos - 60),
            3,
            glm::vec2(0, 0));

        if (mWorldState.mCameraSubject->mFlipX)
        {
            mWorldState.DebugRayCast(rend,
                glm::vec2(mWorldState.mCameraSubject->mXPos, mWorldState.mCameraSubject->mYPos - 20),
                glm::vec2(mWorldState.mCameraSubject->mXPos - 25, mWorldState.mCameraSubject->mYPos - 20), 1);

            mWorldState.DebugRayCast(rend,
                glm::vec2(mWorldState.mCameraSubject->mXPos, mWorldState.mCameraSubject->mYPos - 50),
                glm::vec2(mWorldState.mCameraSubject->mXPos - 25, mWorldState.mCameraSubject->mYPos - 50), 1);
        }
        else
        {
            mWorldState.DebugRayCast(rend,
                glm::vec2(mWorldState.mCameraSubject->mXPos, mWorldState.mCameraSubject->mYPos - 20),
                glm::vec2(mWorldState.mCameraSubject->mXPos + 25, mWorldState.mCameraSubject->mYPos - 20), 2);

            mWorldState.DebugRayCast(rend,
                glm::vec2(mWorldState.mCameraSubject->mXPos, mWorldState.mCameraSubject->mYPos - 50),
                glm::vec2(mWorldState.mCameraSubject->mXPos + 25, mWorldState.mCameraSubject->mYPos - 50), 2);
        }
    }

    if (mState == ePaused)
    {
        rend.PathBegin();
        f32 w = static_cast<f32>(rend.Width());
        f32 h = static_cast<f32>(rend.Height());

        rend.PathLineTo(0.0f, 0.0f);
        rend.PathLineTo(0.0f, h);
        rend.PathLineTo(w, h);
        rend.PathLineTo(w, 0.0f);
        rend.PathFill(ColourU8{ 0, 0, 0, 200 }, AbstractRenderer::eLayers::ePauseMenu, AbstractRenderer::eNormal, AbstractRenderer::eScreen);

        f32 textSize = Percent2(h, 8.0f);
        f32 bounds[4] = {};
        rend.TextBounds((w / 2.0f), (h / 2.0f), textSize, "Paused", bounds);
        rend.Text(
            (w / 2.0f) - ((bounds[2] - bounds[0]) / 2.0f),
            (h / 2.0f) - ((bounds[3] - bounds[1]) / 2.0f),
            textSize, "Paused", ColourU8{ 255, 255, 255, 255 }, AbstractRenderer::eLayers::ePauseMenu, AbstractRenderer::eNormal, AbstractRenderer::eScreen);
    }
}
<|endoftext|>