<commit_before>/**
 * \file
 * \brief      PySceneManager class implementation.
 * \author     Thomas Moeller
 * \details
 *
 * Copyright (C) the PyInventor contributors. All rights reserved.
 * This file is part of PyInventor, distributed under the BSD 3-Clause
 * License. For full terms see the included COPYING file.
 */

#include <Inventor/SoSceneManager.h>
#include <Inventor/events/SoLocation2Event.h>
#include <Inventor/events/SoMouseButtonEvent.h>
#include <Inventor/events/SoKeyboardEvent.h>
#include <Inventor/nodes/SoNode.h>
#include <Inventor/engines/SoEngine.h>
#include <Inventor/elements/SoGLLazyElement.h> // for GL.h, whose location is distribution specific under system/ or sys/
#include <Inventor/fields/SoSFColor.h>
#include <Inventor/SoDB.h>

#ifdef TGS_VERSION
#include <Inventor/events/SoMouseWheelEvent.h>
#endif

#include "PySceneManager.h"

#pragma warning ( disable : 4127 ) // conditional expression is constant in Py_DECREF
#pragma warning ( disable : 4244 ) // possible loss of data when converting int to short in SbVec2s

PyTypeObject *PySceneManager::getType()
{
	static PyMemberDef members[] =
	{
		{"scene", T_OBJECT_EX, offsetof(Object, scene), 0, "scene graph"},
		{"redisplay", T_OBJECT_EX, offsetof(Object, renderCallback), 0, "render callback"},
		{"background", T_OBJECT_EX, offsetof(Object, backgroundColor), 0, "background color"},
		{NULL}  /* Sentinel */
	};

	static PyMethodDef methods[] =
	{
		{"render", (PyCFunction) render, METH_NOARGS, "Renders the scene into an OpenGL context" },
		{"resize", (PyCFunction) resize, METH_VARARGS, "Sets the window size" },
		{"mouse_button", (PyCFunction) mouse_button, METH_VARARGS, "Sends mouse button event into the scene for processing" },
		{"mouse_move", (PyCFunction) mouse_move, METH_VARARGS, "Sends mouse move event into the scene for processing" },
		{"key", (PyCFunction) key, METH_VARARGS, "Sends keyboard event into the scene for processing" },
		{NULL}  /* Sentinel */
	};

	static PyTypeObject managerType =
	{
		PyVarObject_HEAD_INIT(NULL, 0)
		"SceneManager",            /* tp_name */
		sizeof(Object),            /* tp_basicsize */
		0,                         /* tp_itemsize */
		(destructor) tp_dealloc,   /* tp_dealloc */
		0,                         /* tp_print */
		0,                         /* tp_getattr */
		0,                         /* tp_setattr */
		0,                         /* tp_reserved */
		0,                         /* tp_repr */
		0,                         /* tp_as_number */
		0,                         /* tp_as_sequence */
		0,                         /* tp_as_mapping */
		0,                         /* tp_hash  */
		0,                         /* tp_call */
		0,                         /* tp_str */
		0,                         /* tp_getattro */
		(setattrofunc)tp_setattro, /* tp_setattro */
		0,                         /* tp_as_buffer */
		Py_TPFLAGS_DEFAULT |
			Py_TPFLAGS_BASETYPE,   /* tp_flags */
		"Scene manager object",    /* tp_doc */
		0,                         /* tp_traverse */
		0,                         /* tp_clear */
		0,                         /* tp_richcompare */
		0,                         /* tp_weaklistoffset */
		0,                         /* tp_iter */
		0,                         /* tp_iternext */
		methods,                   /* tp_methods */
		members,                   /* tp_members */
		0,                         /* tp_getset */
		0,                         /* tp_base */
		0,                         /* tp_dict */
		0,                         /* tp_descr_get */
		0,                         /* tp_descr_set */
		0,                         /* tp_dictoffset */
		(initproc) tp_init,        /* tp_init */
		0,                         /* tp_alloc */
		tp_new,                    /* tp_new */
	};

	return &managerType;
}

void PySceneManager::tp_dealloc(Object* self)
{
	if (self->sceneManager)
	{
		delete self->sceneManager;
	}

	Py_XDECREF(self->scene);
	Py_XDECREF(self->renderCallback);

    Py_TYPE(self)->tp_free((PyObject*)self);
}

PyObject* PySceneManager::tp_new(PyTypeObject *type, PyObject* /*args*/, PyObject* /*kwds*/)
{
	PySceneObject::initSoDB();

    Object *self = (Object *)type->tp_alloc(type, 0);
    if (self != NULL)
	{
		self->scene = 0;
		self->renderCallback = 0;
		self->sceneManager = 0;
	}

    return (PyObject *) self;
}

int PySceneManager::tp_init(Object *self, PyObject *args, PyObject *kwds)
{
	PyObject *background = 0;
	static char *kwlist[] = { "background", NULL};

	if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &background))
        return -1;

	self->scene = PySceneObject::createWrapper("Separator");
	self->sceneManager = new SoSceneManager();
	if (self->scene && self->sceneManager)
	{
		self->sceneManager->setSceneGraph((SoNode*) ((PySceneObject::Object*) self->scene)->inventorObject);
	}
	self->sceneManager->setRenderCallback(renderCBFunc, self);
	self->sceneManager->activate();

	Py_INCREF(Py_None);
	self->renderCallback = Py_None;

    // configure background color
	if (background && PySequence_Check(background))
	{
		PyObject *seq = PySequence_Fast(background, "expected a sequence");
		size_t n = PySequence_Size(seq);
        if (n == 3)
        {
            SbColor color(0, 0, 0);
            for (int i = 0; i < 3; ++i)
            {
                PyObject *seqItem = PySequence_GetItem(seq, i);
                if (seqItem)
                {
                    if (PyFloat_Check(seqItem))
                        color[i] = (float) PyFloat_AsDouble(seqItem);
                    else if (PyLong_Check(seqItem))
                        color[i] = (float) PyLong_AsDouble(seqItem);
                }
            }
            if (self->sceneManager)
                self->sceneManager->setBackgroundColor(color);
        }

		Py_XDECREF(seq);
	}

	return 0;
}

int PySceneManager::tp_setattro(Object* self, PyObject *attrname, PyObject *value)
{
	int result = 0;

	result = PyObject_GenericSetAttr((PyObject*) self, attrname, value);

	const char *attr = PyUnicode_AsUTF8(attrname);
	if (attr && (strcmp(attr, "scene") == 0))
	{
		if (PyNode_Check(self->scene))
		{
			SoFieldContainer *fc = ((PySceneObject::Object*) self->scene)->inventorObject;
			if (fc && fc->isOfType(SoNode::getClassTypeId()))
			{
				self->sceneManager->setSceneGraph((SoNode*) fc);
				self->sceneManager->scheduleRedraw();
			}
			else
			{
				PyErr_SetString(PyExc_IndexError, "Scene object must be of type SoNode");
			}
		}
		else
		{
			PyErr_SetString(PyExc_IndexError, "Scene must be of type Node");
		}
	}
	else if (attr && (strcmp(attr, "background") == 0))
	{
        SoSFColor tmp;
        tmp.setValue(SbColor(0, 0, 0));
        if (PySceneObject::setField(&tmp, value) == 0)
        {
            self->sceneManager->setBackgroundColor(tmp.getValue());
            self->sceneManager->scheduleRedraw();
        }
    }

	return result;
}

void PySceneManager::renderCBFunc(void *userdata, SoSceneManager * /*mgr*/)
{
	Object *self = (Object *) userdata;
	if ((self != NULL) && (self->renderCallback != NULL) && PyCallable_Check(self->renderCallback))
	{
		PyObject *value = PyObject_CallObject(self->renderCallback, NULL);
		if (value != NULL)
		{
			Py_DECREF(value);
		}
	}
}

PyObject* PySceneManager::render(Object *self)
{
	self->sceneManager->render();

    // need to flush or nothing will be shown on OS X
    glFlush();

    Py_INCREF(Py_None);
    return Py_None;
}

PyObject* PySceneManager::resize(Object *self, PyObject *args)
{
    int width = 0, height = 0;
    if (PyArg_ParseTuple(args, "ii", &width, &height))
	{
        // for Coin both setWindowSize() and setSize() must be called
        // in order to get correct rendering and event handling
		self->sceneManager->setWindowSize(SbVec2s(width, height));
        self->sceneManager->setSize(SbVec2s(width, height));
	}

    Py_INCREF(Py_None);
    return Py_None;
}

PyObject* PySceneManager::mouse_button(Object *self, PyObject *args)
{
    int button = 0, state = 0, x = 0, y = 0;
    if (PyArg_ParseTuple(args, "iiii", &button, &state, &x, &y))
	{
		y = self->sceneManager->getWindowSize()[1] - y;

        #ifdef TGS_VERSION
		// Coin does not have wheel event (yet)
        if (button > 2)
		{
			// wheel
			SoMouseWheelEvent ev;
			ev.setTime(SbTime::getTimeOfDay());
			ev.setDelta(state ? -120 : 120);
			if (self->sceneManager->processEvent(&ev))
			{
				SoDB::getSensorManager()->processDelayQueue(FALSE);
			}
		}
		else
        #endif
		{
			SoMouseButtonEvent ev;
			ev.setTime(SbTime::getTimeOfDay());
			ev.setPosition(SbVec2s(x, y));
			ev.setButton((SoMouseButtonEvent::Button) (button + 1));
			ev.setState(state ? SoMouseButtonEvent::UP : SoMouseButtonEvent::DOWN);
			if (self->sceneManager->processEvent(&ev))
			{
				SoDB::getSensorManager()->processDelayQueue(FALSE);
			}
		}
	}

    Py_INCREF(Py_None);
    return Py_None;
}

PyObject* PySceneManager::mouse_move(Object *self, PyObject *args)
{
    int x = 0, y = 0;
    if (PyArg_ParseTuple(args, "ii", &x, &y))
	{
		y = self->sceneManager->getWindowSize()[1] - y;

		SoLocation2Event ev;
		ev.setTime(SbTime::getTimeOfDay());
		ev.setPosition(SbVec2s(x, y));
		if (self->sceneManager->processEvent(&ev))
		{
			SoDB::getSensorManager()->processDelayQueue(FALSE);
		}
	}

    Py_INCREF(Py_None);
    return Py_None;
}

PyObject* PySceneManager::key(Object *self, PyObject *args)
{
    char key;
    if (PyArg_ParseTuple(args, "c", &key))
	{
		bool mapped = true;
		SoKeyboardEvent ev;
		ev.setTime(SbTime::getTimeOfDay());

		if ((key >= 'a') && (key <= 'z'))
		{
			ev.setKey(SoKeyboardEvent::Key(SoKeyboardEvent::A + (key - 'a')));
		}
		else if ((key >= 'A') && (key <= 'Z'))
		{
			ev.setKey(SoKeyboardEvent::Key(SoKeyboardEvent::A + (key - 'Z')));
			ev.setShiftDown(TRUE);
		}
		else switch (key)
		{
		case '\n':
		case '\r':		ev.setKey(SoKeyboardEvent::RETURN); break;
		case '\t':		ev.setKey(SoKeyboardEvent::TAB); break;
		case ' ':		ev.setKey(SoKeyboardEvent::SPACE); break;
		case ',':		ev.setKey(SoKeyboardEvent::COMMA); break;
		case '.':		ev.setKey(SoKeyboardEvent::PERIOD); break;
		case '=':		ev.setKey(SoKeyboardEvent::EQUAL); break;
		case '-':		ev.setKey(SoKeyboardEvent::PAD_SUBTRACT); break;
		case '+':		ev.setKey(SoKeyboardEvent::PAD_ADD); break;
		case '/':		ev.setKey(SoKeyboardEvent::PAD_DIVIDE); break;
		case '*':		ev.setKey(SoKeyboardEvent::PAD_MULTIPLY); break;
		case '\x1b':	ev.setKey(SoKeyboardEvent::ESCAPE); break;
		case '\x08':	ev.setKey(SoKeyboardEvent::BACKSPACE); break;
		default:
			mapped = false;
		}

		if (mapped)
		{
			ev.setState(SoButtonEvent::DOWN);
			SbBool processed = self->sceneManager->processEvent(&ev);
			ev.setState(SoButtonEvent::UP);
			processed |= self->sceneManager->processEvent(&ev);
			if (processed)
			{
				SoDB::getSensorManager()->processDelayQueue(FALSE);
			}
		}
	}

    Py_INCREF(Py_None);
    return Py_None;
}

