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

#include "corridormap/vec2.h"
#include "corridormap/runtime.h"
#include "debugdraw.h"

namespace corridormap {

namespace
{
    Vec2 to_image(Vec2 v, const Draw_Params& params)
    {
        Vec2 inv_dim = sub(params.bounds_max, params.bounds_min);
        inv_dim = make_vec2(1.f / inv_dim.x, 1.f / inv_dim.y);
        return mul(mul(sub(v, params.bounds_min), inv_dim), params.image_dimensions);
    }

    struct NVG_State_Scope
    {
        NVGcontext* _vg;

        NVG_State_Scope(NVGcontext* vg)
            : _vg(vg)
        {
            nvgSave(_vg);
        }

        ~NVG_State_Scope()
        {
            nvgRestore(_vg);
        }
    };
}

void draw_voronoi_diagram(NVGcontext* vg, const Draw_Params& params)
{
    // background.
    {
        NVG_State_Scope s(vg);
        nvgFillColor(vg, nvgRGB(120, 120, 120));
        nvgBeginPath(vg);
        nvgRect(vg, 0, 0, params.image_dimensions.x, params.image_dimensions.y);
        nvgFill(vg);
    }

    // obstacles.
    {
        NVG_State_Scope s(vg);
        nvgFillColor(vg, nvgRGB(255, 255, 255));

        int offset = 0;
        for (int i = 0; i < params.obstacles->num_polys; ++i)
        {
            nvgBeginPath(vg);

            Vec2 vert = make_vec2(params.obstacles->x[offset], params.obstacles->y[offset]);
            Vec2 img_vert = to_image(vert, params);
            nvgMoveTo(vg, img_vert.x, img_vert.y);

            for (int v = 1; v < params.obstacles->num_poly_verts[i]; ++v)
            {
                Vec2 vert = make_vec2(params.obstacles->x[offset + v], params.obstacles->y[offset + v]);
                Vec2 img_vert = to_image(vert, params);
                nvgLineTo(vg, img_vert.x, img_vert.y);
            }

            nvgClosePath(vg);
            nvgFill(vg);

            offset += params.obstacles->num_poly_verts[i];
        }
    }

    // edges.
    {
        NVG_State_Scope s(vg);
        nvgStrokeColor(vg, nvgRGB(0, 0, 255));
        nvgStrokeWidth(vg, 2.f);

        for (Edge* edge = first(params.diagram->edges); edge != 0; edge = next(params.diagram->edges, edge))
        {
            Half_Edge* e0 = edge->dir + 0;

            Vec2 u = to_image(source(*params.diagram, e0)->pos, params);
            Vec2 v = to_image(target(*params.diagram, e0)->pos, params);

            nvgBeginPath(vg);
            nvgMoveTo(vg, u.x, u.y);

            for (Event* e = event(*params.diagram, e0); e != 0; e = next(*params.diagram, e, 0))
            {
                Vec2 p = to_image(e->pos, params);
                nvgLineTo(vg, p.x, p.y);
            }

            nvgLineTo(vg, v.x, v.y);
            nvgStroke(vg);
        }
    }

    // events.
    {
        NVG_State_Scope s(vg);
        nvgBeginPath(vg);
        nvgStrokeColor(vg, nvgRGB(0, 0, 255));
        nvgStrokeWidth(vg, 2.f);

        for (Event* e = first(params.diagram->events); e != 0; e = next(params.diagram->events, e))
        {
            Vec2 p = to_image(e->pos, params);
            nvgCircle(vg, p.x, p.y, 4.f);
        }

        nvgStroke(vg);
    }

    // vertices.
    {
        NVG_State_Scope s(vg);
        nvgBeginPath(vg);
        nvgStrokeColor(vg, nvgRGB(0, 0, 255));
        nvgStrokeWidth(vg, 2.f);

        for (Vertex* v = first(params.diagram->vertices); v != 0; v = next(params.diagram->vertices, v))
        {
            Vec2 p = to_image(v->pos, params);
            nvgCircle(vg, p.x, p.y, 8.f);
        }

        nvgStroke(vg);
    }

    // corridor bounds.
    {
        NVG_State_Scope s(vg);
        nvgStrokeColor(vg, nvgRGB(255, 0, 0));
        nvgStrokeWidth(vg, 2.f);

        for (Edge* edge = first(params.diagram->edges); edge != 0; edge = next(params.diagram->edges, edge))
        {
            Half_Edge* e0 = edge->dir + 0;
            Vec2 u = to_image(source(*params.diagram, e0)->pos, params);

            nvgBeginPath(vg);
            nvgMoveTo(vg, u.x, u.y);

            for (Event* e = event(*params.diagram, e0); e != 0; e = next(*params.diagram, e, 0))
            {
                Vec2 diff = sub(e->sides[0], e->pos);
                float dist = len(diff);
                Vec2 n = normalized(diff);
                Vec2 p = add(e->pos, scale(n, dist * 0.6f));
                p = to_image(p, params);
                nvgLineTo(vg, p.x, p.y);
            }

            nvgStroke(vg);

            nvgBeginPath(vg);
            nvgMoveTo(vg, u.x, u.y);

            for (Event* e = event(*params.diagram, e0); e != 0; e = next(*params.diagram, e, 1))
            {
                Vec2 diff = sub(e->sides[1], e->pos);
                float dist = len(diff);
                Vec2 n = normalized(diff);
                Vec2 p = add(e->pos, scale(n, dist * 0.6f));
                p = to_image(p, params);
                nvgLineTo(vg, p.x, p.y);
            }

            nvgStroke(vg);
        }
    }
}

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

#include "corridormap/vec2.h"
#include "corridormap/runtime.h"
#include "debugdraw.h"

namespace corridormap {

namespace
{
    Vec2 to_image(Vec2 v, const Draw_Params& params)
    {
        Vec2 inv_dim = sub(params.bounds_max, params.bounds_min);
        inv_dim = make_vec2(1.f / inv_dim.x, 1.f / inv_dim.y);
        return mul(mul(sub(v, params.bounds_min), inv_dim), params.image_dimensions);
    }

    struct NVG_State_Scope
    {
        NVGcontext* _vg;

        NVG_State_Scope(NVGcontext* vg)
            : _vg(vg)
        {
            nvgSave(_vg);
        }

        ~NVG_State_Scope()
        {
            nvgRestore(_vg);
        }
    };

    struct Segment
    {
        Vec2 a;
        Vec2 b;
    };

    Segment to_image(Vec2 a, Vec2 b, float length_decrease, const Draw_Params& params)
    {
        Segment s;
        s.a = to_image(a, params);
        s.b = to_image(b, params);
        Vec2 d = sub(s.b, s.a);
        float l = len(d);
        d = normalized(d);
        s.b = add(s.a, scale(d, (l >= length_decrease) ? l - length_decrease : 0.f));
        return s;
    }
}

void draw_voronoi_diagram(NVGcontext* vg, const Draw_Params& params)
{
    // background.
    {
        NVG_State_Scope s(vg);
        nvgFillColor(vg, nvgRGB(120, 120, 120));
        nvgBeginPath(vg);
        nvgRect(vg, 0, 0, params.image_dimensions.x, params.image_dimensions.y);
        nvgFill(vg);
    }

    // obstacles.
    {
        NVG_State_Scope s(vg);
        nvgFillColor(vg, nvgRGB(255, 255, 255));

        int offset = 0;
        for (int i = 0; i < params.obstacles->num_polys; ++i)
        {
            nvgBeginPath(vg);

            Vec2 vert = make_vec2(params.obstacles->x[offset], params.obstacles->y[offset]);
            Vec2 img_vert = to_image(vert, params);
            nvgMoveTo(vg, img_vert.x, img_vert.y);

            for (int v = 1; v < params.obstacles->num_poly_verts[i]; ++v)
            {
                Vec2 vert = make_vec2(params.obstacles->x[offset + v], params.obstacles->y[offset + v]);
                Vec2 img_vert = to_image(vert, params);
                nvgLineTo(vg, img_vert.x, img_vert.y);
            }

            nvgClosePath(vg);
            nvgFill(vg);

            offset += params.obstacles->num_poly_verts[i];
        }
    }

    // edges.
    {
        NVG_State_Scope s(vg);
        nvgStrokeColor(vg, nvgRGB(0, 0, 255));
        nvgStrokeWidth(vg, 2.f);

        for (Edge* edge = first(params.diagram->edges); edge != 0; edge = next(params.diagram->edges, edge))
        {
            Half_Edge* e0 = edge->dir + 0;

            Vec2 u = to_image(source(*params.diagram, e0)->pos, params);
            Vec2 v = to_image(target(*params.diagram, e0)->pos, params);

            nvgBeginPath(vg);
            nvgMoveTo(vg, u.x, u.y);

            for (Event* e = event(*params.diagram, e0); e != 0; e = next(*params.diagram, e, 0))
            {
                Vec2 p = to_image(e->pos, params);
                nvgLineTo(vg, p.x, p.y);
            }

            nvgLineTo(vg, v.x, v.y);
            nvgStroke(vg);
        }
    }

    // events.
    {
        NVG_State_Scope s(vg);
        nvgBeginPath(vg);
        nvgStrokeColor(vg, nvgRGB(0, 0, 255));
        nvgStrokeWidth(vg, 2.f);

        for (Event* e = first(params.diagram->events); e != 0; e = next(params.diagram->events, e))
        {
            Vec2 p = to_image(e->pos, params);
            nvgCircle(vg, p.x, p.y, 4.f);
        }

        nvgStroke(vg);
    }

    // vertices.
    {
        NVG_State_Scope s(vg);
        nvgBeginPath(vg);
        nvgStrokeColor(vg, nvgRGB(0, 0, 255));
        nvgStrokeWidth(vg, 2.f);

        for (Vertex* v = first(params.diagram->vertices); v != 0; v = next(params.diagram->vertices, v))
        {
            Vec2 p = to_image(v->pos, params);
            nvgCircle(vg, p.x, p.y, 8.f);
        }

        nvgStroke(vg);
    }

    // corridor bounds.
    {
        NVG_State_Scope s(vg);
        nvgStrokeColor(vg, nvgRGB(255, 0, 0));
        nvgStrokeWidth(vg, 2.f);

        for (Edge* edge = first(params.diagram->edges); edge != 0; edge = next(params.diagram->edges, edge))
        {
            Half_Edge* e0 = edge->dir + 0;

            nvgStrokeColor(vg, nvgRGB(255, 0, 0));
            for (Event* e = event(*params.diagram, e0); e != 0; e = next(*params.diagram, e, 0))
            {
                Segment s = to_image(e->pos, e->sides[0], 32.f, params);
                nvgBeginPath(vg);
                nvgMoveTo(vg, s.a.x, s.a.y);
                nvgLineTo(vg, s.b.x, s.b.y);
                nvgStroke(vg);
            }

            nvgStrokeColor(vg, nvgRGB(0, 255, 0));
            for (Event* e = event(*params.diagram, e0); e != 0; e = next(*params.diagram, e, 0))
            {
                Segment s = to_image(e->pos, e->sides[1], 32.f, params);
                nvgBeginPath(vg);
                nvgMoveTo(vg, s.a.x, s.a.y);
                nvgLineTo(vg, s.b.x, s.b.y);
                nvgStroke(vg);
            }

            Vec2 u = to_image(source(*params.diagram, e0)->pos, params);

            nvgStrokeColor(vg, nvgRGB(255, 0, 0));
            nvgBeginPath(vg);
            nvgMoveTo(vg, u.x, u.y);

            for (Event* e = event(*params.diagram, e0); e != 0; e = next(*params.diagram, e, 0))
            {
                Segment s = to_image(e->pos, e->sides[0], 32.f, params);
                nvgLineTo(vg, s.b.x, s.b.y);
            }
            nvgStroke(vg);

            nvgStrokeColor(vg, nvgRGB(0, 255, 0));
            nvgBeginPath(vg);
            nvgMoveTo(vg, u.x, u.y);

            for (Event* e = event(*params.diagram, e0); e != 0; e = next(*params.diagram, e, 0))
            {
                Segment s = to_image(e->pos, e->sides[1], 32.f, params);
                nvgLineTo(vg, s.b.x, s.b.y);
            }
            nvgStroke(vg);
        }
    }

    // vertex sides.
    {
        NVG_State_Scope s(vg);
        nvgBeginPath(vg);
        nvgStrokeColor(vg, nvgRGB(255, 0, 255));
        nvgStrokeWidth(vg, 2.f);

        for (Vertex* v = first(params.diagram->vertices); v != 0; v = next(params.diagram->vertices, v))
        {
            for (int i = 0; i < max_vertex_sides; ++i)
            {
                Segment s = to_image(v->pos, v->sides[i], 32.f, params);
                nvgBeginPath(vg);
                nvgMoveTo(vg, s.a.x, s.a.y);
                nvgLineTo(vg, s.b.x, s.b.y);
                nvgStroke(vg);
            }
        }
    }
}

}
<|endoftext|>


<commit_before>/**
 * @author: Jeff Thompson
 * See COPYING for copyright and distribution information.
 */

#ifndef NDN_BINARYXMLELEMENTREADER_HPP
#define	NDN_BINARYXMLELEMENTREADER_HPP

#include "../c/encoding/BinaryXMLElementReader.h"

namespace ndn {

/**
 * An ElementListener extends an ndn_ElementListener struct to proved an abstract virtual onReceivedElement function which wraps
 * the onReceivedElement used by the ndn_ElementListener struct.  You must extend this class to override onReceivedElement.
 */
class ElementListener : private ndn_ElementListener {
public:
  ElementListener()
  {
    ndn_ElementListener_init(this, staticOnReceivedElement);
  }

