<commit_before>/*
  Hume Library
  Copyright (C) 2015 Marshall Clyburn

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
  USA
*/

#include "Graphics.h"

namespace hume
{
	Graphics::Graphics() : window(nullptr)
	{
	}

	Graphics::~Graphics()
	{
		if(window) delete window;
	}

	void Graphics::initialize()
	{
		const int types = IMG_INIT_JPG | IMG_INIT_PNG;
		int result = IMG_Init(types);
		if(result != types) throw SDLException();

		result = TTF_Init();
		if(result != 0) throw SDLTTFException();

		return;
	}

	void Graphics::shutdown()
	{
		IMG_Quit();
		TTF_Quit();

		return;
	}

	void Graphics::set_window(Window* const w)
	{
		window = w;
		return;
	}

	Window* Graphics::get_window() const
	{
		return window;
	}

	Image* Graphics::load_image(const std::string& filename)
	{
		Image* image = new Image();
		image->open(filename, window->get_renderer());

		return image;
	}

	Image* Graphics::load_image(const std::string& filename, const Uint8 r, const Uint8 g, const Uint8 b)
	{
		Image* image = new Image(r, g, b);
		image->open(filename, window->get_renderer());

		return image;
	}

	void Graphics::draw(const Blittable* const b, const Properties& p)
	{
		window->draw(b, p);
		return;
	}

	void Graphics::draw_rect(const Properties& p, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
	{
		draw_rect(p.x, p.y, p.w, p.h, r, g, b, a);
		return;
	}

	void Graphics::draw_rect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
	{
		SDL_Renderer* const renderer = window->get_renderer();

		// We'll be restoring the blend mode and colors back to what they were.
		SDL_BlendMode previous;
		uint8_t rgba[4];
		SDL_GetRenderDrawBlendMode(renderer, &previous);
		SDL_GetRenderDrawColor(renderer, &rgba[0], &rgba[1], &rgba[2], &rgba[3]);
		SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
		SDL_SetRenderDrawColor(renderer, r, g, b, a);

		SDL_Rect rect;
		rect.x = x;
		rect.y = y;
		rect.w = w;
		rect.h = h;
		SDL_RenderFillRect(renderer, &rect);

		// Restore blend mode.
		SDL_SetRenderDrawBlendMode(renderer, previous);
		SDL_SetRenderDrawColor(renderer, rgba[0], rgba[1], rgba[2], rgba[3]);

		return;
	}

	void Graphics::clear()
	{
		window->clear();
		return;
	}

	void Graphics::refresh()
	{
		window->present();
		return;
	}
}
<commit_msg>Catch SDL errors as exceptions.<commit_after>/*
  Hume Library
  Copyright (C) 2015 Marshall Clyburn

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
  USA
*/

#include "Graphics.h"

namespace hume
{
	Graphics::Graphics() : window(nullptr)
	{
	}

	Graphics::~Graphics()
	{
		if(window) delete window;
	}

	void Graphics::initialize()
	{
		const int types = IMG_INIT_JPG | IMG_INIT_PNG;
		int result = IMG_Init(types);
		if(result != types) throw SDLException();

		result = TTF_Init();
		if(result != 0) throw SDLTTFException();

		return;
	}

	void Graphics::shutdown()
	{
		IMG_Quit();
		TTF_Quit();

		return;
	}

	void Graphics::set_window(Window* const w)
	{
		window = w;
		return;
	}

	Window* Graphics::get_window() const
	{
		return window;
	}

	Image* Graphics::load_image(const std::string& filename)
	{
		Image* image = new Image();
		image->open(filename, window->get_renderer());

		return image;
	}

	Image* Graphics::load_image(const std::string& filename, const Uint8 r, const Uint8 g, const Uint8 b)
	{
		Image* image = new Image(r, g, b);
		image->open(filename, window->get_renderer());

		return image;
	}

	void Graphics::draw(const Blittable* const b, const Properties& p)
	{
		window->draw(b, p);
		return;
	}

	void Graphics::draw_rect(const Properties& p, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
	{
		draw_rect(p.x, p.y, p.w, p.h, r, g, b, a);
		return;
	}

	void Graphics::draw_rect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
	{
		SDL_Renderer* const renderer = window->get_renderer();

		// We'll be restoring the blend mode and colors back to what they were.
		SDL_BlendMode previous;
		uint8_t rgba[4];
		if(SDL_GetRenderDrawBlendMode(renderer, &previous) != 0) throw SDLException();
		if(SDL_GetRenderDrawColor(renderer, &rgba[0], &rgba[1], &rgba[2], &rgba[3]) != 0) throw SDLException();
		if(SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND) != 0) throw SDLException();
		if(SDL_SetRenderDrawColor(renderer, r, g, b, a) != 0) throw SDLException();

		SDL_Rect rect;
		rect.x = x;
		rect.y = y;
		rect.w = w;
		rect.h = h;
		if(SDL_RenderFillRect(renderer, &rect) != 0) throw SDLException();

		// Restore blend mode.
		if(SDL_SetRenderDrawBlendMode(renderer, previous) != 0) throw SDLException();
		if(SDL_SetRenderDrawColor(renderer, rgba[0], rgba[1], rgba[2], rgba[3]) != 0) throw SDLException();

		return;
	}

	void Graphics::clear()
	{
		window->clear();
		return;
	}