<commit_msg>Added missing include for VSG Inventor.<commit_after>/**
 * \file
 * \brief      PySceneManager class implementation.
 * \author     Thomas Moeller
 * \details
 *
 * Copyright (C) the PyInventor contributors. All rights reserved.
 * This file is part of PyInventor, distributed under the BSD 3-Clause
 * License. For full terms see the included COPYING file.
 */

#include <Inventor/SoSceneManager.h>
#include <Inventor/events/SoLocation2Event.h>
#include <Inventor/events/SoMouseButtonEvent.h>
#include <Inventor/events/SoKeyboardEvent.h>
#include <Inventor/nodes/SoNode.h>
#include <Inventor/engines/SoEngine.h>
#include <Inventor/elements/SoGLLazyElement.h> // for GL.h, whose location is distribution specific under system/ or sys/
#include <Inventor/fields/SoSFColor.h>
#include <Inventor/SoDB.h>

#ifdef TGS_VERSION
#include <Inventor/events/SoMouseWheelEvent.h>
#include <Inventor/sys/SoGL.h>
#endif

#include "PySceneManager.h"

#pragma warning ( disable : 4127 ) // conditional expression is constant in Py_DECREF
#pragma warning ( disable : 4244 ) // possible loss of data when converting int to short in SbVec2s

PyTypeObject *PySceneManager::getType()
{
	static PyMemberDef members[] =
	{
		{"scene", T_OBJECT_EX, offsetof(Object, scene), 0, "scene graph"},
		{"redisplay", T_OBJECT_EX, offsetof(Object, renderCallback), 0, "render callback"},
		{"background", T_OBJECT_EX, offsetof(Object, backgroundColor), 0, "background color"},
		{NULL}  /* Sentinel */
	};

	static PyMethodDef methods[] =
	{
		{"render", (PyCFunction) render, METH_NOARGS, "Renders the scene into an OpenGL context" },
		{"resize", (PyCFunction) resize, METH_VARARGS, "Sets the window size" },
		{"mouse_button", (PyCFunction) mouse_button, METH_VARARGS, "Sends mouse button event into the scene for processing" },
		{"mouse_move", (PyCFunction) mouse_move, METH_VARARGS, "Sends mouse move event into the scene for processing" },
		{"key", (PyCFunction) key, METH_VARARGS, "Sends keyboard event into the scene for processing" },
		{NULL}  /* Sentinel */
	};

	static PyTypeObject managerType =
	{
		PyVarObject_HEAD_INIT(NULL, 0)
		"SceneManager",            /* tp_name */
		sizeof(Object),            /* tp_basicsize */
		0,                         /* tp_itemsize */
		(destructor) tp_dealloc,   /* tp_dealloc */
		0,                         /* tp_print */
		0,                         /* tp_getattr */
		0,                         /* tp_setattr */
		0,                         /* tp_reserved */
		0,                         /* tp_repr */
		0,                         /* tp_as_number */
		0,                         /* tp_as_sequence */
		0,                         /* tp_as_mapping */
		0,                         /* tp_hash  */
		0,                         /* tp_call */
		0,                         /* tp_str */
		0,                         /* tp_getattro */
		(setattrofunc)tp_setattro, /* tp_setattro */
		0,                         /* tp_as_buffer */
		Py_TPFLAGS_DEFAULT |
			Py_TPFLAGS_BASETYPE,   /* tp_flags */
		"Scene manager object",    /* tp_doc */
		0,                         /* tp_traverse */
		0,                         /* tp_clear */
		0,                         /* tp_richcompare */
		0,                         /* tp_weaklistoffset */
		0,                         /* tp_iter */
		0,                         /* tp_iternext */
		methods,                   /* tp_methods */
		members,                   /* tp_members */
		0,                         /* tp_getset */
		0,                         /* tp_base */
		0,                         /* tp_dict */
		0,                         /* tp_descr_get */
		0,                         /* tp_descr_set */
		0,                         /* tp_dictoffset */
		(initproc) tp_init,        /* tp_init */
		0,                         /* tp_alloc */
		tp_new,                    /* tp_new */
	};

	return &managerType;
}

void PySceneManager::tp_dealloc(Object* self)
{
	if (self->sceneManager)
	{
		delete self->sceneManager;
	}

	Py_XDECREF(self->scene);
	Py_XDECREF(self->renderCallback);

    Py_TYPE(self)->tp_free((PyObject*)self);
}

PyObject* PySceneManager::tp_new(PyTypeObject *type, PyObject* /*args*/, PyObject* /*kwds*/)
{
	PySceneObject::initSoDB();

    Object *self = (Object *)type->tp_alloc(type, 0);
    if (self != NULL)
	{
		self->scene = 0;
		self->renderCallback = 0;
		self->sceneManager = 0;
	}

    return (PyObject *) self;
}

int PySceneManager::tp_init(Object *self, PyObject *args, PyObject *kwds)
{
	PyObject *background = 0;
	static char *kwlist[] = { "background", NULL};

	if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &background))
        return -1;

	self->scene = PySceneObject::createWrapper("Separator");
	self->sceneManager = new SoSceneManager();
	if (self->scene && self->sceneManager)
	{
		self->sceneManager->setSceneGraph((SoNode*) ((PySceneObject::Object*) self->scene)->inventorObject);
	}
	self->sceneManager->setRenderCallback(renderCBFunc, self);
	self->sceneManager->activate();

	Py_INCREF(Py_None);
	self->renderCallback = Py_None;

    // configure background color
	if (background && PySequence_Check(background))
	{
		PyObject *seq = PySequence_Fast(background, "expected a sequence");
		size_t n = PySequence_Size(seq);
        if (n == 3)
        {
            SbColor color(0, 0, 0);
            for (int i = 0; i < 3; ++i)
            {
                PyObject *seqItem = PySequence_GetItem(seq, i);
                if (seqItem)
                {
                    if (PyFloat_Check(seqItem))
                        color[i] = (float) PyFloat_AsDouble(seqItem);
                    else if (PyLong_Check(seqItem))
                        color[i] = (float) PyLong_AsDouble(seqItem);
                }
            }
            if (self->sceneManager)
                self->sceneManager->setBackgroundColor(color);
        }

		Py_XDECREF(seq);
	}

	return 0;
}

int PySceneManager::tp_setattro(Object* self, PyObject *attrname, PyObject *value)
{
	int result = 0;

	result = PyObject_GenericSetAttr((PyObject*) self, attrname, value);

	const char *attr = PyUnicode_AsUTF8(attrname);
	if (attr && (strcmp(attr, "scene") == 0))
	{
		if (PyNode_Check(self->scene))
		{
			SoFieldContainer *fc = ((PySceneObject::Object*) self->scene)->inventorObject;
			if (fc && fc->isOfType(SoNode::getClassTypeId()))
			{
				self->sceneManager->setSceneGraph((SoNode*) fc);
				self->sceneManager->scheduleRedraw();
			}
			else
			{
				PyErr_SetString(PyExc_IndexError, "Scene object must be of type SoNode");
			}
		}
		else
		{
			PyErr_SetString(PyExc_IndexError, "Scene must be of type Node");
		}
	}
	else if (attr && (strcmp(attr, "background") == 0))
	{
        SoSFColor tmp;
        tmp.setValue(SbColor(0, 0, 0));
        if (PySceneObject::setField(&tmp, value) == 0)
        {
            self->sceneManager->setBackgroundColor(tmp.getValue());
            self->sceneManager->scheduleRedraw();
        }
    }

	return result;
}

void PySceneManager::renderCBFunc(void *userdata, SoSceneManager * /*mgr*/)
{
	Object *self = (Object *) userdata;
	if ((self != NULL) && (self->renderCallback != NULL) && PyCallable_Check(self->renderCallback))
	{
		PyObject *value = PyObject_CallObject(self->renderCallback, NULL);
		if (value != NULL)
		{
			Py_DECREF(value);
		}
	}
}

PyObject* PySceneManager::render(Object *self)
{
	self->sceneManager->render();

    // need to flush or nothing will be shown on OS X
    glFlush();

    Py_INCREF(Py_None);
    return Py_None;
}

PyObject* PySceneManager::resize(Object *self, PyObject *args)
{
    int width = 0, height = 0;
    if (PyArg_ParseTuple(args, "ii", &width, &height))
	{
        // for Coin both setWindowSize() and setSize() must be called
        // in order to get correct rendering and event handling
		self->sceneManager->setWindowSize(SbVec2s(width, height));
        self->sceneManager->setSize(SbVec2s(width, height));
	}

    Py_INCREF(Py_None);
    return Py_None;
}

PyObject* PySceneManager::mouse_button(Object *self, PyObject *args)
{
    int button = 0, state = 0, x = 0, y = 0;
    if (PyArg_ParseTuple(args, "iiii", &button, &state, &x, &y))
	{
		y = self->sceneManager->getWindowSize()[1] - y;

        #ifdef TGS_VERSION
		// Coin does not have wheel event (yet)
        if (button > 2)
		{
			// wheel
			SoMouseWheelEvent ev;
			ev.setTime(SbTime::getTimeOfDay());
			ev.setDelta(state ? -120 : 120);
			if (self->sceneManager->processEvent(&ev))
			{
				SoDB::getSensorManager()->processDelayQueue(FALSE);
			}
		}
		else
        #endif
		{
			SoMouseButtonEvent ev;
			ev.setTime(SbTime::getTimeOfDay());
			ev.setPosition(SbVec2s(x, y));
			ev.setButton((SoMouseButtonEvent::Button) (button + 1));
			ev.setState(state ? SoMouseButtonEvent::UP : SoMouseButtonEvent::DOWN);
			if (self->sceneManager->processEvent(&ev))
			{
				SoDB::getSensorManager()->processDelayQueue(FALSE);
			}
		}
	}

    Py_INCREF(Py_None);
    return Py_None;
}

PyObject* PySceneManager::mouse_move(Object *self, PyObject *args)
{
    int x = 0, y = 0;
    if (PyArg_ParseTuple(args, "ii", &x, &y))
	{
		y = self->sceneManager->getWindowSize()[1] - y;

		SoLocation2Event ev;
		ev.setTime(SbTime::getTimeOfDay());
		ev.setPosition(SbVec2s(x, y));
		if (self->sceneManager->processEvent(&ev))
		{
			SoDB::getSensorManager()->processDelayQueue(FALSE);
		}
	}

    Py_INCREF(Py_None);
    return Py_None;
}

PyObject* PySceneManager::key(Object *self, PyObject *args)
{
    char key;
    if (PyArg_ParseTuple(args, "c", &key))
	{
		bool mapped = true;
		SoKeyboardEvent ev;
		ev.setTime(SbTime::getTimeOfDay());

		if ((key >= 'a') && (key <= 'z'))
		{
			ev.setKey(SoKeyboardEvent::Key(SoKeyboardEvent::A + (key - 'a')));
		}
		else if ((key >= 'A') && (key <= 'Z'))
		{
			ev.setKey(SoKeyboardEvent::Key(SoKeyboardEvent::A + (key - 'Z')));
			ev.setShiftDown(TRUE);
		}
		else switch (key)
		{
		case '\n':
		case '\r':		ev.setKey(SoKeyboardEvent::RETURN); break;
		case '\t':		ev.setKey(SoKeyboardEvent::TAB); break;
		case ' ':		ev.setKey(SoKeyboardEvent::SPACE); break;
		case ',':		ev.setKey(SoKeyboardEvent::COMMA); break;
		case '.':		ev.setKey(SoKeyboardEvent::PERIOD); break;
		case '=':		ev.setKey(SoKeyboardEvent::EQUAL); break;
		case '-':		ev.setKey(SoKeyboardEvent::PAD_SUBTRACT); break;
		case '+':		ev.setKey(SoKeyboardEvent::PAD_ADD); break;
		case '/':		ev.setKey(SoKeyboardEvent::PAD_DIVIDE); break;
		case '*':		ev.setKey(SoKeyboardEvent::PAD_MULTIPLY); break;
		case '\x1b':	ev.setKey(SoKeyboardEvent::ESCAPE); break;
		case '\x08':	ev.setKey(SoKeyboardEvent::BACKSPACE); break;
		default:
			mapped = false;
		}

		if (mapped)
		{
			ev.setState(SoButtonEvent::DOWN);
			SbBool processed = self->sceneManager->processEvent(&ev);
			ev.setState(SoButtonEvent::UP);
			processed |= self->sceneManager->processEvent(&ev);
			if (processed)
			{
				SoDB::getSensorManager()->processDelayQueue(FALSE);
			}
		}
	}

    Py_INCREF(Py_None);
    return Py_None;
}