  /**
   * This is called when an entire binary XML element is received.  You must extend this class to override this method.
   * @param element pointer to the binary XML element.  This buffer is only valid during this call.  If you need the data
   * later, you must copy.
   * @param elementLength length of element
   */
  virtual void onReceivedElement(unsigned char *element, unsigned int elementLength) = 0;

private:
  /**
   * Call the virtual method onReceivedElement. This is used to initialize the base ndn_ElementListener struct.
   * @param self
   * @param element
   * @param elementLength
   */
  static void staticOnReceivedElement(struct ndn_ElementListener *self, unsigned char *element, unsigned int elementLength);
};

}

#endif
<commit_msg>Make the base ndn_ElementListener public so we can cast<commit_after>/**
 * @author: Jeff Thompson
 * See COPYING for copyright and distribution information.
 */

#ifndef NDN_BINARYXMLELEMENTREADER_HPP
#define	NDN_BINARYXMLELEMENTREADER_HPP

#include "../c/encoding/BinaryXMLElementReader.h"

namespace ndn {

/**
 * An ElementListener extends an ndn_ElementListener struct to proved an abstract virtual onReceivedElement function which wraps
 * the onReceivedElement used by the ndn_ElementListener struct.  You must extend this class to override onReceivedElement.
 */
class ElementListener : public ndn_ElementListener {
public:
  ElementListener()
  {
    ndn_ElementListener_init(this, staticOnReceivedElement);
  }

  /**
   * This is called when an entire binary XML element is received.  You must extend this class to override this method.
   * @param element pointer to the binary XML element.  This buffer is only valid during this call.  If you need the data
   * later, you must copy.
   * @param elementLength length of element
   */
  virtual void onReceivedElement(unsigned char *element, unsigned int elementLength) = 0;

private:
  /**
   * Call the virtual method onReceivedElement. This is used to initialize the base ndn_ElementListener struct.
   * @param self
   * @param element
   * @param elementLength
   */
  static void staticOnReceivedElement(struct ndn_ElementListener *self, unsigned char *element, unsigned int elementLength);
};

}

#endif
<|endoftext|>


<commit_before>#include "crunch.h"

#include <list>
#include <pthread.h>
#include <time.h>

#include <raytracer/raytracer.h>
#include <platform.h>

pthread_mutex_t g_iDataMutex;

void CAOGenerator::RaytraceSceneFromPosition(raytrace::CRaytracer* pTracer, Vector vecUVPosition, Vector vecNormal, CConversionMeshInstance* pMeshInstance, CConversionFace* pFace, size_t iTexel)
{
	// Build rotation matrix
	Matrix4x4 m;
	m.SetOrientation(vecNormal);

	// Turn it sideways so that pitch 90 is up, for more uniform sampling
	Matrix4x4 m2;
	m2.SetRotation(EAngle(0, -90, 0));

	m *= m2;

	float flHits = 0;
	float flTotalHits = 0;

	for (size_t x = 0; x < m_iSamples/2; x++)
	{
		float flRandom = 0;
		if (m_bRandomize)
			flRandom = RemapVal((float)(rand()%10000), 0, 10000.0f, -0.5, 0.5);

		float flPitch = RemapVal(cos(RemapVal((float)x+flRandom, 0, (float)m_iSamples/2, 0, M_PI/2)), 0, 1, 90, 0);

		float flWeight = sin(flPitch * M_PI/180);

		for (size_t y = 0; y <= m_iSamples; y++)
		{
			flRandom = 0;
			if (m_bRandomize)
				flRandom = RemapVal((float)(rand()%10000), 0, 10000.0f, -0.5, 0.5);

			float flYaw = RemapVal((float)y+flRandom, 0, (float)m_iSamples, -180, 180);

			Vector vecDir = AngleVector(EAngle(flPitch, flYaw, 0));

			// Transform relative to the triangle's normal
			Vector vecRay = m * vecDir;

			//RenderSceneFromPosition(vecUVPosition, vecRay, pFace);

			flTotalHits += flWeight;

			Vector vecHit;
			if (pTracer->Raytrace(Ray(vecUVPosition + pFace->GetNormal()*0.01f, vecRay), &vecHit))
			{
				float flDistance = (vecHit - vecUVPosition).Length();
				if (m_flRayFalloff < 0)
					flHits += flWeight;
				else
					flHits += flWeight * (1/pow(2, flDistance/m_flRayFalloff));
			}
			else if (m_bGroundOcclusion && vecRay.y < 0)
			{
				// The following math is basically a plane-ray intersection algorithm,
				// with shortcuts made for the assumption of an infinite plane facing straight up.

				Vector n = Vector(0,1,0);

				float a = -(vecUVPosition.y - pMeshInstance->m_pParent->m_oExtends.m_vecMins.y);
				float b = vecRay.y;

				float flDistance = a/b;

				if (flDistance < 1e-4f || m_flRayFalloff < 0)
					flHits += flWeight;
				else
					flHits += flWeight * (1/pow(2, flDistance/m_flRayFalloff));
			}
		}
	}

	// One last ray directly up, it is skipped in the above loop so it's not done 10 times.
	Vector vecDir = AngleVector(EAngle(90, 0, 0));

	// Transform relative to the triangle's normal
	Vector vecRay = m * vecDir;

	//RenderSceneFromPosition(vecUVPosition, vecRay, pFace);

	flTotalHits++;

	Vector vecHit;
	if (pTracer->Raytrace(Ray(vecUVPosition + pFace->GetNormal()*0.01f, vecRay), &vecHit))
	{
		float flDistance = (vecHit - vecUVPosition).Length();
		if (m_flRayFalloff < 0)
			flHits += 1;
		else
			flHits += (1/pow(2, flDistance/m_flRayFalloff));
	}
	else if (m_bGroundOcclusion && vecRay.y < 0)
	{
		// The following math is basically a plane-ray intersection algorithm,
		// with shortcuts made for the assumption of an infinite plane facing straight up.

		Vector n = Vector(0,1,0);

		float a = -(vecUVPosition.y - pMeshInstance->m_pParent->m_oExtends.m_vecMins.y);
		float b = vecRay.y;

		float flDistance = a/b;

		if (flDistance < 1e-4f || m_flRayFalloff < 0)
			flHits += 1;
		else
			flHits += (1/pow(2, flDistance/m_flRayFalloff));
	}

	float flShadowValue = 1 - ((float)flHits / (float)flTotalHits);

	// Mutex may be dead, try to bail before.
	if (m_bStopGenerating)
		return;

	if (GetNumberOfProcessors() > 1)
	{
		// Keep all locking and unlocking in one branch to prevent processor prediction miss problems.
		// I saw it in some presentation somewhere.
		pthread_mutex_lock(&g_iDataMutex);
		m_avecShadowValues[iTexel] += Vector(flShadowValue, flShadowValue, flShadowValue);
		pthread_mutex_unlock(&g_iDataMutex);
	}
	else
		m_avecShadowValues[iTexel] += Vector(flShadowValue, flShadowValue, flShadowValue);
}

typedef struct
{
	raytrace::CRaytracer*		pTracer;
	Vector						vecUVPosition;
	Vector						vecNormal;
	CConversionMeshInstance*	pMeshInstance;
	CConversionFace*			pFace;
	size_t						iTexel;
} thread_job_t;

typedef struct
{
	pthread_t					iThread;
	CAOGenerator*				pGenerator;
	std::list<thread_job_t>		lJobs;
	pthread_mutex_t				iJobsMutex;
	bool						bQuitWhenDone;
	bool						bDone;
} thread_data_t;

std::vector<thread_data_t> g_aThreads;
size_t g_iJobsGiven = 0;

void RaytraceThreadMain(void* pData)
{
	thread_data_t* pThread = (thread_data_t*)pData;
	while (true)
	{
		pthread_mutex_lock(&pThread->iJobsMutex);
		if (!pThread->lJobs.size())
		{
			pthread_mutex_unlock(&pThread->iJobsMutex);

			if (pThread->bQuitWhenDone)
			{
				pThread->bDone = true;
				pthread_exit(NULL);
				return;
			}
			else
			{
				// Give the main thread a chance to render and whatnot.
				SleepMS(1);
				continue;
			}
		}

		// Copy so we can pop it.
		thread_job_t oThreadJob = pThread->lJobs.front();
		pThread->lJobs.pop_front();

		pthread_mutex_unlock(&pThread->iJobsMutex);

		pThread->pGenerator->RaytraceSceneFromPosition(oThreadJob.pTracer, oThreadJob.vecUVPosition, oThreadJob.vecNormal, oThreadJob.pMeshInstance, oThreadJob.pFace, oThreadJob.iTexel);

		// Give the main thread a chance to render and whatnot.
		SleepMS(1);

		if (pThread->pGenerator->IsStopped())
		{
			pThread->bDone = true;
			pthread_exit(NULL);
			return;
		}
	}
}

void CAOGenerator::RaytraceSetupThreads()
{
	if (GetNumberOfProcessors() == 1)
		return;

	pthread_mutex_init(&g_iDataMutex, NULL);

	g_iJobsGiven = 0;

	// Insert all first so that reallocations are all done before we pass the pointers to the threads.
	g_aThreads.insert(g_aThreads.begin(), GetNumberOfProcessors(), thread_data_t());

	for (size_t i = 0; i < GetNumberOfProcessors(); i++)
	{
		thread_data_t* pThread = &g_aThreads[i];

		pThread->pGenerator = this;
		pThread->bQuitWhenDone = false;
		pThread->bDone = false;
		pthread_mutex_init(&pThread->iJobsMutex, NULL);

		pthread_create(&pThread->iThread, NULL, (void *(*) (void *))&RaytraceThreadMain, (void*)pThread);
	}
}

void CAOGenerator::RaytraceCleanupThreads()
{
	if (GetNumberOfProcessors() == 1)
		return;

	// If there are no threads then we've already cleaned up, don't do it twice.
	if (!g_aThreads.size())
		return;

	for (size_t i = 0; i < g_aThreads.size(); i++)
	{
		thread_data_t* pThread = &g_aThreads[i];

		pthread_mutex_destroy(&pThread->iJobsMutex);

		pthread_detach(pThread->iThread);
	}

	pthread_mutex_destroy(&g_iDataMutex);

	g_aThreads.clear();
}

void CAOGenerator::RaytraceSceneMultithreaded(raytrace::CRaytracer* pTracer, Vector vecUVPosition, Vector vecNormal, CConversionMeshInstance* pMeshInstance, CConversionFace* pFace, size_t iTexel)
{
	if (GetNumberOfProcessors() == 1)
	{
		RaytraceSceneFromPosition(pTracer, vecUVPosition, vecNormal, pMeshInstance, pFace, iTexel);
		return;
	}

	static int iNextThread = 0;

	thread_data_t* pThread = &g_aThreads[(iNextThread++)%g_aThreads.size()];

	pthread_mutex_lock(&pThread->iJobsMutex);

	pThread->lJobs.push_back(thread_job_t());
	thread_job_t* pJob = &pThread->lJobs.back();
	pJob->pTracer = pTracer;
	pJob->vecUVPosition = vecUVPosition;
	pJob->vecNormal = vecNormal;
	pJob->pMeshInstance = pMeshInstance;
	pJob->pFace = pFace;
	pJob->iTexel = iTexel;

	pthread_mutex_unlock(&pThread->iJobsMutex);

	g_iJobsGiven++;
}

void CAOGenerator::RaytraceJoinThreads()
{
	if (GetNumberOfProcessors() == 1)
		return;

	// Doesn't really join the threads per se, just signals for them to quit and then waits for them to be done
	// while calling work progress updates so the user can see what's happening.

	for (size_t i = 0; i < g_aThreads.size(); i++)
		g_aThreads[i].bQuitWhenDone = true;

	if (m_pWorkListener)
		m_pWorkListener->SetAction(L"Rendering", g_iJobsGiven);

	while (true)
	{
		bool bDone = true;
		size_t iWorkRemaining = 0;
		for (size_t t = 0; t < g_aThreads.size(); t++)
		{
			if (!g_aThreads[t].bDone)
				bDone = false;
			iWorkRemaining += g_aThreads[t].lJobs.size();
		}

		if (bDone)
			return;

		if (m_pWorkListener)
			m_pWorkListener->WorkProgress(g_iJobsGiven-iWorkRemaining);

		if (m_bStopGenerating)
		{
			RaytraceCleanupThreads();
			return;
		}
	}
}
<commit_msg>All threads use one job queue. Why did I make a separate job queue for each thread? Seems like it wasn't necessary. Should be slightly faster as there won't be one lone thread trying to chug through the remainder of its stuff at the end.<commit_after>#include "crunch.h"

#include <list>
#include <pthread.h>
#include <time.h>

#include <raytracer/raytracer.h>
#include <platform.h>

pthread_mutex_t g_iDataMutex;

void CAOGenerator::RaytraceSceneFromPosition(raytrace::CRaytracer* pTracer, Vector vecUVPosition, Vector vecNormal, CConversionMeshInstance* pMeshInstance, CConversionFace* pFace, size_t iTexel)
{
	// Build rotation matrix
	Matrix4x4 m;
	m.SetOrientation(vecNormal);

	// Turn it sideways so that pitch 90 is up, for more uniform sampling
	Matrix4x4 m2;
	m2.SetRotation(EAngle(0, -90, 0));

	m *= m2;

	float flHits = 0;
	float flTotalHits = 0;

	for (size_t x = 0; x < m_iSamples/2; x++)
	{
		float flRandom = 0;
		if (m_bRandomize)
			flRandom = RemapVal((float)(rand()%10000), 0, 10000.0f, -0.5, 0.5);

		float flPitch = RemapVal(cos(RemapVal((float)x+flRandom, 0, (float)m_iSamples/2, 0, M_PI/2)), 0, 1, 90, 0);

		float flWeight = sin(flPitch * M_PI/180);

		for (size_t y = 0; y <= m_iSamples; y++)
		{
			flRandom = 0;
			if (m_bRandomize)
				flRandom = RemapVal((float)(rand()%10000), 0, 10000.0f, -0.5, 0.5);

			float flYaw = RemapVal((float)y+flRandom, 0, (float)m_iSamples, -180, 180);

			Vector vecDir = AngleVector(EAngle(flPitch, flYaw, 0));

			// Transform relative to the triangle's normal
			Vector vecRay = m * vecDir;

			//RenderSceneFromPosition(vecUVPosition, vecRay, pFace);

			flTotalHits += flWeight;

			Vector vecHit;
			if (pTracer->Raytrace(Ray(vecUVPosition + pFace->GetNormal()*0.01f, vecRay), &vecHit))
			{
				float flDistance = (vecHit - vecUVPosition).Length();
				if (m_flRayFalloff < 0)
					flHits += flWeight;
				else
					flHits += flWeight * (1/pow(2, flDistance/m_flRayFalloff));
			}
			else if (m_bGroundOcclusion && vecRay.y < 0)
			{
				// The following math is basically a plane-ray intersection algorithm,
				// with shortcuts made for the assumption of an infinite plane facing straight up.

				Vector n = Vector(0,1,0);

				float a = -(vecUVPosition.y - pMeshInstance->m_pParent->m_oExtends.m_vecMins.y);
				float b = vecRay.y;

				float flDistance = a/b;

				if (flDistance < 1e-4f || m_flRayFalloff < 0)
					flHits += flWeight;
				else
					flHits += flWeight * (1/pow(2, flDistance/m_flRayFalloff));
			}
		}
	}

	// One last ray directly up, it is skipped in the above loop so it's not done 10 times.
	Vector vecDir = AngleVector(EAngle(90, 0, 0));

	// Transform relative to the triangle's normal
	Vector vecRay = m * vecDir;

	//RenderSceneFromPosition(vecUVPosition, vecRay, pFace);

	flTotalHits++;

	Vector vecHit;
	if (pTracer->Raytrace(Ray(vecUVPosition + pFace->GetNormal()*0.01f, vecRay), &vecHit))
	{
		float flDistance = (vecHit - vecUVPosition).Length();
		if (m_flRayFalloff < 0)
			flHits += 1;
		else
			flHits += (1/pow(2, flDistance/m_flRayFalloff));
	}
	else if (m_bGroundOcclusion && vecRay.y < 0)
	{
		// The following math is basically a plane-ray intersection algorithm,
		// with shortcuts made for the assumption of an infinite plane facing straight up.

		Vector n = Vector(0,1,0);

		float a = -(vecUVPosition.y - pMeshInstance->m_pParent->m_oExtends.m_vecMins.y);
		float b = vecRay.y;

		float flDistance = a/b;

		if (flDistance < 1e-4f || m_flRayFalloff < 0)
			flHits += 1;
		else
			flHits += (1/pow(2, flDistance/m_flRayFalloff));
	}

	float flShadowValue = 1 - ((float)flHits / (float)flTotalHits);

	// Mutex may be dead, try to bail before.
	if (m_bStopGenerating)
		return;

	if (GetNumberOfProcessors() > 1)
	{
		// Keep all locking and unlocking in one branch to prevent processor prediction miss problems.
		// I saw it in some presentation somewhere.
		pthread_mutex_lock(&g_iDataMutex);
		m_avecShadowValues[iTexel] += Vector(flShadowValue, flShadowValue, flShadowValue);
		pthread_mutex_unlock(&g_iDataMutex);
	}
	else
		m_avecShadowValues[iTexel] += Vector(flShadowValue, flShadowValue, flShadowValue);
}

typedef struct
{
	raytrace::CRaytracer*		pTracer;
	Vector						vecUVPosition;
	Vector						vecNormal;
	CConversionMeshInstance*	pMeshInstance;
	CConversionFace*			pFace;
	size_t						iTexel;
} thread_job_t;

typedef struct
{
	pthread_t					iThread;
	CAOGenerator*				pGenerator;
	bool						bQuitWhenDone;
	bool						bDone;
} thread_data_t;

std::vector<thread_data_t> g_aThreads;
std::list<thread_job_t> g_lJobs;
pthread_mutex_t g_iJobsMutex;
size_t g_iJobsGiven = 0;

void RaytraceThreadMain(void* pData)
{
	thread_data_t* pThread = (thread_data_t*)pData;
	while (true)
	{
		pthread_mutex_lock(&g_iJobsMutex);
		if (!g_lJobs.size())
		{
			pthread_mutex_unlock(&g_iJobsMutex);

			if (pThread->bQuitWhenDone)
			{
				pThread->bDone = true;
				pthread_exit(NULL);
				return;
			}
			else
			{
				// Give the main thread a chance to render and whatnot.
				SleepMS(1);
				continue;
			}
		}

		// Copy so we can pop it.
		thread_job_t oThreadJob = g_lJobs.front();
		g_lJobs.pop_front();

		pthread_mutex_unlock(&g_iJobsMutex);

		pThread->pGenerator->RaytraceSceneFromPosition(oThreadJob.pTracer, oThreadJob.vecUVPosition, oThreadJob.vecNormal, oThreadJob.pMeshInstance, oThreadJob.pFace, oThreadJob.iTexel);

		// Give the main thread a chance to render and whatnot.
		SleepMS(1);

		if (pThread->pGenerator->IsStopped())
		{
			pThread->bDone = true;
			pthread_exit(NULL);
			return;
		}
	}
}

void CAOGenerator::RaytraceSetupThreads()
{
	if (GetNumberOfProcessors() == 1)
		return;

	pthread_mutex_init(&g_iDataMutex, NULL);
	pthread_mutex_init(&g_iJobsMutex, NULL);

	g_iJobsGiven = 0;

	// Insert all first so that reallocations are all done before we pass the pointers to the threads.
	g_aThreads.insert(g_aThreads.begin(), GetNumberOfProcessors(), thread_data_t());

	for (size_t i = 0; i < GetNumberOfProcessors(); i++)
	{
		thread_data_t* pThread = &g_aThreads[i];

		pThread->pGenerator = this;
		pThread->bQuitWhenDone = false;
		pThread->bDone = false;

		pthread_create(&pThread->iThread, NULL, (void *(*) (void *))&RaytraceThreadMain, (void*)pThread);
	}
}

void CAOGenerator::RaytraceCleanupThreads()
{
	if (GetNumberOfProcessors() == 1)
		return;

	// If there are no threads then we've already cleaned up, don't do it twice.
	if (!g_aThreads.size())
		return;

	for (size_t i = 0; i < g_aThreads.size(); i++)
	{
		thread_data_t* pThread = &g_aThreads[i];

		pthread_detach(pThread->iThread);
	}

	pthread_mutex_destroy(&g_iDataMutex);
	pthread_mutex_destroy(&g_iJobsMutex);

	g_aThreads.clear();
}

void CAOGenerator::RaytraceSceneMultithreaded(raytrace::CRaytracer* pTracer, Vector vecUVPosition, Vector vecNormal, CConversionMeshInstance* pMeshInstance, CConversionFace* pFace, size_t iTexel)
{
	if (GetNumberOfProcessors() == 1)
	{
		RaytraceSceneFromPosition(pTracer, vecUVPosition, vecNormal, pMeshInstance, pFace, iTexel);
		return;
	}

	pthread_mutex_lock(&g_iJobsMutex);

	g_lJobs.push_back(thread_job_t());
	thread_job_t* pJob = &g_lJobs.back();
	pJob->pTracer = pTracer;
	pJob->vecUVPosition = vecUVPosition;
	pJob->vecNormal = vecNormal;
	pJob->pMeshInstance = pMeshInstance;
	pJob->pFace = pFace;
	pJob->iTexel = iTexel;

	pthread_mutex_unlock(&g_iJobsMutex);

	g_iJobsGiven++;
}

void CAOGenerator::RaytraceJoinThreads()
{
	if (GetNumberOfProcessors() == 1)
		return;

	// Doesn't really join the threads per se, just signals for them to quit and then waits for them to be done
	// while calling work progress updates so the user can see what's happening.

	for (size_t i = 0; i < g_aThreads.size(); i++)
		g_aThreads[i].bQuitWhenDone = true;

	if (m_pWorkListener)
		m_pWorkListener->SetAction(L"Rendering", g_iJobsGiven);

	while (true)
	{
		bool bDone = true;
		for (size_t t = 0; t < g_aThreads.size(); t++)
		{
			if (!g_aThreads[t].bDone)
				bDone = false;
		}

		if (bDone)
			return;

		if (m_pWorkListener)
			m_pWorkListener->WorkProgress(g_iJobsGiven - g_lJobs.size());

		if (m_bStopGenerating)
		{
			RaytraceCleanupThreads();
			return;
		}
	}
}
<|endoftext|>


<commit_before>#include "master.hpp"

namespace factor
{

THREADHANDLE start_thread(void *(*start_routine)(void *),void *args){
    return (void*) CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)start_routine, args, 0, 0);
}