	void Graphics::refresh()
	{
		window->present();
		return;
	}
}
<|endoftext|>


<commit_before>#include "MarkupSTL.h"
//#include "io.h"
#include <string>
#include <iostream>
#include <fstream>
#include "util.h"
#include "graph.h"
#include "io.h"
#include "opRelate.h"

using namespace std;

#define TEST_DESCR 1
#define GEOM_A_IN 2
#define GEOM_A_OUT 4
#define GEOM_B_IN 8
#define GEOM_B_OUT 16
#define TEST_OP 32
#define TEST_RESULT 64
#define PRED 128

int main(int argC, char* argV[]) {
//	int out=TEST_DESCR+GEOM_A_IN+GEOM_A_OUT+GEOM_B_IN+GEOM_B_OUT+TEST_OP+TEST_RESULT;
	int out=TEST_DESCR+GEOM_A_IN+GEOM_B_IN+TEST_OP+TEST_RESULT;
//	int out=GEOM_A_IN+GEOM_B_IN+TEST_OP+TEST_RESULT+PRED;
//	int out=TEST_DESCR+GEOM_A_IN+GEOM_B_IN+TEST_OP+TEST_RESULT;
//	int out=TEST_DESCR+TEST_RESULT;
//	int out=0;
	int failed=0;
	int succeeded=0;
	string source="d://test.xml";
//	string source="./test.xml";
	string precisionModel="";
	string desc="";
	string geomAin="";
	string geomBin="";
	string geomAout="";
	string geomBout="";
	string opName="";
	string opSig="";
	string opRes="";
	int testCount=0;

	WKTReader *r = new WKTReader(GeometryFactory(PrecisionModel(),10));
	WKTWriter *w=new WKTWriter();
	Geometry *gA;
	Geometry *gB;

	CMarkupSTL xml;
	bool a=xml.Load(source.c_str());

	xml.ResetPos();
	xml.FindElem("run");
	xml.FindChildElem("precisionModel");
	precisionModel=xml.GetChildAttrib("type");
	cout << "Precision Model: " << precisionModel << endl;
	while (xml.FindChildElem("case")) {
		xml.IntoElem();
		testCount++;
		xml.FindChildElem("desc");
		desc=xml.GetChildData();
		if (out & TEST_DESCR) {
			cout << "Test #" << testCount << endl;
			cout << "\t" << desc << endl;
		}
		xml.FindChildElem("a");
		geomAin=xml.GetChildData();
		gA=r->read(geomAin);
		geomAout=w->write(gA);
		if (out &(GEOM_A_IN | GEOM_A_OUT)) {
			cout << "\tGeometry A" << endl;
			if (out & GEOM_A_IN)
				cout << "\t\tIn:" << geomAin << endl;
			if (out & GEOM_A_OUT)
				cout << "\t\tOut:" << geomAout << endl;
		}

		xml.FindChildElem("b");
		geomBin=xml.GetChildData();
		gB=r->read(geomBin);
		geomBout=w->write(gB);
		if (out &(GEOM_B_IN | GEOM_B_OUT)) {
			cout << "\tGeometry B" << endl;
			if (out & GEOM_B_IN)
				cout << "\t\tIn:" << geomBin << endl;
			if (out & GEOM_B_OUT)
				cout << "\t\tOut:" << geomBout << endl;
		}

		xml.FindChildElem("test");
		xml.IntoElem();
        xml.FindChildElem("op");
		opName=xml.GetChildAttrib("name");
		opSig=xml.GetChildAttrib("arg3");
		opRes=xml.GetChildData();
		if (out & TEST_OP)
			cout << "\tOperation '" << opName << "[" << opSig <<"]' should be " << opRes << endl;
		if (opName=="relate") {
			IntersectionMatrix im(gA->relate(gB));
			if (out & TEST_RESULT)
				cout << "\tResult: matrix='" << im.toString() << "' result=" << (im.matches(opSig)?"true":"false") <<endl;
			if (!im.matches(opSig)) failed++; else succeeded++;
		}
		if (out & PRED) {
			cout << "\tEquals:\t\tAB=" << (gA->equals(gB)?"T":"F") << ", BA=" << (gB->equals(gA)?"T":"F") << endl;
			cout << "\tDisjoint:\tAB=" << (gA->disjoint(gB)?"T":"F") << ", BA=" << (gB->disjoint(gA)?"T":"F") << endl;
			cout << "\tIntersects:\tAB=" << (gA->intersects(gB)?"T":"F") << ", BA=" << (gB->intersects(gA)?"T":"F") << endl;
			cout << "\tTouches:\tAB=" << (gA->touches(gB)?"T":"F") << ", BA=" << (gB->touches(gA)?"T":"F") << endl;
			cout << "\tCrosses:\tAB=" << (gA->crosses(gB)?"T":"F") << ", BA=" << (gB->crosses(gA)?"T":"F") << endl;
			cout << "\tWithin:\t\tAB=" << (gA->within(gB)?"T":"F") << ", BA=" << (gB->within(gA)?"T":"F") << endl;
			cout << "\tContains:\tAB=" << (gA->contains(gB)?"T":"F") << ", BA=" << (gB->contains(gA)?"T":"F") << endl;
			cout << "\tOverlaps:\tAB=" << (gA->overlaps(gB)?"T":"F") << ", BA=" << (gB->overlaps(gA)?"T":"F") << endl;
		}

		xml.OutOfElem();
		xml.OutOfElem();
	}
	cout << "Failed: ";
	cout << failed << endl;
	cout << "Succeeded: ";
	cout << succeeded << endl;
	cout << "End Test";
}<commit_msg>Make path to test file relative.<commit_after>#include "MarkupSTL.h"
//#include "io.h"
#include <string>
#include <iostream>
#include <fstream>
#include "util.h"
#include "graph.h"
#include "io.h"
#include "opRelate.h"

using namespace std;

#define TEST_DESCR 1
#define GEOM_A_IN 2
#define GEOM_A_OUT 4
#define GEOM_B_IN 8
#define GEOM_B_OUT 16
#define TEST_OP 32
#define TEST_RESULT 64
#define PRED 128

int main(int argC, char* argV[]) {
//	int out=TEST_DESCR+GEOM_A_IN+GEOM_A_OUT+GEOM_B_IN+GEOM_B_OUT+TEST_OP+TEST_RESULT;
	int out=TEST_DESCR+GEOM_A_IN+GEOM_B_IN+TEST_OP+TEST_RESULT;
//	int out=GEOM_A_IN+GEOM_B_IN+TEST_OP+TEST_RESULT+PRED;
//	int out=TEST_DESCR+GEOM_A_IN+GEOM_B_IN+TEST_OP+TEST_RESULT;
//	int out=TEST_DESCR+TEST_RESULT;
//	int out=0;
	int failed=0;
	int succeeded=0;
//	string source="d://test.xml";
	string source="./test.xml";
	string precisionModel="";
	string desc="";
	string geomAin="";
	string geomBin="";
	string geomAout="";
	string geomBout="";
	string opName="";
	string opSig="";
	string opRes="";
	int testCount=0;

	WKTReader *r = new WKTReader(GeometryFactory(PrecisionModel(),10));
	WKTWriter *w=new WKTWriter();
	Geometry *gA;
	Geometry *gB;

	CMarkupSTL xml;
	bool a=xml.Load(source.c_str());

	xml.ResetPos();
	xml.FindElem("run");
	xml.FindChildElem("precisionModel");
	precisionModel=xml.GetChildAttrib("type");
	cout << "Precision Model: " << precisionModel << endl;
	while (xml.FindChildElem("case")) {
		xml.IntoElem();
		testCount++;
		xml.FindChildElem("desc");
		desc=xml.GetChildData();
		if (out & TEST_DESCR) {
			cout << "Test #" << testCount << endl;
			cout << "\t" << desc << endl;
		}
		xml.FindChildElem("a");
		geomAin=xml.GetChildData();
		gA=r->read(geomAin);
		geomAout=w->write(gA);
		if (out &(GEOM_A_IN | GEOM_A_OUT)) {
			cout << "\tGeometry A" << endl;
			if (out & GEOM_A_IN)
				cout << "\t\tIn:" << geomAin << endl;
			if (out & GEOM_A_OUT)
				cout << "\t\tOut:" << geomAout << endl;
		}

		xml.FindChildElem("b");
		geomBin=xml.GetChildData();
		gB=r->read(geomBin);
		geomBout=w->write(gB);
		if (out &(GEOM_B_IN | GEOM_B_OUT)) {
			cout << "\tGeometry B" << endl;
			if (out & GEOM_B_IN)
				cout << "\t\tIn:" << geomBin << endl;
			if (out & GEOM_B_OUT)
				cout << "\t\tOut:" << geomBout << endl;
		}

		xml.FindChildElem("test");
		xml.IntoElem();
        xml.FindChildElem("op");
		opName=xml.GetChildAttrib("name");
		opSig=xml.GetChildAttrib("arg3");
		opRes=xml.GetChildData();
		if (out & TEST_OP)
			cout << "\tOperation '" << opName << "[" << opSig <<"]' should be " << opRes << endl;
		if (opName=="relate") {
			IntersectionMatrix im(gA->relate(gB));
			if (out & TEST_RESULT)
				cout << "\tResult: matrix='" << im.toString() << "' result=" << (im.matches(opSig)?"true":"false") <<endl;
			if (!im.matches(opSig)) failed++; else succeeded++;
		}
		if (out & PRED) {
			cout << "\tEquals:\t\tAB=" << (gA->equals(gB)?"T":"F") << ", BA=" << (gB->equals(gA)?"T":"F") << endl;
			cout << "\tDisjoint:\tAB=" << (gA->disjoint(gB)?"T":"F") << ", BA=" << (gB->disjoint(gA)?"T":"F") << endl;
			cout << "\tIntersects:\tAB=" << (gA->intersects(gB)?"T":"F") << ", BA=" << (gB->intersects(gA)?"T":"F") << endl;
			cout << "\tTouches:\tAB=" << (gA->touches(gB)?"T":"F") << ", BA=" << (gB->touches(gA)?"T":"F") << endl;
			cout << "\tCrosses:\tAB=" << (gA->crosses(gB)?"T":"F") << ", BA=" << (gB->crosses(gA)?"T":"F") << endl;
			cout << "\tWithin:\t\tAB=" << (gA->within(gB)?"T":"F") << ", BA=" << (gB->within(gA)?"T":"F") << endl;
			cout << "\tContains:\tAB=" << (gA->contains(gB)?"T":"F") << ", BA=" << (gB->contains(gA)?"T":"F") << endl;
			cout << "\tOverlaps:\tAB=" << (gA->overlaps(gB)?"T":"F") << ", BA=" << (gB->overlaps(gA)?"T":"F") << endl;
		}

		xml.OutOfElem();
		xml.OutOfElem();
	}
	cout << "Failed: ";
	cout << failed << endl;
	cout << "Succeeded: ";
	cout << succeeded << endl;
	cout << "End Test";
}
<|endoftext|>


<commit_before>/*!
    \file timestamp.cpp
    \brief Timestamp implementation
    \author Ivan Shynkarenka
    \date 26.01.2016
    \copyright MIT License
*/

#include "time/timestamp.h"

#include "errors/exceptions.h"

#if defined(__APPLE__)
#include <mach/clock.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <math.h>
#include <time.h>
#elif defined(unix) || defined(__unix) || defined(__unix__)
#include <time.h>
#elif defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#endif

namespace CppCommon {

//! @cond INTERNALS
namespace Internals {

#if defined(__APPLE__)

uint32_t CeilLog2(uint32_t x)
{
    uint32_t result = 0;

    --x;
    while (x > 0)
    {
        ++result;
        x >>= 1;
    }

    return result;
}

// This function returns the rational number inside the given interval with
// the smallest denominator (and smallest numerator breaks ties; correctness
// proof neglects floating-point errors).
mach_timebase_info_data_t BestFrac(double a, double b)
{
    if (floor(a) < floor(b))
    {
        mach_timebase_info_data_t rv = { (uint32_t)ceil(a), 1 };
        return rv;
    }

    double m = floor(a);
    mach_timebase_info_data_t next = BestFrac(1 / (b - m), 1 / (a - m));
    mach_timebase_info_data_t rv = { (int)m * next.numer + next.denom, next.numer };
    return rv;
}

// This is just less than the smallest thing we can multiply numer by without
// overflowing. CeilLog2(numer) = 64 - number of leading zeros of numer
uint64_t GetExpressibleSpan(uint32_t numer, uint32_t denom)
{
  uint64_t maxDiffWithoutOverflow = ((uint64_t)1 << (64 - CeilLog2(numer))) - 1;
  return maxDiffWithoutOverflow * numer / denom;
}

// The clock may run up to 0.1% faster or slower than the "exact" tick count.
// However, although the bound on the error is the same as for the pragmatic
// answer, the error is actually minimized over the given accuracy bound.
uint64_t PrepareTimebaseInfo(mach_timebase_info_data_t& tb)
{
    tb.numer = 0;
    tb.denom = 1;

    kern_return_t mtiStatus = mach_timebase_info(&tb);
    if (mtiStatus != KERN_SUCCESS)
        return 0;

    double frac = (double)tb.numer / tb.denom;
    uint64_t spanTarget = 315360000000000000llu;
    if (GetExpressibleSpan(tb.numer, tb.denom) >= spanTarget)
        return 0;

    for (double errorTarget = 1 / 1024.0; errorTarget > 0.000001;)
    {
        mach_timebase_info_data_t newFrac = BestFrac((1 - errorTarget) * frac, (1 + errorTarget) * frac);
        if (GetExpressibleSpan(newFrac.numer, newFrac.denom) < spanTarget)
            break;
        tb = newFrac;
        errorTarget = fabs((double)tb.numer / tb.denom - frac) / frac / 8;
    }

    return mach_absolute_time();
}

#endif

} // namespace Internals
//! @endcond

uint64_t Timestamp::utc()
{
#if defined(__APPLE__)
    clock_serv_t cclock;
    mach_timespec_t mts = { 0 };
    mach_port_t host_port = mach_host_self();
    if (host_port == MACH_PORT_NULL)
        throwex SystemException("Cannot get the current host port!");
    kern_return_t result = host_get_clock_service(host_port, CALENDAR_CLOCK, &cclock);
    if (result != KERN_SUCCESS)
        throwex SystemException("Cannot get the current host clock service!");
    result = clock_get_time(cclock, &mts);
    if (result != KERN_SUCCESS)
        throwex SystemException("Cannot get the current clock time!");
    mach_port_t task_port = mach_task_self();
    if (task_port == MACH_PORT_NULL)
        throwex SystemException("Cannot get the current task port!");
    result = mach_port_deallocate(task_port, cclock);
    if (result != KERN_SUCCESS)
        throwex SystemException("Cannot release the current host clock service!");
    return (mts.tv_sec * 1000 * 1000 * 1000) + mts.tv_nsec;
#elif defined(unix) || defined(__unix) || defined(__unix__)
    struct timespec timestamp;
    if (clock_gettime(CLOCK_REALTIME, &timestamp) != 0)
        throwex SystemException("Cannot get value of CLOCK_REALTIME timer!");
    return (timestamp.tv_sec * 1000 * 1000 * 1000) + timestamp.tv_nsec;
#elif defined(_WIN32) || defined(_WIN64)
    FILETIME ft;
    GetSystemTimePreciseAsFileTime(&ft);

    ULARGE_INTEGER result;
    result.LowPart = ft.dwLowDateTime;
    result.HighPart = ft.dwHighDateTime;
    return (result.QuadPart - 116444736000000000ull) * 100;
#endif
}

uint64_t Timestamp::local()
{
#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
    uint64_t timestamp = utc();

    // Adjust UTC time with local timezone offset
    struct tm local;
    time_t seconds = timestamp / (1000 * 1000 * 1000);
    if (localtime_r(&seconds, &local) != &local)
        throwex SystemException("Cannot convert CLOCK_REALTIME time to local date & time structure!");
    return timestamp + (local.tm_gmtoff * 1000 * 1000 * 1000);
#elif defined(_WIN32) || defined(_WIN64)
    FILETIME ft;
    GetSystemTimePreciseAsFileTime(&ft);

    FILETIME ft_local;
    if (!FileTimeToLocalFileTime(&ft, &ft_local))
        throwex SystemException("Cannot convert UTC file time to local file time structure!");

    ULARGE_INTEGER result;
    result.LowPart = ft_local.dwLowDateTime;
    result.HighPart = ft_local.dwHighDateTime;
    return (result.QuadPart - 116444736000000000ull) * 100;
#endif
}

uint64_t Timestamp::nano()
{
#if defined(__APPLE__)
    static mach_timebase_info_data_t info;
    static uint64_t bias = Internals::PrepareTimebaseInfo(info);
    return (mach_absolute_time() - bias) * info.numer / info.denom;
#elif defined(unix) || defined(__unix) || defined(__unix__)
    struct timespec timestamp = { 0 };
    if (clock_gettime(CLOCK_MONOTONIC, &timestamp) != 0)
        throwex SystemException("Cannot get value of CLOCK_MONOTONIC timer!");
    return (timestamp.tv_sec * 1000 * 1000 * 1000) + timestamp.tv_nsec;
#elif defined(_WIN32) || defined(_WIN64)
    static uint64_t offset = 0;
    static LARGE_INTEGER first = { 0 };
    static LARGE_INTEGER frequency = { 0 };
    static bool initialized = false;
    static bool qpc = true;

    if (!initialized)
    {
        // Calculate timestamp offset
        FILETIME timestamp;
        GetSystemTimePreciseAsFileTime(&timestamp);

        ULARGE_INTEGER result;
        result.LowPart = timestamp.dwLowDateTime;
        result.HighPart = timestamp.dwHighDateTime;

        // Convert 01.01.1601 to 01.01.1970
        result.QuadPart -= 116444736000000000ll;
        offset = result.QuadPart * 100;

        // Setup performance counter
        qpc = QueryPerformanceFrequency(&frequency) && QueryPerformanceCounter(&first);

        initialized = true;
    }

    if (qpc)
    {
        LARGE_INTEGER timestamp = { 0 };
        QueryPerformanceCounter(&timestamp);
        timestamp.QuadPart -= first.QuadPart;
        return offset + ((timestamp.QuadPart * 1000 * 1000 * 1000) / frequency.QuadPart);
    }
    else
        return offset;
#else
    #error Unsupported platform
#endif
}

uint64_t Timestamp::rdts()
{
#if defined(_MSC_VER)
    return __rdtsc();
#elif defined(__i386__)
    uint64_t x;
    __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
    return x;
#elif defined(__x86_64__)
    unsigned hi, lo;
    __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
    return ((uint64_t)lo) | (((uint64_t)hi) << 32);
#endif
}

} // namespace CppCommon
<commit_msg>Test OSX build<commit_after>/*!
    \file timestamp.cpp
    \brief Timestamp implementation
    \author Ivan Shynkarenka
    \date 26.01.2016
    \copyright MIT License
*/

#include "time/timestamp.h"

#include "errors/exceptions.h"

#include <iostream>

#if defined(__APPLE__)
#include <mach/clock.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <math.h>
#include <time.h>
#elif defined(unix) || defined(__unix) || defined(__unix__)
#include <time.h>
#elif defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#endif

namespace CppCommon {

//! @cond INTERNALS
namespace Internals {

#if defined(__APPLE__)

uint32_t CeilLog2(uint32_t x)
{
    uint32_t result = 0;

    --x;
    while (x > 0)
    {
        ++result;
        x >>= 1;
    }

    return result;
}

// This function returns the rational number inside the given interval with
// the smallest denominator (and smallest numerator breaks ties; correctness
// proof neglects floating-point errors).
mach_timebase_info_data_t BestFrac(double a, double b)
{
    if (floor(a) < floor(b))
    {
        mach_timebase_info_data_t rv = { (uint32_t)ceil(a), 1 };
        return rv;
    }

    double m = floor(a);
    mach_timebase_info_data_t next = BestFrac(1 / (b - m), 1 / (a - m));
    mach_timebase_info_data_t rv = { (int)m * next.numer + next.denom, next.numer };
    return rv;
}

// This is just less than the smallest thing we can multiply numer by without
// overflowing. CeilLog2(numer) = 64 - number of leading zeros of numer
uint64_t GetExpressibleSpan(uint32_t numer, uint32_t denom)
{
  uint64_t maxDiffWithoutOverflow = ((uint64_t)1 << (64 - CeilLog2(numer))) - 1;
  return maxDiffWithoutOverflow * numer / denom;
}

// The clock may run up to 0.1% faster or slower than the "exact" tick count.
// However, although the bound on the error is the same as for the pragmatic
// answer, the error is actually minimized over the given accuracy bound.
uint64_t PrepareTimebaseInfo(mach_timebase_info_data_t& tb)
{
    tb.numer = 0;
    tb.denom = 1;

    kern_return_t mtiStatus = mach_timebase_info(&tb);
    if (mtiStatus != KERN_SUCCESS)
        return 0;

    double frac = (double)tb.numer / tb.denom;
    uint64_t spanTarget = 315360000000000000llu;
    if (GetExpressibleSpan(tb.numer, tb.denom) >= spanTarget)
        return 0;

    for (double errorTarget = 1 / 1024.0; errorTarget > 0.000001;)
    {
        mach_timebase_info_data_t newFrac = BestFrac((1 - errorTarget) * frac, (1 + errorTarget) * frac);
        if (GetExpressibleSpan(newFrac.numer, newFrac.denom) < spanTarget)
            break;
        tb = newFrac;
        errorTarget = fabs((double)tb.numer / tb.denom - frac) / frac / 8;
    }

    return mach_absolute_time();
}

#endif

} // namespace Internals
//! @endcond

uint64_t Timestamp::utc()
{
#if defined(__APPLE__)
    clock_serv_t cclock;
    mach_timespec_t mts = { 0 };
    mach_port_t host_port = mach_host_self();
    if (host_port == MACH_PORT_NULL)
        throwex SystemException("Cannot get the current host port!");
    kern_return_t result = host_get_clock_service(host_port, CALENDAR_CLOCK, &cclock);
    if (result != KERN_SUCCESS)
        throwex SystemException("Cannot get the current host clock service!");
    result = clock_get_time(cclock, &mts);
    if (result != KERN_SUCCESS)
        throwex SystemException("Cannot get the current clock time!");
    mach_port_t task_port = mach_task_self();
    if (task_port == MACH_PORT_NULL)
        throwex SystemException("Cannot get the current task port!");
    result = mach_port_deallocate(task_port, cclock);
    if (result != KERN_SUCCESS)
        throwex SystemException("Cannot release the current host clock service!");
    std::cerr << "Sec: " << mts.tv_sec << " - Nano: " << mts.tv_nsec << std::endl;
    return (mts.tv_sec * 1000 * 1000 * 1000) + mts.tv_nsec;
#elif defined(unix) || defined(__unix) || defined(__unix__)
    struct timespec timestamp;
    if (clock_gettime(CLOCK_REALTIME, &timestamp) != 0)
        throwex SystemException("Cannot get value of CLOCK_REALTIME timer!");
    return (timestamp.tv_sec * 1000 * 1000 * 1000) + timestamp.tv_nsec;
#elif defined(_WIN32) || defined(_WIN64)
    FILETIME ft;
    GetSystemTimePreciseAsFileTime(&ft);

    ULARGE_INTEGER result;
    result.LowPart = ft.dwLowDateTime;
    result.HighPart = ft.dwHighDateTime;
    return (result.QuadPart - 116444736000000000ull) * 100;
#endif
}

uint64_t Timestamp::local()
{
#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
    uint64_t timestamp = utc();

    // Adjust UTC time with local timezone offset
    struct tm local;
    time_t seconds = timestamp / (1000 * 1000 * 1000);
    if (localtime_r(&seconds, &local) != &local)
        throwex SystemException("Cannot convert CLOCK_REALTIME time to local date & time structure!");
    return timestamp + (local.tm_gmtoff * 1000 * 1000 * 1000);
#elif defined(_WIN32) || defined(_WIN64)
    FILETIME ft;
    GetSystemTimePreciseAsFileTime(&ft);

    FILETIME ft_local;
    if (!FileTimeToLocalFileTime(&ft, &ft_local))
        throwex SystemException("Cannot convert UTC file time to local file time structure!");

    ULARGE_INTEGER result;
    result.LowPart = ft_local.dwLowDateTime;
    result.HighPart = ft_local.dwHighDateTime;
    return (result.QuadPart - 116444736000000000ull) * 100;
#endif
}

uint64_t Timestamp::nano()
{
#if defined(__APPLE__)
    static mach_timebase_info_data_t info;
    static uint64_t bias = Internals::PrepareTimebaseInfo(info);
    return (mach_absolute_time() - bias) * info.numer / info.denom;
#elif defined(unix) || defined(__unix) || defined(__unix__)
    struct timespec timestamp = { 0 };
    if (clock_gettime(CLOCK_MONOTONIC, &timestamp) != 0)
        throwex SystemException("Cannot get value of CLOCK_MONOTONIC timer!");
    return (timestamp.tv_sec * 1000 * 1000 * 1000) + timestamp.tv_nsec;
#elif defined(_WIN32) || defined(_WIN64)
    static uint64_t offset = 0;
    static LARGE_INTEGER first = { 0 };
    static LARGE_INTEGER frequency = { 0 };
    static bool initialized = false;
    static bool qpc = true;

    if (!initialized)
    {
        // Calculate timestamp offset
        FILETIME timestamp;
        GetSystemTimePreciseAsFileTime(&timestamp);

        ULARGE_INTEGER result;
        result.LowPart = timestamp.dwLowDateTime;
        result.HighPart = timestamp.dwHighDateTime;

        // Convert 01.01.1601 to 01.01.1970
        result.QuadPart -= 116444736000000000ll;
        offset = result.QuadPart * 100;

        // Setup performance counter
        qpc = QueryPerformanceFrequency(&frequency) && QueryPerformanceCounter(&first);

        initialized = true;
    }

    if (qpc)
    {
        LARGE_INTEGER timestamp = { 0 };
        QueryPerformanceCounter(&timestamp);
        timestamp.QuadPart -= first.QuadPart;
        return offset + ((timestamp.QuadPart * 1000 * 1000 * 1000) / frequency.QuadPart);
    }
    else
        return offset;
#else
    #error Unsupported platform
#endif
}

uint64_t Timestamp::rdts()
{
#if defined(_MSC_VER)
    return __rdtsc();
#elif defined(__i386__)
    uint64_t x;
    __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
    return x;
#elif defined(__x86_64__)
    unsigned hi, lo;
    __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
    return ((uint64_t)lo) | (((uint64_t)hi) << 32);
#endif
}

} // namespace CppCommon
<|endoftext|>


<commit_before>#define _HAS_EXCEPTIONS 0
#define _STATIC_CPPLIB

#include "platform_api.h"

#ifdef GAME_PROJECT
#include "game.cpp"
#elif defined(RESOURCE_CONVERTER_PROJECT)
#include "resource_converter.cpp"
#else
#error "You did not specified project type!"
#endif

#include <windows.h>

u64 PlatformGetFileSize(char* path)
{
  HANDLE fileHandle = CreateFile(
    path,
    FILE_READ_ATTRIBUTES,
    FILE_SHARE_READ,
    nullptr,
    OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL,
    0
  );

  if (fileHandle == INVALID_HANDLE_VALUE)
  {
    OutputDebugStringA("Was not able to open a file!\n");
    return 0;
  }

  LARGE_INTEGER size;
  BOOL getFileSizeResult = GetFileSizeEx(
    fileHandle,
    &size
  );

  if (!getFileSizeResult)
  {
    OutputDebugStringA("Was not able to get a file size!\n");
    return 0;
  }

  CloseHandle(fileHandle);
  return u64(size.QuadPart);
}

u32 PlatformLoadFile(char* path, void* memory, u32 memorySize)
{
  HANDLE fileHandle = CreateFile(
    path,
    GENERIC_READ,
    FILE_SHARE_READ,
    nullptr,
    OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL,
    0
  );

  if (fileHandle == INVALID_HANDLE_VALUE)
  {
    OutputDebugStringA("Was not able to open a file!\n");
    return 0;
  }

  DWORD bytesRead;
  BOOL readResult = ReadFile(
    fileHandle,
    memory,
    memorySize,
    &bytesRead,
    nullptr
  );

  if (!readResult)
  {
    OutputDebugStringA("Was not able to read from a file!\n");
    return 0;
  }

  CloseHandle(fileHandle);
  return bytesRead;
}

bool PlatformWriteFile(char* path, void* memory, u32 bytesToWrite)
{
  // TODO: handle directory creation

  HANDLE fileHandle = CreateFile(
    path,
    GENERIC_WRITE,
    0,
    nullptr,
    CREATE_ALWAYS,
    FILE_ATTRIBUTE_NORMAL,
    0
  );

  if (fileHandle == INVALID_HANDLE_VALUE)
  {
    OutputDebugStringA("Was not able to create or owerwrite a file!\n");
    return false;
  }

  DWORD bytesWritten;
  BOOL writeResult = WriteFile(
    fileHandle,
    memory,
    bytesToWrite,
    &bytesWritten,
    nullptr
  );

  if (!writeResult)
  {
    OutputDebugStringA("Was not able to write to a file!\n");
    CloseHandle(fileHandle);
    return false;
  }

  if (bytesToWrite != bytesWritten)
  {
    OutputDebugStringA("Bytes to write was not equal to bytes written!\n");
    CloseHandle(fileHandle);
    return false;
  }

  CloseHandle(fileHandle);
  return true;
}

struct Win32BackBuffer
{
  BITMAPINFO info;
  u32* memory;
};

struct
{
  bool            shouldRun;
  u32             windowWidth;
  u32             windowHeight;