<|endoftext|>


<commit_before>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2015
Raffaello D. Di Napoli

This file is part of Abaclade.

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

Abaclade 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 General
Public License for more details.

You should have received a copy of the GNU General Public License along with Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#include <abaclade.hxx>
#include <abaclade/app.hxx>
#include <abaclade/coroutine.hxx>
#include <abaclade/range.hxx>

using namespace abc;

////////////////////////////////////////////////////////////////////////////////////////////////////
// coroutines_app

class coroutines_app : public app {
public:
   /*! Main function of the program.

   @param vsArgs
      Arguments that were provided to this program via command line.
   @return
      Return value of this program.
   */
   virtual int main(collections::mvector<istr const> const & vsArgs) override {
      ABC_TRACE_FUNC(this, vsArgs);

      auto & pcorosched = this_thread::attach_coroutine_scheduler();

      // Open a pipe in asynchronous I/O mode.
      auto pair(io::binary::pipe(true));

      // Schedule the reader.
      pcorosched->add(coroutine([this, &pair] () -> void {
         ABC_TRACE_FUNC(this/*, pair*/);

         for (;;) {
            int i;
            io::text::stdout()->print(ABC_SL("reading\n"));
            // This will cause a context switch if the read would block.
            std::size_t cbRead = pair.first->read(&i, sizeof i);
            // Execution resumes here, after other coroutines have received CPU time.
            io::text::stdout()->print(ABC_SL("read {}\n"), i);
            if (!cbRead) {
               // Detect EOF.
               break;
            }
            // Consume i.
         }
         io::text::stdout()->write_line(ABC_SL("reader terminating"));
      }));

      // Schedule the writer.
      pcorosched->add(coroutine([this, &pair] () -> void {
         ABC_TRACE_FUNC(this/*, pair*/);

         ABC_FOR_EACH(int i, make_range(1, 10)) {
            io::text::stdout()->print(ABC_SL("writing {}\n"), i);
            // This will cause a context switch if the write would block.
            pair.second->write(&i, sizeof i);
            // Execution resumes here, after other coroutines have received CPU time.
         }
         // Close the writing end of the pipe to report EOF on the reading end.
         pair.second.reset();
         io::text::stdout()->write_line(ABC_SL("writer terminating"));
      }));

      // Switch this thread to run coroutines, until they all terminate.
      pcorosched->run();
      // Execution resumes here, after all coroutines have terminated.
      io::text::stdout()->write_line(ABC_SL("main terminating"));
      return 0;
   }
};

ABC_APP_CLASS(coroutines_app)
<commit_msg>Improve coroutines example to generate a more realistic call sequence<commit_after>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2015
Raffaello D. Di Napoli

This file is part of Abaclade.

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

Abaclade 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 General
Public License for more details.

You should have received a copy of the GNU General Public License along with Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#include <abaclade.hxx>
#include <abaclade/app.hxx>
#include <abaclade/coroutine.hxx>
#include <abaclade/range.hxx>

using namespace abc;

////////////////////////////////////////////////////////////////////////////////////////////////////
// coroutines_app

class coroutines_app : public app {
public:
   /*! Main function of the program.

   @param vsArgs
      Arguments that were provided to this program via command line.
   @return
      Return value of this program.
   */
   virtual int main(collections::mvector<istr const> const & vsArgs) override {
      ABC_TRACE_FUNC(this, vsArgs);

      auto & pcorosched = this_thread::attach_coroutine_scheduler();

      // Open a pipe in asynchronous I/O mode.
      auto pair(io::binary::pipe(true));

      // Schedule the reader.
      pcorosched->add(coroutine([this, &pair] () -> void {
         ABC_TRACE_FUNC(this/*, pair*/);

         io::text::stdout()->write_line(ABC_SL("reader: starting"));
         for (;;) {
            int i;
            io::text::stdout()->print(ABC_SL("reader: reading\n"));
            // This will cause a context switch if the read would block.
            std::size_t cbRead = pair.first->read(&i, sizeof i);
            // Execution resumes here, after other coroutines have received CPU time.
            io::text::stdout()->print(ABC_SL("reader: read {}\n"), i);
            if (!cbRead) {
               // Detect EOF.
               break;
            }
            // Consume i.
         }
         io::text::stdout()->write_line(ABC_SL("reader: terminating"));
      }));

      // Schedule the writer.
      pcorosched->add(coroutine([this, &pair] () -> void {
         ABC_TRACE_FUNC(this/*, pair*/);

         io::text::stdout()->write_line(ABC_SL("writer: starting"));
         ABC_FOR_EACH(int i, make_range(1, 10)) {
            io::text::stdout()->print(ABC_SL("writer: writing {}\n"), i);
            // This will cause a context switch if the write would block.
            pair.second->write(&i, sizeof i);
            // Execution resumes here, after other coroutines have received CPU time.

            /* Halt this coroutine for a few milliseconds. This will give the reader a chance to be
            scheduled, as well as create a more realistic non-continuous data flow into the pipe. */
            io::text::stdout()->write_line(ABC_SL("writer: yielding"));
            this_thread::coroutine_scheduler()->yield_for(50);
            // Execution resumes here, after other coroutines have received CPU time.
         }
         // Close the writing end of the pipe to report EOF on the reading end.
         pair.second.reset();
         io::text::stdout()->write_line(ABC_SL("writer: terminating"));
      }));

      // Switch this thread to run coroutines, until they all terminate.
      pcorosched->run();
      // Execution resumes here, after all coroutines have terminated.
      io::text::stdout()->write_line(ABC_SL("main: terminating"));
      return 0;
   }
};

ABC_APP_CLASS(coroutines_app)
<|endoftext|>


<commit_before>/**
 This file is part of Deformable Shape Tracking (DEST).

 Copyright Christoph Heindl 2015

 Deformable Shape Tracking is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 Deformable Shape Tracking 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 General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with Deformable Shape Tracking. If not, see <http://www.gnu.org/licenses/>.
 */

#include <dest/dest.h>

#include <dest/io/database_io.h>
#include <dest/face/face_detector.h>
#include <dest/util/draw.h>
#include <dest/util/convert.h>
#include <iostream>
#include <opencv2/opencv.hpp>

#include <tclap/CmdLine.h>

int main(int argc, char **argv)
{
    struct {
        dest::core::TrainingParameters trainingParams;
        dest::core::SampleCreationParameters createParams;
        dest::io::ImportParameters importParams;
        std::string db;
        std::string rects;
        std::string output;
        bool showInitialSamples;
    } opts;

    try {
        TCLAP::CmdLine cmd("Train cascade of regressors using a landmark database and initial rectangles.", ' ', "0.9");

        TCLAP::ValueArg<int> numCascadesArg("", "train-num-cascades", "Number of cascades to train.", false, 10, "int", cmd);
        TCLAP::ValueArg<int> numTreesArg("", "train-num-trees", "Number of trees per cascade.", false, 500, "int", cmd);
        TCLAP::ValueArg<int> maxTreeDepthArg("", "train-max-depth", "Maximum tree depth.", false, 5, "int", cmd);
        TCLAP::ValueArg<int> numPixelsArg("", "train-num-pixels", "Number of random pixel coordinates", false, 400, "int", cmd);
        TCLAP::ValueArg<int> numSplitTestsArg("", "train-num-splits", "Number of random split tests at each tree node", false, 20, "int", cmd);
        TCLAP::ValueArg<float> lambdaArg("", "train-lambda", "Prior that favors closer pixel coordinates.", false, 0.1f, "float", cmd);
        TCLAP::ValueArg<float> learnArg("", "train-learn", "Learning rate of each tree.", false, 0.08f, "float", cmd);

        TCLAP::ValueArg<int> numShapesPerImageArg("", "create-num-shapes", "Number of shapes per image to create.", false, 20, "int", cmd);
        TCLAP::ValueArg<int> numTransformsPerShapeArg("", "create-num-transforms", "Number of transform perturbation per shape", false, 10, "int", cmd);

        TCLAP::SwitchArg noCombinationsArg("", "create-no-combinations", "Disable linear combinations of shapes.", cmd, false);

        TCLAP::SwitchArg showInitialSamplesArg("", "show-samples", "Show generated samples", cmd, false);
        TCLAP::ValueArg<std::string> rectsArg("r", "rectangles", "Initial detection rectangles to train on.", true, "rectangles.csv", "string", cmd);
        TCLAP::ValueArg<std::string> outputArg("o", "output", "Trained regressor output.", false, "dest.bin", "string", cmd);
        TCLAP::ValueArg<int> maxImageSizeArg("", "load-max-size", "Maximum size of images in the database", false, 2048, "int", cmd);
        TCLAP::SwitchArg mirrorImageArg("", "load-mirrored", "Additionally mirror each database image, shape and rects.", cmd, false);
        TCLAP::UnlabeledValueArg<std::string> databaseArg("database", "Path to database directory to load", true, "./db", "string", cmd);

        cmd.parse(argc, argv);

        opts.createParams.numShapesPerImage = numShapesPerImageArg.getValue();
        opts.createParams.numTransformPertubationsPerShape = numTransformsPerShapeArg.getValue();
        opts.createParams.useLinearCombinationsOfShapes = !noCombinationsArg.getValue();

        opts.trainingParams.numCascades = numCascadesArg.getValue();
        opts.trainingParams.numTrees = numTreesArg.getValue();
        opts.trainingParams.maxTreeDepth = maxTreeDepthArg.getValue();
        opts.trainingParams.numRandomPixelCoordinates = numPixelsArg.getValue();
        opts.trainingParams.numRandomSplitTestsPerNode = numSplitTestsArg.getValue();
        opts.trainingParams.exponentialLambda = lambdaArg.getValue();
        opts.trainingParams.learningRate = learnArg.getValue();

        opts.importParams.maxImageSideLength = maxImageSizeArg.getValue();
        opts.importParams.generateVerticallyMirrored = mirrorImageArg.getValue();

        opts.showInitialSamples = showInitialSamplesArg.getValue();
        opts.db = databaseArg.getValue();
        opts.rects = rectsArg.getValue();
        opts.output = outputArg.getValue();
    }
    catch (TCLAP::ArgException &e) {
        std::cerr << "Error: " << e.error() << " for arg " << e.argId() << std::endl;
        return -1;
    }

    dest::core::InputData inputs;
    if (!dest::io::importDatabase(opts.db, opts.rects, inputs.images, inputs.shapes, inputs.rects, opts.importParams)) {
        std::cerr << "Failed to load database." << std::endl;
        return -1;
    }

    dest::core::InputData::normalizeShapes(inputs);
    dest::core::InputData validation;
    dest::core::InputData::randomPartition(inputs, validation, 0.01f);

    dest::core::SampleData td(inputs);
    td.params = opts.trainingParams;

    dest::core::SampleData::createTrainingSamples(td, opts.createParams);

    if (opts.showInitialSamples) {
        size_t i = 0;
        bool done = false;
        while (i < td.samples.size() && !done) {
            dest::core::SampleData::Sample &s = td.samples[i];

            cv::Mat tmp = dest::util::drawShape(td.input->images[s.inputIdx], s.shapeToImage * s.estimate.colwise().homogeneous(), cv::Scalar(0, 255, 0));
            dest::core::Rect r = s.shapeToImage * dest::core::unitRectangle().colwise().homogeneous();
            dest::core::Shape target = s.shapeToImage * s.target.colwise().homogeneous();
            dest::util::drawShape(tmp, target, cv::Scalar(255,255,255));
            dest::util::drawRect(tmp, r, cv::Scalar(0,255,0));

            cv::imshow("Samples - Press ESC to skip", tmp);
            if (cv::waitKey() == 27)
                done = true;
            ++i;
        }
    }

    dest::core::Tracker t;
    t.fit(td);

    std::cout << "Saving tracker to " << opts.output << std::endl;
    t.save(opts.output);

    dest::core::SampleData tdValidation(validation);
    dest::core::SampleCreationParameters validationCreateParams;
    validationCreateParams.numShapesPerImage = 1;
    validationCreateParams.numTransformPertubationsPerShape = 1;
    validationCreateParams.useLinearCombinationsOfShapes = false;

    dest::core::SampleData::createTrainingSamples(tdValidation, validationCreateParams);
    for (size_t i = 0; i < tdValidation.samples.size(); ++i) {
        dest::core::SampleData::Sample &s = tdValidation.samples[i];

        dest::core::Shape shape = t.predict(validation.images[s.inputIdx], s.shapeToImage);

        cv::Mat tmp = dest::util::drawShape(validation.images[s.inputIdx], shape, cv::Scalar(0, 255, 0));
        cv::imshow("result", tmp);
        cv::waitKey();
    }

    return 0;
}
<commit_msg>Adding random seed parameter<commit_after>/**
 This file is part of Deformable Shape Tracking (DEST).

 Copyright Christoph Heindl 2015

 Deformable Shape Tracking is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 Deformable Shape Tracking 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 General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with Deformable Shape Tracking. If not, see <http://www.gnu.org/licenses/>.
 */