DWORD dwTlsIndex;

void init_platform_globals()
{
	if ((dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES)
		fatal_error("TlsAlloc failed - out of indexes",0);
}

void register_vm_with_thread(factor_vm *vm)
{
	if (! TlsSetValue(dwTlsIndex, vm))
		fatal_error("TlsSetValue failed",0);
}

factor_vm *tls_vm()
{
	factor_vm *vm = (factor_vm*)TlsGetValue(dwTlsIndex);
	assert(vm != NULL);
	return vm;
}

u64 system_micros()
{
	FILETIME t;
	GetSystemTimeAsFileTime(&t);
	return (((u64)t.dwLowDateTime | (u64)t.dwHighDateTime<<32)
		- EPOCH_OFFSET) / 10;
}

u64 nano_count()
{
	LARGE_INTEGER count;
	LARGE_INTEGER frequency;
	BOOL ret;
	ret = QueryPerformanceCounter(&count);
	if(ret == 0)
		fatal_error("QueryPerformanceCounter", 0);
	ret = QueryPerformanceFrequency(&frequency);
	if(ret == 0)
		fatal_error("QueryPerformanceFrequency", 0);

	return count.QuadPart*(1000000000/frequency.QuadPart);
}

void sleep_nanos(u64 nsec)
{
	Sleep((DWORD)(nsec/1000000));
}

LONG factor_vm::exception_handler(PEXCEPTION_POINTERS pe)
{
	PEXCEPTION_RECORD e = (PEXCEPTION_RECORD)pe->ExceptionRecord;
	CONTEXT *c = (CONTEXT*)pe->ContextRecord;

	if(in_code_heap_p(c->EIP))
		signal_callstack_top = (stack_frame *)c->ESP;
	else
		signal_callstack_top = NULL;

        switch (e->ExceptionCode)
        {
        case EXCEPTION_ACCESS_VIOLATION:
		signal_fault_addr = e->ExceptionInformation[1];
		c->EIP = (cell)factor::memory_signal_handler_impl;
                break;

	case STATUS_FLOAT_DENORMAL_OPERAND:
	case STATUS_FLOAT_DIVIDE_BY_ZERO:
	case STATUS_FLOAT_INEXACT_RESULT:
	case STATUS_FLOAT_INVALID_OPERATION:
	case STATUS_FLOAT_OVERFLOW:
	case STATUS_FLOAT_STACK_CHECK:
	case STATUS_FLOAT_UNDERFLOW:
	case STATUS_FLOAT_MULTIPLE_FAULTS:
	case STATUS_FLOAT_MULTIPLE_TRAPS:
		signal_fpu_status = fpu_status(X87SW(c) | MXCSR(c));
		X87SW(c) = 0;
		MXCSR(c) &= 0xffffffc0;
		c->EIP = (cell)factor::fp_signal_handler_impl;
		break;
	case 0x40010006:
		/* If the Widcomm bluetooth stack is installed, the BTTray.exe
		process injects code into running programs. For some reason this
		results in random SEH exceptions with this (undocumented)
		exception code being raised. The workaround seems to be ignoring
		this altogether, since that is what happens if SEH is not
		enabled. Don't really have any idea what this exception means. */
		break;
	default:
		signal_number = e->ExceptionCode;
		c->EIP = (cell)factor::misc_signal_handler_impl;
		break;
	}
	return EXCEPTION_CONTINUE_EXECUTION;
}

FACTOR_STDCALL LONG exception_handler(PEXCEPTION_POINTERS pe)
{
	return tls_vm()->exception_handler(pe);
}

bool handler_added = 0;

void factor_vm::c_to_factor_toplevel(cell quot)
{
	if(!handler_added){
		if(!AddVectoredExceptionHandler(0, (PVECTORED_EXCEPTION_HANDLER)factor::exception_handler))
			fatal_error("AddVectoredExceptionHandler failed", 0);
		handler_added = 1;
	}
	c_to_factor(quot,this);
 	RemoveVectoredExceptionHandler((void *)factor::exception_handler);
}

void factor_vm::open_console()
{
}

}
<commit_msg>workaround for QueryPerformanceCounter: if the high part of the count doesn't increment when the low part overflows, keep track of this and add the correction on future calls to nano_count<commit_after>#include "master.hpp"