  void*           memory;
  u32             memorySize;
  RenderTarget    renderBuffer;
  Win32BackBuffer backBuffer;

} g_platformData
{
  true,
  640,
  480,
  nullptr,
  0,
  {},
  {}
};

void Win32SetupRenderingBuffers(u32 width, u32 height)
{
  u8* platformMemory = (u8*)g_platformData.memory;

  BITMAPINFO info {};
  info.bmiHeader.biSize = sizeof(info.bmiHeader);
  info.bmiHeader.biWidth = width;
  info.bmiHeader.biHeight = height;
  info.bmiHeader.biPlanes = 1;
  info.bmiHeader.biBitCount = 32;
  info.bmiHeader.biCompression = BI_RGB;

  g_platformData.backBuffer.info = info;
  g_platformData.backBuffer.memory = (u32*)platformMemory;
  platformMemory += width * height * sizeof(u32);

  Texture** texture = &g_platformData.renderBuffer.texture;
  *texture = (Texture*)platformMemory;
  (*texture)->width = width;
  (*texture)->height = height;
  platformMemory += width * height * sizeof(Color32) + sizeof(Texture);

  g_platformData.renderBuffer.zBuffer = (float*)platformMemory;
  platformMemory += width * height * sizeof(float);

  assert(u32(platformMemory - (u8*)g_platformData.memory) <= g_platformData.memorySize);
}

void Win32PresentToWindow(
    HDC windowDC,
    u32 windowWidth,
    u32 windowHeight,
    Win32BackBuffer* backBuffer,
    RenderTarget* renderBuffer)
{
  u32 bufferWidth = renderBuffer->texture->width;
  u32 bufferHeight = renderBuffer->texture->height;

  // TODO: think about just allocating back-buffer here, on the stack
  for (u32 y = 0; y < bufferHeight; ++y)
  {
    for (u32 x = 0; x < bufferWidth; ++x)
    {
      Color32 bufferColor = renderBuffer->texture->GetTexel(x, y);

      backBuffer->memory[y * bufferWidth + x] =
          u32(bufferColor.b) |
          u32(bufferColor.g) << 8 |
          u32(bufferColor.r) << 16;
    }
  }

  StretchDIBits(
    windowDC,
    0,
    0,
    windowWidth,
    windowHeight,
    0,
    0,
    backBuffer->info.bmiHeader.biWidth,
    backBuffer->info.bmiHeader.biHeight,
    backBuffer->memory,
    &backBuffer->info,
    DIB_RGB_COLORS,
    SRCCOPY);
}

LRESULT CALLBACK Win32WindowProc(
  HWND   window,
  UINT   message,
  WPARAM wParam,
  LPARAM lParam)
{
  switch (message)
  {
    case WM_SIZE:
    {
      g_platformData.windowWidth = LOWORD(lParam);
      g_platformData.windowHeight = HIWORD(lParam);
    } break;
    case WM_EXITSIZEMOVE:
    {
      // this is basically free with manual memory management
      Win32SetupRenderingBuffers(g_platformData.windowWidth, g_platformData.windowHeight);
    } break;
    case WM_PAINT:
    {
      PAINTSTRUCT ps;
      HDC windowDC = BeginPaint(window, &ps);

      Win32PresentToWindow(
        windowDC,
        g_platformData.windowWidth,
        g_platformData.windowHeight,
        &g_platformData.backBuffer,
        &g_platformData.renderBuffer);

      EndPaint(window, &ps);
    } break;
    case WM_CLOSE:
    case WM_DESTROY:
    {
      g_platformData.shouldRun = false;
    } break;
    default:
    {
      return DefWindowProc(window, message, wParam, lParam);
    } break;
  }

  return 0;
}

global const u32 g_keyMapSize = 0xA5 + 1;
global u32 g_keyMap[g_keyMapSize] {};

int CALLBACK WinMain(
  HINSTANCE instance,
  HINSTANCE /* prevInstance */,
  char*     /* cmdLine */,
  int       /* cmdShow */)
{
  // damn vs2013 can't do array initialization proper
  {
    g_keyMap[VK_BACK]       = KbKey::Backspace;
    g_keyMap[VK_TAB]        = KbKey::Tab;
    g_keyMap[VK_RETURN]     = KbKey::Return;
    g_keyMap[VK_ESCAPE]     = KbKey::Escape;
    g_keyMap[VK_SPACE]      = KbKey::Space;
    g_keyMap[VK_END]        = KbKey::End;
    g_keyMap[VK_HOME]       = KbKey::Home;
    g_keyMap[VK_LEFT]       = KbKey::Left;
    g_keyMap[VK_UP]         = KbKey::Up;
    g_keyMap[VK_RIGHT]      = KbKey::Right;
    g_keyMap[VK_DOWN]       = KbKey::Down;
    g_keyMap[VK_DELETE]     = KbKey::Delete;
    g_keyMap[0x30]          = KbKey::N_0;
    g_keyMap[0x31]          = KbKey::N_1;
    g_keyMap[0x32]          = KbKey::N_2;
    g_keyMap[0x33]          = KbKey::N_3;
    g_keyMap[0x34]          = KbKey::N_4;
    g_keyMap[0x35]          = KbKey::N_5;
    g_keyMap[0x36]          = KbKey::N_6;
    g_keyMap[0x37]          = KbKey::N_7;
    g_keyMap[0x38]          = KbKey::N_8;
    g_keyMap[0x39]          = KbKey::N_9;
    g_keyMap[0x41]          = KbKey::A;
    g_keyMap[0x42]          = KbKey::B;
    g_keyMap[0x43]          = KbKey::C;
    g_keyMap[0x44]          = KbKey::D;
    g_keyMap[0x45]          = KbKey::E;
    g_keyMap[0x46]          = KbKey::F;
    g_keyMap[0x47]          = KbKey::G;
    g_keyMap[0x48]          = KbKey::H;
    g_keyMap[0x49]          = KbKey::I;
    g_keyMap[0x4A]          = KbKey::J;
    g_keyMap[0x4B]          = KbKey::K;
    g_keyMap[0x4C]          = KbKey::L;
    g_keyMap[0x4D]          = KbKey::M;
    g_keyMap[0x4E]          = KbKey::N;
    g_keyMap[0x4F]          = KbKey::O;
    g_keyMap[0x50]          = KbKey::P;
    g_keyMap[0x51]          = KbKey::Q;
    g_keyMap[0x52]          = KbKey::R;
    g_keyMap[0x53]          = KbKey::S;
    g_keyMap[0x54]          = KbKey::T;
    g_keyMap[0x55]          = KbKey::U;
    g_keyMap[0x56]          = KbKey::V;
    g_keyMap[0x57]          = KbKey::W;
    g_keyMap[0x58]          = KbKey::X;
    g_keyMap[0x59]          = KbKey::Y;
    g_keyMap[0x5A]          = KbKey::Z;
    g_keyMap[VK_F1]         = KbKey::F1;
    g_keyMap[VK_F2]         = KbKey::F2;
    g_keyMap[VK_F3]         = KbKey::F3;
    g_keyMap[VK_F4]         = KbKey::F4;
    g_keyMap[VK_F5]         = KbKey::F5;
    g_keyMap[VK_F6]         = KbKey::F6;
    g_keyMap[VK_F7]         = KbKey::F7;
    g_keyMap[VK_F8]         = KbKey::F8;
    g_keyMap[VK_F9]         = KbKey::F9;
    g_keyMap[VK_F10]        = KbKey::F10;
    g_keyMap[VK_F11]        = KbKey::F11;
    g_keyMap[VK_F12]        = KbKey::F12;
    g_keyMap[VK_LSHIFT]     = KbKey::ShiftL;
    g_keyMap[VK_RSHIFT]     = KbKey::ShiftR;
    g_keyMap[VK_LCONTROL]   = KbKey::ControlL;
    g_keyMap[VK_RCONTROL]   = KbKey::ControlR;
    g_keyMap[VK_LMENU]      = KbKey::AltL;
    g_keyMap[VK_RMENU]      = KbKey::AltR; // 0xA5 Right MENU key
  }

  //*****CREATING A WINDOW*****//
  WNDCLASSEX wndClass {};
  wndClass.cbSize = sizeof(wndClass);
  wndClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
  wndClass.lpfnWndProc = Win32WindowProc;
  wndClass.hInstance = instance;
  wndClass.lpszClassName = "Software Renderer Window Class Name";

  RegisterClassEx(&wndClass);

  HWND window = CreateWindowEx(
    0,
    wndClass.lpszClassName,
    "Software Renderer",
    WS_OVERLAPPEDWINDOW | WS_VISIBLE,
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    g_platformData.windowWidth,
    g_platformData.windowHeight,
    0,
    0,
    instance,
    nullptr
  );

  //*****ALLOCATING MEMORY*****//
  g_platformData.memorySize = 128 * Mb;
  g_platformData.memory = VirtualAlloc(
    nullptr,
    g_platformData.memorySize,
    MEM_RESERVE | MEM_COMMIT,
    PAGE_READWRITE
  );
  assert(g_platformData.memory);

  u32   gameMemorySize = 512 * Mb;
  void* gameMemory = VirtualAlloc(
    nullptr,
    gameMemorySize,
    MEM_RESERVE | MEM_COMMIT,
    PAGE_READWRITE
  );
  assert(gameMemory);

  //*****MISC SETUP*****//
  Win32SetupRenderingBuffers(g_platformData.windowWidth, g_platformData.windowHeight);

  HDC windowDC = GetDC(window);
  MSG message {};
  bool kbState[KbKey::LastKey] {};

  LARGE_INTEGER lastFrameTime;
  LARGE_INTEGER queryFrequency;
  QueryPerformanceCounter(&lastFrameTime);
  QueryPerformanceFrequency(&queryFrequency);

  GameInitialize(gameMemory, gameMemorySize);

  //*****RENDERING LOOP*****//
  while (g_platformData.shouldRun)
  {
    LARGE_INTEGER currentFrameTime;
    QueryPerformanceCounter(&currentFrameTime);
    u64 ticksElapsed = currentFrameTime.QuadPart - lastFrameTime.QuadPart;
    float deltaTime = float(ticksElapsed) / float(queryFrequency.QuadPart);
    lastFrameTime = currentFrameTime;

    // TODO: sort this out
    char windowTitle[256];
    wsprintf(windowTitle, "Software Renderer \t %ums per frame", u32(deltaTime * 1000.0f));
    SetWindowText(window, windowTitle);

    while (PeekMessage(&message, window, 0, 0, PM_REMOVE))
    {
      TranslateMessage(&message);

      if (message.message == WM_KEYDOWN || message.message == WM_KEYUP)
      {
        u32 keyMapIdx = message.wParam;
        if (keyMapIdx < g_keyMapSize)
        {
          u32 kbStateIdx = g_keyMap[keyMapIdx];
          assert(kbStateIdx < KbKey::LastKey);

          kbState[kbStateIdx] = message.message == WM_KEYDOWN;
        }
      }

      DispatchMessage(&message);
    }

    bool gameWantsToContinue = GameUpdate(
        deltaTime,
        gameMemory,
        gameMemorySize,
        &g_platformData.renderBuffer,
        kbState);

    g_platformData.shouldRun &= gameWantsToContinue;

    Win32PresentToWindow(
      windowDC,
      g_platformData.windowWidth,
      g_platformData.windowHeight,
      &g_platformData.backBuffer,
      &g_platformData.renderBuffer);
  }

  return 0;
}
<commit_msg>compiling under msvc 2013<commit_after>#define _HAS_EXCEPTIONS 0
#define _STATIC_CPPLIB

#include "platform_api.h"

#ifdef GAME_PROJECT
#include "game.cpp"
#elif defined(RESOURCE_CONVERTER_PROJECT)
#include "resource_converter.cpp"
#else
#error "You did not specified project type!"
#endif

#include <windows.h>

u64 PlatformGetFileSize(const char* path)
{
  HANDLE fileHandle = CreateFile(
    path,
    FILE_READ_ATTRIBUTES,
    FILE_SHARE_READ,
    nullptr,
    OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL,
    0
  );

  if (fileHandle == INVALID_HANDLE_VALUE)
  {
    OutputDebugStringA("Was not able to open a file!\n");
    return 0;
  }

  LARGE_INTEGER size;
  BOOL getFileSizeResult = GetFileSizeEx(
    fileHandle,
    &size
  );

  if (!getFileSizeResult)
  {
    OutputDebugStringA("Was not able to get a file size!\n");
    return 0;
  }

  CloseHandle(fileHandle);
  return u64(size.QuadPart);
}

u32 PlatformLoadFile(const char* path, void* memory, u32 memorySize)
{
  HANDLE fileHandle = CreateFile(
    path,
    GENERIC_READ,
    FILE_SHARE_READ,
    nullptr,
    OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL,
    0
  );

  if (fileHandle == INVALID_HANDLE_VALUE)
  {
    OutputDebugStringA("Was not able to open a file!\n");
    return 0;
  }

  DWORD bytesRead;
  BOOL readResult = ReadFile(
    fileHandle,
    memory,
    memorySize,
    &bytesRead,
    nullptr
  );

  if (!readResult)
  {
    OutputDebugStringA("Was not able to read from a file!\n");
    return 0;
  }

  CloseHandle(fileHandle);
  return bytesRead;
}

bool PlatformWriteFile(const char* path, void* memory, u32 bytesToWrite)
{
  // TODO: handle directory creation

  HANDLE fileHandle = CreateFile(
    path,
    GENERIC_WRITE,
    0,
    nullptr,
    CREATE_ALWAYS,
    FILE_ATTRIBUTE_NORMAL,
    0
  );

  if (fileHandle == INVALID_HANDLE_VALUE)
  {
    OutputDebugStringA("Was not able to create or owerwrite a file!\n");
    return false;
  }

  DWORD bytesWritten;
  BOOL writeResult = WriteFile(
    fileHandle,
    memory,
    bytesToWrite,
    &bytesWritten,
    nullptr
  );

  if (!writeResult)
  {
    OutputDebugStringA("Was not able to write to a file!\n");
    CloseHandle(fileHandle);
    return false;
  }

  if (bytesToWrite != bytesWritten)
  {
    OutputDebugStringA("Bytes to write was not equal to bytes written!\n");
    CloseHandle(fileHandle);
    return false;
  }

  CloseHandle(fileHandle);
  return true;
}

struct Win32BackBuffer
{
  BITMAPINFO info;
  u32* memory;
};

struct
{
  bool            shouldRun;
  u32             windowWidth;
  u32             windowHeight;