#include <dest/dest.h>

#include <dest/io/database_io.h>
#include <dest/face/face_detector.h>
#include <dest/util/draw.h>
#include <dest/util/convert.h>
#include <iostream>
#include <opencv2/opencv.hpp>

#include <tclap/CmdLine.h>

int main(int argc, char **argv)
{
    struct {
        dest::core::TrainingParameters trainingParams;
        dest::core::SampleCreationParameters createParams;
        dest::io::ImportParameters importParams;
        std::string db;
        std::string rects;
        std::string output;
        int randomSeed;
        bool showInitialSamples;
    } opts;

    try {
        TCLAP::CmdLine cmd("Train cascade of regressors using a landmark database and initial rectangles.", ' ', "0.9");

        TCLAP::ValueArg<int> numCascadesArg("", "train-num-cascades", "Number of cascades to train.", false, 10, "int", cmd);
        TCLAP::ValueArg<int> numTreesArg("", "train-num-trees", "Number of trees per cascade.", false, 500, "int", cmd);
        TCLAP::ValueArg<int> maxTreeDepthArg("", "train-max-depth", "Maximum tree depth.", false, 5, "int", cmd);
        TCLAP::ValueArg<int> numPixelsArg("", "train-num-pixels", "Number of random pixel coordinates", false, 400, "int", cmd);
        TCLAP::ValueArg<int> numSplitTestsArg("", "train-num-splits", "Number of random split tests at each tree node", false, 20, "int", cmd);
        TCLAP::ValueArg<int> randomSeedArg("", "train-rnd-seed", "Seed for the random number generator", false, 10, "int", cmd);
        TCLAP::ValueArg<float> lambdaArg("", "train-lambda", "Prior that favors closer pixel coordinates.", false, 0.1f, "float", cmd);
        TCLAP::ValueArg<float> learnArg("", "train-learn", "Learning rate of each tree.", false, 0.08f, "float", cmd);

        TCLAP::ValueArg<int> numShapesPerImageArg("", "create-num-shapes", "Number of shapes per image to create.", false, 20, "int", cmd);
        TCLAP::ValueArg<int> numTransformsPerShapeArg("", "create-num-transforms", "Number of transform perturbation per shape", false, 10, "int", cmd);

        TCLAP::SwitchArg noCombinationsArg("", "create-no-combinations", "Disable linear combinations of shapes.", cmd, false);

        TCLAP::SwitchArg showInitialSamplesArg("", "show-samples", "Show generated samples", cmd, false);
        TCLAP::ValueArg<std::string> rectsArg("r", "rectangles", "Initial detection rectangles to train on.", true, "rectangles.csv", "string", cmd);
        TCLAP::ValueArg<std::string> outputArg("o", "output", "Trained regressor output.", false, "dest.bin", "string", cmd);
        TCLAP::ValueArg<int> maxImageSizeArg("", "load-max-size", "Maximum size of images in the database", false, 2048, "int", cmd);
        TCLAP::SwitchArg mirrorImageArg("", "load-mirrored", "Additionally mirror each database image, shape and rects.", cmd, false);
        TCLAP::UnlabeledValueArg<std::string> databaseArg("database", "Path to database directory to load", true, "./db", "string", cmd);

        cmd.parse(argc, argv);

        opts.createParams.numShapesPerImage = numShapesPerImageArg.getValue();
        opts.createParams.numTransformPertubationsPerShape = numTransformsPerShapeArg.getValue();
        opts.createParams.useLinearCombinationsOfShapes = !noCombinationsArg.getValue();

        opts.trainingParams.numCascades = numCascadesArg.getValue();
        opts.trainingParams.numTrees = numTreesArg.getValue();
        opts.trainingParams.maxTreeDepth = maxTreeDepthArg.getValue();
        opts.trainingParams.numRandomPixelCoordinates = numPixelsArg.getValue();
        opts.trainingParams.numRandomSplitTestsPerNode = numSplitTestsArg.getValue();
        opts.trainingParams.exponentialLambda = lambdaArg.getValue();
        opts.trainingParams.learningRate = learnArg.getValue();
        opts.randomSeed = randomSeedArg.getValue();

        opts.importParams.maxImageSideLength = maxImageSizeArg.getValue();
        opts.importParams.generateVerticallyMirrored = mirrorImageArg.getValue();

        opts.showInitialSamples = showInitialSamplesArg.getValue();
        opts.db = databaseArg.getValue();
        opts.rects = rectsArg.getValue();
        opts.output = outputArg.getValue();
    }
    catch (TCLAP::ArgException &e) {
        std::cerr << "Error: " << e.error() << " for arg " << e.argId() << std::endl;
        return -1;
    }

    dest::core::InputData inputs;
    inputs.rnd.seed(static_cast<unsigned int>(opts.randomSeed));
    if (!dest::io::importDatabase(opts.db, opts.rects, inputs.images, inputs.shapes, inputs.rects, opts.importParams)) {
        std::cerr << "Failed to load database." << std::endl;
        return -1;
    }

    dest::core::InputData::normalizeShapes(inputs);
    dest::core::InputData validation;
    dest::core::InputData::randomPartition(inputs, validation, 0.01f);

    dest::core::SampleData td(inputs);
    td.params = opts.trainingParams;

    dest::core::SampleData::createTrainingSamples(td, opts.createParams);

    if (opts.showInitialSamples) {
        size_t i = 0;
        bool done = false;
        while (i < td.samples.size() && !done) {
            dest::core::SampleData::Sample &s = td.samples[i];

            cv::Mat tmp = dest::util::drawShape(td.input->images[s.inputIdx], s.shapeToImage * s.estimate.colwise().homogeneous(), cv::Scalar(0, 255, 0));
            dest::core::Rect r = s.shapeToImage * dest::core::unitRectangle().colwise().homogeneous();
            dest::core::Shape target = s.shapeToImage * s.target.colwise().homogeneous();
            dest::util::drawShape(tmp, target, cv::Scalar(255,255,255));
            dest::util::drawRect(tmp, r, cv::Scalar(0,255,0));

            cv::imshow("Samples - Press ESC to skip", tmp);
            if (cv::waitKey() == 27)
                done = true;
            ++i;
        }
    }

    dest::core::Tracker t;
    t.fit(td);

    std::cout << "Saving tracker to " << opts.output << std::endl;
    t.save(opts.output);

    dest::core::SampleData tdValidation(validation);
    dest::core::SampleCreationParameters validationCreateParams;
    validationCreateParams.numShapesPerImage = 1;
    validationCreateParams.numTransformPertubationsPerShape = 1;
    validationCreateParams.useLinearCombinationsOfShapes = false;

    dest::core::SampleData::createTrainingSamples(tdValidation, validationCreateParams);
    for (size_t i = 0; i < tdValidation.samples.size(); ++i) {
        dest::core::SampleData::Sample &s = tdValidation.samples[i];

        dest::core::Shape shape = t.predict(validation.images[s.inputIdx], s.shapeToImage);

        cv::Mat tmp = dest::util::drawShape(validation.images[s.inputIdx], shape, cv::Scalar(0, 255, 0));
        cv::imshow("result", tmp);
        cv::waitKey();
    }

    return 0;
}
<|endoftext|>


<commit_before>/********************************************************************* *\
 * INTEL CORPORATION PROPRIETARY INFORMATION
 * This software is supplied under the terms of a license agreement or
 * nondisclosure agreement with Intel Corporation and may not be copied
 * or disclosed except in accordance with the terms of that agreement.
 * Copyright (C) 2014 Intel Corporation. All Rights Reserved.
 ********************************************************************* */

#include "QOSPRayWindow.h"

QOSPRayWindow::QOSPRayWindow(OSPRenderer renderer) : frameCount_(0), renderingEnabled_(false), rotationRate_(0.f), benchmarkWarmUpFrames_(0), benchmarkFrames_(0), frameBuffer_(NULL), renderer_(NULL), camera_(NULL)
{
    // assign renderer
    if(!renderer)
        throw std::runtime_error("QOSPRayWindow: must be constructed with an existing renderer");

    renderer_ = renderer;

    // setup camera
    camera_ = ospNewCamera("perspective");

    if(!camera_)
        throw std::runtime_error("QOSPRayWindow: could not create camera type 'perspective'");

    ospCommit(camera_);

    ospSetParam(renderer_, "camera", camera_);
}

QOSPRayWindow::~QOSPRayWindow()
{
    // free the frame buffer and camera
    // we don't own the renderer!
    if(frameBuffer_)
    {
        ospFreeFrameBuffer(frameBuffer_);
    }

    if(camera_)
    {
        ospRelease(camera_);
    }
}

void QOSPRayWindow::setRenderingEnabled(bool renderingEnabled)
{
    renderingEnabled_ = renderingEnabled;

    // trigger render if true
    if(renderingEnabled_ == true)
    {
        updateGL();
    }
}

void QOSPRayWindow::setRotationRate(float rotationRate)
{
    rotationRate_ = rotationRate;
}

void QOSPRayWindow::setBenchmarkParameters(int benchmarkWarmUpFrames, int benchmarkFrames)
{
    benchmarkWarmUpFrames_ = benchmarkWarmUpFrames;
    benchmarkFrames_ = benchmarkFrames;
}

void QOSPRayWindow::setWorldBounds(const osp::box3f &worldBounds)
{
    worldBounds_ = worldBounds;

    // set viewport look at point to center of world bounds
    viewport_.at = center(worldBounds_);

    // set viewport from point relative to center of world bounds
    viewport_.from = viewport_.at - 2.f * viewport_.frame.l.vy;

    updateGL();
}

void QOSPRayWindow::paintGL()
{
    if(!renderingEnabled_ || !frameBuffer_ || !renderer_)
    {
        return;
    }

    // if we're benchmarking and we've completed the required number of warm-up frames, start the timer
    if(benchmarkFrames_ > 0 && frameCount_ == benchmarkWarmUpFrames_)
    {
        std::cout << "starting benchmark timer" << std::endl;
        benchmarkTimer_.start();
    }

    // update OSPRay camera if viewport has been modified
    if(viewport_.modified)
    {
        ospSetVec3f(camera_,"pos" ,viewport_.from);
        ospSetVec3f(camera_,"dir" ,viewport_.at - viewport_.from);
        ospSetVec3f(camera_,"up", viewport_.up);
        ospSetf(camera_,"aspect", viewport_.aspect);
        ospSetf(camera_,"fovy", viewport_.fovY);

        ospCommit(camera_);

        viewport_.modified = false;
    }

    ospRenderFrame(frameBuffer_, renderer_);

    uint32 * mappedFrameBuffer = (unsigned int *)ospMapFrameBuffer(frameBuffer_);

    glDrawPixels(windowSize_.x, windowSize_.y, GL_RGBA, GL_UNSIGNED_BYTE, mappedFrameBuffer);

    ospUnmapFrameBuffer(mappedFrameBuffer, frameBuffer_);

    // automatic rotation
    if(rotationRate_ != 0.f)
    {
        rotateCenter(rotationRate_, 0.f);
    }

    // increment frame counter
    frameCount_++;

    // quit if we're benchmarking and have exceeded the needed number of frames
    if(benchmarkFrames_ > 0 && frameCount_ >= benchmarkWarmUpFrames_ + benchmarkFrames_)
    {
        float elapsedSeconds = float(benchmarkTimer_.elapsed()) / 1000.f;

        std::cout << "benchmark: " << elapsedSeconds << " elapsed seconds ==> " << float(benchmarkFrames_) / elapsedSeconds << " fps" << std::endl;

        QCoreApplication::quit();
    }

    // force continuous rendering if we have automatic rotation or benchmarking enabled
    if(rotationRate_ != 0.f || benchmarkFrames_ > 0)
    {
        update();
    }
}

void QOSPRayWindow::resizeGL(int width, int height)
{
    windowSize_ = osp::vec2i(width, height);

    // reallocate OSPRay framebuffer for new size
    if(frameBuffer_)
    {
        ospFreeFrameBuffer(frameBuffer_);
    }

    frameBuffer_ = ospNewFrameBuffer(windowSize_, OSP_RGBA_I8);

    // update viewport aspect ratio
    viewport_.aspect = float(width) / float(height);
    viewport_.modified = true;

    // update OpenGL viewport and force redraw
    glViewport(0, 0, width, height);
    updateGL();
}