namespace factor
{

THREADHANDLE start_thread(void *(*start_routine)(void *),void *args){
    return (void*) CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)start_routine, args, 0, 0);
}

DWORD dwTlsIndex;

void init_platform_globals()
{
	if ((dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES)
		fatal_error("TlsAlloc failed - out of indexes",0);
}

void register_vm_with_thread(factor_vm *vm)
{
	if (! TlsSetValue(dwTlsIndex, vm))
		fatal_error("TlsSetValue failed",0);
}

factor_vm *tls_vm()
{
	factor_vm *vm = (factor_vm*)TlsGetValue(dwTlsIndex);
	assert(vm != NULL);
	return vm;
}

u64 system_micros()
{
	FILETIME t;
	GetSystemTimeAsFileTime(&t);
	return (((u64)t.dwLowDateTime | (u64)t.dwHighDateTime<<32)
		- EPOCH_OFFSET) / 10;
}

/* On VirtualBox, QueryPerformanceCounter does not increment
the high part every time the low part overflows.  Workaround. */
u64 nano_count()
{
	LARGE_INTEGER count;
	LARGE_INTEGER frequency;
	static u32 hi_correction = 0;
	static u32 hi = 0xffffffff;
	static u32 lo = 0xffffffff;
	BOOL ret;
	ret = QueryPerformanceCounter(&count);
	if(ret == 0)
		fatal_error("QueryPerformanceCounter", 0);
	ret = QueryPerformanceFrequency(&frequency);
	if(ret == 0)
		fatal_error("QueryPerformanceFrequency", 0);

	if((u32)count.LowPart < lo && (u32)count.HighPart == hi)
		hi_correction++;

	hi = count.HighPart;
	lo = count.LowPart;
	count.HighPart += hi_correction;

	return count.QuadPart*(1000000000/frequency.QuadPart);
}

void sleep_nanos(u64 nsec)
{
	Sleep((DWORD)(nsec/1000000));
}

LONG factor_vm::exception_handler(PEXCEPTION_POINTERS pe)
{
	PEXCEPTION_RECORD e = (PEXCEPTION_RECORD)pe->ExceptionRecord;
	CONTEXT *c = (CONTEXT*)pe->ContextRecord;

	if(in_code_heap_p(c->EIP))
		signal_callstack_top = (stack_frame *)c->ESP;
	else
		signal_callstack_top = NULL;

        switch (e->ExceptionCode)
        {
        case EXCEPTION_ACCESS_VIOLATION:
		signal_fault_addr = e->ExceptionInformation[1];
		c->EIP = (cell)factor::memory_signal_handler_impl;
                break;

	case STATUS_FLOAT_DENORMAL_OPERAND:
	case STATUS_FLOAT_DIVIDE_BY_ZERO:
	case STATUS_FLOAT_INEXACT_RESULT:
	case STATUS_FLOAT_INVALID_OPERATION:
	case STATUS_FLOAT_OVERFLOW:
	case STATUS_FLOAT_STACK_CHECK:
	case STATUS_FLOAT_UNDERFLOW:
	case STATUS_FLOAT_MULTIPLE_FAULTS:
	case STATUS_FLOAT_MULTIPLE_TRAPS:
		signal_fpu_status = fpu_status(X87SW(c) | MXCSR(c));
		X87SW(c) = 0;
		MXCSR(c) &= 0xffffffc0;
		c->EIP = (cell)factor::fp_signal_handler_impl;
		break;
	case 0x40010006:
		/* If the Widcomm bluetooth stack is installed, the BTTray.exe
		process injects code into running programs. For some reason this
		results in random SEH exceptions with this (undocumented)
		exception code being raised. The workaround seems to be ignoring
		this altogether, since that is what happens if SEH is not
		enabled. Don't really have any idea what this exception means. */
		break;
	default:
		signal_number = e->ExceptionCode;
		c->EIP = (cell)factor::misc_signal_handler_impl;
		break;
	}
	return EXCEPTION_CONTINUE_EXECUTION;
}

FACTOR_STDCALL LONG exception_handler(PEXCEPTION_POINTERS pe)
{
	return tls_vm()->exception_handler(pe);
}

bool handler_added = 0;

void factor_vm::c_to_factor_toplevel(cell quot)
{
	if(!handler_added){
		if(!AddVectoredExceptionHandler(0, (PVECTORED_EXCEPTION_HANDLER)factor::exception_handler))
			fatal_error("AddVectoredExceptionHandler failed", 0);
		handler_added = 1;
	}
	c_to_factor(quot,this);
 	RemoveVectoredExceptionHandler((void *)factor::exception_handler);
}

void factor_vm::open_console()
{
}

}
<|endoftext|>


<commit_before>#include "iconv.h"

#include <v8.h>
#include <node.h>
#include <node_buffer.h>

#include <cstring>
#include <cerrno>

using namespace v8;
using namespace node;

namespace {

class Iconv: public ObjectWrap {
public:
  static void Initialize(Handle<Object>& target);
  static Handle<Value> New(const Arguments& args);
  static Handle<Value> Convert(const Arguments& args);

  Iconv(iconv_t conv);
  ~Iconv(); // destructor may not run if program is short-lived or aborted

  // the actual conversion happens here
  Handle<Value> Convert(char* data, size_t length);

private:
  iconv_t conv_;
};

Iconv::Iconv(iconv_t conv): conv_(conv) {
  assert(conv_ != (iconv_t) -1);
}

Iconv::~Iconv() {
  ::iconv_close(conv_);
}

// helper class: reverse linked list of dumb buffers
struct chunk {
  chunk *const prev;
  size_t size;
  char data[32 * 1024];

  chunk(chunk *prev): prev(prev), size(0) {
  }
};

// the actual conversion happens here
Handle<Value> Iconv::Convert(char* data, size_t length) {
  assert(conv_ != (iconv_t) -1);
  assert(data != 0);

  chunk *c = 0;
  char *inbuf = data;
  size_t inbytesleft = length;
  size_t offset = 0;

  while (true) {
    // placement new on stack
    c = new chunk(c);

    char *outbuf = c->data;
    size_t outbytesleft = sizeof(c->data);

    size_t rv = ::iconv(conv_, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
    c->size = sizeof(c->data) - outbytesleft;
    offset += c->size;

    if (rv == (size_t) -1) {
      if (errno == E2BIG) {
        continue;
      }
      if (errno == EINVAL) {
        return ThrowException(ErrnoException(errno, "iconv", "Incomplete character sequence."));
      }
      if (errno == EILSEQ) {
        return ThrowException(ErrnoException(errno, "iconv", "Illegal character sequence."));
      }
      return ThrowException(ErrnoException(errno, "iconv"));
    }

    assert(inbytesleft == 0);
    break;
  }

  // copy linked list of chunks into Buffer in reverse order (last chunk at the top, second-to-last chunk below that, etc)
  Buffer& b = *Buffer::New(offset);
  for (chunk *t; c != 0; t = c->prev, delete c, c = t) {
    offset -= c->size;
    memcpy(b.data() + offset, c->data, c->size);
  }

  return b.handle_;
}

Handle<Value> Iconv::Convert(const Arguments& args) {
  HandleScope scope;

  Iconv* self = ObjectWrap::Unwrap<Iconv>(args.This());
  Local<Value> arg = args[0];

  if (arg->IsString()) {
    String::Utf8Value string(arg->ToString());
    return self->Convert(*string, string.length());
  }

  if (arg->IsObject()) {
    Handle<Value> object = arg->ToObject();
    if (Buffer::HasInstance(object)) {
      Buffer& buffer = *ObjectWrap::Unwrap<Buffer>(arg->ToObject());
      return self->Convert(buffer.data(), buffer.length());
    }
  }

  return Undefined();
}

Handle<Value> Iconv::New(const Arguments& args) {
  HandleScope scope;

  // inconsistency: node-iconv expects (source, target) while native iconv expects (target, source)
  // wontfix for now, node-iconv's approach feels more intuitive
  String::AsciiValue sourceEncoding(args[0]->ToString());
  String::AsciiValue targetEncoding(args[1]->ToString());

  iconv_t conv = ::iconv_open(*targetEncoding, *sourceEncoding);
  if (conv == (iconv_t) -1) {
    return ThrowException(ErrnoException(errno, "iconv_open", "Conversion not supported."));
  }

  Iconv* instance = new Iconv(conv);
  instance->Wrap(args.Holder());

  return args.This();
}

void Iconv::Initialize(Handle<Object>& target) {
  HandleScope scope;

  Local<FunctionTemplate> t = FunctionTemplate::New(Iconv::New);
  t->InstanceTemplate()->SetInternalFieldCount(1);

  NODE_SET_PROTOTYPE_METHOD(t, "convert", Iconv::Convert);

  target->Set(String::NewSymbol("Iconv"), t->GetFunction());
}

extern "C" void init(Handle<Object> target) {
  Iconv::Initialize(target);
}

} // namespace
<commit_msg>Remove erroneous comment (refactoring leftover).<commit_after>#include "iconv.h"

#include <v8.h>
#include <node.h>
#include <node_buffer.h>

#include <cstring>
#include <cerrno>

using namespace v8;
using namespace node;

namespace {

class Iconv: public ObjectWrap {
public:
  static void Initialize(Handle<Object>& target);
  static Handle<Value> New(const Arguments& args);
  static Handle<Value> Convert(const Arguments& args);

  Iconv(iconv_t conv);
  ~Iconv(); // destructor may not run if program is short-lived or aborted

  // the actual conversion happens here
  Handle<Value> Convert(char* data, size_t length);

private:
  iconv_t conv_;
};

Iconv::Iconv(iconv_t conv): conv_(conv) {
  assert(conv_ != (iconv_t) -1);
}

Iconv::~Iconv() {
  ::iconv_close(conv_);
}

// helper class: reverse linked list of dumb buffers
struct chunk {
  chunk *const prev;
  size_t size;
  char data[32 * 1024];

  chunk(chunk *prev): prev(prev), size(0) {
  }
};

// the actual conversion happens here
Handle<Value> Iconv::Convert(char* data, size_t length) {
  assert(conv_ != (iconv_t) -1);
  assert(data != 0);

  chunk *c = 0;
  char *inbuf = data;
  size_t inbytesleft = length;
  size_t offset = 0;

  while (true) {
    c = new chunk(c);

    char *outbuf = c->data;
    size_t outbytesleft = sizeof(c->data);

    size_t rv = ::iconv(conv_, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
    c->size = sizeof(c->data) - outbytesleft;
    offset += c->size;

    if (rv == (size_t) -1) {
      if (errno == E2BIG) {
        continue;
      }
      if (errno == EINVAL) {
        return ThrowException(ErrnoException(errno, "iconv", "Incomplete character sequence."));
      }
      if (errno == EILSEQ) {
        return ThrowException(ErrnoException(errno, "iconv", "Illegal character sequence."));
      }
      return ThrowException(ErrnoException(errno, "iconv"));
    }

    assert(inbytesleft == 0);
    break;
  }

  // copy linked list of chunks into Buffer in reverse order (last chunk at the top, second-to-last chunk below that, etc)
  Buffer& b = *Buffer::New(offset);
  for (chunk *t; c != 0; t = c->prev, delete c, c = t) {
    offset -= c->size;
    memcpy(b.data() + offset, c->data, c->size);
  }

  return b.handle_;
}

Handle<Value> Iconv::Convert(const Arguments& args) {
  HandleScope scope;

  Iconv* self = ObjectWrap::Unwrap<Iconv>(args.This());
  Local<Value> arg = args[0];

  if (arg->IsString()) {
    String::Utf8Value string(arg->ToString());
    return self->Convert(*string, string.length());
  }

  if (arg->IsObject()) {
    Handle<Value> object = arg->ToObject();
    if (Buffer::HasInstance(object)) {
      Buffer& buffer = *ObjectWrap::Unwrap<Buffer>(arg->ToObject());
      return self->Convert(buffer.data(), buffer.length());
    }
  }

  return Undefined();
}

Handle<Value> Iconv::New(const Arguments& args) {
  HandleScope scope;

  // inconsistency: node-iconv expects (source, target) while native iconv expects (target, source)
  // wontfix for now, node-iconv's approach feels more intuitive
  String::AsciiValue sourceEncoding(args[0]->ToString());
  String::AsciiValue targetEncoding(args[1]->ToString());

  iconv_t conv = ::iconv_open(*targetEncoding, *sourceEncoding);
  if (conv == (iconv_t) -1) {
    return ThrowException(ErrnoException(errno, "iconv_open", "Conversion not supported."));
  }

  Iconv* instance = new Iconv(conv);
  instance->Wrap(args.Holder());

  return args.This();
}

void Iconv::Initialize(Handle<Object>& target) {
  HandleScope scope;

  Local<FunctionTemplate> t = FunctionTemplate::New(Iconv::New);
  t->InstanceTemplate()->SetInternalFieldCount(1);

  NODE_SET_PROTOTYPE_METHOD(t, "convert", Iconv::Convert);

  target->Set(String::NewSymbol("Iconv"), t->GetFunction());
}

extern "C" void init(Handle<Object> target) {
  Iconv::Initialize(target);
}

} // namespace
<|endoftext|>


<commit_before>//===----- CompileOnDemandLayerTest.cpp - Unit tests for the COD layer ----===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "OrcTestCommon.h"
#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h"
#include "gtest/gtest.h"

using namespace llvm;
using namespace llvm::orc;

namespace {

class DummyCallbackManager : public orc::JITCompileCallbackManagerBase {
public:
  DummyCallbackManager()
      : JITCompileCallbackManagerBase(0), NextStubAddress(0),
        UniversalCompile([]() { return 0; }) {
  }