  void*           memory;
  u32             memorySize;
  RenderTarget    renderBuffer;
  Win32BackBuffer backBuffer;

} g_platformData
{
  true,
  640,
  480,
  nullptr,
  0,
  {},
  {}
};

void Win32SetupRenderingBuffers(u32 width, u32 height)
{
  u8* platformMemory = (u8*)g_platformData.memory;

  BITMAPINFO info {};
  info.bmiHeader.biSize = sizeof(info.bmiHeader);
  info.bmiHeader.biWidth = width;
  info.bmiHeader.biHeight = height;
  info.bmiHeader.biPlanes = 1;
  info.bmiHeader.biBitCount = 32;
  info.bmiHeader.biCompression = BI_RGB;

  g_platformData.backBuffer.info = info;
  g_platformData.backBuffer.memory = (u32*)platformMemory;
  platformMemory += width * height * sizeof(u32);

  Texture** texture = &g_platformData.renderBuffer.texture;
  *texture = (Texture*)platformMemory;
  (*texture)->width = width;
  (*texture)->height = height;
  platformMemory += width * height * sizeof(Color32) + sizeof(Texture);

  g_platformData.renderBuffer.zBuffer = (float*)platformMemory;
  platformMemory += width * height * sizeof(float);

  assert(u32(platformMemory - (u8*)g_platformData.memory) <= g_platformData.memorySize);
}

void Win32PresentToWindow(
    HDC windowDC,
    u32 windowWidth,
    u32 windowHeight,
    Win32BackBuffer* backBuffer,
    RenderTarget* renderBuffer)
{
  u32 bufferWidth = renderBuffer->texture->width;
  u32 bufferHeight = renderBuffer->texture->height;

  // TODO: think about just allocating back-buffer here, on the stack
  for (u32 y = 0; y < bufferHeight; ++y)
  {
    for (u32 x = 0; x < bufferWidth; ++x)
    {
      Color32 bufferColor = renderBuffer->texture->GetTexel(x, y);

      backBuffer->memory[y * bufferWidth + x] =
          u32(bufferColor.b) |
          u32(bufferColor.g) << 8 |
          u32(bufferColor.r) << 16;
    }
  }

  StretchDIBits(
    windowDC,
    0,
    0,
    windowWidth,
    windowHeight,
    0,
    0,
    backBuffer->info.bmiHeader.biWidth,
    backBuffer->info.bmiHeader.biHeight,
    backBuffer->memory,
    &backBuffer->info,
    DIB_RGB_COLORS,
    SRCCOPY);
}

LRESULT CALLBACK Win32WindowProc(
  HWND   window,
  UINT   message,
  WPARAM wParam,
  LPARAM lParam)
{
  switch (message)
  {
    case WM_SIZE:
    {
      g_platformData.windowWidth = LOWORD(lParam);
      g_platformData.windowHeight = HIWORD(lParam);
    } break;
    case WM_EXITSIZEMOVE:
    {
      // this is basically free with manual memory management
      Win32SetupRenderingBuffers(g_platformData.windowWidth, g_platformData.windowHeight);
    } break;
    case WM_PAINT:
    {
      PAINTSTRUCT ps;
      HDC windowDC = BeginPaint(window, &ps);

      Win32PresentToWindow(
        windowDC,
        g_platformData.windowWidth,
        g_platformData.windowHeight,
        &g_platformData.backBuffer,
        &g_platformData.renderBuffer);

      EndPaint(window, &ps);
    } break;
    case WM_CLOSE:
    case WM_DESTROY:
    {
      g_platformData.shouldRun = false;
    } break;
    default:
    {
      return DefWindowProc(window, message, wParam, lParam);
    } break;
  }

  return 0;
}

global const u32 g_keyMapSize = 0xA5 + 1;
global u32 g_keyMap[g_keyMapSize] {};

int CALLBACK WinMain(
  HINSTANCE instance,
  HINSTANCE /* prevInstance */,
  char*     /* cmdLine */,
  int       /* cmdShow */)
{
  // damn vs2013 can't do array initialization proper
  {
    g_keyMap[VK_BACK]       = KbKey::Backspace;
    g_keyMap[VK_TAB]        = KbKey::Tab;
    g_keyMap[VK_RETURN]     = KbKey::Return;
    g_keyMap[VK_ESCAPE]     = KbKey::Escape;
    g_keyMap[VK_SPACE]      = KbKey::Space;
    g_keyMap[VK_END]        = KbKey::End;
    g_keyMap[VK_HOME]       = KbKey::Home;
    g_keyMap[VK_LEFT]       = KbKey::Left;
    g_keyMap[VK_UP]         = KbKey::Up;
    g_keyMap[VK_RIGHT]      = KbKey::Right;
    g_keyMap[VK_DOWN]       = KbKey::Down;
    g_keyMap[VK_DELETE]     = KbKey::Delete;
    g_keyMap[0x30]          = KbKey::N_0;
    g_keyMap[0x31]          = KbKey::N_1;
    g_keyMap[0x32]          = KbKey::N_2;
    g_keyMap[0x33]          = KbKey::N_3;
    g_keyMap[0x34]          = KbKey::N_4;
    g_keyMap[0x35]          = KbKey::N_5;
    g_keyMap[0x36]          = KbKey::N_6;
    g_keyMap[0x37]          = KbKey::N_7;
    g_keyMap[0x38]          = KbKey::N_8;
    g_keyMap[0x39]          = KbKey::N_9;
    g_keyMap[0x41]          = KbKey::A;
    g_keyMap[0x42]          = KbKey::B;
    g_keyMap[0x43]          = KbKey::C;
    g_keyMap[0x44]          = KbKey::D;
    g_keyMap[0x45]          = KbKey::E;
    g_keyMap[0x46]          = KbKey::F;
    g_keyMap[0x47]          = KbKey::G;
    g_keyMap[0x48]          = KbKey::H;
    g_keyMap[0x49]          = KbKey::I;
    g_keyMap[0x4A]          = KbKey::J;
    g_keyMap[0x4B]          = KbKey::K;
    g_keyMap[0x4C]          = KbKey::L;
    g_keyMap[0x4D]          = KbKey::M;
    g_keyMap[0x4E]          = KbKey::N;
    g_keyMap[0x4F]          = KbKey::O;
    g_keyMap[0x50]          = KbKey::P;
    g_keyMap[0x51]          = KbKey::Q;
    g_keyMap[0x52]          = KbKey::R;
    g_keyMap[0x53]          = KbKey::S;
    g_keyMap[0x54]          = KbKey::T;
    g_keyMap[0x55]          = KbKey::U;
    g_keyMap[0x56]          = KbKey::V;
    g_keyMap[0x57]          = KbKey::W;
    g_keyMap[0x58]          = KbKey::X;
    g_keyMap[0x59]          = KbKey::Y;
    g_keyMap[0x5A]          = KbKey::Z;
    g_keyMap[VK_F1]         = KbKey::F1;
    g_keyMap[VK_F2]         = KbKey::F2;
    g_keyMap[VK_F3]         = KbKey::F3;
    g_keyMap[VK_F4]         = KbKey::F4;
    g_keyMap[VK_F5]         = KbKey::F5;
    g_keyMap[VK_F6]         = KbKey::F6;
    g_keyMap[VK_F7]         = KbKey::F7;
    g_keyMap[VK_F8]         = KbKey::F8;
    g_keyMap[VK_F9]         = KbKey::F9;
    g_keyMap[VK_F10]        = KbKey::F10;
    g_keyMap[VK_F11]        = KbKey::F11;
    g_keyMap[VK_F12]        = KbKey::F12;
    g_keyMap[VK_LSHIFT]     = KbKey::ShiftL;
    g_keyMap[VK_RSHIFT]     = KbKey::ShiftR;
    g_keyMap[VK_LCONTROL]   = KbKey::ControlL;
    g_keyMap[VK_RCONTROL]   = KbKey::ControlR;
    g_keyMap[VK_LMENU]      = KbKey::AltL;
    g_keyMap[VK_RMENU]      = KbKey::AltR; // 0xA5 Right MENU key
  }

  //*****CREATING A WINDOW*****//
  WNDCLASSEX wndClass {};
  wndClass.cbSize = sizeof(wndClass);
  wndClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
  wndClass.lpfnWndProc = Win32WindowProc;
  wndClass.hInstance = instance;
  wndClass.lpszClassName = "Software Renderer Window Class Name";

  RegisterClassEx(&wndClass);

  HWND window = CreateWindowEx(
    0,
    wndClass.lpszClassName,
    "Software Renderer",
    WS_OVERLAPPEDWINDOW | WS_VISIBLE,
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    g_platformData.windowWidth,
    g_platformData.windowHeight,
    0,
    0,
    instance,
    nullptr
  );

  //*****ALLOCATING MEMORY*****//
  g_platformData.memorySize = 128 * Mb;
  g_platformData.memory = VirtualAlloc(
    nullptr,
    g_platformData.memorySize,
    MEM_RESERVE | MEM_COMMIT,
    PAGE_READWRITE
  );
  assert(g_platformData.memory);

  u32   gameMemorySize = 512 * Mb;
  void* gameMemory = VirtualAlloc(
    nullptr,
    gameMemorySize,
    MEM_RESERVE | MEM_COMMIT,
    PAGE_READWRITE
  );
  assert(gameMemory);

  //*****MISC SETUP*****//
  Win32SetupRenderingBuffers(g_platformData.windowWidth, g_platformData.windowHeight);

  HDC windowDC = GetDC(window);
  MSG message {};
  bool kbState[KbKey::LastKey] {};

  LARGE_INTEGER lastFrameTime;
  LARGE_INTEGER queryFrequency;
  QueryPerformanceCounter(&lastFrameTime);
  QueryPerformanceFrequency(&queryFrequency);

  GameInitialize(gameMemory, gameMemorySize);

  //*****RENDERING LOOP*****//
  while (g_platformData.shouldRun)
  {
    LARGE_INTEGER currentFrameTime;
    QueryPerformanceCounter(&currentFrameTime);
    u64 ticksElapsed = currentFrameTime.QuadPart - lastFrameTime.QuadPart;
    float deltaTime = float(ticksElapsed) / float(queryFrequency.QuadPart);
    lastFrameTime = currentFrameTime;

    // TODO: sort this out
    char windowTitle[256];
    wsprintf(windowTitle, "Software Renderer \t %ums per frame", u32(deltaTime * 1000.0f));
    SetWindowText(window, windowTitle);

    while (PeekMessage(&message, window, 0, 0, PM_REMOVE))
    {
      TranslateMessage(&message);

      if (message.message == WM_KEYDOWN || message.message == WM_KEYUP)
      {
        u32 keyMapIdx = message.wParam;
        if (keyMapIdx < g_keyMapSize)
        {
          u32 kbStateIdx = g_keyMap[keyMapIdx];
          assert(kbStateIdx < KbKey::LastKey);

          kbState[kbStateIdx] = message.message == WM_KEYDOWN;
        }
      }

      DispatchMessage(&message);
    }

    bool gameWantsToContinue = GameUpdate(
        deltaTime,
        gameMemory,
        gameMemorySize,
        &g_platformData.renderBuffer,
        kbState);

    g_platformData.shouldRun &= gameWantsToContinue;

    Win32PresentToWindow(
      windowDC,
      g_platformData.windowWidth,
      g_platformData.windowHeight,
      &g_platformData.backBuffer,
      &g_platformData.renderBuffer);
  }

  return 0;
}
<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_ERR_ELEMENTWISE_ERROR_CHECKER_HPP
#define STAN_MATH_PRIM_ERR_ELEMENTWISE_ERROR_CHECKER_HPP

#include <stan/math/prim/err/throw_domain_error.hpp>
#include <stan/math/prim/fun/get.hpp>
#include <stan/math/prim/fun/size.hpp>
#include <stan/math/prim/fun/value_of_rec.hpp>
#include <stan/math/prim/meta/is_eigen.hpp>
#include <stan/math/prim/meta/is_var_matrix.hpp>
#include <stan/math/prim/meta/is_vector.hpp>
#include <stan/math/prim/meta/is_stan_scalar.hpp>
#include <string>
#include <sstream>
#include <vector>

namespace stan {
namespace math {
namespace internal {

/** Apply an error check to a container, signal failure with `false`.
 * Apply a predicate like is_positive to the double underlying every scalar in a
 * container, producing true if the predicate holds everywhere and `false` if it
 * fails anywhere.
 * @tparam F type of predicate
 */
template <typename F>
class Iser {
  const F& is_good;