void QOSPRayWindow::mousePressEvent(QMouseEvent * event)
{
    lastMousePosition_ = event->pos();
}

void QOSPRayWindow::mouseReleaseEvent(QMouseEvent * event)
{
    lastMousePosition_ = event->pos();
}

void QOSPRayWindow::mouseMoveEvent(QMouseEvent * event)
{
    int dx = event->x() - lastMousePosition_.x();
    int dy = event->y() - lastMousePosition_.y();

    if(event->buttons() & Qt::LeftButton)
    {
        // camera rotation about center point
        const float rotationSpeed = 0.003f;

        float du = dx * rotationSpeed;
        float dv = dy * rotationSpeed;

        rotateCenter(du, dv);
    }
    else if(event->buttons() & Qt::RightButton)
    {
        // camera distance from center point
        const float motionSpeed = 0.012f;

        float forward = dy * motionSpeed;
        float oldDistance = length(viewport_.at - viewport_.from);
        float newDistance = oldDistance - forward;

        if(newDistance < 1e-3f)
            return;

        viewport_.from = viewport_.at - newDistance * viewport_.frame.l.vy;
        viewport_.frame.p = viewport_.from;

        viewport_.modified = true;
    }

    lastMousePosition_ = event->pos();

    updateGL();
}

void QOSPRayWindow::rotateCenter(float du, float dv)
{
    const osp::vec3f pivot = center(worldBounds_);

    osp::affine3f xfm = osp::affine3f::translate(pivot)
                      * osp::affine3f::rotate(viewport_.frame.l.vx, -dv)
                      * osp::affine3f::rotate(viewport_.frame.l.vz, -du)
                      * osp::affine3f::translate(-pivot);

    viewport_.frame = xfm * viewport_.frame;
    viewport_.from  = xfmPoint(xfm, viewport_.from);
    viewport_.at    = xfmPoint(xfm, viewport_.at);
    viewport_.snapUp();

    viewport_.modified = true;
}
<commit_msg>change default camera distance.<commit_after>/********************************************************************* *\
 * INTEL CORPORATION PROPRIETARY INFORMATION
 * This software is supplied under the terms of a license agreement or
 * nondisclosure agreement with Intel Corporation and may not be copied
 * or disclosed except in accordance with the terms of that agreement.
 * Copyright (C) 2014 Intel Corporation. All Rights Reserved.
 ********************************************************************* */

#include "QOSPRayWindow.h"

QOSPRayWindow::QOSPRayWindow(OSPRenderer renderer) : frameCount_(0), renderingEnabled_(false), rotationRate_(0.f), benchmarkWarmUpFrames_(0), benchmarkFrames_(0), frameBuffer_(NULL), renderer_(NULL), camera_(NULL)
{
    // assign renderer
    if(!renderer)
        throw std::runtime_error("QOSPRayWindow: must be constructed with an existing renderer");

    renderer_ = renderer;

    // setup camera
    camera_ = ospNewCamera("perspective");

    if(!camera_)
        throw std::runtime_error("QOSPRayWindow: could not create camera type 'perspective'");

    ospCommit(camera_);

    ospSetParam(renderer_, "camera", camera_);
}

QOSPRayWindow::~QOSPRayWindow()
{
    // free the frame buffer and camera
    // we don't own the renderer!
    if(frameBuffer_)
    {
        ospFreeFrameBuffer(frameBuffer_);
    }

    if(camera_)
    {
        ospRelease(camera_);
    }
}

void QOSPRayWindow::setRenderingEnabled(bool renderingEnabled)
{
    renderingEnabled_ = renderingEnabled;

    // trigger render if true
    if(renderingEnabled_ == true)
    {
        updateGL();
    }
}

void QOSPRayWindow::setRotationRate(float rotationRate)
{
    rotationRate_ = rotationRate;
}

void QOSPRayWindow::setBenchmarkParameters(int benchmarkWarmUpFrames, int benchmarkFrames)
{
    benchmarkWarmUpFrames_ = benchmarkWarmUpFrames;
    benchmarkFrames_ = benchmarkFrames;
}

void QOSPRayWindow::setWorldBounds(const osp::box3f &worldBounds)
{
    worldBounds_ = worldBounds;

    // set viewport look at point to center of world bounds
    viewport_.at = center(worldBounds_);

    // set viewport from point relative to center of world bounds
    viewport_.from = viewport_.at - 1.5f * viewport_.frame.l.vy;

    updateGL();
}

void QOSPRayWindow::paintGL()
{
    if(!renderingEnabled_ || !frameBuffer_ || !renderer_)
    {
        return;
    }

    // if we're benchmarking and we've completed the required number of warm-up frames, start the timer
    if(benchmarkFrames_ > 0 && frameCount_ == benchmarkWarmUpFrames_)
    {
        std::cout << "starting benchmark timer" << std::endl;
        benchmarkTimer_.start();
    }

    // update OSPRay camera if viewport has been modified
    if(viewport_.modified)
    {
        ospSetVec3f(camera_,"pos" ,viewport_.from);
        ospSetVec3f(camera_,"dir" ,viewport_.at - viewport_.from);
        ospSetVec3f(camera_,"up", viewport_.up);
        ospSetf(camera_,"aspect", viewport_.aspect);
        ospSetf(camera_,"fovy", viewport_.fovY);

        ospCommit(camera_);

        viewport_.modified = false;
    }

    ospRenderFrame(frameBuffer_, renderer_);

    uint32 * mappedFrameBuffer = (unsigned int *)ospMapFrameBuffer(frameBuffer_);

    glDrawPixels(windowSize_.x, windowSize_.y, GL_RGBA, GL_UNSIGNED_BYTE, mappedFrameBuffer);

    ospUnmapFrameBuffer(mappedFrameBuffer, frameBuffer_);

    // automatic rotation
    if(rotationRate_ != 0.f)
    {
        rotateCenter(rotationRate_, 0.f);
    }

    // increment frame counter
    frameCount_++;

    // quit if we're benchmarking and have exceeded the needed number of frames
    if(benchmarkFrames_ > 0 && frameCount_ >= benchmarkWarmUpFrames_ + benchmarkFrames_)
    {
        float elapsedSeconds = float(benchmarkTimer_.elapsed()) / 1000.f;

        std::cout << "benchmark: " << elapsedSeconds << " elapsed seconds ==> " << float(benchmarkFrames_) / elapsedSeconds << " fps" << std::endl;

        QCoreApplication::quit();
    }

    // force continuous rendering if we have automatic rotation or benchmarking enabled
    if(rotationRate_ != 0.f || benchmarkFrames_ > 0)
    {
        update();
    }
}

void QOSPRayWindow::resizeGL(int width, int height)
{
    windowSize_ = osp::vec2i(width, height);

    // reallocate OSPRay framebuffer for new size
    if(frameBuffer_)
    {
        ospFreeFrameBuffer(frameBuffer_);
    }

    frameBuffer_ = ospNewFrameBuffer(windowSize_, OSP_RGBA_I8);

    // update viewport aspect ratio
    viewport_.aspect = float(width) / float(height);
    viewport_.modified = true;

    // update OpenGL viewport and force redraw
    glViewport(0, 0, width, height);
    updateGL();
}

void QOSPRayWindow::mousePressEvent(QMouseEvent * event)
{
    lastMousePosition_ = event->pos();
}

void QOSPRayWindow::mouseReleaseEvent(QMouseEvent * event)
{
    lastMousePosition_ = event->pos();
}

void QOSPRayWindow::mouseMoveEvent(QMouseEvent * event)
{
    int dx = event->x() - lastMousePosition_.x();
    int dy = event->y() - lastMousePosition_.y();

    if(event->buttons() & Qt::LeftButton)
    {
        // camera rotation about center point
        const float rotationSpeed = 0.003f;

        float du = dx * rotationSpeed;
        float dv = dy * rotationSpeed;

        rotateCenter(du, dv);
    }
    else if(event->buttons() & Qt::RightButton)
    {
        // camera distance from center point
        const float motionSpeed = 0.012f;

        float forward = dy * motionSpeed;
        float oldDistance = length(viewport_.at - viewport_.from);
        float newDistance = oldDistance - forward;

        if(newDistance < 1e-3f)
            return;

        viewport_.from = viewport_.at - newDistance * viewport_.frame.l.vy;
        viewport_.frame.p = viewport_.from;

        viewport_.modified = true;
    }

    lastMousePosition_ = event->pos();

    updateGL();
}

void QOSPRayWindow::rotateCenter(float du, float dv)
{
    const osp::vec3f pivot = center(worldBounds_);

    osp::affine3f xfm = osp::affine3f::translate(pivot)
                      * osp::affine3f::rotate(viewport_.frame.l.vx, -dv)
                      * osp::affine3f::rotate(viewport_.frame.l.vz, -du)
                      * osp::affine3f::translate(-pivot);

    viewport_.frame = xfm * viewport_.frame;
    viewport_.from  = xfmPoint(xfm, viewport_.from);
    viewport_.at    = xfmPoint(xfm, viewport_.at);
    viewport_.snapUp();

    viewport_.modified = true;
}
<|endoftext|>


<commit_before><commit_msg>lossened cut for pileup<commit_after><|endoftext|>


<commit_before>AliAnalysisTask *AddTaskTRDPIDTree(Int_t trigger=0, Int_t system=0){
  //get the current analysis manager
  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    Error("AddTask_pachmay_PIDTRDTree", "No analysis manager found.");
    return 0;
  }

  //========= Add task to the ANALYSIS manager =====
  AliTRDPIDTree *task = new AliTRDPIDTree("TRDPIDTree");
  if(trigger==0) task->SelectCollisionCandidates(AliVEvent::kMB | AliVEvent::kINT1 | AliVEvent::kINT5 | AliVEvent::kINT7 | AliVEvent::kINT8);
  if(trigger==1) task->SelectCollisionCandidates(AliVEvent::kMB | AliVEvent::kINT7 | AliVEvent::kINT8);
  if(trigger==2) task->SelectCollisionCandidates(AliVEvent::kMB | AliVEvent::kCentral | AliVEvent::kSemiCentral);
  if(trigger==3) task->SelectCollisionCandidates(AliVEvent::kTRD);
  if(system==1) task->SetppAnalysis();
  if(system==2) task->SetpPbAnalysis();
  if(system==3) task->SetPbPbAnalysis();
//  task->SetPbPbAnalysis();
  mgr->AddTask(task);

  //================================================
  //              data containers
  //================================================
  //            find input container
  //below the trunk version
  AliAnalysisDataContainer *cinput  = mgr->GetCommonInputContainer();

  //dumm output container
  AliAnalysisDataContainer *coutput1 =
      mgr->CreateContainer("TRDPIDTree_tree",
                           TTree::Class(),
                           AliAnalysisManager::kOutputContainer,
                           "TRDPIDTree_tree.root");
  AliAnalysisDataContainer *coutput2 =
      mgr->CreateContainer("TRDPIDTree_list",
                           TList::Class(),
                           AliAnalysisManager::kOutputContainer,
                           "TRDPIDTree_hists.root");

  //connect containers
  mgr->ConnectInput(task,  0, cinput );
  mgr->ConnectOutput(task,  1, coutput1);
  mgr->ConnectOutput(task,  2, coutput2);

  return task;
}
<commit_msg>Files become a name, that depends on the used trigger<commit_after>AliAnalysisTask *AddTaskTRDPIDTree(Int_t trigger=0, Int_t system=0){
  //get the current analysis manager
  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    Error("AddTask_pachmay_PIDTRDTree", "No analysis manager found.");
    return 0;
  }

  //========= Add task to the ANALYSIS manager =====
  AliTRDPIDTree *task = new AliTRDPIDTree("TRDPIDTree");
  if(trigger==0) task->SelectCollisionCandidates(AliVEvent::kMB | AliVEvent::kINT1 | AliVEvent::kINT5 | AliVEvent::kINT7 | AliVEvent::kINT8);
  if(trigger==1) task->SelectCollisionCandidates(AliVEvent::kMB | AliVEvent::kINT7 | AliVEvent::kINT8);
  if(trigger==2) task->SelectCollisionCandidates(AliVEvent::kMB | AliVEvent::kCentral | AliVEvent::kSemiCentral);
  if(trigger==3) task->SelectCollisionCandidates(AliVEvent::kTRD);
  if(system==1) task->SetppAnalysis();
  if(system==2) task->SetpPbAnalysis();
  if(system==3) task->SetPbPbAnalysis();