  CompileCallbackInfo getCompileCallback() override {
    return CompileCallbackInfo(++NextStubAddress, UniversalCompile);
  }
public:
  TargetAddress NextStubAddress;
  CompileFtor UniversalCompile;
};

class DummyStubsManager : public orc::IndirectStubsManagerBase {
public:
  std::error_code createStub(StringRef StubName, TargetAddress InitAddr,
                             JITSymbolFlags Flags) override {
    llvm_unreachable("Not implemented");
  }

  std::error_code createStubs(const StubInitsMap &StubInits) override {
    llvm_unreachable("Not implemented");
  }

  JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) override {
    llvm_unreachable("Not implemented");
  }

  JITSymbol findPointer(StringRef Name) override {
    llvm_unreachable("Not implemented");
  }

  std::error_code updatePointer(StringRef Name,
                                TargetAddress NewAddr) override {
    llvm_unreachable("Not implemented");
  }
};

TEST(CompileOnDemandLayerTest, FindSymbol) {
  auto MockBaseLayer =
    createMockBaseLayer<int>(DoNothingAndReturn<int>(0),
                             DoNothingAndReturn<void>(),
                             [](const std::string &Name, bool) {
                               if (Name == "foo")
                                 return JITSymbol(1, JITSymbolFlags::Exported);
                               return JITSymbol(nullptr);
                             },
                             DoNothingAndReturn<JITSymbol>(nullptr));

  typedef decltype(MockBaseLayer) MockBaseLayerT;
  DummyCallbackManager CallbackMgr;
  auto StubsMgrBuilder =
    []() {
      return llvm::make_unique<DummyStubsManager>();
    };

  llvm::orc::CompileOnDemandLayer<MockBaseLayerT>
    COD(MockBaseLayer,
        [](Function &F) { std::set<Function*> S; S.insert(&F); return S; },
        CallbackMgr, StubsMgrBuilder, true);
  auto Sym = COD.findSymbol("foo", true);

  EXPECT_TRUE(!!Sym)
    << "CompileOnDemand::findSymbol should call findSymbol in the base layer.";
}

}
<commit_msg>Orc: Streamline some lambda usage in a unit test<commit_after>//===----- CompileOnDemandLayerTest.cpp - Unit tests for the COD layer ----===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "OrcTestCommon.h"
#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h"
#include "gtest/gtest.h"

using namespace llvm;
using namespace llvm::orc;

namespace {

class DummyCallbackManager : public orc::JITCompileCallbackManagerBase {
public:
  DummyCallbackManager()
      : JITCompileCallbackManagerBase(0), NextStubAddress(0),
        UniversalCompile([]() { return 0; }) {
  }

  CompileCallbackInfo getCompileCallback() override {
    return CompileCallbackInfo(++NextStubAddress, UniversalCompile);
  }
public:
  TargetAddress NextStubAddress;
  CompileFtor UniversalCompile;
};

class DummyStubsManager : public orc::IndirectStubsManagerBase {
public:
  std::error_code createStub(StringRef StubName, TargetAddress InitAddr,
                             JITSymbolFlags Flags) override {
    llvm_unreachable("Not implemented");
  }

  std::error_code createStubs(const StubInitsMap &StubInits) override {
    llvm_unreachable("Not implemented");
  }

  JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) override {
    llvm_unreachable("Not implemented");
  }

  JITSymbol findPointer(StringRef Name) override {
    llvm_unreachable("Not implemented");
  }

  std::error_code updatePointer(StringRef Name,
                                TargetAddress NewAddr) override {
    llvm_unreachable("Not implemented");
  }
};

TEST(CompileOnDemandLayerTest, FindSymbol) {
  auto MockBaseLayer =
    createMockBaseLayer<int>(DoNothingAndReturn<int>(0),
                             DoNothingAndReturn<void>(),
                             [](const std::string &Name, bool) {
                               if (Name == "foo")
                                 return JITSymbol(1, JITSymbolFlags::Exported);
                               return JITSymbol(nullptr);
                             },
                             DoNothingAndReturn<JITSymbol>(nullptr));

  typedef decltype(MockBaseLayer) MockBaseLayerT;
  DummyCallbackManager CallbackMgr;

  llvm::orc::CompileOnDemandLayer<MockBaseLayerT> COD(
      MockBaseLayer, [](Function &F) { return std::set<Function *>{&F}; },
      CallbackMgr, [] { return llvm::make_unique<DummyStubsManager>(); }, true);

  auto Sym = COD.findSymbol("foo", true);

  EXPECT_TRUE(!!Sym)
    << "CompileOnDemand::findSymbol should call findSymbol in the base layer.";
}

}
<|endoftext|>


<commit_before>/*

    OF-TangibleFramework . Framework for Taller de Sistemes Interactius I
    Universitat Pompeu Fabra

    Copyright (c) 2009 Carles F. Julià <carles.fernandez@upf.edu>

    Permission is hereby granted, free of charge, to any person
    obtaining a copy of this software and associated documentation
    files (the "Software"), to deal in the Software without
    restriction, including without limitation the rights to use,
    copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following
    conditions:

    The above copyright notice and this permission notice shall be
    included in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    OTHER DEALINGS IN THE SOFTWARE.

*/

#ifndef TUIO_TEVENT_H
#define TUIO_TEVENT_H

#include <vector>
#include <iostream>
#include "Singleton.hpp"

namespace tuio {

///This class assigns a single identifier to every TTEvent subclass
class EventTypes : public Singleton<EventTypes>
{
    private:
    unsigned int n;
    protected:
    friend class Singleton<EventTypes>;
    EventTypes():n(0){}
    public:
    /*unsigned int getNumber()
    {
        return n++;
    }*/
    template<typename T>
    unsigned int get_number()
    {
        static bool ins = false;
        static unsigned int uniquename;
        if (!ins)
        {
            uniquename = n++;
            ins = true;
        }
        return uniquename;
    }
};

///Base class for all TEvents
class TEvent {
  public:
      unsigned int name;
    TEvent(){}

};

///The TTEvent template class allows every TEvent subclass to get a single differenciate identifier.
template <typename TE>
class TTEvent : public TEvent
{
    public:
    TTEvent()
    {
        static bool ins = false;
        static unsigned int uniquename;
        if (!ins)
        {
            uniquename = EventTypes::Instance().get_number<TE>();
            ins = true;
        }
        name = uniquename;
    }
};

} // namespace tuio

#endif
<commit_msg>debugging capabilities of TEvents<commit_after>/*

    OF-TangibleFramework . Framework for Taller de Sistemes Interactius I
    Universitat Pompeu Fabra

    Copyright (c) 2009 Carles F. Julià <carles.fernandez@upf.edu>

    Permission is hereby granted, free of charge, to any person
    obtaining a copy of this software and associated documentation
    files (the "Software"), to deal in the Software without
    restriction, including without limitation the rights to use,
    copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following
    conditions:

    The above copyright notice and this permission notice shall be
    included in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    OTHER DEALINGS IN THE SOFTWARE.

*/

#ifndef TUIO_TEVENT_H
#define TUIO_TEVENT_H

#include <vector>
#include <iostream>
#include "Singleton.hpp"

namespace tuio {

///This class assigns a single identifier to every TTEvent subclass
class EventTypes : public Singleton<EventTypes>
{
    private:
    unsigned int n;
    protected:
    friend class Singleton<EventTypes>;
    EventTypes():n(0){}
    public:
    /*unsigned int getNumber()
    {
        return n++;
    }*/
    template<typename T>
    unsigned int get_number()
    {
        static bool ins = false;
        static unsigned int uniquename;
        if (!ins)
        {
            uniquename = n++;
            ins = true;
        }
        return uniquename;
    }
};

///Base class for all TEvents
class TEvent {
  public:
      unsigned int name;
#ifdef DEBUG
      std::string debugName;
#endif
    TEvent(){}

};

///The TTEvent template class allows every TEvent subclass to get a single differenciate identifier.
template <typename TE>
class TTEvent : public TEvent
{
    public:
    TTEvent()
    {
        static bool ins = false;
        static unsigned int uniquename;
        if (!ins)
        {
            uniquename = EventTypes::Instance().get_number<TE>();
            ins = true;
        }
        name = uniquename;
    }
};

} // namespace tuio

#endif
<|endoftext|>


<commit_before><commit_msg>format<commit_after><|endoftext|>


<commit_before>#include "LdConfigDirWrapper.h"
#include "PEFile.h"

bufsize_t LdConfigDirWrapper::getLdConfigDirSize()
{
    bufsize_t dirSize = 0;

    if (m_Exe->getBitMode() == Executable::BITS_32) {
        dirSize = sizeof(pe::IMAGE_LOAD_CONFIG_DIRECTORY32);
    } else if (m_Exe->getBitMode() == Executable::BITS_64) {
        dirSize = sizeof(pe::IMAGE_LOAD_CONFIG_DIRECTORY64);
    }
    return dirSize;
}

bufsize_t LdConfigDirWrapper::getW81partSize()
{
    bufsize_t dirSize = 0;

    if (m_Exe->getBitMode() == Executable::BITS_32) {
        dirSize = sizeof(pe::IMAGE_LOAD_CONFIG_D32_W81);
    } else if (m_Exe->getBitMode() == Executable::BITS_64) {
        dirSize = sizeof(pe::IMAGE_LOAD_CONFIG_D64_W81);
    }
    return dirSize;
}

void* LdConfigDirWrapper::getLdConfigDirPtr()
{
    IMAGE_DATA_DIRECTORY *d = getDataDirectory(m_Exe);
    if (!d) return NULL;

    offset_t rva = static_cast<offset_t>(d[pe::DIR_LOAD_CONFIG].VirtualAddress);
    if (rva == 0) return NULL;

    bufsize_t dirSize = getLdConfigDirSize();
    BYTE *ptr = m_Exe->getContentAt(rva, Executable::RVA, dirSize);
    return ptr;
}

pe::IMAGE_LOAD_CONFIG_DIRECTORY32* LdConfigDirWrapper::ldConf32()
{
    if (m_Exe->getBitMode() != Executable::BITS_32) return NULL;
    return (pe::IMAGE_LOAD_CONFIG_DIRECTORY32*) getLdConfigDirPtr();
}

pe::IMAGE_LOAD_CONFIG_DIRECTORY64* LdConfigDirWrapper::ldConf64()
{
    if (m_Exe->getBitMode() != Executable::BITS_64) return NULL;
    return (pe::IMAGE_LOAD_CONFIG_DIRECTORY64*) getLdConfigDirPtr();
}

void* LdConfigDirWrapper::getW81part()
{
    void *ldPtr = getLdConfigDirPtr();
    if (ldPtr == NULL) return false;

    size_t dirSize = getLdConfigDirSize();

    size_t realSize = 0;
    if (m_Exe->getBitMode() == Executable::BITS_32) {
        realSize = ((pe::IMAGE_LOAD_CONFIG_DIRECTORY32*) ldPtr)->Size;

    } else if (m_Exe->getBitMode() == Executable::BITS_64) {
        realSize = ((pe::IMAGE_LOAD_CONFIG_DIRECTORY64*) ldPtr)->Size;
    }

    if (realSize <= dirSize) return NULL;

    if (realSize > dirSize) {
        offset_t offset = this->getOffset(ldPtr);
        if (offset == INVALID_ADDR) return NULL;

        offset += dirSize;
        return m_Exe->getContentAt(offset, getW81partSize());
    }
    return NULL;
}