 public:
  /**
   * @param is_good predicate to check, must accept doubles and produce bools
   */
  explicit Iser(const F& is_good) : is_good(is_good) {}

  /**
   * Check the scalar.
   * @tparam T type of scalar
   * @param x scalar
   * @return `false` if the scalar fails the error check
   */
  template <typename T, typename = require_stan_scalar_t<T>>
  bool is(const T& x) {
    return is_good(value_of_rec(x));
  }

  /**
   * Check all the scalars inside the container.
   * @tparam T type of scalar
   * @param x container
   * @return `false` if any of the scalars fail the error check
   */
  template <typename T, typename = require_not_stan_scalar_t<T>,
            typename = void>
  bool is(const T& x) {
    for (size_t i = 0; i < stan::math::size(x); ++i)
      if (!is(stan::get(x, i)))
        return false;
    return true;
  }
};

/**
 * No-op.
 */
inline void pipe_in(std::stringstream& ss) {}
/**
 * Pipes given arguments into a stringstream.
 *
 * @tparam Arg0 type of the first argument
 * @tparam Args types of remaining arguments
 * @param ss stringstream to pipe arguments in
 * @param arg0 the first argument
 * @param args remining arguments
 */
template <typename Arg0, typename... Args>
inline void pipe_in(std::stringstream& ss, Arg0 arg0, const Args... args) {
  ss << arg0;
  pipe_in(ss, args...);
}

/**
 * Throws domain error with concatenation of arguments for the error message.
 * @tparam Args types of arguments
 * @param args arguments
 */
template <typename... Args>
void elementwise_throw_domain_error(const Args... args) {
  std::stringstream ss;
  pipe_in(ss, args...);
  throw std::domain_error(ss.str());
}

}  // namespace internal

/**
 * Check that the predicate holds for the value of `x`, working elementwise on
 * containers. If `x` is a scalar, check the double underlying the scalar. If
 * `x` is a container, check each element inside `x`, recursively. This overload
 * works on scalars.
 * @tparam F type of predicate
 * @tparam T type of `x`
 * @tparam Indexings types of `indexings`
 * @param is_good predicate to check, must accept doubles and produce bools
 * @param function function name (for error messages)
 * @param name variable name (for error messages)
 * @param x variable to check, can be a scalar, a container of scalars, a
 * container of containers of scalars, etc
 * @param must_be message describing what the value should be
 * @param indexings any additional indexing to print. Intended for internal use
 * in `elementwise_check` only.
 * @throws `std::domain_error` if `is_good` returns `false` for the value
 * of any element in `x`
 */
template <typename F, typename T, typename... Indexings,
          require_stan_scalar_t<T>* = nullptr>
inline void elementwise_check(const F& is_good, const char* function,
                              const char* name, const T& x, const char* must_be,
                              const Indexings&... indexings) {
  if (unlikely(!is_good(value_of_rec(x)))) {
    internal::elementwise_throw_domain_error(function, ": ", name, indexings...,
                                             " is ", x, ", but must be ",
                                             must_be, "!");
  }
}
/**
 * Check that the predicate holds for the value of `x`, working elementwise on
 * containers. If `x` is a scalar, check the double underlying the scalar. If
 * `x` is a container, check each element inside `x`, recursively. This overload
 * works on Eigen types that support linear indexing.
 * @tparam F type of predicate
 * @tparam T type of `x`
 * @tparam Indexings types of `indexings`
 * @param is_good predicate to check, must accept doubles and produce bools
 * @param function function name (for error messages)
 * @param name variable name (for error messages)
 * @param x variable to check, can be a scalar, a container of scalars, a
 * container of containers of scalars, etc
 * @param must_be message describing what the value should be
 * @param indexings any additional indexing to print. Intended for internal use
 * in `elementwise_check` only.
 * @throws `std::domain_error` if `is_good` returns `false` for the value
 * of any element in `x`
 */
template <typename F, typename T, typename... Indexings,
          require_eigen_t<T>* = nullptr,
          std::enable_if_t<static_cast<bool>(Eigen::internal::traits<T>::Flags&(
              Eigen::LinearAccessBit | Eigen::DirectAccessBit))>* = nullptr>
inline void elementwise_check(const F& is_good, const char* function,
                              const char* name, const T& x, const char* must_be,
                              const Indexings&... indexings) {
  for (size_t i = 0; i < x.size(); i++) {
    auto scal = value_of_rec(x.coeff(i));
    if (unlikely(!is_good(scal))) {
      if (is_eigen_vector<T>::value) {
        internal::elementwise_throw_domain_error(
            function, ": ", name, indexings..., "[", i + error_index::value,
            "] is ", scal, ", but must be ", must_be, "!");
      } else if (Eigen::internal::traits<T>::Flags & Eigen::RowMajorBit) {
        internal::elementwise_throw_domain_error(
            function, ": ", name, indexings..., "[",
            i / x.cols() + error_index::value, ", ",
            i % x.cols() + error_index::value, "] is ", scal, ", but must be ",
            must_be, "!");
      } else {
        internal::elementwise_throw_domain_error(
            function, ": ", name, indexings..., "[",
            i % x.rows() + error_index::value, ", ",
            i / x.rows() + error_index::value, "] is ", scal, ", but must be ",
            must_be, "!");
      }
    }
  }
}
/**
 * Check that the predicate holds for the value of `x`, working elementwise on
 * containers. If `x` is a scalar, check the double underlying the scalar. If
 * `x` is a container, check each element inside `x`, recursively. This overload
 * works on col-major Eigen types that do not support linear indexing.
 * @tparam F type of predicate
 * @tparam T type of `x`
 * @tparam Indexings types of `indexings`
 * @param is_good predicate to check, must accept doubles and produce bools
 * @param function function name (for error messages)
 * @param name variable name (for error messages)
 * @param x variable to check, can be a scalar, a container of scalars, a
 * container of containers of scalars, etc
 * @param must_be message describing what the value should be
 * @param indexings any additional indexing to print. Intended for internal use
 * in `elementwise_check` only.
 * @throws `std::domain_error` if `is_good` returns `false` for the value
 * of any element in `x`
 */
template <
    typename F, typename T, typename... Indexings,
    require_eigen_t<T>* = nullptr,
    std::enable_if_t<!(Eigen::internal::traits<T>::Flags
                       & (Eigen::LinearAccessBit | Eigen::DirectAccessBit))
                     && !(Eigen::internal::traits<T>::Flags
                          & Eigen::RowMajorBit)>* = nullptr>
inline void elementwise_check(const F& is_good, const char* function,
                              const char* name, const T& x, const char* must_be,
                              const Indexings&... indexings) {
  for (size_t i = 0; i < x.rows(); i++) {
    for (size_t j = 0; j < x.cols(); j++) {
      auto scal = value_of_rec(x.coeff(i, j));
      if (unlikely(!is_good(scal))) {
        internal::elementwise_throw_domain_error(
            function, ": ", name, indexings..., "[", i + error_index::value,
            ", ", j + error_index::value, "] is ", scal, ", but must be ",
            must_be, "!");
      }
    }
  }
}
/**
 * Check that the predicate holds for the value of `x`, working elementwise on
 * containers. If `x` is a scalar, check the double underlying the scalar. If
 * `x` is a container, check each element inside `x`, recursively. This overload
 * works on row-major Eigen types that do not support linear indexing.
 * @tparam F type of predicate
 * @tparam T type of `x`
 * @tparam Indexings types of `indexings`
 * @param is_good predicate to check, must accept doubles and produce bools
 * @param function function name (for error messages)
 * @param name variable name (for error messages)
 * @param x variable to check, can be a scalar, a container of scalars, a
 * container of containers of scalars, etc
 * @param must_be message describing what the value should be
 * @param indexings any additional indexing to print. Intended for internal use
 * in `elementwise_check` only.
 * @throws `std::domain_error` if `is_good` returns `false` for the value
 * of any element in `x`
 */
template <
    typename F, typename T, typename... Indexings,
    require_eigen_t<T>* = nullptr,
    std::enable_if_t<!(Eigen::internal::traits<T>::Flags
                       & (Eigen::LinearAccessBit | Eigen::DirectAccessBit))
                     && static_cast<bool>(Eigen::internal::traits<T>::Flags
                                          & Eigen::RowMajorBit)>* = nullptr>
inline void elementwise_check(const F& is_good, const char* function,
                              const char* name, const T& x, const char* must_be,
                              const Indexings&... indexings) {
  for (size_t j = 0; j < x.cols(); j++) {
    for (size_t i = 0; i < x.rows(); i++) {
      auto scal = value_of_rec(x.coeff(i, j));
      if (unlikely(!is_good(scal))) {
        internal::elementwise_throw_domain_error(
            function, ": ", name, indexings..., "[", i + error_index::value,
            ", ", j + error_index::value, "] is ", scal, ", but must be ",
            must_be, "!");
      }
    }
  }
}
/**
 * Check that the predicate holds for the value of `x`, working elementwise on
 * containers. If `x` is a scalar, check the double underlying the scalar. If
 * `x` is a container, check each element inside `x`, recursively. This overload
 * works on `std::vector`s.
 * @tparam F type of predicate
 * @tparam T type of `x`
 * @tparam Indexings types of `indexings`
 * @param is_good predicate to check, must accept doubles and produce bools
 * @param function function name (for error messages)
 * @param name variable name (for error messages)
 * @param x variable to check, can be a scalar, a container of scalars, a
 * container of containers of scalars, etc
 * @param must_be message describing what the value should be
 * @param indexings any additional indexing to print. Intended for internal use
 * in `elementwise_check` only.
 * @throws `std::domain_error` if `is_good` returns `false` for the value
 * of any element in `x`
 */
template <typename F, typename T, typename... Indexings,
          require_std_vector_t<T>* = nullptr>
inline void elementwise_check(const F& is_good, const char* function,
                              const char* name, const T& x, const char* must_be,
                              const Indexings&... indexings) {
  for (size_t j = 0; j < x.size(); j++) {
    elementwise_check(is_good, function, name, x[j], must_be, indexings..., "[",
                      j + error_index::value, "]");
  }
}
/**
 * Check that the predicate holds for the value of `x`, working elementwise on
 * containers. If `x` is a scalar, check the double underlying the scalar. If
 * `x` is a container, check each element inside `x`, recursively. This overload
 * works on `var`s containing Eigen types.
 * @tparam F type of predicate
 * @tparam T type of `x`
 * @tparam Indexings types of `indexings`
 * @param is_good predicate to check, must accept doubles and produce bools
 * @param function function name (for error messages)
 * @param name variable name (for error messages)
 * @param x variable to check, can be a scalar, a container of scalars, a
 * container of containers of scalars, etc
 * @param must_be message describing what the value should be
 * @param indexings any additional indexing to print. Intended for internal use
 * in `elementwise_check` only.
 * @throws `std::domain_error` if `is_good` returns `false` for the value
 * of any element in `x`
 */
template <typename F, typename T, typename... Indexings,
          require_var_matrix_t<T>* = nullptr>
inline void elementwise_check(const F& is_good, const char* function,
                              const char* name, const T& x, const char* must_be,
                              const Indexings&... indexings) {
  elementwise_check(is_good, function, name, x.val(), must_be, indexings...);
}

/**
 * Check that the predicate holds for the value of `x`, working elementwise on
 * containers. If `x` is a scalar, check the double underlying the scalar. If
 * `x` is a container, check each element inside `x`, recursively.
 * @tparam F type of predicate
 * @tparam T type of `x`
 * @param is_good predicate to check, must accept doubles and produce bools
 * @param x variable to check, can be a scalar, a container of scalars, a
 * container of containers of scalars, etc
 * @return `false` if any of the scalars fail the error check
 */
template <typename F, typename T>
inline bool elementwise_is(const F& is_good, const T& x) {
  return internal::Iser<F>{is_good}.is(x);
}

}  // namespace math
}  // namespace stan
#endif
<commit_msg>applied Ben's suggestion<commit_after>#ifndef STAN_MATH_PRIM_ERR_ELEMENTWISE_ERROR_CHECKER_HPP
#define STAN_MATH_PRIM_ERR_ELEMENTWISE_ERROR_CHECKER_HPP

#include <stan/math/prim/err/throw_domain_error.hpp>
#include <stan/math/prim/fun/get.hpp>
#include <stan/math/prim/fun/size.hpp>
#include <stan/math/prim/fun/value_of_rec.hpp>
#include <stan/math/prim/meta/is_eigen.hpp>
#include <stan/math/prim/meta/is_var_matrix.hpp>
#include <stan/math/prim/meta/is_vector.hpp>
#include <stan/math/prim/meta/is_stan_scalar.hpp>
#include <string>
#include <sstream>
#include <vector>

namespace stan {
namespace math {
namespace internal {

/** Apply an error check to a container, signal failure with `false`.
 * Apply a predicate like is_positive to the double underlying every scalar in a
 * container, producing true if the predicate holds everywhere and `false` if it
 * fails anywhere.
 * @tparam F type of predicate
 */
template <typename F>
class Iser {
  const F& is_good;