//  task->SetPbPbAnalysis();
  mgr->AddTask(task);

  //================================================
   //              data containers
   //================================================
   //            find input container
   //below the trunk version
   AliAnalysisDataContainer *cinput  = mgr->GetCommonInputContainer();

   //dumm output container
   AliAnalysisDataContainer *coutput1 =
       mgr->CreateContainer("TRDPIDTree_tree",
                            TTree::Class(),
                            AliAnalysisManager::kOutputContainer,
                            Form("TRDPIDTree_tree_T%i.root",trigger));
   AliAnalysisDataContainer *coutput2 =
       mgr->CreateContainer("TRDPIDTree_list",
                            TList::Class(),
                            AliAnalysisManager::kOutputContainer,
                            Form("TRDPIDTree_hists_T%i.root",trigger));

  //connect containers
  mgr->ConnectInput(task,  0, cinput );
  mgr->ConnectOutput(task,  1, coutput1);
  mgr->ConnectOutput(task,  2, coutput2);

  return task;
}
<|endoftext|>


<commit_before>#ifndef  BOOST_ARCHIVE_BASIC_SERIALIZER_HPP
#define BOOST_ARCHIVE_BASIC_SERIALIZER_HPP

// MS compatible compilers support #pragma once
#if defined(_MSC_VER)
# pragma once
#endif

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// basic_serializer.hpp: extenstion of type_info required for serialization.

// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

//  See http://www.boost.org for updates, documentation, and revision history.

#include <boost/assert.hpp>
#include <cstddef> // NULL

#include <boost/noncopyable.hpp>
#include <boost/config.hpp>
#include <boost/serialization/extended_type_info.hpp>

#ifdef BOOST_MSVC
#  pragma warning(push)
#  pragma warning(disable : 4511 4512)
#endif

namespace boost {
namespace archive {
namespace detail {

class basic_serializer :
    private boost::noncopyable
{
    const boost::serialization::extended_type_info * m_eti;
protected:
    explicit basic_serializer(
        const boost::serialization::extended_type_info & eti
    ) :
        m_eti(& eti)
    {
        BOOST_ASSERT(NULL != & eti);
    }
public:
    inline bool
    operator<(const basic_serializer & rhs) const {
        // can't compare address since there can be multiple eti records
        // for the same type in different execution modules (that is, DLLS)
        // leave this here as a reminder not to do this!
        // return & lhs.get_eti() < & rhs.get_eti();
        return get_eti() < rhs.get_eti();
    }
    const char * get_debug_info() const {
        return m_eti->get_debug_info();
    }
    const boost::serialization::extended_type_info & get_eti() const {
        return * m_eti;
    }
};

class basic_serializer_arg : public basic_serializer {
public:
    basic_serializer_arg(const serialization::extended_type_info & eti) :
        basic_serializer(eti)
    {}
};

} // namespace detail
} // namespace archive
} // namespace boost

#ifdef BOOST_MSVC
#pragma warning(pop)
#endif

#endif // BOOST_ARCHIVE_BASIC_SERIALIZER_HPP
<commit_msg>Disable an assertion in BOOST that GCC 6.x warns about.<commit_after>#ifndef  BOOST_ARCHIVE_BASIC_SERIALIZER_HPP
#define BOOST_ARCHIVE_BASIC_SERIALIZER_HPP

// MS compatible compilers support #pragma once
#if defined(_MSC_VER)
# pragma once
#endif

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// basic_serializer.hpp: extenstion of type_info required for serialization.

// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

//  See http://www.boost.org for updates, documentation, and revision history.

#include <boost/assert.hpp>
#include <cstddef> // NULL

#include <boost/noncopyable.hpp>
#include <boost/config.hpp>
#include <boost/serialization/extended_type_info.hpp>

#ifdef BOOST_MSVC
#  pragma warning(push)
#  pragma warning(disable : 4511 4512)
#endif

namespace boost {
namespace archive {
namespace detail {

class basic_serializer :
    private boost::noncopyable
{
    const boost::serialization::extended_type_info * m_eti;
protected:
    explicit basic_serializer(
        const boost::serialization::extended_type_info & eti
    ) :
        m_eti(& eti)
    {
    }
public:
    inline bool
    operator<(const basic_serializer & rhs) const {
        // can't compare address since there can be multiple eti records
        // for the same type in different execution modules (that is, DLLS)
        // leave this here as a reminder not to do this!
        // return & lhs.get_eti() < & rhs.get_eti();
        return get_eti() < rhs.get_eti();
    }
    const char * get_debug_info() const {
        return m_eti->get_debug_info();
    }
    const boost::serialization::extended_type_info & get_eti() const {
        return * m_eti;
    }
};

class basic_serializer_arg : public basic_serializer {
public:
    basic_serializer_arg(const serialization::extended_type_info & eti) :
        basic_serializer(eti)
    {}
};

} // namespace detail
} // namespace archive
} // namespace boost

#ifdef BOOST_MSVC
#pragma warning(pop)
#endif

#endif // BOOST_ARCHIVE_BASIC_SERIALIZER_HPP
<|endoftext|>


<commit_before>/****************************************************************************
 **
 ** Copyright (C) Qxt Foundation. Some rights reserved.
 **
 ** This file is part of the QxtGui module of the Qxt library.
 **
 ** This library is free software; you can redistribute it and/or modify it
 ** under the terms of the Common Public License, version 1.0, as published
 ** by IBM, and/or under the terms of the GNU Lesser General Public License,
 ** version 2.1, as published by the Free Software Foundation.
 **
 ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
 ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
 ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
 ** FITNESS FOR A PARTICULAR PURPOSE.
 **
 ** You should have received a copy of the CPL and the LGPL along with this
 ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files
 ** included with the source distribution for more information.
 ** If you did not receive a copy of the licenses, contact the Qxt Foundation.
 **
 ** <http://libqxt.org>  <foundation@libqxt.org>
 **
 ****************************************************************************/

/*!
    \class QxtJSON
    \inmodule QxtCore
    \brief The QxtJSON class implements serializing/deserializing from/to JSON

    implements JSON (JavaScript Object Notation) is a lightweight data-interchange format.
    see http://www.json.org/

    \section2 Type Conversion
    \table 80%
    \header \o JSON Type \o Qt Type
    \row  \o object \o QVariantMap/QVariantHash
    \row  \o array \o QVariantList/QStringList
    \row  \o string \o QString
    \row  \o number \o int,double
    \row  \o true \o bool
    \row  \o false \o bool
    \row  \o null \o QVariant()

    \endtable

*/

#include "qxtjson.h"
#include <QVariant>
#include <QDebug>
#include <QTextStream>
#include <QStringList>

QString QxtJSON::stringify(QVariant v){
    if (v.isNull()){
        return "null";
    }
    int t = v.type();
    if (t == QVariant::String){
        return "\""+v.toString()+"\"";
    }
    else if (t == QVariant::Bool){
        return v.toBool()?"true":"false";
    }else if (t ==  QVariant::Int){
        return QString::number(v.toInt());
    }else if (t ==  QVariant::Double){
        return QString::number(v.toDouble());
    }else if (t == QVariant::Map){
        QString r="{";
        QMap<QString, QVariant> map = v.toMap();
        QMapIterator<QString, QVariant> i(map);
        while (i.hasNext()){
            i.next();
            r+="\""+i.key()+"\":"+stringify(i.value())+",";
        }
        r.chop(1);
        r+="}";
        return r;
    }else if (t == QVariant::Hash){
        QString r="{";
        QHash<QString, QVariant> map = v.toHash();
        QHashIterator<QString, QVariant> i(map);
        while (i.hasNext()){
            i.next();
            r+="\""+i.key()+"\":"+stringify(i.value())+",";
        }
        r.chop(1);
        r+="}";
        return r;
    }else if (t == QVariant::StringList){
        QString r="[";
        QStringList l = v.toStringList();
        foreach(QString i, l){
            r+="\""+i+"\",";
        }
        r.chop(1);
        r+="]";
        return r;
    }else if (t == QVariant::List){
        QString r="[";
        QVariantList l = v.toList();
        foreach(QVariant i, l){
            r+=stringify(i)+",";
        }
        r.chop(1);
        r+="]";
        return r;
    }

    return QString();
}

static QVariant parseValue(QTextStream &s,bool & error);
static QVariantMap parseObject (QTextStream & s,bool & error);
static QVariantList parseArray (QTextStream & s,bool & error);
static QString parseString (QTextStream & s,bool & error);
static QVariant parseLiteral (QTextStream & s,bool & error);

QVariant QxtJSON::parse(QString string){
    QTextStream s(&string);
    bool error=false;
    return parseValue(s,error);
}

static QVariant parseValue(QTextStream &s,bool & error){
    s.skipWhiteSpace();
    QChar c;
    while(!s.atEnd() && !error){
        s>>c;
        if (c=='{'){
            return parseObject(s,error);
        } else if (c=='"'){
            return parseString(s,error);
        } else if (c=='['){
            return parseArray(s,error);
        } else {
            return parseLiteral(s,error);
        }
        s.skipWhiteSpace();
    }
    return QVariant();
}

static QVariantMap parseObject (QTextStream & s,bool & error){
    s.skipWhiteSpace();
    QVariantMap o;
    QString key;
    bool atVal=false;

    QChar c;
    while(!s.atEnd() && !error){
        s>>c;
        if (c=='}'){
            return o;
        } else if (c==',' || c==':'){
            /*
              They're syntactic sugar, since key:value come in bundles anyway
              Could check for error handling. too lazy.
            */
        } else if (c=='"'){
            if(atVal){
                o[key]=parseString(s,error);
                atVal=false;
            }else{
                key=parseString(s,error);
                atVal=true;
            }
        } else if (c=='['){
            if(atVal){
                o[key]=parseArray(s,error);
                atVal=false;
            }else{
                error=true;
                return QVariantMap();
            }
        } else if (c=='{'){
            if(atVal){
                o[key]=parseObject(s,error);
                atVal=false;
            }else{
                error=true;
                return QVariantMap();
            }
        } else {
            if(atVal){
                o[key]=parseLiteral(s,error);
                atVal=false;
            }else{
                error=true;
                return QVariantMap();
            }
        }
        s.skipWhiteSpace();
    }
    error=true;
    return QVariantMap();
}
static QVariantList parseArray (QTextStream & s,bool & error){
    s.skipWhiteSpace();
    QVariantList l;
    QChar c;
    while(!s.atEnd() && !error){
        s>>c;
        if (c==']'){
            return l;
        } else if (c==','){
        } else if (c=='"'){
            l.append(parseString(s,error));
        } else if (c=='['){
            l.append(parseArray(s,error));
        } else if (c=='{'){
            l.append(parseObject(s,error));
        } else {
            l.append(parseLiteral(s,error));
        }
        s.skipWhiteSpace();
    }
    error=true;
    return QVariantList();
}
static QString parseString (QTextStream & s,bool & error){
    QString str;
    QChar c;
    while(!s.atEnd() && !error){
        s>>c;
        if(c=='"'){
            return str;
        }else if(c=='\\'){
            s>>c;
            if(c=='b'){
                str.append('\b');
            }else if(c=='f'){
                str.append('\f');
            }else if(c=='n'){
                str.append('\n');
            }else if(c=='r'){
                str.append('\r');
            }else if(c=='t'){
                str.append('\t');
            }else if(c=='f'){
                str.append('\f');
            }else if(c=='u'){
                short u;
                s>>u;
                str.append(QChar(u));
            }else{
                str.append(c);
            }
        }else{
            str.append(c);
        }
    }
    error=true;
    return QString();
}
static QVariant parseLiteral (QTextStream & s,bool & error){
    s.seek(s.pos()-1);
    QChar c;
    while(!s.atEnd() && !error){
        s>>c;
        if (c=='t'){
            s>>c;//r
            s>>c;//u
            s>>c;//e
            return true;
        } else if (c=='f'){
            s>>c;//a
            s>>c;//l
            s>>c;//s
            s>>c;//e
            return false;
        }else if (c=='n'){
            s>>c;//u
            s>>c;//l
            s>>c;//l
            return QVariant();
        }else if (c=='-' || c.isDigit()){
            QString n;
            while(!s.atEnd() && !error && !c.isSpace()){
                n.append(c);
                s>>c;
            }
            if(n.contains('.')){
                return n.toDouble();
            }else{
                return n.toInt();
            }
        }
    }
    error=true;
    return QVariant();
}
<commit_msg>fixed bug in literal parsing<commit_after>/****************************************************************************
 **
 ** Copyright (C) Qxt Foundation. Some rights reserved.
 **
 ** This file is part of the QxtGui module of the Qxt library.
 **
 ** This library is free software; you can redistribute it and/or modify it
 ** under the terms of the Common Public License, version 1.0, as published
 ** by IBM, and/or under the terms of the GNU Lesser General Public License,
 ** version 2.1, as published by the Free Software Foundation.
 **
 ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
 ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
 ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
 ** FITNESS FOR A PARTICULAR PURPOSE.
 **
 ** You should have received a copy of the CPL and the LGPL along with this
 ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files
 ** included with the source distribution for more information.
 ** If you did not receive a copy of the licenses, contact the Qxt Foundation.
 **
 ** <http://libqxt.org>  <foundation@libqxt.org>
 **
 ****************************************************************************/