pe::IMAGE_LOAD_CONFIG_D32_W81* LdConfigDirWrapper::getW81part32()
{
    if (m_Exe->getBitMode() != Executable::BITS_32) return NULL;
    return (pe::IMAGE_LOAD_CONFIG_D32_W81*) getW81part();
}

pe::IMAGE_LOAD_CONFIG_D64_W81* LdConfigDirWrapper::getW81part64()
{
    if (m_Exe->getBitMode() != Executable::BITS_64) return NULL;
    return (pe::IMAGE_LOAD_CONFIG_D64_W81*) getW81part();
}

bool LdConfigDirWrapper::wrap()
{
    clear();
    if (!getPtr()) return false;

    bool isOk = false;
    size_t count = this->getNumValue(SEH_COUNT, &isOk);
    if (!isOk) return false;

    for (int i = 0 ; i < count; i++) {
        LdConfigEntryWrapper *entry = new LdConfigEntryWrapper(m_Exe, this, i);
        if (entry->getPtr() == NULL) {
            delete entry;
            break;
        }
        this->entries.push_back(entry);
    }
    return true;
}

void* LdConfigDirWrapper::getPtr()
{
    void *ptr = ldConf32();
    if (ptr == NULL) ptr = ldConf64();
    return ptr;
}

void* LdConfigDirWrapper::firstSEHPtr()
{
    bool isOk = false;
    uint64_t offset = this->getNumValue(SEH_TABLE, &isOk);
    if (!isOk) return NULL;

    Executable::addr_type aT = containsAddrType(SEH_TABLE);
    if (aT == Executable::NOT_ADDR) return NULL;

    bufsize_t handlerSize = static_cast<bufsize_t>(this->getSEHSize());
    char *ptr = (char*) m_Exe->getContentAt(offset, aT, handlerSize);
    if (!ptr) return NULL;

    return ptr;
}

bufsize_t LdConfigDirWrapper::getSize()
{
    if (getPtr() == NULL) return 0;
    bufsize_t totalSize = getLdConfigDirSize();

    if (this->isW81()) totalSize += this->getW81partSize();
    return totalSize;
}

void* LdConfigDirWrapper::getFieldPtr(size_t fId, size_t subField)
{
    pe::IMAGE_LOAD_CONFIG_DIRECTORY32* ld32 = ldConf32();
    pe::IMAGE_LOAD_CONFIG_DIRECTORY64* ld64 = ldConf64();
    if (ld64 == NULL && ld32 == NULL) return NULL;

    pe::IMAGE_LOAD_CONFIG_D32_W81* p32 = getW81part32();
    pe::IMAGE_LOAD_CONFIG_D64_W81* p64 = getW81part64();
    if (p32 == NULL && p64 == NULL) {
        if (fId > SEH_COUNT) this->getPtr();
    }

    switch (fId) {
        case SIZE : return (ld32) ? (void*) &ld32->Size :  (void*) &ld64->Size;
        case TIMEST : return (ld32) ? (void*) &ld32->TimeDateStamp : (void*) &ld64->TimeDateStamp ;
        case MAJOR_VER : return (ld32) ? (void*) &ld32->MajorVersion : (void*) &ld64->MajorVersion ;
        case MINOR_VER : return (ld32) ? (void*) &ld32->MinorVersion : (void*) &ld64->MinorVersion ;
        case GLOBAL_FLAGS_CLEAR : return (ld32) ? (void*) &ld32->GlobalFlagsClear :  (void*) &ld64->GlobalFlagsClear ;
        case GLOBAL_FLAGS_SET : return (ld32) ? (void*) &ld32->GlobalFlagsSet :  (void*) &ld64->GlobalFlagsSet ;
        case CRITICAT_SEC_TIMEOUT : return (ld32) ? (void*) &ld32->CriticalSectionDefaultTimeout:  (void*) &ld64->CriticalSectionDefaultTimeout ;
        case DECOMMIT_FREE : return (ld32) ? (void*) &ld32->DeCommitFreeBlockThreshold : (void*) &ld64->DeCommitFreeBlockThreshold ;

        case DECOMMIT_TOTAL : return (ld32) ? (void*) &ld32->DeCommitTotalFreeThreshold :  (void*) &ld64->DeCommitTotalFreeThreshold ;
        case LOCK_PREFIX : return (ld32) ? (void*) &ld32->LockPrefixTable :  (void*) &ld64->LockPrefixTable ;
        case MAX_ALLOC : return (ld32) ? (void*) &ld32->MaximumAllocationSize :  (void*) &ld64->MaximumAllocationSize ;
        case VIRTUAL_MEM : return (ld32) ? (void*) &ld32->VirtualMemoryThreshold :  (void*) &ld64->VirtualMemoryThreshold ;
        case PROC_HEAP_FLAGS : return (ld32) ? (void*) &ld32->ProcessHeapFlags :  (void*) &ld64->ProcessHeapFlags ;
        case PROC_AFF_MASK : return (ld32) ? (void*) &ld32->ProcessAffinityMask :  (void*) &ld64->ProcessAffinityMask ;

        case CSD_VER : return (ld32) ? (void*) &ld32->CSDVersion :  (void*) &ld64->CSDVersion ;
        case RESERVED1 : return (ld32) ? (void*) &ld32->Reserved1 :  (void*) &ld64->Reserved1 ;
        case EDIT_LIST : return (ld32) ? (void*) &ld32->EditList :  (void*) &ld64->EditList ;
        case SEC_COOKIE : return (ld32) ? (void*) &ld32->SecurityCookie :  (void*) &ld64->SecurityCookie ;
        case SEH_TABLE : return (ld32) ? (void*) &ld32->SEHandlerTable :  (void*) &ld64->SEHandlerTable ;
        case SEH_COUNT : return (ld32) ? (void*) &ld32->SEHandlerCount :  (void*) &ld64->SEHandlerCount ;

        // W8.1 part:
        case GUARD_CHECK : return (p32) ? (void*) &p32->GuardCFCheckFunctionPointer :  (void*) &p64->GuardCFCheckFunctionPointer;
        case RESERVED2 : return (p32) ? (void*) &p32->Reserved2 :  (void*) &p64->Reserved2;
        case GUARD_TABLE: return (p32) ? (void*) &p32->GuardCFFunctionTable :  (void*) &p64->GuardCFFunctionTable;
        case GUARD_COUNT: return (p32) ? (void*) &p32->GuardCFFunctionCount :  (void*) &p64->GuardCFFunctionCount;
        case GUARD_FLAGS: return (p32) ? (void*) &p32->GuardFlags:  (void*) &p64->GuardFlags;
    }
    return this->getPtr();
}

QString LdConfigDirWrapper::getFieldName(size_t fieldId)
{
    switch (fieldId) {
        case SIZE : return "Size";
        case TIMEST : return "TimeDateStamp";
        case MAJOR_VER : return "MajorVersion";
        case MINOR_VER : return "MinorVersion";
        case GLOBAL_FLAGS_CLEAR : return "GlobalFlagsClear";
        case GLOBAL_FLAGS_SET : return "GlobalFlagsSet";
        case CRITICAT_SEC_TIMEOUT : return "CriticalSectionDefaultTimeout";
        case DECOMMIT_FREE : return "DeCommitFreeBlockThreshold";
        case DECOMMIT_TOTAL : return "DeCommitTotalFreeThreshold";
        case LOCK_PREFIX : return "LockPrefixTable";
        case MAX_ALLOC : return "MaximumAllocationSize";
        case VIRTUAL_MEM : return "VirtualMemoryThreshold";
        case PROC_AFF_MASK : return "ProcessAffinityMask";
        case PROC_HEAP_FLAGS : return "ProcessHeapFlags";
        case CSD_VER : return "CSDVersion";
        case RESERVED1 : return "Reserved";
        case EDIT_LIST : return "EditList";
        case SEC_COOKIE : return "SecurityCookie";
        case SEH_TABLE : return "SEHandlerTable";
        case SEH_COUNT : return "SEHandlerCount";
        // W8.1 part :
        case GUARD_CHECK : return "GuardCFCheckFunctionPtr";
        case RESERVED2 : return "Reserved2";
        case GUARD_TABLE: return "GuardCFFunctionTable";
        case GUARD_COUNT: return "GuardCFFunctionCount";
        case GUARD_FLAGS: return "GuardFlags";
    }
    return getName();
}

Executable::addr_type LdConfigDirWrapper::containsAddrType(size_t fieldId, size_t subField)
{
    switch (fieldId) {
        case LOCK_PREFIX :
        case EDIT_LIST :
        case SEC_COOKIE :
        case SEH_TABLE :
        case GUARD_CHECK :
        case GUARD_TABLE :
            return Executable::VA;
    }
    return Executable::NOT_ADDR;
}

//----------------

void* LdConfigEntryWrapper::getPtr()
{
    if (this->parentDir == NULL) return NULL;
    void* first = parentDir->firstSEHPtr();
    if (first == NULL) return NULL;

    bufsize_t size = static_cast<bufsize_t>(parentDir->getSEHSize());
    offset_t offset = this->getOffset(first);
    if (offset == INVALID_ADDR) return NULL;

    offset += (this->entryNum * size);
    void *ptr = m_Exe->getContentAt(offset, Executable::RAW, size);
    return ptr;
}

bufsize_t LdConfigEntryWrapper::getSize()
{
    if (this->parentDir == NULL) return 0;
    return static_cast<bufsize_t>(parentDir->getSEHSize());
}

<commit_msg>[BUGFIX] In LdConfigDirWrapper::getW81part() : fixed invalid return value<commit_after>#include "LdConfigDirWrapper.h"
#include "PEFile.h"

bufsize_t LdConfigDirWrapper::getLdConfigDirSize()
{
    bufsize_t dirSize = 0;

    if (m_Exe->getBitMode() == Executable::BITS_32) {
        dirSize = sizeof(pe::IMAGE_LOAD_CONFIG_DIRECTORY32);
    } else if (m_Exe->getBitMode() == Executable::BITS_64) {
        dirSize = sizeof(pe::IMAGE_LOAD_CONFIG_DIRECTORY64);
    }
    return dirSize;
}

bufsize_t LdConfigDirWrapper::getW81partSize()
{
    bufsize_t dirSize = 0;

    if (m_Exe->getBitMode() == Executable::BITS_32) {
        dirSize = sizeof(pe::IMAGE_LOAD_CONFIG_D32_W81);
    } else if (m_Exe->getBitMode() == Executable::BITS_64) {
        dirSize = sizeof(pe::IMAGE_LOAD_CONFIG_D64_W81);
    }
    return dirSize;
}

void* LdConfigDirWrapper::getLdConfigDirPtr()
{
    IMAGE_DATA_DIRECTORY *d = getDataDirectory(m_Exe);
    if (!d) return NULL;

    offset_t rva = static_cast<offset_t>(d[pe::DIR_LOAD_CONFIG].VirtualAddress);
    if (rva == 0) return NULL;

    bufsize_t dirSize = getLdConfigDirSize();
    BYTE *ptr = m_Exe->getContentAt(rva, Executable::RVA, dirSize);
    return ptr;
}

pe::IMAGE_LOAD_CONFIG_DIRECTORY32* LdConfigDirWrapper::ldConf32()
{
    if (m_Exe->getBitMode() != Executable::BITS_32) return NULL;
    return (pe::IMAGE_LOAD_CONFIG_DIRECTORY32*) getLdConfigDirPtr();
}

pe::IMAGE_LOAD_CONFIG_DIRECTORY64* LdConfigDirWrapper::ldConf64()
{
    if (m_Exe->getBitMode() != Executable::BITS_64) return NULL;
    return (pe::IMAGE_LOAD_CONFIG_DIRECTORY64*) getLdConfigDirPtr();
}

void* LdConfigDirWrapper::getW81part()
{
    void *ldPtr = getLdConfigDirPtr();
    if (ldPtr == NULL) return NULL;

    size_t dirSize = getLdConfigDirSize();

    size_t realSize = 0;
    if (m_Exe->getBitMode() == Executable::BITS_32) {
        realSize = ((pe::IMAGE_LOAD_CONFIG_DIRECTORY32*) ldPtr)->Size;

    } else if (m_Exe->getBitMode() == Executable::BITS_64) {
        realSize = ((pe::IMAGE_LOAD_CONFIG_DIRECTORY64*) ldPtr)->Size;
    }

    if (realSize <= dirSize) return NULL;

    if (realSize > dirSize) {
        offset_t offset = this->getOffset(ldPtr);
        if (offset == INVALID_ADDR) return NULL;

        offset += dirSize;
        return m_Exe->getContentAt(offset, getW81partSize());
    }
    return NULL;
}

pe::IMAGE_LOAD_CONFIG_D32_W81* LdConfigDirWrapper::getW81part32()
{
    if (m_Exe->getBitMode() != Executable::BITS_32) return NULL;
    return (pe::IMAGE_LOAD_CONFIG_D32_W81*) getW81part();
}

pe::IMAGE_LOAD_CONFIG_D64_W81* LdConfigDirWrapper::getW81part64()
{
    if (m_Exe->getBitMode() != Executable::BITS_64) return NULL;
    return (pe::IMAGE_LOAD_CONFIG_D64_W81*) getW81part();
}