 public:
  /**
   * @param is_good predicate to check, must accept doubles and produce bools
   */
  explicit Iser(const F& is_good) : is_good(is_good) {}

  /**
   * Check the scalar.
   * @tparam T type of scalar
   * @param x scalar
   * @return `false` if the scalar fails the error check
   */
  template <typename T, typename = require_stan_scalar_t<T>>
  bool is(const T& x) {
    return is_good(value_of_rec(x));
  }

  /**
   * Check all the scalars inside the container.
   * @tparam T type of scalar
   * @param x container
   * @return `false` if any of the scalars fail the error check
   */
  template <typename T, typename = require_not_stan_scalar_t<T>,
            typename = void>
  bool is(const T& x) {
    for (size_t i = 0; i < stan::math::size(x); ++i)
      if (!is(stan::get(x, i)))
        return false;
    return true;
  }
};

/**
 * No-op.
 */
inline void pipe_in(std::stringstream& ss) {}
/**
 * Pipes given arguments into a stringstream.
 *
 * @tparam Arg0 type of the first argument
 * @tparam Args types of remaining arguments
 * @param ss stringstream to pipe arguments in
 * @param arg0 the first argument
 * @param args remining arguments
 */
template <typename Arg0, typename... Args>
inline void pipe_in(std::stringstream& ss, Arg0 arg0, const Args... args) {
  ss << arg0;
  pipe_in(ss, args...);
}

/**
 * Throws domain error with concatenation of arguments for the error message.
 * @tparam Args types of arguments
 * @param args arguments
 */
template <typename... Args>
void elementwise_throw_domain_error(const Args... args) {
  std::stringstream ss;
  pipe_in(ss, args...);
  throw std::domain_error(ss.str());
}

}  // namespace internal

/**
 * Check that the predicate holds for the value of `x`. This overload
 * works on scalars.
 *
 * @tparam F type of predicate
 * @tparam T type of `x`
 * @tparam Indexings types of `indexings`
 * @param is_good predicate to check, must accept doubles and produce bools
 * @param function function name (for error messages)
 * @param name variable name (for error messages)
 * @param x variable to check, can be a scalar, a container of scalars, a
 * container of containers of scalars, etc
 * @param must_be message describing what the value should be
 * @param indexings any additional indexing to print. Intended for internal use
 * in `elementwise_check` only.
 * @throws `std::domain_error` if `is_good` returns `false` for the value
 * of any element in `x`
 */
template <typename F, typename T, typename... Indexings,
          require_stan_scalar_t<T>* = nullptr>
inline void elementwise_check(const F& is_good, const char* function,
                              const char* name, const T& x, const char* must_be,
                              const Indexings&... indexings) {
  if (unlikely(!is_good(value_of_rec(x)))) {
    internal::elementwise_throw_domain_error(function, ": ", name, indexings...,
                                             " is ", x, ", but must be ",
                                             must_be, "!");
  }
}
/**
 * Check that the predicate holds for all elements of the value of `x`. This overload
 * works on Eigen types that support linear indexing.
 *
 * @tparam F type of predicate
 * @tparam T type of `x`
 * @tparam Indexings types of `indexings`
 * @param is_good predicate to check, must accept doubles and produce bools
 * @param function function name (for error messages)
 * @param name variable name (for error messages)
 * @param x variable to check, can be a scalar, a container of scalars, a
 * container of containers of scalars, etc
 * @param must_be message describing what the value should be
 * @param indexings any additional indexing to print. Intended for internal use
 * in `elementwise_check` only.
 * @throws `std::domain_error` if `is_good` returns `false` for the value
 * of any element in `x`
 */
template <typename F, typename T, typename... Indexings,
          require_eigen_t<T>* = nullptr,
          std::enable_if_t<static_cast<bool>(Eigen::internal::traits<T>::Flags&(
              Eigen::LinearAccessBit | Eigen::DirectAccessBit))>* = nullptr>
inline void elementwise_check(const F& is_good, const char* function,
                              const char* name, const T& x, const char* must_be,
                              const Indexings&... indexings) {
  for (size_t i = 0; i < x.size(); i++) {
    auto scal = value_of_rec(x.coeff(i));
    if (unlikely(!is_good(scal))) {
      if (is_eigen_vector<T>::value) {
        internal::elementwise_throw_domain_error(
            function, ": ", name, indexings..., "[", i + error_index::value,
            "] is ", scal, ", but must be ", must_be, "!");
      } else if (Eigen::internal::traits<T>::Flags & Eigen::RowMajorBit) {
        internal::elementwise_throw_domain_error(
            function, ": ", name, indexings..., "[",
            i / x.cols() + error_index::value, ", ",
            i % x.cols() + error_index::value, "] is ", scal, ", but must be ",
            must_be, "!");
      } else {
        internal::elementwise_throw_domain_error(
            function, ": ", name, indexings..., "[",
            i % x.rows() + error_index::value, ", ",
            i / x.rows() + error_index::value, "] is ", scal, ", but must be ",
            must_be, "!");
      }
    }
  }
}

/**
 * Check that the predicate holds for all elements of the value of `x`. This overload
 * works on col-major Eigen types that do not support linear indexing.
 *
 * @tparam F type of predicate
 * @tparam T type of `x`
 * @tparam Indexings types of `indexings`
 * @param is_good predicate to check, must accept doubles and produce bools
 * @param function function name (for error messages)
 * @param name variable name (for error messages)
 * @param x variable to check, can be a scalar, a container of scalars, a
 * container of containers of scalars, etc
 * @param must_be message describing what the value should be
 * @param indexings any additional indexing to print. Intended for internal use
 * in `elementwise_check` only.
 * @throws `std::domain_error` if `is_good` returns `false` for the value
 * of any element in `x`
 */
template <
    typename F, typename T, typename... Indexings,
    require_eigen_t<T>* = nullptr,
    std::enable_if_t<!(Eigen::internal::traits<T>::Flags
                       & (Eigen::LinearAccessBit | Eigen::DirectAccessBit))
                     && !(Eigen::internal::traits<T>::Flags
                          & Eigen::RowMajorBit)>* = nullptr>
inline void elementwise_check(const F& is_good, const char* function,
                              const char* name, const T& x, const char* must_be,
                              const Indexings&... indexings) {
  for (size_t i = 0; i < x.rows(); i++) {
    for (size_t j = 0; j < x.cols(); j++) {
      auto scal = value_of_rec(x.coeff(i, j));
      if (unlikely(!is_good(scal))) {
        internal::elementwise_throw_domain_error(
            function, ": ", name, indexings..., "[", i + error_index::value,
            ", ", j + error_index::value, "] is ", scal, ", but must be ",
            must_be, "!");
      }
    }
  }
}

/**
 * Check that the predicate holds for all the elements of the value of `x`. This overload
 * works on row-major Eigen types that do not support linear indexing.
 *
 * @tparam F type of predicate
 * @tparam T type of `x`
 * @tparam Indexings types of `indexings`
 * @param is_good predicate to check, must accept doubles and produce bools
 * @param function function name (for error messages)
 * @param name variable name (for error messages)
 * @param x variable to check, can be a scalar, a container of scalars, a
 * container of containers of scalars, etc
 * @param must_be message describing what the value should be
 * @param indexings any additional indexing to print. Intended for internal use
 * in `elementwise_check` only.
 * @throws `std::domain_error` if `is_good` returns `false` for the value
 * of any element in `x`
 */
template <
    typename F, typename T, typename... Indexings,
    require_eigen_t<T>* = nullptr,
    std::enable_if_t<!(Eigen::internal::traits<T>::Flags
                       & (Eigen::LinearAccessBit | Eigen::DirectAccessBit))
                     && static_cast<bool>(Eigen::internal::traits<T>::Flags
                                          & Eigen::RowMajorBit)>* = nullptr>
inline void elementwise_check(const F& is_good, const char* function,
                              const char* name, const T& x, const char* must_be,
                              const Indexings&... indexings) {
  for (size_t j = 0; j < x.cols(); j++) {
    for (size_t i = 0; i < x.rows(); i++) {
      auto scal = value_of_rec(x.coeff(i, j));
      if (unlikely(!is_good(scal))) {
        internal::elementwise_throw_domain_error(
            function, ": ", name, indexings..., "[", i + error_index::value,
            ", ", j + error_index::value, "] is ", scal, ", but must be ",
            must_be, "!");
      }
    }
  }
}

/**
 * Check that the predicate holds for all elements of the value of `x`. This overload
 * works on `std::vector` types.
 *
 * @tparam F type of predicate
 * @tparam T type of `x`
 * @tparam Indexings types of `indexings`
 * @param is_good predicate to check, must accept doubles and produce bools
 * @param function function name (for error messages)
 * @param name variable name (for error messages)
 * @param x variable to check, can be a scalar, a container of scalars, a
 * container of containers of scalars, etc
 * @param must_be message describing what the value should be
 * @param indexings any additional indexing to print. Intended for internal use
 * in `elementwise_check` only.
 * @throws `std::domain_error` if `is_good` returns `false` for the value
 * of any element in `x`
 */
template <typename F, typename T, typename... Indexings,
          require_std_vector_t<T>* = nullptr>
inline void elementwise_check(const F& is_good, const char* function,
                              const char* name, const T& x, const char* must_be,
                              const Indexings&... indexings) {
  for (size_t j = 0; j < x.size(); j++) {
    elementwise_check(is_good, function, name, x[j], must_be, indexings..., "[",
                      j + error_index::value, "]");
  }
}

/**
 * Check that the predicate holds for all elements of the value of `x`. This overload
 * works on `var`s containing Eigen types.
 *
 * @tparam F type of predicate
 * @tparam T type of `x`
 * @tparam Indexings types of `indexings`
 * @param is_good predicate to check, must accept doubles and produce bools
 * @param function function name (for error messages)
 * @param name variable name (for error messages)
 * @param x variable to check, can be a scalar, a container of scalars, a
 * container of containers of scalars, etc
 * @param must_be message describing what the value should be
 * @param indexings any additional indexing to print. Intended for internal use
 * in `elementwise_check` only.
 * @throws `std::domain_error` if `is_good` returns `false` for the value
 * of any element in `x`
 */
template <typename F, typename T, typename... Indexings,
          require_var_matrix_t<T>* = nullptr>
inline void elementwise_check(const F& is_good, const char* function,
                              const char* name, const T& x, const char* must_be,
                              const Indexings&... indexings) {
  elementwise_check(is_good, function, name, x.val(), must_be, indexings...);
}

/**
 * Check that the predicate holds for the value of `x`, working elementwise on
 * containers. If `x` is a scalar, check the double underlying the scalar. If
 * `x` is a container, check each element inside `x`, recursively.
 *
 * @tparam F type of predicate
 * @tparam T type of `x`
 * @param is_good predicate to check, must accept doubles and produce bools
 * @param x variable to check, can be a scalar, a container of scalars, a
 * container of containers of scalars, etc
 * @return `false` if any of the scalars fail the error check
 */
template <typename F, typename T>
inline bool elementwise_is(const F& is_good, const T& x) {
  return internal::Iser<F>{is_good}.is(x);
}

}  // namespace math
}  // namespace stan
#endif
<|endoftext|>


<commit_before>#include <iostream>
#include <unordered_set>
#include "stream.hpp"
#include "chunker.hpp"

namespace vg {

using namespace std;
using namespace xg;

PathChunker::PathChunker(xg::XG* xindex) : xg(xindex) {

}

PathChunker::~PathChunker() {

}

void PathChunker::extract_subgraph(const Region& region, int context, int length,
                                   bool forward_only, VG& subgraph, Region& out_region) {

    // extract our path range into the graph
    Graph g;
    xg->for_path_range(region.seq, region.start, region.end, [&](int64_t id, bool) {
            *g.add_node() = xg->node(id);
        });

    // expand the context and get path information
    // if forward_only true, then we only go forward.
    xg->expand_context(g, context, true, true, true, !forward_only);
    if (length) {
        xg->expand_context(g, context, true, false, true, !forward_only);
    }

    // build the vg of the subgraph
    subgraph.extend(g);
    subgraph.remove_orphan_edges();

    // get our range endpoints before context expansion
    list<mapping_t>& mappings = subgraph.paths.get_path(region.seq);
    size_t mappings_size = mappings.size();
    int64_t input_start_node = xg->node_at_path_position(region.seq, region.start);
    vector<size_t> first_positions = xg->position_in_path(input_start_node, region.seq);
    int64_t input_end_node = xg->node_at_path_position(region.seq, region.end);
    vector<size_t> last_positions = xg->position_in_path(input_end_node, region.seq);

    // the distance between then and the nodes in our input range
    size_t left_padding = 0;
    size_t right_padding = 0;
    // do we need to rewrite back to our graph?
    bool rewrite_paths = false;

    // Endpoints not in cycles: we can get our output region directly from xg lookups
    if (first_positions.size() == 1  && last_positions.size() == 1) {
        // start and end of our expanded chunk
        auto start_it = mappings.begin();
        auto end_it = --mappings.end();

        // find our input range in the expanded path. we know these nodes only appear once.
        for (; start_it != mappings.end() && start_it->node_id() != input_start_node; ++start_it);
        for (; end_it != mappings.begin() && end_it->node_id() != input_end_node; --end_it);

        // walk back our start point as we can without rank discontinuities. doesn't matter
        // if we encounter cycles here, because we keep a running path length
        auto cur_it = start_it;
        auto prev_it = cur_it;
        if (prev_it != mappings.begin()) {
            for (; prev_it != mappings.begin(); --prev_it) {
                cur_it = prev_it;
                --cur_it;
                if ((prev_it->rank > 0 || cur_it->rank > 0) && cur_it->rank + 1 != prev_it->rank) {
                    break;
                }
                left_padding += cur_it->length;
            }
        }
        start_it = prev_it;
        // walk forward the end point
        cur_it = end_it;
        prev_it = cur_it;
        for (++cur_it; cur_it != mappings.end(); ++prev_it, ++cur_it) {
            if ((prev_it->rank > 0 || cur_it->rank > 0) && prev_it->rank + 1 != cur_it->rank) {
                break;
            }
            right_padding += cur_it->length;
        }
        end_it = prev_it;

        rewrite_paths = start_it != mappings.begin() || end_it != --mappings.end();

        // cut out nodes before and after discontinuity
        mappings.erase(mappings.begin(), start_it);
        mappings.erase(++end_it, mappings.end());
    }
    // We're clipping at a cycle in the reference path.  Just preserve the path as-is from the
    // input region.
    else {
        mappings.clear();
        xg->for_path_range(region.seq, region.start, region.end, [&](int64_t id, bool rev) {
                mapping_t mapping;
                mapping.set_node_id(id);
                mapping.set_is_reverse(rev);
                mappings.push_back(mapping);
            });
        rewrite_paths = true;
    }

    // Cut our graph so that our reference path end points are graph tips.  This will let the
    // snarl finder use the path to find telomeres.
    Node* start_node = subgraph.get_node(mappings.begin()->node_id());
    if (!mappings.begin()->is_reverse() && subgraph.start_degree(start_node) != 0) {
        for (auto edge : subgraph.edges_to(start_node)) {
            subgraph.destroy_edge(edge);
        }
    } else if (mappings.begin()->is_reverse() && subgraph.end_degree(start_node) != 0) {
        for (auto edge : subgraph.edges_from(start_node)) {
            subgraph.destroy_edge(edge);
        }
    }
    Node* end_node = subgraph.get_node(mappings.rbegin()->node_id());
    if (!mappings.rbegin()->is_reverse() && subgraph.end_degree(end_node) != 0) {
        for (auto edge : subgraph.edges_from(end_node)) {
            subgraph.destroy_edge(edge);
        }
    } else if (mappings.rbegin()->is_reverse() && subgraph.start_degree(end_node) != 0) {
        for (auto edge : subgraph.edges_to(end_node)) {
            subgraph.destroy_edge(edge);
        }
    }

    // Sync our updated paths lists back into the Graph protobuf
    if (rewrite_paths) {
        subgraph.paths.rebuild_node_mapping();
        subgraph.paths.rebuild_mapping_aux();
        subgraph.graph.clear_path();
        subgraph.paths.to_graph(subgraph.graph);
    }

    // start could fall inside a node.  we find out where in the path the
    // 0-offset point of the node is.
    int64_t input_start_pos = xg->node_start_at_path_position(region.seq, region.start);
    int64_t input_end_pos = xg->node_start_at_path_position(region.seq, region.end);
    out_region.seq = region.seq;
    out_region.start = input_start_pos - left_padding;
    out_region.end = input_end_pos + xg->node_length(input_end_node) + right_padding - 1;
}

void PathChunker::extract_id_range(vg::id_t start, vg::id_t end, int context, int length,
                                   bool forward_only, VG& subgraph, Region& out_region) {

    Graph g;

    for (vg::id_t i = start; i <= end; ++i) {
        *g.add_node() = xg->node(i);
    }

    // expand the context and get path information
    // if forward_only true, then we only go forward.
    xg->expand_context(g, context, true, true, true, !forward_only);
    if (length) {
        xg->expand_context(g, context, true, false, true, !forward_only);
    }

    // build the vg
    subgraph.extend(g);
    subgraph.remove_orphan_edges();

    out_region.start = subgraph.min_node_id();
    out_region.end = subgraph.max_node_id();
}

}
<commit_msg>dont cut chunk ends in cycles<commit_after>#include <iostream>
#include <unordered_set>
#include "stream.hpp"
#include "chunker.hpp"

namespace vg {

using namespace std;
using namespace xg;

PathChunker::PathChunker(xg::XG* xindex) : xg(xindex) {

}

PathChunker::~PathChunker() {

}

void PathChunker::extract_subgraph(const Region& region, int context, int length,
                                   bool forward_only, VG& subgraph, Region& out_region) {

    // extract our path range into the graph
    Graph g;
    xg->for_path_range(region.seq, region.start, region.end, [&](int64_t id, bool) {
            *g.add_node() = xg->node(id);
        });

    // expand the context and get path information
    // if forward_only true, then we only go forward.
    xg->expand_context(g, context, true, true, true, !forward_only);
    if (length) {
        xg->expand_context(g, context, true, false, true, !forward_only);
    }

    // build the vg of the subgraph
    subgraph.extend(g);
    subgraph.remove_orphan_edges();

    // get our range endpoints before context expansion
    list<mapping_t>& mappings = subgraph.paths.get_path(region.seq);
    size_t mappings_size = mappings.size();
    int64_t input_start_node = xg->node_at_path_position(region.seq, region.start);
    vector<size_t> first_positions = xg->position_in_path(input_start_node, region.seq);
    int64_t input_end_node = xg->node_at_path_position(region.seq, region.end);
    vector<size_t> last_positions = xg->position_in_path(input_end_node, region.seq);

    // the distance between then and the nodes in our input range
    size_t left_padding = 0;
    size_t right_padding = 0;
    // do we need to rewrite back to our graph?
    bool rewrite_paths = false;

    // Endpoints not in cycles: we can get our output region directly from xg lookups
    if (first_positions.size() == 1  && last_positions.size() == 1) {
        // start and end of our expanded chunk
        auto start_it = mappings.begin();
        auto end_it = --mappings.end();

        // find our input range in the expanded path. we know these nodes only appear once.
        for (; start_it != mappings.end() && start_it->node_id() != input_start_node; ++start_it);
        for (; end_it != mappings.begin() && end_it->node_id() != input_end_node; --end_it);

        // walk back our start point as we can without rank discontinuities. doesn't matter
        // if we encounter cycles here, because we keep a running path length
        auto cur_it = start_it;
        auto prev_it = cur_it;
        if (prev_it != mappings.begin()) {
            for (; prev_it != mappings.begin(); --prev_it) {
                cur_it = prev_it;
                --cur_it;
                if ((prev_it->rank > 0 || cur_it->rank > 0) && cur_it->rank + 1 != prev_it->rank) {
                    break;
                }
                left_padding += cur_it->length;
            }
        }
        start_it = prev_it;
        // walk forward the end point
        cur_it = end_it;
        prev_it = cur_it;
        for (++cur_it; cur_it != mappings.end(); ++prev_it, ++cur_it) {
            if ((prev_it->rank > 0 || cur_it->rank > 0) && prev_it->rank + 1 != cur_it->rank) {
                break;
            }
            right_padding += cur_it->length;
        }
        end_it = prev_it;

        rewrite_paths = start_it != mappings.begin() || end_it != --mappings.end();

        // cut out nodes before and after discontinuity
        mappings.erase(mappings.begin(), start_it);
        mappings.erase(++end_it, mappings.end());
    }
    // We're clipping at a cycle in the reference path.  Just preserve the path as-is from the
    // input region.
    else {
        mappings.clear();
        xg->for_path_range(region.seq, region.start, region.end, [&](int64_t id, bool rev) {
                mapping_t mapping;
                mapping.set_node_id(id);
                mapping.set_is_reverse(rev);
                mappings.push_back(mapping);
            });
        rewrite_paths = true;
    }

    // Cut our graph so that our reference path end points are graph tips.  This will let the
    // snarl finder use the path to find telomeres.
    Node* start_node = subgraph.get_node(mappings.begin()->node_id());
    if (rewrite_paths && xg->position_in_path(start_node->id(), region.seq).size() == 1) {
        if (!mappings.begin()->is_reverse() && subgraph.start_degree(start_node) != 0) {
            for (auto edge : subgraph.edges_to(start_node)) {
                subgraph.destroy_edge(edge);
            }
        } else if (mappings.begin()->is_reverse() && subgraph.end_degree(start_node) != 0) {
            for (auto edge : subgraph.edges_from(start_node)) {
                subgraph.destroy_edge(edge);
            }
        }
    }
    Node* end_node = subgraph.get_node(mappings.rbegin()->node_id());
    if (rewrite_paths && xg->position_in_path(end_node->id(), region.seq).size() == 1) {
        if (!mappings.rbegin()->is_reverse() && subgraph.end_degree(end_node) != 0) {
            for (auto edge : subgraph.edges_from(end_node)) {
                subgraph.destroy_edge(edge);
            }
        } else if (mappings.rbegin()->is_reverse() && subgraph.start_degree(end_node) != 0) {
            for (auto edge : subgraph.edges_to(end_node)) {
                subgraph.destroy_edge(edge);
            }
        }
    }

    // Sync our updated paths lists back into the Graph protobuf
    if (rewrite_paths) {
        subgraph.paths.rebuild_node_mapping();
        subgraph.paths.rebuild_mapping_aux();
        subgraph.graph.clear_path();
        subgraph.paths.to_graph(subgraph.graph);
    }

    // start could fall inside a node.  we find out where in the path the
    // 0-offset point of the node is.
    int64_t input_start_pos = xg->node_start_at_path_position(region.seq, region.start);
    int64_t input_end_pos = xg->node_start_at_path_position(region.seq, region.end);
    out_region.seq = region.seq;
    out_region.start = input_start_pos - left_padding;
    out_region.end = input_end_pos + xg->node_length(input_end_node) + right_padding - 1;
}

void PathChunker::extract_id_range(vg::id_t start, vg::id_t end, int context, int length,
                                   bool forward_only, VG& subgraph, Region& out_region) {

    Graph g;

    for (vg::id_t i = start; i <= end; ++i) {
        *g.add_node() = xg->node(i);
    }

    // expand the context and get path information
    // if forward_only true, then we only go forward.
    xg->expand_context(g, context, true, true, true, !forward_only);
    if (length) {
        xg->expand_context(g, context, true, false, true, !forward_only);
    }

    // build the vg
    subgraph.extend(g);
    subgraph.remove_orphan_edges();

    out_region.start = subgraph.min_node_id();
    out_region.end = subgraph.max_node_id();
}

}
<|endoftext|>