/*!
    \class QxtJSON
    \inmodule QxtCore
    \brief The QxtJSON class implements serializing/deserializing from/to JSON

    implements JSON (JavaScript Object Notation) is a lightweight data-interchange format.
    see http://www.json.org/

    \section2 Type Conversion
    \table 80%
    \header \o JSON Type \o Qt Type
    \row  \o object \o QVariantMap/QVariantHash
    \row  \o array \o QVariantList/QStringList
    \row  \o string \o QString
    \row  \o number \o int,double
    \row  \o true \o bool
    \row  \o false \o bool
    \row  \o null \o QVariant()

    \endtable

*/

#include "qxtjson.h"
#include <QVariant>
#include <QDebug>
#include <QTextStream>
#include <QStringList>

QString QxtJSON::stringify(QVariant v){
    if (v.isNull()){
        return "null";
    }
    int t = v.type();
    if (t == QVariant::String){
        return "\""+v.toString()+"\"";
    }
    else if (t == QVariant::Bool){
        return v.toBool()?"true":"false";
    }else if (t ==  QVariant::Int){
        return QString::number(v.toInt());
    }else if (t ==  QVariant::Double){
        return QString::number(v.toDouble());
    }else if (t == QVariant::Map){
        QString r="{";
        QMap<QString, QVariant> map = v.toMap();
        QMapIterator<QString, QVariant> i(map);
        while (i.hasNext()){
            i.next();
            r+="\""+i.key()+"\":"+stringify(i.value())+",";
        }
        r.chop(1);
        r+="}";
        return r;
    }else if (t == QVariant::Hash){
        QString r="{";
        QHash<QString, QVariant> map = v.toHash();
        QHashIterator<QString, QVariant> i(map);
        while (i.hasNext()){
            i.next();
            r+="\""+i.key()+"\":"+stringify(i.value())+",";
        }
        r.chop(1);
        r+="}";
        return r;
    }else if (t == QVariant::StringList){
        QString r="[";
        QStringList l = v.toStringList();
        foreach(QString i, l){
            r+="\""+i+"\",";
        }
        r.chop(1);
        r+="]";
        return r;
    }else if (t == QVariant::List){
        QString r="[";
        QVariantList l = v.toList();
        foreach(QVariant i, l){
            r+=stringify(i)+",";
        }
        r.chop(1);
        r+="]";
        return r;
    }

    return QString();
}

static QVariant parseValue(QTextStream &s,bool & error);
static QVariantMap parseObject (QTextStream & s,bool & error);
static QVariantList parseArray (QTextStream & s,bool & error);
static QString parseString (QTextStream & s,bool & error);
static QVariant parseLiteral (QTextStream & s,bool & error);

QVariant QxtJSON::parse(QString string){
    QTextStream s(&string);
    bool error=false;
    QVariant v=parseValue(s,error);
    if(error)
        return QVariant();
    return v;
}

static QVariant parseValue(QTextStream &s,bool & error){
    s.skipWhiteSpace();
    QChar c;
    while(!s.atEnd() && !error){
        s>>c;
        if (c=='{'){
            return parseObject(s,error);
        } else if (c=='"'){
            return parseString(s,error);
        } else if (c=='['){
            return parseArray(s,error);
        } else {
            return parseLiteral(s,error);
        }
        s.skipWhiteSpace();
    }
    return QVariant();
}