bool LdConfigDirWrapper::wrap()
{
    clear();
    if (!getPtr()) return false;

    bool isOk = false;
    size_t count = this->getNumValue(SEH_COUNT, &isOk);
    if (!isOk) return false;

    for (int i = 0 ; i < count; i++) {
        LdConfigEntryWrapper *entry = new LdConfigEntryWrapper(m_Exe, this, i);
        if (entry->getPtr() == NULL) {
            delete entry;
            break;
        }
        this->entries.push_back(entry);
    }
    return true;
}

void* LdConfigDirWrapper::getPtr()
{
    void *ptr = ldConf32();
    if (ptr == NULL) ptr = ldConf64();
    return ptr;
}

void* LdConfigDirWrapper::firstSEHPtr()
{
    bool isOk = false;
    uint64_t offset = this->getNumValue(SEH_TABLE, &isOk);
    if (!isOk) return NULL;

    Executable::addr_type aT = containsAddrType(SEH_TABLE);
    if (aT == Executable::NOT_ADDR) return NULL;

    bufsize_t handlerSize = static_cast<bufsize_t>(this->getSEHSize());
    char *ptr = (char*) m_Exe->getContentAt(offset, aT, handlerSize);
    if (!ptr) return NULL;

    return ptr;
}

bufsize_t LdConfigDirWrapper::getSize()
{
    if (getPtr() == NULL) return 0;
    bufsize_t totalSize = getLdConfigDirSize();

    if (this->isW81()) totalSize += this->getW81partSize();
    return totalSize;
}

void* LdConfigDirWrapper::getFieldPtr(size_t fId, size_t subField)
{
    pe::IMAGE_LOAD_CONFIG_DIRECTORY32* ld32 = ldConf32();
    pe::IMAGE_LOAD_CONFIG_DIRECTORY64* ld64 = ldConf64();
    if (ld64 == NULL && ld32 == NULL) return NULL;

    pe::IMAGE_LOAD_CONFIG_D32_W81* p32 = getW81part32();
    pe::IMAGE_LOAD_CONFIG_D64_W81* p64 = getW81part64();
    if (p32 == NULL && p64 == NULL) {
        if (fId > SEH_COUNT) this->getPtr();
    }

    switch (fId) {
        case SIZE : return (ld32) ? (void*) &ld32->Size :  (void*) &ld64->Size;
        case TIMEST : return (ld32) ? (void*) &ld32->TimeDateStamp : (void*) &ld64->TimeDateStamp ;
        case MAJOR_VER : return (ld32) ? (void*) &ld32->MajorVersion : (void*) &ld64->MajorVersion ;
        case MINOR_VER : return (ld32) ? (void*) &ld32->MinorVersion : (void*) &ld64->MinorVersion ;
        case GLOBAL_FLAGS_CLEAR : return (ld32) ? (void*) &ld32->GlobalFlagsClear :  (void*) &ld64->GlobalFlagsClear ;
        case GLOBAL_FLAGS_SET : return (ld32) ? (void*) &ld32->GlobalFlagsSet :  (void*) &ld64->GlobalFlagsSet ;
        case CRITICAT_SEC_TIMEOUT : return (ld32) ? (void*) &ld32->CriticalSectionDefaultTimeout:  (void*) &ld64->CriticalSectionDefaultTimeout ;
        case DECOMMIT_FREE : return (ld32) ? (void*) &ld32->DeCommitFreeBlockThreshold : (void*) &ld64->DeCommitFreeBlockThreshold ;

        case DECOMMIT_TOTAL : return (ld32) ? (void*) &ld32->DeCommitTotalFreeThreshold :  (void*) &ld64->DeCommitTotalFreeThreshold ;
        case LOCK_PREFIX : return (ld32) ? (void*) &ld32->LockPrefixTable :  (void*) &ld64->LockPrefixTable ;
        case MAX_ALLOC : return (ld32) ? (void*) &ld32->MaximumAllocationSize :  (void*) &ld64->MaximumAllocationSize ;
        case VIRTUAL_MEM : return (ld32) ? (void*) &ld32->VirtualMemoryThreshold :  (void*) &ld64->VirtualMemoryThreshold ;
        case PROC_HEAP_FLAGS : return (ld32) ? (void*) &ld32->ProcessHeapFlags :  (void*) &ld64->ProcessHeapFlags ;
        case PROC_AFF_MASK : return (ld32) ? (void*) &ld32->ProcessAffinityMask :  (void*) &ld64->ProcessAffinityMask ;

        case CSD_VER : return (ld32) ? (void*) &ld32->CSDVersion :  (void*) &ld64->CSDVersion ;
        case RESERVED1 : return (ld32) ? (void*) &ld32->Reserved1 :  (void*) &ld64->Reserved1 ;
        case EDIT_LIST : return (ld32) ? (void*) &ld32->EditList :  (void*) &ld64->EditList ;
        case SEC_COOKIE : return (ld32) ? (void*) &ld32->SecurityCookie :  (void*) &ld64->SecurityCookie ;
        case SEH_TABLE : return (ld32) ? (void*) &ld32->SEHandlerTable :  (void*) &ld64->SEHandlerTable ;
        case SEH_COUNT : return (ld32) ? (void*) &ld32->SEHandlerCount :  (void*) &ld64->SEHandlerCount ;

        // W8.1 part:
        case GUARD_CHECK : return (p32) ? (void*) &p32->GuardCFCheckFunctionPointer :  (void*) &p64->GuardCFCheckFunctionPointer;
        case RESERVED2 : return (p32) ? (void*) &p32->Reserved2 :  (void*) &p64->Reserved2;
        case GUARD_TABLE: return (p32) ? (void*) &p32->GuardCFFunctionTable :  (void*) &p64->GuardCFFunctionTable;
        case GUARD_COUNT: return (p32) ? (void*) &p32->GuardCFFunctionCount :  (void*) &p64->GuardCFFunctionCount;
        case GUARD_FLAGS: return (p32) ? (void*) &p32->GuardFlags:  (void*) &p64->GuardFlags;
    }
    return this->getPtr();
}

QString LdConfigDirWrapper::getFieldName(size_t fieldId)
{
    switch (fieldId) {
        case SIZE : return "Size";
        case TIMEST : return "TimeDateStamp";
        case MAJOR_VER : return "MajorVersion";
        case MINOR_VER : return "MinorVersion";
        case GLOBAL_FLAGS_CLEAR : return "GlobalFlagsClear";
        case GLOBAL_FLAGS_SET : return "GlobalFlagsSet";
        case CRITICAT_SEC_TIMEOUT : return "CriticalSectionDefaultTimeout";
        case DECOMMIT_FREE : return "DeCommitFreeBlockThreshold";
        case DECOMMIT_TOTAL : return "DeCommitTotalFreeThreshold";
        case LOCK_PREFIX : return "LockPrefixTable";
        case MAX_ALLOC : return "MaximumAllocationSize";
        case VIRTUAL_MEM : return "VirtualMemoryThreshold";
        case PROC_AFF_MASK : return "ProcessAffinityMask";
        case PROC_HEAP_FLAGS : return "ProcessHeapFlags";
        case CSD_VER : return "CSDVersion";
        case RESERVED1 : return "Reserved";
        case EDIT_LIST : return "EditList";
        case SEC_COOKIE : return "SecurityCookie";
        case SEH_TABLE : return "SEHandlerTable";
        case SEH_COUNT : return "SEHandlerCount";
        // W8.1 part :
        case GUARD_CHECK : return "GuardCFCheckFunctionPtr";
        case RESERVED2 : return "Reserved2";
        case GUARD_TABLE: return "GuardCFFunctionTable";
        case GUARD_COUNT: return "GuardCFFunctionCount";
        case GUARD_FLAGS: return "GuardFlags";
    }
    return getName();
}

Executable::addr_type LdConfigDirWrapper::containsAddrType(size_t fieldId, size_t subField)
{
    switch (fieldId) {
        case LOCK_PREFIX :
        case EDIT_LIST :
        case SEC_COOKIE :
        case SEH_TABLE :
        case GUARD_CHECK :
        case GUARD_TABLE :
            return Executable::VA;
    }
    return Executable::NOT_ADDR;
}

//----------------

void* LdConfigEntryWrapper::getPtr()
{
    if (this->parentDir == NULL) return NULL;
    void* first = parentDir->firstSEHPtr();
    if (first == NULL) return NULL;

    bufsize_t size = static_cast<bufsize_t>(parentDir->getSEHSize());
    offset_t offset = this->getOffset(first);
    if (offset == INVALID_ADDR) return NULL;

    offset += (this->entryNum * size);
    void *ptr = m_Exe->getContentAt(offset, Executable::RAW, size);
    return ptr;
}

bufsize_t LdConfigEntryWrapper::getSize()
{
    if (this->parentDir == NULL) return 0;
    return static_cast<bufsize_t>(parentDir->getSEHSize());
}

<|endoftext|>


<commit_before><commit_msg>INTEGRATION: CWS pchfix02 (1.56.112); FILE MERGED 2006/09/01 17:57:47 kaib 1.56.112.1: #i68856# Added header markers and pch files<commit_after><|endoftext|>


<commit_before>/*
* This source file is part of ArkGameFrame
* For the latest info, see https://github.com/ArkGame
*
* Copyright (c) 2013-2018 ArkGame authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

#include "AFMemAlloc.h"

bool g_needRecord = false;
std::atomic_int g_totalAlloc = 0;
std::map<void*, AllocItem> g_memMap;
std::mutex g_memMapMutex;

bool g_usePool = false;
AFMemPool* g_pool[POOL_SIZE];
uint32_t g_poolTotal[POOL_SIZE] = { 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024 };
uint32_t g_poolSize[POOL_SIZE] = { 16, 32, 64, 128, 256, 512, 1024, 2048 };
uint32_t g_poolUsed[POOL_SIZE] = { 0, 0, 0, 0, 0, 0, 0, 0 };

AFMemAlloc::AFMemAlloc()
{

}

AFMemAlloc::~AFMemAlloc()
{

}

void AFMemAlloc::Start(bool need_record/* = true*/)
{
    g_totalAlloc = 0;
    g_memMap.clear();
    g_needRecord = need_record;
}

void AFMemAlloc::CheckLeak()
{
    printf("Memory check leak start-----------------------\n");

    if (g_totalAlloc == 0)
    {
        printf("No memory leak!\n");
    }
    else
    {
        printf("Find leak, %d bytes!\n", g_totalAlloc.load());
        for (auto& iter : g_memMap)
        {
            AllocItem& record = iter.second;
            printf("%s(%d) %d bytes\n", record.filename.c_str(), record.line, record.length);
        }
    }

    printf("Memory check leak end-------------------------\n");
}

void AFMemAlloc::InitPool()
{
    for (int i = 0; i < POOL_SIZE; ++i)
    {
        g_pool[i] = ARK_NEW AFMemPool(g_poolTotal[i], g_poolSize[i]);
    }

    g_usePool = true;
}

void AFMemAlloc::ClearPool()
{
    for (int i = 0; i < POOL_SIZE; ++i)
    {
        delete g_pool[i];
    }

    g_usePool = false;
}

void* AFMemAlloc::AllocDebug(size_t bytes, const char* file, int line)
{
    ARK_ASSERT_NO_EFFECT(bytes > 0);

    void* ptr = AllocInternal(bytes);
    if (ptr == nullptr)
    {
        return nullptr;
    }

    if (g_needRecord)
    {
        AllocItem record;
        record.length = bytes;
        record.filename = file;
        record.line = line;
        g_memMapMutex.lock();
        g_memMap[ptr] = record;
        g_memMapMutex.unlock();
        g_totalAlloc += bytes;
    }

    return ptr;
}

void* AFMemAlloc::ReallocDebug(void* addr, size_t bytes, const char* file, int line)
{
    if (g_needRecord)
    {
        if (addr != nullptr)
        {
            AllocItem record = g_memMap[addr];
            g_totalAlloc -= record.length;
            g_memMapMutex.lock();
            g_memMap.erase(addr);
            g_memMapMutex.unlock();
        }
    }

    ARK_ASSERT_NO_EFFECT(bytes > 0);

    void* ptr = ReallocInternal(addr, bytes);
    if (ptr == nullptr)
    {
        return nullptr;
    }

    if (g_needRecord)
    {
        AllocItem record;
        record.length = bytes;
        record.filename = file;
        record.line = line;
        g_memMapMutex.lock();
        g_memMap[ptr] = record;
        g_memMapMutex.unlock();
        g_totalAlloc += bytes;
    }

    return ptr;
}

void* AFMemAlloc::CallocDebug(size_t count, size_t bytes, const char* file, int line)
{
    ARK_ASSERT_NO_EFFECT(bytes > 0);

    void* ptr = CallocInternal(count, bytes);
    if (ptr == nullptr)
    {
        return nullptr;
    }

    if (g_needRecord)
    {
        AllocItem record;
        record.length = bytes;
        record.filename = file;
        record.line = line;
        g_memMapMutex.lock();
        g_memMap[ptr] = record;
        g_memMapMutex.unlock();
        g_totalAlloc += bytes;
    }

    return ptr;
}

void AFMemAlloc::FreeDebug(void* p)
{
    if (g_needRecord)
    {
        if (p != nullptr)
        {
            AllocItem record = g_memMap[p];
            g_totalAlloc -= record.length;
            g_memMapMutex.lock();
            g_memMap.erase(p);
            g_memMapMutex.unlock();
        }
    }

    FreeInternal(p);
}

void* AFMemAlloc::Alloc(size_t bytes)
{
    ARK_ASSERT_NO_EFFECT(bytes > 0);

    void* ptr = AllocInternal(bytes);
    if (ptr == nullptr)
    {
        return nullptr;
    }

    return ptr;
}

void* AFMemAlloc::Realloc(void* addr, size_t bytes)
{
    ARK_ASSERT_NO_EFFECT(bytes > 0);

    void* ptr = ReallocInternal(addr, bytes);
    if (ptr == nullptr)
    {
        return nullptr;
    }

    return ptr;
}

void* AFMemAlloc::Calloc(size_t count, size_t bytes)
{
    ARK_ASSERT_NO_EFFECT(bytes > 0);

    void* ptr = CallocInternal(count, bytes);
    if (ptr == nullptr)
    {
        return nullptr;
    }

    return ptr;
}

void AFMemAlloc::Free(void* p)
{
    FreeInternal(p);
}

int32_t AFMemAlloc::SizeToPoolIndex(size_t size)
{
    uint32_t allocSize = AFMisc::GetNearest2N(size);
    uint32_t nIndexT = allocSize >> 4;
    int32_t cIndex = -1;
    while (nIndexT)
    {
        nIndexT = nIndexT >> 1;
        ++cIndex;
    }

    return cIndex;
}

void AFMemAlloc::Dump()
{
    printf("Memory dump start---------------------\n");
    for (int i = 0; i < POOL_SIZE; ++i)
    {
        printf("[Size:%d]:Used:%d    /   Total:%d    (%d bytes) \r\n", g_poolSize[i], g_poolUsed[i], g_poolTotal[i], g_poolSize[i] * g_poolUsed[i]);
    }

    printf("Total: %d bytes used\n", g_totalAlloc);
    printf("Memory dump end-----------------------\n");
}

void* AFMemAlloc::AllocInternal(size_t bytes)
{
    if (g_usePool)
    {
        return AllocFromPool(bytes);
    }
    else
    {
        return ::malloc(bytes);
    }
}

void* AFMemAlloc::ReallocInternal(void* addr, size_t bytes)
{
    if (g_usePool)
    {
        return ReallocFromPool(addr, bytes);
    }
    else
    {
        return ::realloc(addr, bytes);
    }
}

void* AFMemAlloc::CallocInternal(size_t count, size_t bytes)
{
    if (g_usePool)
    {
        return CallocFromPool(count, bytes);
    }
    else
    {
        return ::calloc(count, bytes);
    }
}

void AFMemAlloc::FreeInternal(void* p)
{
    if (g_usePool)
    {
        FreeFromPool(p);
    }
    else
    {
        ::free(p);
    }
}

void* AFMemAlloc::AllocFromPool(uint32_t bytes)
{
    if (bytes < 16)
    {
        bytes = 16;
    }
    else if (bytes > 2048)
    {
        return ::malloc(bytes);
    }

    int32_t index = SizeToPoolIndex(bytes);
    ARK_ASSERT_NO_EFFECT(index != -1);

    g_poolUsed[index]++;
    return g_pool[index]->Alloc(bytes);
}

void* AFMemAlloc::ReallocFromPool(void* addr, size_t bytes)
{
    if (addr == nullptr)
    {
        return AllocFromPool(bytes);
    }

    uint32_t poolIndex = FreeFromPool(addr);
    if (poolIndex != -1)
    {
        void* ptr = AllocFromPool(bytes);
        memcpy(ptr, addr, g_pool[poolIndex]->mnUnitSize);
        return ptr;
    }
    else
    {
        return ::realloc(addr, bytes);
    }
}

void* AFMemAlloc::CallocFromPool(size_t count, size_t bytes)
{
    return AllocFromPool(count * bytes);
}

size_t AFMemAlloc::FreeFromPool(void* p)
{
    uint32_t poolIndex = -1;
    for (int i = 0; i < POOL_SIZE; ++i)
    {
        if (g_pool[i]->InPool(p))
        {
            poolIndex = i;
            g_pool[poolIndex]->Free(p);
            g_poolUsed[poolIndex]--;
            break;
        }
    }

    if (poolIndex < 0)
    {
        ::free(p);
    }

    return poolIndex;
}<commit_msg>fix atomic error in vs2017<commit_after>/*
* This source file is part of ArkGameFrame
* For the latest info, see https://github.com/ArkGame
*
* Copyright (c) 2013-2018 ArkGame authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

#include "AFMemAlloc.h"

bool g_needRecord = false;
std::atomic_int g_totalAlloc = 0;
std::map<void*, AllocItem> g_memMap;
std::mutex g_memMapMutex;

bool g_usePool = false;
AFMemPool* g_pool[POOL_SIZE];
uint32_t g_poolTotal[POOL_SIZE] = { 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024 };
uint32_t g_poolSize[POOL_SIZE] = { 16, 32, 64, 128, 256, 512, 1024, 2048 };
uint32_t g_poolUsed[POOL_SIZE] = { 0, 0, 0, 0, 0, 0, 0, 0 };

AFMemAlloc::AFMemAlloc()
{

}

AFMemAlloc::~AFMemAlloc()
{

}

void AFMemAlloc::Start(bool need_record/* = true*/)
{
    g_totalAlloc = 0;
    g_memMap.clear();
    g_needRecord = need_record;
}

void AFMemAlloc::CheckLeak()
{
    printf("Memory check leak start-----------------------\n");

    if (g_totalAlloc == 0)
    {
        printf("No memory leak!\n");
    }
    else
    {
        printf("Find leak, %d bytes!\n", g_totalAlloc.load());
        for (auto& iter : g_memMap)
        {
            AllocItem& record = iter.second;
            printf("%s(%d) %d bytes\n", record.filename.c_str(), record.line, record.length);
        }
    }

    printf("Memory check leak end-------------------------\n");
}

void AFMemAlloc::InitPool()
{
    for (int i = 0; i < POOL_SIZE; ++i)
    {
        g_pool[i] = ARK_NEW AFMemPool(g_poolTotal[i], g_poolSize[i]);
    }

    g_usePool = true;
}

void AFMemAlloc::ClearPool()
{
    for (int i = 0; i < POOL_SIZE; ++i)
    {
        delete g_pool[i];
    }

    g_usePool = false;
}

void* AFMemAlloc::AllocDebug(size_t bytes, const char* file, int line)
{
    ARK_ASSERT_NO_EFFECT(bytes > 0);

    void* ptr = AllocInternal(bytes);
    if (ptr == nullptr)
    {
        return nullptr;
    }

    if (g_needRecord)
    {
        AllocItem record;
        record.length = bytes;
        record.filename = file;
        record.line = line;
        g_memMapMutex.lock();
        g_memMap[ptr] = record;
        g_memMapMutex.unlock();
        g_totalAlloc += bytes;
    }

    return ptr;
}

void* AFMemAlloc::ReallocDebug(void* addr, size_t bytes, const char* file, int line)
{
    if (g_needRecord)
    {
        if (addr != nullptr)
        {
            AllocItem record = g_memMap[addr];
            g_totalAlloc -= record.length;
            g_memMapMutex.lock();
            g_memMap.erase(addr);
            g_memMapMutex.unlock();
        }
    }

    ARK_ASSERT_NO_EFFECT(bytes > 0);

    void* ptr = ReallocInternal(addr, bytes);
    if (ptr == nullptr)
    {
        return nullptr;
    }

    if (g_needRecord)
    {
        AllocItem record;
        record.length = bytes;
        record.filename = file;
        record.line = line;
        g_memMapMutex.lock();
        g_memMap[ptr] = record;
        g_memMapMutex.unlock();
        g_totalAlloc += bytes;
    }

    return ptr;
}

void* AFMemAlloc::CallocDebug(size_t count, size_t bytes, const char* file, int line)
{
    ARK_ASSERT_NO_EFFECT(bytes > 0);

    void* ptr = CallocInternal(count, bytes);
    if (ptr == nullptr)
    {
        return nullptr;
    }

    if (g_needRecord)
    {
        AllocItem record;
        record.length = bytes;
        record.filename = file;
        record.line = line;
        g_memMapMutex.lock();
        g_memMap[ptr] = record;
        g_memMapMutex.unlock();
        g_totalAlloc += bytes;
    }

    return ptr;
}

void AFMemAlloc::FreeDebug(void* p)
{
    if (g_needRecord)
    {
        if (p != nullptr)
        {
            AllocItem record = g_memMap[p];
            g_totalAlloc -= record.length;
            g_memMapMutex.lock();
            g_memMap.erase(p);
            g_memMapMutex.unlock();
        }
    }

    FreeInternal(p);
}

void* AFMemAlloc::Alloc(size_t bytes)
{
    ARK_ASSERT_NO_EFFECT(bytes > 0);

    void* ptr = AllocInternal(bytes);
    if (ptr == nullptr)
    {
        return nullptr;
    }

    return ptr;
}

void* AFMemAlloc::Realloc(void* addr, size_t bytes)
{
    ARK_ASSERT_NO_EFFECT(bytes > 0);

    void* ptr = ReallocInternal(addr, bytes);
    if (ptr == nullptr)
    {
        return nullptr;
    }

    return ptr;
}

void* AFMemAlloc::Calloc(size_t count, size_t bytes)
{
    ARK_ASSERT_NO_EFFECT(bytes > 0);

    void* ptr = CallocInternal(count, bytes);
    if (ptr == nullptr)
    {
        return nullptr;
    }

    return ptr;
}

void AFMemAlloc::Free(void* p)
{
    FreeInternal(p);
}

int32_t AFMemAlloc::SizeToPoolIndex(size_t size)
{
    uint32_t allocSize = AFMisc::GetNearest2N(size);
    uint32_t nIndexT = allocSize >> 4;
    int32_t cIndex = -1;
    while (nIndexT)
    {
        nIndexT = nIndexT >> 1;
        ++cIndex;
    }

    return cIndex;
}

void AFMemAlloc::Dump()
{
    printf("Memory dump start---------------------\n");
    for (int i = 0; i < POOL_SIZE; ++i)
    {
        printf("[Size:%d]:Used:%d    /   Total:%d    (%d bytes) \r\n", g_poolSize[i], g_poolUsed[i], g_poolTotal[i], g_poolSize[i] * g_poolUsed[i]);
    }

    printf("Total: %d bytes used\n", g_totalAlloc.load());
    printf("Memory dump end-----------------------\n");
}

void* AFMemAlloc::AllocInternal(size_t bytes)
{
    if (g_usePool)
    {
        return AllocFromPool(bytes);
    }
    else
    {
        return ::malloc(bytes);
    }
}

void* AFMemAlloc::ReallocInternal(void* addr, size_t bytes)
{
    if (g_usePool)
    {
        return ReallocFromPool(addr, bytes);
    }
    else
    {
        return ::realloc(addr, bytes);
    }
}

void* AFMemAlloc::CallocInternal(size_t count, size_t bytes)
{
    if (g_usePool)
    {
        return CallocFromPool(count, bytes);
    }
    else
    {
        return ::calloc(count, bytes);
    }
}

void AFMemAlloc::FreeInternal(void* p)
{
    if (g_usePool)
    {
        FreeFromPool(p);
    }
    else
    {
        ::free(p);
    }
}

void* AFMemAlloc::AllocFromPool(uint32_t bytes)
{
    if (bytes < 16)
    {
        bytes = 16;
    }
    else if (bytes > 2048)
    {
        return ::malloc(bytes);
    }

    int32_t index = SizeToPoolIndex(bytes);
    ARK_ASSERT_NO_EFFECT(index != -1);

    g_poolUsed[index]++;
    return g_pool[index]->Alloc(bytes);
}

void* AFMemAlloc::ReallocFromPool(void* addr, size_t bytes)
{
    if (addr == nullptr)
    {
        return AllocFromPool(bytes);
    }

    uint32_t poolIndex = FreeFromPool(addr);
    if (poolIndex != -1)
    {
        void* ptr = AllocFromPool(bytes);
        memcpy(ptr, addr, g_pool[poolIndex]->mnUnitSize);
        return ptr;
    }
    else
    {
        return ::realloc(addr, bytes);
    }
}

void* AFMemAlloc::CallocFromPool(size_t count, size_t bytes)
{
    return AllocFromPool(count * bytes);
}

size_t AFMemAlloc::FreeFromPool(void* p)
{
    uint32_t poolIndex = -1;
    for (int i = 0; i < POOL_SIZE; ++i)
    {
        if (g_pool[i]->InPool(p))
        {
            poolIndex = i;
            g_pool[poolIndex]->Free(p);
            g_poolUsed[poolIndex]--;
            break;
        }
    }

    if (poolIndex < 0)
    {
        ::free(p);
    }

    return poolIndex;
}<|endoftext|>