static QVariantMap parseObject (QTextStream & s,bool & error){
    s.skipWhiteSpace();
    QVariantMap o;
    QString key;
    bool atVal=false;

    QChar c;
    while(!s.atEnd() && !error){
        s>>c;
        if (c=='}'){
            return o;
        } else if (c==',' || c==':'){
            /*
              They're syntactic sugar, since key:value come in bundles anyway
              Could check for error handling. too lazy.
            */
        } else if (c=='"'){
            if(atVal){
                o[key]=parseString(s,error);
                atVal=false;
            }else{
                key=parseString(s,error);
                atVal=true;
            }
        } else if (c=='['){
            if(atVal){
                o[key]=parseArray(s,error);
                atVal=false;
            }else{
                error=true;
                return QVariantMap();
            }
        } else if (c=='{'){
            if(atVal){
                o[key]=parseObject(s,error);
                atVal=false;
            }else{
                error=true;
                return QVariantMap();
            }
        } else {
            if(atVal){
                o[key]=parseLiteral(s,error);
                atVal=false;
            }else{
                error=true;
                return QVariantMap();
            }
        }
        s.skipWhiteSpace();
    }
    error=true;
    return QVariantMap();
}
static QVariantList parseArray (QTextStream & s,bool & error){
    s.skipWhiteSpace();
    QVariantList l;
    QChar c;
    while(!s.atEnd() && !error){
        s>>c;
        if (c==']'){
            return l;
        } else if (c==','){
        } else if (c=='"'){
            l.append(parseString(s,error));
        } else if (c=='['){
            l.append(parseArray(s,error));
        } else if (c=='{'){
            l.append(parseObject(s,error));
        } else {
            l.append(parseLiteral(s,error));
        }
        s.skipWhiteSpace();
    }
    error=true;
    return QVariantList();
}
static QString parseString (QTextStream & s,bool & error){
    QString str;
    QChar c;
    while(!s.atEnd() && !error){
        s>>c;
        if(c=='"'){
            return str;
        }else if(c=='\\'){
            s>>c;
            if(c=='b'){
                str.append('\b');
            }else if(c=='f'){
                str.append('\f');
            }else if(c=='n'){
                str.append('\n');
            }else if(c=='r'){
                str.append('\r');
            }else if(c=='t'){
                str.append('\t');
            }else if(c=='f'){
                str.append('\f');
            }else if(c=='u'){
                short u;
                s>>u;
                str.append(QChar(u));
            }else{
                str.append(c);
            }
        }else{
            str.append(c);
        }
    }
    error=true;
    return QString();
}
static QVariant parseLiteral (QTextStream & s,bool & error){
    s.seek(s.pos()-1);
    QChar c;
    while(!s.atEnd() && !error){
        s>>c;
        if (c=='t'){
            s>>c;//r
            s>>c;//u
            s>>c;//e
            return true;
        } else if (c=='f'){
            s>>c;//a
            s>>c;//l
            s>>c;//s
            s>>c;//e
            return false;
        }else if (c=='n'){
            s>>c;//u
            s>>c;//l
            s>>c;//l
            return QVariant();
        }else if (c=='-' || c.isDigit()){
            QString n;
            while(!s.atEnd() && !error && ( c.isDigit()  || (c=='.') || (c=='E') || (c=='e') || (c=='-') || (c=='+') )){
                n.append(c);
                s>>c;
            }
            if(n.contains('.')){
                return n.toDouble();
            }else{
                return n.toInt();
            }
        }
    }
    error=true;
    return QVariant();
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

/**
 * Randomized malloc, for detecting memory-based non-determinisms in redex.
 * To use, build redex-all-malloc-dbg, and then run as follows (you'll probably
 * want all the args from a "real" redex run, but this is the idea):
 *
 *   MALLOC_SEED=seed1 ./redex-all-malloc-dbg --out out-seed1.apk in.apk
 *   MALLOC_SEED=seed2 ./redex-all-malloc-dbg --out out-seed2.apk in.apk
 *
 * If the two output APKs differ, it could be because of an indeterminism
 * caused by branching on pointer values (e.g. containers sorted by pointer
 * keys).
 *
 * Note that this is NOT an attempt to make a deterministic allocator. System
 * malloc is non deterministic (practically speaking), but it will often behave
 * very similarly, which can hide non determinisms caused by pointers. This
 * allocator is intended to make such non determinisms happen *every* time,
 * instead of only once in a while.
 */

#ifdef __APPLE__
#include <dlfcn.h>
#endif

#include <algorithm>

#include <cstdio>
#include <cstdlib>
#include <cstring>

#include <map>
#include <string>
#include <vector>

#include <thread>

#include "Debug.h"

namespace {

// The tinyest PRNG ever.
// http://www.woodmann.com/forum/showthread.php?3100-super-tiny-PRNG
class TinyPRNG {
 public:
  explicit TinyPRNG(const std::string& randSeed) { seed(randSeed); }

  uint32_t next_rand() {
    uint32_t result = 0;
    for (int i = 0; i < 32; i++) {
      // Advance the rand state.
      m_next_rand += (m_next_rand * m_next_rand) | 5;
      // pull out the high bit.
      result |= (m_next_rand >> 31) << i;
    }
    return result;
  }

  void seed(const std::string& randSeed) {
    constexpr auto state_size = sizeof(m_next_rand);
    char state[state_size] = {};
    std::string::size_type idx = 0;
    for (auto& e : randSeed) {
      state[idx % state_size] ^= e;
      idx++;
    }
    memcpy(&m_next_rand, state, state_size);
  }

 private:
  uint32_t m_next_rand = 0;
};

} // namespace

#ifdef __APPLE__
typedef void* (*MallocFn)(size_t);
static auto libc_malloc =
    reinterpret_cast<MallocFn>(dlsym(RTLD_NEXT, "malloc"));
typedef void* (*CallocFn)(size_t, size_t);
static auto libc_calloc =
    reinterpret_cast<CallocFn>(dlsym(RTLD_NEXT, "calloc"));
typedef void* (*MemalignFn)(size_t, size_t);
static auto libc_memalign =
    reinterpret_cast<MemalignFn>(dlsym(RTLD_NEXT, "memalign"));
typedef int (*PosixMemalignFn)(void**, size_t, size_t);
static auto libc_posix_memalign =
    reinterpret_cast<MemalignFn>(dlsym(RTLD_NEXT, "posix_memalign"));
#endif

#ifdef __linux__
extern "C" {
extern void* __libc_malloc(size_t size);
extern void* __libc_calloc(size_t nelem, size_t elsize);
extern void* __libc_memalign(size_t alignment, size_t size);
// This isn't found?
// extern int __posix_memalign(void** out, size_t alignment, size_t size);
}

static auto libc_malloc = __libc_malloc;
static auto libc_calloc = __libc_calloc;
static auto libc_memalign = __libc_memalign;
// static auto libc_posix_memalign = __posix_memalign;
#endif

namespace {

size_t next_power_of_two(size_t x) {
  // Turn off all but msb.
  while ((x & (x - 1)) != 0) {
    x &= x - 1;
  }
  return x << 1;
}

constexpr bool PRINT_SEED = false;

template <bool ENABLE_RAND>
class MallocDebug {
 public:
  explicit MallocDebug() : m_rand("wharblegarbl") {
    const char* seed_env = getenv("MALLOC_SEED");
    if (seed_env != nullptr) {
      if (PRINT_SEED) {
        printf("re-seeding with %s\n", seed_env);
      }
      m_rand.seed(seed_env);
    }
  }

  void* malloc(size_t size, bool randomize = true) noexcept {
    if (m_in_malloc) {
      return libc_malloc(size);
    }
    m_in_malloc = true;
    auto ret = malloc_impl<false>(
        randomize, size, m_blocks, [](size_t s) { return libc_malloc(s); });
    m_in_malloc = false;
    return ret;
  }

  void* calloc(size_t nelem, size_t elsize) noexcept {
    if (m_in_malloc) {
      return libc_calloc(nelem, elsize);
    }
    m_in_malloc = true;
    auto ret = malloc_impl<true>(false, nelem * elsize, m_blocks, [](size_t s) {
      return libc_malloc(s);
    });
    m_in_malloc = false;
    return ret;
  }

  void* memalign(size_t alignment,
                 size_t bytes,
                 bool randomize = true) noexcept {
    if (m_in_malloc) {
      return libc_memalign(alignment, bytes);
    }
    m_in_malloc = true;
    auto ret = malloc_impl<false>(
        randomize,
        bytes,
        m_aligned_blocks[alignment],
        [](size_t, size_t a, size_t b) { return libc_memalign(a, b); },
        alignment,
        bytes);
    m_in_malloc = false;
    return ret;
  }

  int posix_memalign(void** out,
                     size_t alignment,
                     size_t size,
                     bool randomize = true) noexcept {
    if (m_in_malloc) {
      *out = memalign(alignment, size);
      return 0;
    }
    m_in_malloc = true;
    auto ret = malloc_impl<false>(
        randomize,
        size,
        m_aligned_blocks[alignment],
        [](size_t, size_t a, size_t b) { return libc_memalign(a, b); },
        alignment,
        size);
    m_in_malloc = false;
    *out = ret;
    return 0;
  }

 private:
  struct Block {
    void* ptr;
    size_t size;
    Block(void* ptr, size_t size) : ptr(ptr), size(size) {}
    ~Block() { free(ptr); }

    Block(const Block&) = delete;
    Block(Block&& other) noexcept : ptr(other.release()), size(other.size) {}

    Block& operator=(const Block&) = delete;
    Block& operator=(Block&& rhs) noexcept {
      ptr = rhs.release();
      size = rhs.size;
      return *this;
    }

    void* release() {
      void* tmp = ptr;
      ptr = nullptr;
      return tmp;
    }
  };

  bool m_in_malloc = false;
  using BlockCache = std::map<size_t, std::vector<Block>>;
  BlockCache m_blocks;
  std::map<size_t, BlockCache> m_aligned_blocks;
  TinyPRNG m_rand;

  template <bool ZERO, typename Fn, typename... Args>
  void* malloc_impl(bool randomize,
                    size_t size,
                    BlockCache& blocks,
                    Fn fn,
                    Args... args) noexcept {
    constexpr int block_count = 8;
    auto next_size = std::max(sizeof(uint32_t), next_power_of_two(size));

    auto it = blocks.find(next_size);
    if (it == blocks.end()) {
      it = blocks.emplace(next_size, std::vector<Block>()).first;
    }

    auto& vec = it->second;

    while (vec.size() < block_count) {
      auto ptr = fn(next_size, args...);
      vec.emplace_back(ptr, next_size);
    }

    auto idx = m_rand.next_rand() % block_count;
    auto block_size = vec[idx].size;
    void* block_ptr = vec[idx].release();
    vec.erase(vec.begin() + idx);

    always_assert(block_size >= size);

    if (ZERO) {
      // Zero out.
      memset(block_ptr, 0, size);
    } else if (ENABLE_RAND && randomize) {
      // Fill with garbage. Assume we have at least 4-byte alignment, and at
      // least 4-byte allocation (hence the std::max above).
      size_t len = (size + sizeof(uint32_t) - 1) / sizeof(uint32_t);
      for (size_t i = 0; i < len; ++i) {
        (reinterpret_cast<uint32_t*>(block_ptr))[i] = m_rand.next_rand();
      }
    }

    return block_ptr;
  }
};

thread_local MallocDebug<true> malloc_debug;

} // namespace

extern "C" {

void* malloc(size_t sz) { return malloc_debug.malloc(sz); }

void* calloc(size_t nelem, size_t elsize) {
  return malloc_debug.calloc(nelem, elsize);
}

void* memalign(size_t alignment, size_t bytes) {
  return malloc_debug.memalign(alignment, bytes);
}

int posix_memalign(void** out, size_t alignment, size_t size) {
  return malloc_debug.posix_memalign(out, alignment, size);
}
}
<commit_msg>More granular chunking<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

/**
 * Randomized malloc, for detecting memory-based non-determinisms in redex.
 * To use, build redex-all-malloc-dbg, and then run as follows (you'll probably
 * want all the args from a "real" redex run, but this is the idea):
 *
 *   MALLOC_SEED=seed1 ./redex-all-malloc-dbg --out out-seed1.apk in.apk
 *   MALLOC_SEED=seed2 ./redex-all-malloc-dbg --out out-seed2.apk in.apk
 *
 * If the two output APKs differ, it could be because of an indeterminism
 * caused by branching on pointer values (e.g. containers sorted by pointer
 * keys).
 *
 * Note that this is NOT an attempt to make a deterministic allocator. System
 * malloc is non deterministic (practically speaking), but it will often behave
 * very similarly, which can hide non determinisms caused by pointers. This
 * allocator is intended to make such non determinisms happen *every* time,
 * instead of only once in a while.
 */

#ifdef __APPLE__
#include <dlfcn.h>
#endif

#include <algorithm>

#include <cstdio>
#include <cstdlib>
#include <cstring>

#include <map>
#include <string>
#include <vector>

#include <thread>

#include "Debug.h"

namespace {

// The tinyest PRNG ever.
// http://www.woodmann.com/forum/showthread.php?3100-super-tiny-PRNG
class TinyPRNG {
 public:
  explicit TinyPRNG(const std::string& randSeed) { seed(randSeed); }

  uint32_t next_rand() {
    uint32_t result = 0;
    for (int i = 0; i < 32; i++) {
      // Advance the rand state.
      m_next_rand += (m_next_rand * m_next_rand) | 5;
      // pull out the high bit.
      result |= (m_next_rand >> 31) << i;
    }
    return result;
  }

  void seed(const std::string& randSeed) {
    constexpr auto state_size = sizeof(m_next_rand);
    char state[state_size] = {};
    std::string::size_type idx = 0;
    for (auto& e : randSeed) {
      state[idx % state_size] ^= e;
      idx++;
    }
    memcpy(&m_next_rand, state, state_size);
  }

 private:
  uint32_t m_next_rand = 0;
};

} // namespace

#ifdef __APPLE__
typedef void* (*MallocFn)(size_t);
static auto libc_malloc =
    reinterpret_cast<MallocFn>(dlsym(RTLD_NEXT, "malloc"));
typedef void* (*CallocFn)(size_t, size_t);
static auto libc_calloc =
    reinterpret_cast<CallocFn>(dlsym(RTLD_NEXT, "calloc"));
typedef void* (*MemalignFn)(size_t, size_t);
static auto libc_memalign =
    reinterpret_cast<MemalignFn>(dlsym(RTLD_NEXT, "memalign"));
typedef int (*PosixMemalignFn)(void**, size_t, size_t);
static auto libc_posix_memalign =
    reinterpret_cast<MemalignFn>(dlsym(RTLD_NEXT, "posix_memalign"));
#endif

#ifdef __linux__
extern "C" {
extern void* __libc_malloc(size_t size);
extern void* __libc_calloc(size_t nelem, size_t elsize);
extern void* __libc_memalign(size_t alignment, size_t size);
// This isn't found?
// extern int __posix_memalign(void** out, size_t alignment, size_t size);
}

static auto libc_malloc = __libc_malloc;
static auto libc_calloc = __libc_calloc;
static auto libc_memalign = __libc_memalign;
// static auto libc_posix_memalign = __posix_memalign;
#endif

namespace {

size_t next_power_of_two(size_t x) {
  // Turn off all but msb.
  while ((x & (x - 1)) != 0) {
    x &= x - 1;
  }
  return x << 1;
}

constexpr bool PRINT_SEED = false;

template <bool ENABLE_RAND>
class MallocDebug {
 public:
  explicit MallocDebug() : m_rand("wharblegarbl") {
    const char* seed_env = getenv("MALLOC_SEED");
    if (seed_env != nullptr) {
      if (PRINT_SEED) {
        printf("re-seeding with %s\n", seed_env);
      }
      m_rand.seed(seed_env);
    }
  }

  void* malloc(size_t size, bool randomize = true) noexcept {
    if (m_in_malloc) {
      return libc_malloc(size);
    }
    m_in_malloc = true;
    auto ret = malloc_impl<false>(
        randomize, size, m_blocks, [](size_t s) { return libc_malloc(s); });
    m_in_malloc = false;
    return ret;
  }

  void* calloc(size_t nelem, size_t elsize) noexcept {
    if (m_in_malloc) {
      return libc_calloc(nelem, elsize);
    }
    m_in_malloc = true;
    auto ret = malloc_impl<true>(false, nelem * elsize, m_blocks, [](size_t s) {
      return libc_malloc(s);
    });
    m_in_malloc = false;
    return ret;
  }

  void* memalign(size_t alignment,
                 size_t bytes,
                 bool randomize = true) noexcept {
    if (m_in_malloc) {
      return libc_memalign(alignment, bytes);
    }
    m_in_malloc = true;
    auto ret = malloc_impl<false>(
        randomize,
        bytes,
        m_aligned_blocks[alignment],
        [](size_t, size_t a, size_t b) { return libc_memalign(a, b); },
        alignment,
        bytes);
    m_in_malloc = false;
    return ret;
  }

  int posix_memalign(void** out,
                     size_t alignment,
                     size_t size,
                     bool randomize = true) noexcept {
    if (m_in_malloc) {
      *out = memalign(alignment, size);
      return 0;
    }
    m_in_malloc = true;
    auto ret = malloc_impl<false>(
        randomize,
        size,
        m_aligned_blocks[alignment],
        [](size_t, size_t a, size_t b) { return libc_memalign(a, b); },
        alignment,
        size);
    m_in_malloc = false;
    *out = ret;
    return 0;
  }

 private:
  struct Block {
    void* ptr;
    size_t size;
    Block(void* ptr, size_t size) : ptr(ptr), size(size) {}
    ~Block() { free(ptr); }

    Block(const Block&) = delete;
    Block(Block&& other) noexcept : ptr(other.release()), size(other.size) {}

    Block& operator=(const Block&) = delete;
    Block& operator=(Block&& rhs) noexcept {
      ptr = rhs.release();
      size = rhs.size;
      return *this;
    }

    void* release() {
      void* tmp = ptr;
      ptr = nullptr;
      return tmp;
    }
  };

  bool m_in_malloc = false;
  using BlockCache = std::map<size_t, std::vector<Block>>;
  BlockCache m_blocks;
  std::map<size_t, BlockCache> m_aligned_blocks;
  TinyPRNG m_rand;

  template <bool ZERO, typename Fn, typename... Args>
  void* malloc_impl(bool randomize,
                    size_t size,
                    BlockCache& blocks,
                    Fn fn,
                    Args... args) noexcept {
    size_t block_count = 8;

    // Size scheme:
    //   up to 1024, align by 4: this range has the highest alignment overhead
    //   up to 64k, align by 1024: that may amortize
    //   powers of 2 from here: not enough overlapping entries

    auto round_up = [](size_t n, size_t r) { return (n + r - 1) & ~(r - 1); };

    auto next_size = size <= 1024        ? round_up(size, 4)
                     : size <= 64 * 1024 ? round_up(size, 1024)
                                         : next_power_of_two(size);

    // For sizes >= 1M, reduce the block count.
    if (next_size >= 1024 * 1024) {
      block_count = 4;
    }

    auto it = blocks.find(next_size);
    if (it == blocks.end()) {
      it = blocks.emplace(next_size, std::vector<Block>()).first;
    }

    auto& vec = it->second;

    while (vec.size() < block_count) {
      auto ptr = fn(next_size, args...);
      vec.emplace_back(ptr, next_size);
    }

    auto idx = m_rand.next_rand() % block_count;
    auto block_size = vec[idx].size;
    void* block_ptr = vec[idx].release();
    vec.erase(vec.begin() + idx);

    always_assert(block_size >= size);

    if (ZERO) {
      // Zero out.
      memset(block_ptr, 0, size);
    } else if (ENABLE_RAND && randomize) {
      // Fill with garbage. Assume we have at least 4-byte alignment, and at
      // least 4-byte allocation (hence the std::max above).
      size_t len = (size + sizeof(uint32_t) - 1) / sizeof(uint32_t);
      for (size_t i = 0; i < len; ++i) {
        (reinterpret_cast<uint32_t*>(block_ptr))[i] = m_rand.next_rand();
      }
    }

    return block_ptr;
  }
};

thread_local MallocDebug<true> malloc_debug;

} // namespace

extern "C" {

void* malloc(size_t sz) { return malloc_debug.malloc(sz); }

void* calloc(size_t nelem, size_t elsize) {
  return malloc_debug.calloc(nelem, elsize);
}

void* memalign(size_t alignment, size_t bytes) {
  return malloc_debug.memalign(alignment, bytes);
}

int posix_memalign(void** out, size_t alignment, size_t size) {
  return malloc_debug.posix_memalign(out, alignment, size);
}
}
<|endoftext|>