<commit_before>/*************************************************************************
 *                                                                       *
 * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith.       *
 * All rights reserved.  Email: russ@q12.org   Web: www.q12.org          *
 *                                                                       *
 * This library is free software; you can redistribute it and/or         *
 * modify it under the terms of EITHER:                                  *
 *   (1) The GNU Lesser General Public License as published by the Free  *
 *       Software Foundation; either version 2.1 of the License, or (at  *
 *       your option) any later version. The text of the GNU Lesser      *
 *       General Public License is included with this library in the     *
 *       file LICENSE.TXT.                                               *
 *   (2) The BSD-style license that is included with this library in     *
 *       the file LICENSE-BSD.TXT.                                       *
 *                                                                       *
 * This library is distributed in the hope that it will be useful,       *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files    *
 * LICENSE.TXT and LICENSE-BSD.TXT for more details.                     *
 *                                                                       *
 *************************************************************************/

/*

TODO
----

* gettimeofday() and the pentium time stamp counter return the real time,
  not the process time. fix this somehow!

*/

#include <ode/common.h>
#include <ode/timer.h>

// misc defines
#define ALLOCA dALLOCA16

//****************************************************************************
// implementation for windows based on the multimedia performance counter.

#ifdef WIN32

#include "windows.h"

static inline void getClockCount (unsigned long cc[2])
{
  LARGE_INTEGER a;
  QueryPerformanceCounter (&a);
  cc[0] = a.LowPart;
  cc[1] = a.HighPart;
}

static inline void serialize()
{
}

static inline double loadClockCount (unsigned long cc[2])
{
  LARGE_INTEGER a;
  a.LowPart = cc[0];
  a.HighPart = cc[1];
  return double(a.QuadPart);
}

double dTimerResolution()
{
  return 1.0/dTimerTicksPerSecond();
}

double dTimerTicksPerSecond()
{
  static int query=0;
  static double hz=0.0;
  if (!query) {
    LARGE_INTEGER a;
    QueryPerformanceFrequency (&a);
    hz = double(a.QuadPart);
    query = 1;
  }
  return hz;
}

#endif

//****************************************************************************
// implementation based on the pentium time stamp counter. the timer functions
// can be serializing or non-serializing. serializing will ensure that all
// instructions have executed and data has been written back before the cpu
// time stamp counter is read. the CPUID instruction is used to serialize.

#if defined(PENTIUM) && !defined(WIN32)

// we need to know the clock rate so that the timing function can report
// accurate times. this number only needs to be set accurately if we're
// doing performance tests and care about real-world time numbers - otherwise,
// just ignore this. i have not worked out how to determine this number
// automatically yet.

#define PENTIUM_HZ (500e6)

static inline void getClockCount (unsigned long cc[2])
{
#ifndef X86_64_SYSTEM
  asm volatile (
	"rdtsc\n"
	"movl %%eax,(%%esi)\n"
	"movl %%edx,4(%%esi)\n"
	: : "S" (cc) : "%eax","%edx","cc","memory");
#else
  asm volatile (
	"rdtsc\n"
	"movl %%eax,(%%rsi)\n"
	"movl %%edx,4(%%rsi)\n"
	: : "S" (cc) : "%eax","%edx","cc","memory");
#endif
}

static inline void serialize()
{
#ifndef X86_64_SYSTEM
  asm volatile (
	"mov $0,%%eax\n"
	"cpuid\n"
	: : : "%eax","%ebx","%ecx","%edx","cc","memory");
#else
  asm volatile (
	"mov $0,%%rax\n"
	"cpuid\n"
	: : : "%rax","%rbx","%rcx","%rdx","cc","memory");
#endif
}

static inline double loadClockCount (unsigned long a[2])
{
  double ret;
#ifndef X86_64_SYSTEM
  asm volatile ("fildll %1; fstpl %0" : "=m" (ret) : "m" (a[0]) :
		"cc","memory");
#else
  asm volatile ("fildll %1; fstpl %0" : "=m" (ret) : "m" (a[0]) :
		"cc","memory");
#endif
  return ret;
}

double dTimerResolution()
{
  return 1.0/PENTIUM_HZ;
}

double dTimerTicksPerSecond()
{
  return PENTIUM_HZ;
}

#endif

//****************************************************************************
// otherwise, do the implementation based on gettimeofday().

#if !defined(PENTIUM) && !defined(WIN32)

#ifndef macintosh

#include <sys/time.h>
#include <unistd.h>

static inline void getClockCount (unsigned long cc[2])
{
  struct timeval tv;
  gettimeofday (&tv,0);
  cc[0] = tv.tv_usec;
  cc[1] = tv.tv_sec;
}

#else // macintosh

#include <MacTypes.h>
#include <Timer.h>

static inline void getClockCount (unsigned long cc[2])
{
  UnsignedWide ms;
  Microseconds (&ms);
  cc[1] = ms.lo / 1000000;
  cc[0] = ms.lo - ( cc[1] * 1000000 );
}

#endif

static inline void serialize()
{
}

static inline double loadClockCount (unsigned long a[2])
{
  return a[1]*1.0e6 + a[0];
}

double dTimerResolution()
{
  unsigned long cc1[2],cc2[2];
  getClockCount (cc1);
  do {
    getClockCount (cc2);
  }
  while (cc1[0]==cc2[0] && cc1[1]==cc2[1]);
  do {
    getClockCount (cc1);
  }
  while (cc1[0]==cc2[0] && cc1[1]==cc2[1]);
  double t1 = loadClockCount (cc1);
  double t2 = loadClockCount (cc2);
  return (t1-t2) / dTimerTicksPerSecond();
}

double dTimerTicksPerSecond()
{
  return 1000000;
}

#endif

//****************************************************************************
// stop watches

void dStopwatchReset (dStopwatch *s)
{
  s->time = 0;
  s->cc[0] = 0;
  s->cc[1] = 0;
}

void dStopwatchStart (dStopwatch *s)
{
  serialize();
  getClockCount (s->cc);
}

void dStopwatchStop  (dStopwatch *s)
{
  unsigned long cc[2];
  serialize();
  getClockCount (cc);
  double t1 = loadClockCount (s->cc);
  double t2 = loadClockCount (cc);
  s->time += t2-t1;
}

double dStopwatchTime (dStopwatch *s)
{
  return s->time / dTimerTicksPerSecond();
}

//****************************************************************************
// code timers

// maximum number of events to record
#define MAXNUM 100

static int num = 0;		// number of entries used in event array
static struct {
  unsigned long cc[2];		// clock counts
  double total_t;		// total clocks used in this slot.
  double total_p;		// total percentage points used in this slot.
  int count;			// number of times this slot has been updated.
  char *description;		// pointer to static string
} event[MAXNUM];

// make sure all slot totals and counts reset to 0 at start

static void initSlots()
{
  static int initialized=0;
  if (!initialized) {
    for (int i=0; i<MAXNUM; i++) {
      event[i].count = 0;
      event[i].total_t = 0;
      event[i].total_p = 0;
    }
    initialized = 1;
  }
}

void dTimerStart (const char *description)
{
  initSlots();
  event[0].description = const_cast<char*> (description);
  num = 1;
  serialize();
  getClockCount (event[0].cc);
}

void dTimerNow (const char *description)
{
  if (num < MAXNUM) {
    // do not serialize
    getClockCount (event[num].cc);
    event[num].description = const_cast<char*> (description);
    num++;
  }
}

void dTimerEnd()
{
  if (num < MAXNUM) {
    serialize();
    getClockCount (event[num].cc);
    event[num].description = "TOTAL";
    num++;
  }
}

//****************************************************************************
// print report

static void fprintDoubleWithPrefix (FILE *f, double a, char *fmt)
{
  if (a >= 0.999999) {
    fprintf (f,fmt,a);
    return;
  }
  a *= 1000.0;
  if (a >= 0.999999) {
    fprintf (f,fmt,a);
    fprintf (f,"m");
    return;
  }
  a *= 1000.0;
  if (a >= 0.999999) {
    fprintf (f,fmt,a);
    fprintf (f,"u");
    return;
  }
  a *= 1000.0;
  fprintf (f,fmt,a);
  fprintf (f,"n");
}

void dTimerReport (FILE *fout, int average)
{
  int i;
  size_t maxl;
  double ccunit = 1.0/dTimerTicksPerSecond();
  fprintf (fout,"\nTimer Report (");
  fprintDoubleWithPrefix (fout,ccunit,"%.2f ");
  fprintf (fout,"s resolution)\n------------\n");
  if (num < 1) return;

  // get maximum description length
  maxl = 0;
  for (i=0; i<num; i++) {
    size_t l = strlen (event[i].description);
    if (l > maxl) maxl = l;
  }

  // calculate total time
  double t1 = loadClockCount (event[0].cc);
  double t2 = loadClockCount (event[num-1].cc);
  double total = t2 - t1;
  if (total <= 0) total = 1;

  // compute time difference for all slots except the last one. update totals
  double *times = (double*) ALLOCA (num * sizeof(double));
  for (i=0; i < (num-1); i++) {
    double t1 = loadClockCount (event[i].cc);
    double t2 = loadClockCount (event[i+1].cc);
    times[i] = t2 - t1;
    event[i].count++;
    event[i].total_t += times[i];
    event[i].total_p += times[i]/total * 100.0;
  }

  // print report (with optional averages)
  for (i=0; i<num; i++) {
    double t,p;
    if (i < (num-1)) {
      t = times[i];
      p = t/total * 100.0;
    }
    else {
      t = total;
      p = 100.0;
    }
    fprintf (fout,"%-*s %7.2fms %6.2f%%",maxl,event[i].description,
	     t*ccunit * 1000.0, p);
    if (average && i < (num-1)) {
      fprintf (fout,"  (avg %7.2fms %6.2f%%)",
	       (event[i].total_t / event[i].count)*ccunit * 1000.0,
	       event[i].total_p / event[i].count);
    }
    fprintf (fout,"\n");
  }
  fprintf (fout,"\n");
}
<commit_msg>Fix PIC build: register bx should not be clobbered<commit_after>/*************************************************************************
 *                                                                       *
 * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith.       *
 * All rights reserved.  Email: russ@q12.org   Web: www.q12.org          *
 *                                                                       *
 * This library is free software; you can redistribute it and/or         *
 * modify it under the terms of EITHER:                                  *
 *   (1) The GNU Lesser General Public License as published by the Free  *
 *       Software Foundation; either version 2.1 of the License, or (at  *
 *       your option) any later version. The text of the GNU Lesser      *
 *       General Public License is included with this library in the     *
 *       file LICENSE.TXT.                                               *
 *   (2) The BSD-style license that is included with this library in     *
 *       the file LICENSE-BSD.TXT.                                       *
 *                                                                       *
 * This library is distributed in the hope that it will be useful,       *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files    *
 * LICENSE.TXT and LICENSE-BSD.TXT for more details.                     *
 *                                                                       *
 *************************************************************************/

/*

TODO
----

* gettimeofday() and the pentium time stamp counter return the real time,
  not the process time. fix this somehow!

*/

#include <ode/common.h>
#include <ode/timer.h>

// misc defines
#define ALLOCA dALLOCA16

//****************************************************************************
// implementation for windows based on the multimedia performance counter.

#ifdef WIN32

#include "windows.h"

static inline void getClockCount (unsigned long cc[2])
{
  LARGE_INTEGER a;
  QueryPerformanceCounter (&a);
  cc[0] = a.LowPart;
  cc[1] = a.HighPart;
}

static inline void serialize()
{
}

static inline double loadClockCount (unsigned long cc[2])
{
  LARGE_INTEGER a;
  a.LowPart = cc[0];
  a.HighPart = cc[1];
  return double(a.QuadPart);
}

double dTimerResolution()
{
  return 1.0/dTimerTicksPerSecond();
}

double dTimerTicksPerSecond()
{
  static int query=0;
  static double hz=0.0;
  if (!query) {
    LARGE_INTEGER a;
    QueryPerformanceFrequency (&a);
    hz = double(a.QuadPart);
    query = 1;
  }
  return hz;
}

#endif

//****************************************************************************
// implementation based on the pentium time stamp counter. the timer functions
// can be serializing or non-serializing. serializing will ensure that all
// instructions have executed and data has been written back before the cpu
// time stamp counter is read. the CPUID instruction is used to serialize.

#if defined(PENTIUM) && !defined(WIN32)

// we need to know the clock rate so that the timing function can report
// accurate times. this number only needs to be set accurately if we're
// doing performance tests and care about real-world time numbers - otherwise,
// just ignore this. i have not worked out how to determine this number
// automatically yet.

#define PENTIUM_HZ (500e6)

static inline void getClockCount (unsigned long cc[2])
{
#ifndef X86_64_SYSTEM
  asm volatile (
	"rdtsc\n"
	"movl %%eax,(%%esi)\n"
	"movl %%edx,4(%%esi)\n"
	: : "S" (cc) : "%eax","%edx","cc","memory");
#else
  asm volatile (
	"rdtsc\n"
	"movl %%eax,(%%rsi)\n"
	"movl %%edx,4(%%rsi)\n"
	: : "S" (cc) : "%eax","%edx","cc","memory");
#endif
}

static inline void serialize()
{
#ifndef X86_64_SYSTEM
  asm volatile (
	"mov $0,%%eax\n"
	"push %%ebx\n"
	"cpuid\n"
	"pop %%ebx\n"
	: : : "%eax","%ecx","%edx","cc","memory");
#else
  asm volatile (
	"mov $0,%%rax\n"
	"push %rbx\n"
	"cpuid\n"
	"pop %rbx\n"
	: : : "%rax","%rcx","%rdx","cc","memory");
#endif
}

static inline double loadClockCount (unsigned long a[2])
{
  double ret;
#ifndef X86_64_SYSTEM
  asm volatile ("fildll %1; fstpl %0" : "=m" (ret) : "m" (a[0]) :
		"cc","memory");
#else
  asm volatile ("fildll %1; fstpl %0" : "=m" (ret) : "m" (a[0]) :
		"cc","memory");
#endif
  return ret;
}

double dTimerResolution()
{
  return 1.0/PENTIUM_HZ;
}

double dTimerTicksPerSecond()
{
  return PENTIUM_HZ;
}

#endif

//****************************************************************************
// otherwise, do the implementation based on gettimeofday().

#if !defined(PENTIUM) && !defined(WIN32)

#ifndef macintosh

#include <sys/time.h>
#include <unistd.h>

static inline void getClockCount (unsigned long cc[2])
{
  struct timeval tv;
  gettimeofday (&tv,0);
  cc[0] = tv.tv_usec;
  cc[1] = tv.tv_sec;
}

#else // macintosh

#include <MacTypes.h>
#include <Timer.h>

static inline void getClockCount (unsigned long cc[2])
{
  UnsignedWide ms;
  Microseconds (&ms);
  cc[1] = ms.lo / 1000000;
  cc[0] = ms.lo - ( cc[1] * 1000000 );
}

#endif

static inline void serialize()
{
}

static inline double loadClockCount (unsigned long a[2])
{
  return a[1]*1.0e6 + a[0];
}

double dTimerResolution()
{
  unsigned long cc1[2],cc2[2];
  getClockCount (cc1);
  do {
    getClockCount (cc2);
  }
  while (cc1[0]==cc2[0] && cc1[1]==cc2[1]);
  do {
    getClockCount (cc1);
  }
  while (cc1[0]==cc2[0] && cc1[1]==cc2[1]);
  double t1 = loadClockCount (cc1);
  double t2 = loadClockCount (cc2);
  return (t1-t2) / dTimerTicksPerSecond();
}

double dTimerTicksPerSecond()
{
  return 1000000;
}

#endif

//****************************************************************************
// stop watches

void dStopwatchReset (dStopwatch *s)
{
  s->time = 0;
  s->cc[0] = 0;
  s->cc[1] = 0;
}

void dStopwatchStart (dStopwatch *s)
{
  serialize();
  getClockCount (s->cc);
}

void dStopwatchStop  (dStopwatch *s)
{
  unsigned long cc[2];
  serialize();
  getClockCount (cc);
  double t1 = loadClockCount (s->cc);
  double t2 = loadClockCount (cc);
  s->time += t2-t1;
}

double dStopwatchTime (dStopwatch *s)
{
  return s->time / dTimerTicksPerSecond();
}

//****************************************************************************
// code timers

// maximum number of events to record
#define MAXNUM 100

static int num = 0;		// number of entries used in event array
static struct {
  unsigned long cc[2];		// clock counts
  double total_t;		// total clocks used in this slot.
  double total_p;		// total percentage points used in this slot.
  int count;			// number of times this slot has been updated.
  char *description;		// pointer to static string
} event[MAXNUM];

// make sure all slot totals and counts reset to 0 at start

static void initSlots()
{
  static int initialized=0;
  if (!initialized) {
    for (int i=0; i<MAXNUM; i++) {
      event[i].count = 0;
      event[i].total_t = 0;
      event[i].total_p = 0;
    }
    initialized = 1;
  }
}

void dTimerStart (const char *description)
{
  initSlots();
  event[0].description = const_cast<char*> (description);
  num = 1;
  serialize();
  getClockCount (event[0].cc);
}

void dTimerNow (const char *description)
{
  if (num < MAXNUM) {
    // do not serialize
    getClockCount (event[num].cc);
    event[num].description = const_cast<char*> (description);
    num++;
  }
}

void dTimerEnd()
{
  if (num < MAXNUM) {
    serialize();
    getClockCount (event[num].cc);
    event[num].description = "TOTAL";
    num++;
  }
}

//****************************************************************************
// print report

static void fprintDoubleWithPrefix (FILE *f, double a, char *fmt)
{
  if (a >= 0.999999) {
    fprintf (f,fmt,a);
    return;
  }
  a *= 1000.0;
  if (a >= 0.999999) {
    fprintf (f,fmt,a);
    fprintf (f,"m");
    return;
  }
  a *= 1000.0;
  if (a >= 0.999999) {
    fprintf (f,fmt,a);
    fprintf (f,"u");
    return;
  }
  a *= 1000.0;
  fprintf (f,fmt,a);
  fprintf (f,"n");
}

void dTimerReport (FILE *fout, int average)
{
  int i;
  size_t maxl;
  double ccunit = 1.0/dTimerTicksPerSecond();
  fprintf (fout,"\nTimer Report (");
  fprintDoubleWithPrefix (fout,ccunit,"%.2f ");
  fprintf (fout,"s resolution)\n------------\n");
  if (num < 1) return;

  // get maximum description length
  maxl = 0;
  for (i=0; i<num; i++) {
    size_t l = strlen (event[i].description);
    if (l > maxl) maxl = l;
  }

  // calculate total time
  double t1 = loadClockCount (event[0].cc);
  double t2 = loadClockCount (event[num-1].cc);
  double total = t2 - t1;
  if (total <= 0) total = 1;

  // compute time difference for all slots except the last one. update totals
  double *times = (double*) ALLOCA (num * sizeof(double));
  for (i=0; i < (num-1); i++) {
    double t1 = loadClockCount (event[i].cc);
    double t2 = loadClockCount (event[i+1].cc);
    times[i] = t2 - t1;
    event[i].count++;
    event[i].total_t += times[i];
    event[i].total_p += times[i]/total * 100.0;
  }

  // print report (with optional averages)
  for (i=0; i<num; i++) {
    double t,p;
    if (i < (num-1)) {
      t = times[i];
      p = t/total * 100.0;
    }
    else {
      t = total;
      p = 100.0;
    }
    fprintf (fout,"%-*s %7.2fms %6.2f%%",maxl,event[i].description,
	     t*ccunit * 1000.0, p);
    if (average && i < (num-1)) {
      fprintf (fout,"  (avg %7.2fms %6.2f%%)",
	       (event[i].total_t / event[i].count)*ccunit * 1000.0,
	       event[i].total_p / event[i].count);
    }
    fprintf (fout,"\n");
  }
  fprintf (fout,"\n");
}
<|endoftext|>


<commit_before>#include "util.cpp"

/*
//util classes
struct Server {
	//input
	int capacity, size;
	//output
	int row = -1, slot = -1, pool = -1;
};

struct Input {
	int r, s, u, p, m;
	vector<vector<int>> blocked_slots;//first index: row, second index: slot
	vector<Server> servers;
};
*/

struct Row {
	int num, area, capacity;
};

bool sort_servers(const Server &a, const Server &b)	{
	if (a.capacity*b.size != b.capacity*a.size)
		return a.capacity*b.size > b.capacity*a.size;
	else
		return a.size < b.size;
}

bool sort_rows(const Row &a, const Row &b)	{
	if (a.capacity*b.area != b.capacity*a.area)
		return a.capacity*b.area > b.capacity*a.area;
	else
		return a.area < b.area;
}

void place_blocked_slots(vector<vector<int>>& field, Row &row, int row_index, vector<int>& slots)	{
	for (int i = 0; i < slots.size(); i++)
	{
		field[row_index][slots[i]] = 1;
		row.area--;
	}
}

bool assign_server_to_row(int s, vector<int>& field, Server &server)	{
	for (int i = 0; i < s-server.size; i++)
	{
	 	int cnt_occ = 0;
		for (int j = 0; j < server.size; j++)
			cnt_occ += field[i+j];
		if (cnt_occ == 0)
		{
			for (int j = 0; j < server.size; j++)
				field[i+j] = 1;
			server.slot = i;
			return true;
		}
	}
	return false;
}

void placeServers(Input &input) {
	// sort servers
	sort(input.servers.begin(),input.servers.end(),sort_servers);

	// create field and rows
	vector<vector<int>> field(input.r, vector<int>(input.s));
	vector<Row> rows(input.r);

	for (int i = 0; i < input.r; i++)
	{
		rows[i].num = i;
		rows[i].capacity = 0;
		rows[i].area = input.s;
		place_blocked_slots(field,rows[i],i,input.blocked_slots[i]);
	}

	// iterate through all servers
	for (int i = 0; i < input.m; i++)
	{
		sort(rows.begin(),rows.end(),sort_rows);

		// try to assign each server to worst possible row
		for (int j = 0; j < input.r; j++)
		{
			if (assign_server_to_row(input.s,field[j],input.servers[i]))
			{
				rows[j].area -= input.servers[i].size;
				rows[j].capacity += input.servers[i].capacity;
				input.servers[i].row = j;
			}
		}
	}
}
<commit_msg>fixed placeservers.cpp<commit_after>#include "util.cpp"

/*
//util classes
struct Server {
	//input
	int capacity, size;
	//output
	int row = -1, slot = -1, pool = -1;
};

struct Input {
	int r, s, u, p, m;
	vector<vector<int>> blocked_slots;//first index: row, second index: slot
	vector<Server> servers;
};
*/

struct Row {
	int num, area, capacity;
};

bool sort_servers(const Server &a, const Server &b)	{
	if (a.capacity*b.size != b.capacity*a.size)
		return a.capacity*b.size > b.capacity*a.size;
	else
		return a.size < b.size;
}

bool sort_rows(const Row &a, const Row &b)	{
	if (a.capacity*b.area != b.capacity*a.area)
		return a.capacity*b.area > b.capacity*a.area;
	else
		return a.area < b.area;
}

void place_blocked_slots(vector<vector<int>>& field, Row &row, int row_index, vector<int>& slots)	{
	for (int i = 0; i < slots.size(); i++)
	{
		field[row_index][slots[i]] = 1;
		row.area--;
	}
}

bool assign_server_to_row(int s, vector<int>& field, Server &server)	{
	for (int i = 0; i < s-server.size; i++)
	{
	 	int cnt_occ = 0;
		for (int j = 0; j < server.size; j++)
			cnt_occ += field[i+j];
		if (cnt_occ == 0)
		{
			for (int j = 0; j < server.size; j++)
				field[i+j] = 1;
			server.slot = i;
			return true;
		}
	}
	return false;
}

void placeServers(Input &input) {
	// sort servers
	sort(input.servers.begin(),input.servers.end(),sort_servers);

	// create field and rows
	vector<vector<int>> field(input.r, vector<int>(input.s));
	vector<Row> rows(input.r);

	for (int i = 0; i < input.r; i++)
	{
		rows[i].num = i;
		rows[i].capacity = 0;
		rows[i].area = input.s;
		place_blocked_slots(field,rows[i],i,input.blocked_slots[i]);
	}

	// iterate through all servers
	for (int i = 0; i < input.m; i++)
	{
		sort(rows.begin(),rows.end(),sort_rows);

		// try to assign each server to worst possible row
		for (int j = 0; j < input.r; j++)
		{
			if (assign_server_to_row(input.s,field[j],input.servers[i]))
			{
				rows[j].area -= input.servers[i].size;
				rows[j].capacity += input.servers[i].capacity;
				input.servers[i].row = row[j].num;
			}
		}
	}
}
<|endoftext|>


<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/
#include <osg/Array>

using namespace osg;

static char* s_ArrayNames[] =
{
    "Array", // 0
    "ByteArray",     // 1
    "ShortArray",    // 2
    "IntArray",      // 3

    "UByteArray",    // 4
    "UShortArray",   // 5
    "UIntArray",     // 6
    "Vec4ubArray",   // 7

    "FloatArray",    // 8
    "Vec2Array",     // 9
    "Vec3Array",     // 10
    "Vec4Array",     // 11

    "Vec2sArray",    // 12
    "Vec3sArray",    // 13
    "Vec4sArray",    // 14

    "Vec2bArray",    // 15
    "Vec3bArray",    // 16
    "Vec4bArray",    // 17
};

const char* Array::className() const
{
    if (_arrayType>=ArrayType && _arrayType<=Vec4bArrayType)
        return s_ArrayNames[_arrayType];
    else
        return "UnkownArray";
}

<commit_msg>From Simon Julier, fixed typo of unknown.<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/
#include <osg/Array>

using namespace osg;

static char* s_ArrayNames[] =
{
    "Array", // 0
    "ByteArray",     // 1
    "ShortArray",    // 2
    "IntArray",      // 3

    "UByteArray",    // 4
    "UShortArray",   // 5
    "UIntArray",     // 6
    "Vec4ubArray",   // 7

    "FloatArray",    // 8
    "Vec2Array",     // 9
    "Vec3Array",     // 10
    "Vec4Array",     // 11

    "Vec2sArray",    // 12
    "Vec3sArray",    // 13
    "Vec4sArray",    // 14

    "Vec2bArray",    // 15
    "Vec3bArray",    // 16
    "Vec4bArray",    // 17
};

const char* Array::className() const
{
    if (_arrayType>=ArrayType && _arrayType<=Vec4bArrayType)
        return s_ArrayNames[_arrayType];
    else
        return "UnknownArray";
}

<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
/// \file  pcapcut.cpp
//------------------------------------------------------------------------------
/// \brief Utility for cutting a part of a large pcap file
/// \see
///      Alternative implementation using pcap.h
//------------------------------------------------------------------------------
// Copyright (c) 2016 Serge Aleynikov <saleyn@gmail.com>
// Created: 2016-11-28
//------------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is part of the utxx open-source project.

Copyright (C) 2016 Serge Aleynikov <saleyn@gmail.com>

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

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

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

***** END LICENSE BLOCK *****
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <signal.h>
#include <utxx/pcap.hpp>
#include <utxx/string.hpp>
#include <utxx/path.hpp>
#include <utxx/get_option.hpp>
#include <utxx/buffer.hpp>
#include <utxx/version.hpp>

using namespace std;

//------------------------------------------------------------------------------
void usage(std::string const& err="")
{
    auto prog = utxx::path::basename(
        utxx::path::program::name().c_str(),
        utxx::path::program::name().c_str() + utxx::path::program::name().size()
    );

    if (!err.empty())
        cerr << "Invalid option: " << err << "\n\n";
    else {
        cerr << prog <<
        " - Tool for extracting packets from a pcap file\n"
        "Copyright (c) 2016 Serge Aleynikov\n"  <<
        VERSION() << "\n\n"                     <<
        "Usage: " << prog                       <<
        "[-V] [-h] -f InputFile -s StartPktNum -e EndPktNum [-n NumPkts] [-c|--count]"
                    " -o|-O OutputFile [-h]\n\n"
        "   -V|--version            - Version\n"
        "   -h|--help               - Help screen\n"
        "   -f InputFile            - Input file name\n"
        "   -o OutputFile           - Ouput file name (don't overwrite if exists)\n"
        "   -O OutputFile           - Ouput file name (overwrite if exists)\n"
        "   -s|--start StartPktNum  - Starting packet number (counting from 1)\n"
        "   -e|--end   EndPktNum    - Ending packet number (must be >= StartPktNum)\n"
        "   -n|--num   TotNumPkts   - Number of packets to save\n"
        "   -r|--raw                - Output raw packet payload only without pcap format\n"
        "   -c|--count              - Count number of packets in the file\n"
        "   -v                      - Verbose\n\n";
    }

    exit(1);
}

//------------------------------------------------------------------------------
void unhandled_exception() {
  auto p = current_exception();
  try    { rethrow_exception(p); }
  catch  ( exception& e ) { cerr << e.what() << endl; }
  catch  ( ... )          { cerr << "Unknown exception" << endl; }
  exit(1);
}

//------------------------------------------------------------------------------
//  MAIN
//------------------------------------------------------------------------------
int main(int argc, char *argv[])
{
    string in_file;
    string out_file;
    size_t pk_start  = 1, pk_end = 0, pk_cnt = 0;
    bool   overwrite = false;
    bool   raw_mode  = false;
    bool   count     = false;
    bool   verbose   = false;

    set_terminate (&unhandled_exception);

    utxx::opts_parser opts(argc, argv);

    while (opts.next()) {
        if (opts.match("-f", "",        &in_file))  continue;
        if (opts.match("-o", "",        &out_file)) continue;
        if (opts.match("-O", "",        &out_file)){overwrite=true; continue;}
        if (opts.match("-r", "--raw",   &raw_mode)) continue;
        if (opts.match("-s", "--start", &pk_start)) continue;
        if (opts.match("-e", "--end",   &pk_end))   continue;
        if (opts.match("-n", "--num",   &pk_cnt))   continue;
        if (opts.match("-c", "--count", &count))    continue;
        if (opts.match("-v", "",        &verbose))  continue;
        if (opts.match("-V", "--version")) throw std::runtime_error(VERSION());
        if (opts.is_help())                         usage();

        usage(opts());
    }

    if (pk_end > 0 && pk_cnt > 0)
        throw std::runtime_error("Cannot specify both -n and -e options!");
    else if (!pk_end && !pk_cnt && !count)
        throw std::runtime_error("Must specify either -n or -e option!");
    else if (!pk_start && !count)
        throw std::runtime_error("PktStartNumber (-s) must be greater than 0!");
    else if (pk_end && pk_end < pk_start)
        throw std::runtime_error
             ("Ending packet number (-e) must not be less than starting packet number (-s)!");
    else if (in_file.empty() || (!count && out_file.empty()))
        throw std::runtime_error("Must specify -f and -o options!");
    else if (!count && utxx::path::file_exists(out_file)) {
        if (!overwrite)
            throw std::runtime_error("Found existing output file: " + out_file);
        if (!utxx::path::file_unlink(out_file))
            throw std::runtime_error("Error deleting file " + out_file +
                                     ": " + strerror(errno));
    }

    if (pk_cnt) {
        pk_end = pk_start + pk_cnt - 1;
        pk_cnt = 0;
    }

    utxx::pcap fin;
    if (fin.open_read(in_file) < 0)
        throw std::runtime_error("Error opening " + in_file + ": " + strerror(errno));
    else if (fin.read_file_header() < 0)
        throw std::runtime_error("File " + in_file + " is not in PCAP format!");

    int n = 0;
    utxx::pcap fout(fin.big_endian(), fin.nsec_time());

    if (!count) {
        n = raw_mode ? fout.open(out_file.c_str(), "wb")
                    : fout.open_write(out_file, false, fin.get_link_type());
        if (n < 0)
            throw std::runtime_error("Error creating file " + out_file + ": " + strerror(errno));
    }

    utxx::basic_io_buffer<(1024*1024)> buf;

    while ((n = fin.read(buf.wr_ptr(), buf.capacity())) > 0) {
        buf.commit(n);
        while (buf.size() > sizeof(utxx::pcap::packet_header)) {
            const char*       header;
            const char*       begin  = header = buf.rd_ptr();
            int               frame_sz, sz;
            utxx::pcap::proto proto;

            // sz - total size of payload including frame_sz
            std::tie(frame_sz, sz, proto) = fin.read_packet_hdr_and_frame(begin, n);

            bool ok = frame_sz > 0 && int(buf.size()) >= sz;

            if (verbose)
                cerr << "Pkt#"     << (pk_cnt+1) << " FrameSz=" << setw(2)    << frame_sz
                     << " Bytes="  << sz         << " BufSz="   << buf.size()
                     << " Offset=" << fin.tell() << (ok ? "" : " ***")        << endl;

            if (!ok) { // Not enough data in the buffer
                buf.reserve(sz);
                break;
            }

            if (++pk_cnt >= pk_start && !count) {
                if (pk_cnt > pk_end)
                    goto DONE;

                // Write to the output file
                if (!raw_mode) {
                    fout.write_packet_header(fin.packet());
                    buf.read(sizeof(utxx::pcap::packet_header));
                    sz    -= sizeof(utxx::pcap::packet_header);
                } else {
                    buf.read(frame_sz);
                    sz    -= frame_sz;
                }
                if (fout.write(buf.rd_ptr(), sz) < 0)
                    throw std::runtime_error(string("Error writing to file: ") + strerror(errno));
            }

            buf.read(sz);
        }

        buf.crunch();
    }

  DONE:
    fout.close();
    fin.close();

    if (count)
        cout << pk_cnt << " packets\n";

    return 0;
}<commit_msg>Fix typo<commit_after>//------------------------------------------------------------------------------
/// \file  pcapcut.cpp
//------------------------------------------------------------------------------
/// \brief Utility for cutting a part of a large pcap file
/// \see
///      Alternative implementation using pcap.h
//------------------------------------------------------------------------------
// Copyright (c) 2016 Serge Aleynikov <saleyn@gmail.com>
// Created: 2016-11-28
//------------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is part of the utxx open-source project.

Copyright (C) 2016 Serge Aleynikov <saleyn@gmail.com>

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

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

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

***** END LICENSE BLOCK *****
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <signal.h>
#include <utxx/pcap.hpp>
#include <utxx/string.hpp>
#include <utxx/path.hpp>
#include <utxx/get_option.hpp>
#include <utxx/buffer.hpp>
#include <utxx/version.hpp>

using namespace std;

//------------------------------------------------------------------------------
void usage(std::string const& err="")
{
    auto prog = utxx::path::basename(
        utxx::path::program::name().c_str(),
        utxx::path::program::name().c_str() + utxx::path::program::name().size()
    );

    if (!err.empty())
        cerr << "Invalid option: " << err << "\n\n";
    else {
        cerr << prog <<
        " - Tool for extracting packets from a pcap file\n"
        "Copyright (c) 2016 Serge Aleynikov\n"  <<
        VERSION() << "\n\n"                     <<
        "Usage: " << prog                       <<
        "[-V] [-h] -f InputFile -s StartPktNum -e EndPktNum [-n NumPkts] [-c|--count]"
                    " -o|-O OutputFile [-h]\n\n"
        "   -V|--version            - Version\n"
        "   -h|--help               - Help screen\n"
        "   -f InputFile            - Input file name\n"
        "   -o OutputFile           - Ouput file name (don't overwrite if exists)\n"
        "   -O OutputFile           - Ouput file name (overwrite if exists)\n"
        "   -s|--start StartPktNum  - Starting packet number (counting from 1)\n"
        "   -e|--end   EndPktNum    - Ending packet number (must be >= StartPktNum)\n"
        "   -n|--num   TotNumPkts   - Number of packets to save\n"
        "   -r|--raw                - Output raw packet payload only without pcap format\n"
        "   -c|--count              - Count number of packets in the file\n"
        "   -v                      - Verbose\n\n";
    }

    exit(1);
}

//------------------------------------------------------------------------------
void unhandled_exception() {
  auto p = current_exception();
  try    { rethrow_exception(p); }
  catch  ( exception& e ) { cerr << e.what() << endl; }
  catch  ( ... )          { cerr << "Unknown exception" << endl; }
  exit(1);
}

//------------------------------------------------------------------------------
//  MAIN
//------------------------------------------------------------------------------
int main(int argc, char *argv[])
{
    string in_file;
    string out_file;
    size_t pk_start  = 1, pk_end = 0, pk_cnt = 0;
    bool   overwrite = false;
    bool   raw_mode  = false;
    bool   count     = false;
    bool   verbose   = false;

    set_terminate (&unhandled_exception);

    utxx::opts_parser opts(argc, argv);

    while (opts.next()) {
        if (opts.match("-f", "",        &in_file))  continue;
        if (opts.match("-o", "",        &out_file)) continue;
        if (opts.match("-O", "",        &out_file)){overwrite=true; continue;}
        if (opts.match("-r", "--raw",   &raw_mode)) continue;
        if (opts.match("-s", "--start", &pk_start)) continue;
        if (opts.match("-e", "--end",   &pk_end))   continue;
        if (opts.match("-n", "--num",   &pk_cnt))   continue;
        if (opts.match("-c", "--count", &count))    continue;
        if (opts.match("-v", "",        &verbose))  continue;
        if (opts.match("-V", "--version")) throw std::runtime_error(VERSION());
        if (opts.is_help())                         usage();

        usage(opts());
    }

    if (pk_end > 0 && pk_cnt > 0)
        throw std::runtime_error("Cannot specify both -n and -e options!");
    else if (!pk_end && !pk_cnt && !count)
        throw std::runtime_error("Must specify either -n or -e option!");
    else if (!pk_start && !count)
        throw std::runtime_error("PktStartNumber (-s) must be greater than 0!");
    else if (pk_end && pk_end < pk_start)
        throw std::runtime_error
             ("Ending packet number (-e) must not be less than starting packet number (-s)!");
    else if (in_file.empty() || (!count && out_file.empty()))
        throw std::runtime_error("Must specify -f and -o options!");
    else if (!count && utxx::path::file_exists(out_file)) {
        if (!overwrite)
            throw std::runtime_error("Found existing output file: " + out_file);
        if (!utxx::path::file_unlink(out_file))
            throw std::runtime_error("Error deleting file " + out_file +
                                     ": " + strerror(errno));
    }

    if (pk_cnt) {
        pk_end = pk_start + pk_cnt - 1;
        pk_cnt = 0;
    }

    utxx::pcap fin;
    if (fin.open_read(in_file) < 0)
        throw std::runtime_error("Error opening " + in_file + ": " + strerror(errno));
    else if (fin.read_file_header() < 0)
        throw std::runtime_error("File " + in_file + " is not in PCAP format!");

    int n = 0;
    utxx::pcap fout(fin.big_endian(), fin.nsec_time());

    if (!count) {
        n = raw_mode ? fout.open(out_file.c_str(), "wb")
                    : fout.open_write(out_file, false, fin.get_link_type());
        if (n < 0)
            throw std::runtime_error("Error creating file " + out_file + ": " + strerror(errno));
    }

    utxx::basic_io_buffer<(1024*1024)> buf;

    while ((n = fin.read(buf.wr_ptr(), buf.capacity())) > 0) {
        buf.commit(n);
        if (verbose)
            cerr << "Read "    << n   << " bytes from source file (offset="
                 << fin.tell() << ')' << endl;

        while (buf.size() > sizeof(utxx::pcap::packet_header)) {
            const char*       header;
            const char*       begin  = header = buf.rd_ptr();
            int               frame_sz, sz;
            utxx::pcap::proto proto;

            // sz - total size of payload including frame_sz
            std::tie(frame_sz, sz, proto) = fin.read_packet_hdr_and_frame(begin, n);

            if (frame_sz < 0 || int(buf.size()) < sz) { // Not enough data in the buffer
                if (verbose && frame_sz < 0)
                    cerr << "Pkt#" << (pk_cnt+1) << ": Cannot read frame size of packet\n";
                buf.reserve(sz);
                break;
            }

            if (verbose)
                cerr << "Pkt#"     << (pk_cnt+1) << " FrameSz=" << setw(2)    << frame_sz
                     << " Bytes="  << sz         << " BufSz="   << buf.size()
                     << endl;

            if (++pk_cnt >= pk_start && !count) {
                if (pk_cnt > pk_end)
                    goto DONE;

                // Write to the output file
                if (!raw_mode) {
                    fout.write_packet_header(fin.packet());
                    buf.read(sizeof(utxx::pcap::packet_header));
                    sz    -= sizeof(utxx::pcap::packet_header);
                } else {
                    buf.read(frame_sz);
                    sz    -= frame_sz;
                }
                if (fout.write(buf.rd_ptr(), sz) < 0)
                    throw std::runtime_error(string("Error writing to file: ") + strerror(errno));
            }

            buf.read(sz);
        }

        buf.crunch();
    }

  DONE:
    fout.close();
    fin.close();

    if (count)
        cout << pk_cnt << " packets\n";

    return 0;
}<|endoftext|>


<commit_before>#include <QtCore>
#include <QtQml>
#include <QVariant>
#include <QJSValue>
#include <QPointer>
#include "qfappdispatcher.h"

/*!
   \qmltype AppDispatcher
   \inqmlmodule QuickFlux
   \brief Message Dispatcher

    AppDispatcher is a singleton object in QML scope for delivering action message.

 */

/*!
  \qmlsignal AppDispatcher::dispatched(string type, object message)

  This signal is emitted when a message is ready to dispatch by AppDispatcher.

  There has several methods to listen this signal:

Method 1 - Using Connections component

\code
import QuickFlux 1.0

Connections {
    target: AppDispatcher
    onDispatched: {
        switch (type) {
            case "OpenItem";
                // ...
                break;
            case "DeleteItem";
                // ...
                break;
        }
    }
}
\endcode

Method 2 - Using helper component, AppListener
\code
AppListener {
    filter: "ItemOpen";
    onDispatched: {
      /// ...
    }
}
\endcode

Method 3 - Using addListener
\code
Component.onCompleted: {
   AppDispatcher.addListener(function() {
     switch (type) {
        case "OpenItem";
          // ...
            break;
        case "DeleteItem";
          // ...
            break;
     }
   });
}
\endcode

 */

/*!
  \class QFAppDispatcher
  \inmodule QuickFlux

  QFAppDispatcher is the C++ implementation of AppDispatcher in QML scope.
  You may need this class to setup communication between C++ and QML.

\code
#include "qfappdispatcher.h"
\endcode

 */

QFAppDispatcher::QFAppDispatcher(QObject *parent) : QObject(parent)
{
    m_dispatching = false;
    nextListenerId = 1;
}

QFAppDispatcher::~QFAppDispatcher()
{

}

/*!
  \qmlmethod AppDispatcher::dispatch(string type, object message)

  Dispatch a message with type via the AppDispatcher.
  The message will be placed on a queue and delivery via the "dispatched" signal.
  Listeners may listen on the "dispatched" signal directly,
  or using helper components like AppListener / AppScript to capture signal.

\code
MouseArea {
    anchors.fill: parent
    onClicked: {
        AppDispatcher.dispatch(ActionTypes.askToRemoveItem, { uid: uid });
    }
}
\endcode

Usually, it will emit "dispatched" signal immediately after calling dispatch().
However, if AppDispatcher is still dispatching messages,
the new messages will be placed on a queue,
and wait until it is finished.
It guarantees the order of messages are arrived in sequence to listeners

\code

AppListener {
    filter: ActionTypes.askToRemoveItem
    onDispatched: {
        if (options.skipRemoveConfirmation) {
            AppDispatcher.dispatch(ActionTypes.removeItem,message);
            // Because AppDispatcher is still dispatching ActionTypes.askToRemoveItem,
            // ActionTypes.removeItem will be placed in a queue and will dispatch when
            // all the listeners received current message.
        }
    }
}

\endcode

 */

void QFAppDispatcher::dispatch(QString type, QJSValue message)
{
    if (m_dispatching) {
        m_queue.enqueue(QPair<QString,QJSValue> (type,message) );
        return;
    }

    m_dispatching = true;
    emitDispatched(type,message);

    while (m_queue.size() > 0) {
        QPair<QString,QJSValue> pair = m_queue.dequeue();
        emitDispatched(pair.first,pair.second);
    }
    m_dispatching = false;
}

/*!
  \qmlmethod AppDispatcher::waitFor(int listenerId)

  Waits for a callback specifed via the listenerId to be executed before continue execution of current callback.
  You should call this method only by a callback registered via addListener.

 */

void QFAppDispatcher::waitFor(QList<int> ids)
{
    if (!m_dispatching || ids.size() == 0)
        return;

    int id = dispatchingListenerId;

    waitingListeners[id] = true;
    invokeListeners(ids);
    waitingListeners.remove(id);
}

/*!

  \qmlmethod int AppDispatcher::addListener(func callback)

  Registers a callback to be invoked with every dispatched message. Returns a listener ID that can be used with waitFor().

 */

int QFAppDispatcher::addListener(QJSValue callback)
{
    QFListener* listener = new QFListener(this);
    listener->setCallback(callback);

    return addListener(listener);
}

/*! \fn int QFAppDispatcher::addListener(QFListener *listener)

  It is private API. Do not use it.

 */
int QFAppDispatcher::addListener(QFListener *listener)
{
    m_listeners[nextListenerId] = listener;
    listener->setListenerId(nextListenerId);
    return nextListenerId++;
}

/*!
  \qmlmethod AppDispatcher::removeListener(int listenerId)

  Remove a callback by the listenerId returned by addListener
 */

void QFAppDispatcher::removeListener(int id)
{
    if (m_listeners.contains(id)) {
        QFListener* listener = m_listeners[id].data();
        if (listener->parent() == this) {
            listener->deleteLater();
        }
        m_listeners.remove(id);
    }
}

void QFAppDispatcher::dispatch(const QString &type, const QVariant &message)
{
    if (m_engine.isNull()) {
        qWarning() << "QFAppDispatcher::dispatch() - Unexpected error: engine is not available.";
        return;
    }

    QJSValue value = m_engine->toScriptValue<QVariant>(message);

    dispatch(type, value);
}

/*! \fn QFAppDispatcher *QFAppDispatcher::instance(QQmlEngine *engine)

  \a engine The instance of QQmlEngine

  Obtain the singleton instance of AppDispatcher for specific QQmlEngine

 */

QFAppDispatcher *QFAppDispatcher::instance(QQmlEngine *engine)
{
    QFAppDispatcher *dispatcher = qobject_cast<QFAppDispatcher*>(singletonObject(engine,"QuickFlux",1,0,"AppDispatcher"));

    return dispatcher;
}

/*! \fn QObject *QFAppDispatcher::singletonObject(QQmlEngine *engine, QString package, int versionMajor, int versionMinor, QString typeName)

 \a engine QQmlEngine instance

 \a package The package name of the singleton object

 \a versionMajor The major version no. of the singleton object

 \a versionMinor The minor version no. of the singleton object

 \a typeName The name of the singleton object

  Obtain a singleton object from a package for specific QQmlEngine instance.
  It is useful when you need to get a singleton Actions object from C++.

 */

QObject *QFAppDispatcher::singletonObject(QQmlEngine *engine, QString package, int versionMajor, int versionMinor, QString typeName)
{
    QString pattern  = "import QtQuick 2.0\nimport %1 %2.%3;QtObject { property var object : %4 }";

    QString qml = pattern.arg(package).arg(versionMajor).arg(versionMinor).arg(typeName);

    QObject* holder = 0;

    QQmlComponent comp (engine);
    comp.setData(qml.toUtf8(),QUrl());
    holder = comp.create();

    if (!holder) {
        qWarning() << QString("QuickFlux: Failed to gain singleton object: %1").arg(typeName);
        qWarning() << QString("Error: ") << comp.errorString();
        return 0;
    }

    QObject*object = holder->property("object").value<QObject*>();
    holder->deleteLater();

    if (!object) {
        qWarning() << QString("QuickFlux: Failed to gain singleton object: %1").arg(typeName);
        qWarning() << QString("Error: Unknown");
    }

    return object;
}

void QFAppDispatcher::emitDispatched(QString type, QJSValue message)
{
    dispatchingMessage = message;
    dispatchingMessageType = type;
    pendingListeners.clear();
    waitingListeners.clear();

    QMapIterator<int, QPointer<QFListener> > iter(m_listeners);
    QList<int> ids;
    while (iter.hasNext()) {
        iter.next();
        pendingListeners[iter.key()] = true;
        ids << iter.key();
    }

    invokeListeners(ids);

    emit dispatched(type,message);
}

void QFAppDispatcher::invokeListeners(QList<int> ids)
{
    for (int i = 0 ; i < ids.size() ; i++) {
        int next = ids.at(i);

        if (waitingListeners.contains(next)) {
            qWarning() << "AppDispatcher: Cyclic dependency detected";
        }

        if (!pendingListeners.contains(next))
            continue;

        pendingListeners.remove(next);
        dispatchingListenerId = next;

        QFListener* listener = m_listeners[next].data();

        if (listener) {
            listener->dispatch(this,dispatchingMessageType,dispatchingMessage);
        }
    }
}

QQmlEngine *QFAppDispatcher::engine() const
{
    return m_engine.data();
}

void QFAppDispatcher::setEngine(QQmlEngine *engine)
{
    m_engine = engine;
}

<commit_msg>Add document of QFAppDispatcher::dispatch()<commit_after>#include <QtCore>
#include <QtQml>
#include <QVariant>
#include <QJSValue>
#include <QPointer>
#include "qfappdispatcher.h"

/*!
   \qmltype AppDispatcher
   \inqmlmodule QuickFlux
   \brief Message Dispatcher

    AppDispatcher is a singleton object in QML scope for delivering action message.

 */

/*!
  \qmlsignal AppDispatcher::dispatched(string type, object message)

  This signal is emitted when a message is ready to dispatch by AppDispatcher.

  There has several methods to listen this signal:

Method 1 - Using Connections component

\code
import QuickFlux 1.0

Connections {
    target: AppDispatcher
    onDispatched: {
        switch (type) {
            case "OpenItem";
                // ...
                break;
            case "DeleteItem";
                // ...
                break;
        }
    }
}
\endcode

Method 2 - Using helper component, AppListener
\code
AppListener {
    filter: "ItemOpen";
    onDispatched: {
      /// ...
    }
}
\endcode

Method 3 - Using addListener
\code
Component.onCompleted: {
   AppDispatcher.addListener(function() {
     switch (type) {
        case "OpenItem";
          // ...
            break;
        case "DeleteItem";
          // ...
            break;
     }
   });
}
\endcode

 */

/*! \fn QFAppDispatcher::dispatched(QString type,QJSValue message)

  This signal is emitted when a message is ready to dispatch by AppDispatcher.

 */

/*!
  \class QFAppDispatcher
  \inmodule QuickFlux

  QFAppDispatcher is the C++ implementation of AppDispatcher in QML scope.
  You may need this class to setup communication between C++ and QML.

\code
#include "qfappdispatcher.h"
\endcode

 */

QFAppDispatcher::QFAppDispatcher(QObject *parent) : QObject(parent)
{
    m_dispatching = false;
    nextListenerId = 1;
}

QFAppDispatcher::~QFAppDispatcher()
{

}

/*!
  \qmlmethod AppDispatcher::dispatch(string type, object message)

  Dispatch a message with type via the AppDispatcher.
  The message will be placed on a queue and delivery via the "dispatched" signal.
  Listeners may listen on the "dispatched" signal directly,
  or using helper components like AppListener / AppScript to capture signal.

\code
MouseArea {
    anchors.fill: parent
    onClicked: {
        AppDispatcher.dispatch(ActionTypes.askToRemoveItem, { uid: uid });
    }
}
\endcode

Usually, it will emit "dispatched" signal immediately after calling dispatch().
However, if AppDispatcher is still dispatching messages,
the new messages will be placed on a queue,
and wait until it is finished.
It guarantees the order of messages are arrived in sequence to listeners

\code

AppListener {
    filter: ActionTypes.askToRemoveItem
    onDispatched: {
        if (options.skipRemoveConfirmation) {
            AppDispatcher.dispatch(ActionTypes.removeItem,message);
            // Because AppDispatcher is still dispatching ActionTypes.askToRemoveItem,
            // ActionTypes.removeItem will be placed in a queue and will dispatch when
            // all the listeners received current message.
        }
    }
}

\endcode

 */

void QFAppDispatcher::dispatch(QString type, QJSValue message)
{
    if (m_dispatching) {
        m_queue.enqueue(QPair<QString,QJSValue> (type,message) );
        return;
    }

    m_dispatching = true;
    emitDispatched(type,message);

    while (m_queue.size() > 0) {
        QPair<QString,QJSValue> pair = m_queue.dequeue();
        emitDispatched(pair.first,pair.second);
    }
    m_dispatching = false;
}

/*!
  \qmlmethod AppDispatcher::waitFor(int listenerId)

  Waits for a callback specifed via the listenerId to be executed before continue execution of current callback.
  You should call this method only by a callback registered via addListener.

 */

void QFAppDispatcher::waitFor(QList<int> ids)
{
    if (!m_dispatching || ids.size() == 0)
        return;

    int id = dispatchingListenerId;

    waitingListeners[id] = true;
    invokeListeners(ids);
    waitingListeners.remove(id);
}

/*!

  \qmlmethod int AppDispatcher::addListener(func callback)

  Registers a callback to be invoked with every dispatched message. Returns a listener ID that can be used with waitFor().

 */

int QFAppDispatcher::addListener(QJSValue callback)
{
    QFListener* listener = new QFListener(this);
    listener->setCallback(callback);

    return addListener(listener);
}

/*! \fn int QFAppDispatcher::addListener(QFListener *listener)

  It is private API. Do not use it.

 */
int QFAppDispatcher::addListener(QFListener *listener)
{
    m_listeners[nextListenerId] = listener;
    listener->setListenerId(nextListenerId);
    return nextListenerId++;
}

/*!
  \qmlmethod AppDispatcher::removeListener(int listenerId)

  Remove a callback by the listenerId returned by addListener
 */

void QFAppDispatcher::removeListener(int id)
{
    if (m_listeners.contains(id)) {
        QFListener* listener = m_listeners[id].data();
        if (listener->parent() == this) {
            listener->deleteLater();
        }
        m_listeners.remove(id);
    }
}

/*! \fn QFAppDispatcher::dispatch(const QString& type, const QVariant& message)

  Dispatch a message with type via the AppDispatcher.
  The message will be placed on a queue and delivery via the "dispatched" signal.
  Listeners may listen on the "dispatched" signal directly,
  or using helper components like AppListener / AppScript to capture signal.
 */

void QFAppDispatcher::dispatch(const QString &type, const QVariant &message)
{
    if (m_engine.isNull()) {
        qWarning() << "QFAppDispatcher::dispatch() - Unexpected error: engine is not available.";
        return;
    }

    QJSValue value = m_engine->toScriptValue<QVariant>(message);

    dispatch(type, value);
}

/*! \fn QFAppDispatcher *QFAppDispatcher::instance(QQmlEngine *engine)

  \a engine The instance of QQmlEngine

  Obtain the singleton instance of AppDispatcher for specific QQmlEngine

 */

QFAppDispatcher *QFAppDispatcher::instance(QQmlEngine *engine)
{
    QFAppDispatcher *dispatcher = qobject_cast<QFAppDispatcher*>(singletonObject(engine,"QuickFlux",1,0,"AppDispatcher"));

    return dispatcher;
}

/*! \fn QObject *QFAppDispatcher::singletonObject(QQmlEngine *engine, QString package, int versionMajor, int versionMinor, QString typeName)

 \a engine QQmlEngine instance

 \a package The package name of the singleton object

 \a versionMajor The major version no. of the singleton object

 \a versionMinor The minor version no. of the singleton object

 \a typeName The name of the singleton object

  Obtain a singleton object from a package for specific QQmlEngine instance.
  It is useful when you need to get a singleton Actions object from C++.

 */

QObject *QFAppDispatcher::singletonObject(QQmlEngine *engine, QString package, int versionMajor, int versionMinor, QString typeName)
{
    QString pattern  = "import QtQuick 2.0\nimport %1 %2.%3;QtObject { property var object : %4 }";

    QString qml = pattern.arg(package).arg(versionMajor).arg(versionMinor).arg(typeName);

    QObject* holder = 0;

    QQmlComponent comp (engine);
    comp.setData(qml.toUtf8(),QUrl());
    holder = comp.create();

    if (!holder) {
        qWarning() << QString("QuickFlux: Failed to gain singleton object: %1").arg(typeName);
        qWarning() << QString("Error: ") << comp.errorString();
        return 0;
    }

    QObject*object = holder->property("object").value<QObject*>();
    holder->deleteLater();

    if (!object) {
        qWarning() << QString("QuickFlux: Failed to gain singleton object: %1").arg(typeName);
        qWarning() << QString("Error: Unknown");
    }

    return object;
}

void QFAppDispatcher::emitDispatched(QString type, QJSValue message)
{
    dispatchingMessage = message;
    dispatchingMessageType = type;
    pendingListeners.clear();
    waitingListeners.clear();

    QMapIterator<int, QPointer<QFListener> > iter(m_listeners);
    QList<int> ids;
    while (iter.hasNext()) {
        iter.next();
        pendingListeners[iter.key()] = true;
        ids << iter.key();
    }

    invokeListeners(ids);

    emit dispatched(type,message);
}

void QFAppDispatcher::invokeListeners(QList<int> ids)
{
    for (int i = 0 ; i < ids.size() ; i++) {
        int next = ids.at(i);

        if (waitingListeners.contains(next)) {
            qWarning() << "AppDispatcher: Cyclic dependency detected";
        }

        if (!pendingListeners.contains(next))
            continue;

        pendingListeners.remove(next);
        dispatchingListenerId = next;

        QFListener* listener = m_listeners[next].data();

        if (listener) {
            listener->dispatch(this,dispatchingMessageType,dispatchingMessage);
        }
    }
}

QQmlEngine *QFAppDispatcher::engine() const
{
    return m_engine.data();
}

void QFAppDispatcher::setEngine(QQmlEngine *engine)
{
    m_engine = engine;
}

<|endoftext|>


<commit_before>/*
 * Copyright 2015 - 2021 gary@drinkingtea.net
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

// make sure asserts are enabled for the test file
#undef NDEBUG

#include <functional>
#include <map>
#include <string_view>
#include <ox/std/std.hpp>
#include <ox/fs/ptrarith/nodebuffer.hpp>
#include <ox/fs/filestore/filestoretemplate.hpp>
#include <ox/fs/filesystem/filesystem.hpp>

template<typename T>
struct OX_PACKED NodeType: public ox::ptrarith::Item<T> {
	public:
		size_t fullSize() const {
			return this->size() + sizeof(*this);
		}
};

const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tests = {
	{
		{
			"PtrArith::setSize",
			[](std::string_view) {
				using BuffPtr_t = uint32_t;
				ox::Vector<char> buff(5 * ox::units::MB);
				auto buffer = new (buff.data()) ox::ptrarith::NodeBuffer<BuffPtr_t, NodeType<BuffPtr_t>>(buff.size());
				using String = ox::BString<6>;
				auto a1 = buffer->malloc(sizeof(String));
				auto a2 = buffer->malloc(sizeof(String));
				oxAssert(a1.valid(), "Allocation 1 failed.");
				oxAssert(a2.valid(), "Allocation 2 failed.");
				auto &s1 = *new (buffer->dataOf<String>(a1)) String("asdf");
				auto &s2 = *new (buffer->dataOf<String>(a2)) String("aoeu");
				oxTrace("test") << "s1: " << s1.c_str();
				oxTrace("test") << "s2: " << s2.c_str();
				oxAssert(s1 == "asdf", "Allocation 1 not as expected.");
				oxAssert(s2 == "aoeu", "Allocation 2 not as expected.");
				oxAssert(buffer->free(a1), "Free failed.");
				oxAssert(buffer->free(a2), "Free failed.");
				oxAssert(buffer->setSize(buffer->size() - buffer->available()), "Resize failed.");
				return OxError(0);
			}
		},
		{
			"PathIterator::next1",
			[](std::string_view) {
				ox::String path = "/usr/share/charset.gbag";
				ox::PathIterator it(path.c_str(), path.len());
				auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
				oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "usr") == 0, "PathIterator shows wrong next");
				oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "share") == 0, "PathIterator shows wrong next");
				oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "charset.gbag") == 0, "PathIterator shows wrong next");
				return OxError(0);
			}
		},
		{
			"PathIterator::next2",
			[](std::string_view) {
				ox::String path = "/usr/share/";
				ox::PathIterator it(path.c_str(), path.len());
				auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
				oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "usr") == 0, "PathIterator shows wrong next");
				oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "share") == 0, "PathIterator shows wrong next");
				return OxError(0);
			}
		},
		{
			"PathIterator::next3",
			[](std::string_view) {
				ox::String path = "/";
				ox::PathIterator it(path.c_str(), path.len());
				auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
				oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "\0") == 0, "PathIterator shows wrong next");
				return OxError(0);
			}
		},
		{
			"PathIterator::next4",
			[](std::string_view) {
				ox::String path = "usr/share/charset.gbag";
				ox::PathIterator it(path.c_str(), path.len());
				auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
				oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "usr") == 0, "PathIterator shows wrong next");
				oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "share") == 0, "PathIterator shows wrong next");
				oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "charset.gbag") == 0, "PathIterator shows wrong next");
				return OxError(0);
			}
		},
		{
			"PathIterator::next5",
			[](std::string_view) {
				ox::String path = "usr/share/";
				ox::PathIterator it(path.c_str(), path.len());
				auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
				oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "usr") == 0, "PathIterator shows wrong next");
				oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "share") == 0, "PathIterator shows wrong next");
				return OxError(0);
			}
		},
		{
			"PathIterator::dirPath",
			[] (std::string_view) {
				ox::String path = "/usr/share/charset.gbag";
				ox::PathIterator it(path.c_str(), path.len());
				auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
				oxAssert(it.dirPath(buff, path.len()) == 0 && ox_strcmp(buff, "/usr/share/") == 0, "PathIterator shows incorrect dir path");
				return OxError(0);
			}
		},
		{
			"PathIterator::fileName",
			[](std::string_view) {
				ox::String path = "/usr/share/charset.gbag";
				ox::PathIterator it(path.c_str(), path.len());
				auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
				oxAssert(it.fileName(buff, path.len()) == 0 && ox_strcmp(buff, "charset.gbag") == 0, "PathIterator shows incorrect file name");
				return OxError(0);
			}
		},
		{
			"PathIterator::hasNext",
			[](std::string_view) {
				const auto path = "/file1";
				ox::PathIterator it(path, ox_strlen(path));
				oxAssert(it.hasNext(), "PathIterator shows incorrect hasNext");
				oxAssert(!it.next().hasNext(), "PathIterator shows incorrect hasNext");
				return OxError(0);
			}
		},
		{
			"Ptr::subPtr",
			[](std::string_view) {
				constexpr auto buffLen = 5000;
				ox::ptrarith::Ptr<uint8_t, uint32_t> p(ox_alloca(buffLen), buffLen, 500, 500);
				oxAssert(p.valid(), "Ptr::subPtr: Ptr p is invalid.");

				auto subPtr = p.subPtr<uint64_t>(50);
				oxAssert(subPtr.valid(), "Ptr::subPtr: Ptr subPtr is invalid.");
				return OxError(0);
			}
		},
		{
			"NodeBuffer::insert",
			[](std::string_view) {
				constexpr auto buffLen = 5000;
				auto list = new (ox_alloca(buffLen)) ox::ptrarith::NodeBuffer<uint32_t, ox::FileStoreItem<uint32_t>>(buffLen);
				oxAssert(list->malloc(50).valid(), "NodeBuffer::insert: malloc 1 failed");
				oxAssert(list->malloc(50).valid(), "NodeBuffer::insert: malloc 2 failed");
				auto first = list->firstItem();
				oxAssert(first.valid(), "NodeBuffer::insert: Could not access first item");
				oxAssert(first->size() == 50, "NodeBuffer::insert: First item size invalid");
				return OxError(0);
			}
		},
		{
			"FileStore::readWrite",
			[](std::string_view) {
				constexpr auto buffLen = 5000;
				constexpr auto str1 = "Hello, World!";
				constexpr auto str1Len = ox_strlen(str1) + 1;
				constexpr auto str2 = "Hello, Moon!";
				constexpr auto str2Len = ox_strlen(str2) + 1;
				auto list = new (ox_alloca(buffLen)) ox::ptrarith::NodeBuffer<uint32_t, ox::FileStoreItem<uint32_t>>(buffLen);
				oxAssert(ox::FileStore32::format(list, buffLen), "FileStore::format failed.");
				ox::FileStore32 fileStore(list, buffLen);
				oxAssert(fileStore.write(4, const_cast<char*>(str1), str1Len, 1), "FileStore::write 1 failed.");
				oxAssert(fileStore.write(5, const_cast<char*>(str2), str2Len, 1), "FileStore::write 2 failed.");

				char str1Read[str1Len];
				size_t str1ReadSize = 0;
				oxAssert(fileStore.read(4, reinterpret_cast<void*>(str1Read), str1Len, &str1ReadSize), "FileStore::read 1 failed.");

				return OxError(0);
			}
		},
		{
			"Directory",
			[](std::string_view) {
				ox::Vector<uint8_t> fsBuff(5000);
				oxAssert(ox::FileStore32::format(fsBuff.data(), fsBuff.size()), "FS format failed");
				ox::FileStore32 fileStore(fsBuff.data(), fsBuff.size());
				ox::Directory32 dir(fileStore, 105);

				oxTrace("ox::fs::test::Directory") << "Init";
				oxAssert(dir.init(), "Init failed");

				oxTrace("ox::fs::test::Directory") << "write 1";
				oxAssert(dir.write("/file1", 1), "Directory write of file1 failed");

				oxTrace("ox::fs::test::Directory") << "find";
				oxAssert(dir.find("file1").error, "Could not find file1");
				oxAssert(dir.find("file1").value == 1, "Could not find file1");

				oxTrace("ox::fs::test::Directory") << "write 2";
				oxAssert(dir.write("/file3", 3), "Directory write of file3 failed");

				oxTrace("ox::fs::test::Directory") << "write 3";
				oxAssert(dir.write("/file2", 2), "Directory write of file2 failed");

				return OxError(0);
			}
		},
		{
			"FileSystem",
			[](std::string_view) {
				ox::Vector<uint8_t> fsBuff(5000);
				oxTrace("ox::fs::test::FileSystem") << "format";
				oxAssert(ox::FileSystem32::format(fsBuff.data(), fsBuff.size()), "FileSystem format failed");
				ox::FileSystem32 fs(ox::FileStore32(fsBuff.data(), fsBuff.size()));

				oxTrace("ox::fs::test::FileSystem") << "mkdir";
				oxAssert(fs.mkdir("/dir", true), "mkdir failed");
				oxAssert(fs.stat("/dir").error, "mkdir failed");
				oxAssert(fs.mkdir("/l1d1/l2d1/l3d1", true), "mkdir failed");
				oxAssert(fs.stat("/l1d1/l2d1/l3d1").error, "mkdir failed");
				oxAssert(fs.mkdir("/l1d1/l2d2", true), "mkdir failed");
				oxAssert(fs.stat("/l1d1/l2d2").error, "mkdir failed");

				return OxError(0);
			}
		},
	},
};

int main(int argc, const char **args) {
	int retval = -1;
	if (argc > 1) {
		std::string_view testName = args[1];
		std::string_view testArg = "";
		if (args[2]) {
			testArg = args[2];
		}
		if (tests.find(testName) != tests.end()) {
			retval = tests.at(testName)(testArg);
		}
	}
	return retval;
}
<commit_msg>[ox/fs] Fix broken test that was hidden because of bad asserts<commit_after>/*
 * Copyright 2015 - 2021 gary@drinkingtea.net
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

// make sure asserts are enabled for the test file
#undef NDEBUG

#include <functional>
#include <map>
#include <string_view>
#include <ox/std/std.hpp>
#include <ox/fs/ptrarith/nodebuffer.hpp>
#include <ox/fs/filestore/filestoretemplate.hpp>
#include <ox/fs/filesystem/filesystem.hpp>

template<typename T>
struct OX_PACKED NodeType: public ox::ptrarith::Item<T> {
	public:
		size_t fullSize() const {
			return this->size() + sizeof(*this);
		}
};

const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tests = {
	{
		{
			"PtrArith::setSize",
			[](std::string_view) {
				using BuffPtr_t = uint32_t;
				ox::Vector<char> buff(5 * ox::units::MB);
				auto buffer = new (buff.data()) ox::ptrarith::NodeBuffer<BuffPtr_t, NodeType<BuffPtr_t>>(buff.size());
				using String = ox::BString<6>;
				auto a1 = buffer->malloc(sizeof(String));
				auto a2 = buffer->malloc(sizeof(String));
				oxAssert(a1.valid(), "Allocation 1 failed.");
				oxAssert(a2.valid(), "Allocation 2 failed.");
				auto s1Buff = buffer->dataOf<String>(a1);
				auto s2Buff = buffer->dataOf<String>(a2);
				oxAssert(s1Buff.valid(), "s1 allocation 1 failed.");
				oxAssert(s2Buff.valid(), "s2 allocation 2 failed.");
				auto &s1 = *new (s1Buff) String("asdf");
				auto &s2 = *new (s2Buff) String("aoeu");
				oxTrace("test") << "s1: " << s1.c_str();
				oxTrace("test") << "s2: " << s2.c_str();
				oxAssert(s1 == "asdf", "Allocation 1 not as expected.");
				oxAssert(s2 == "aoeu", "Allocation 2 not as expected.");
				oxAssert(buffer->free(a1), "Free failed.");
				oxAssert(buffer->free(a2), "Free failed.");
				oxAssert(buffer->setSize(buffer->size() - buffer->available()), "Resize failed.");
				return OxError(0);
			}
		},
		{
			"PathIterator::next1",
			[](std::string_view) {
				ox::String path = "/usr/share/charset.gbag";
				ox::PathIterator it(path.c_str(), path.len());
				auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
				oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "usr") == 0, "PathIterator shows wrong next");
				oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "share") == 0, "PathIterator shows wrong next");
				oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "charset.gbag") == 0, "PathIterator shows wrong next");
				return OxError(0);
			}
		},
		{
			"PathIterator::next2",
			[](std::string_view) {
				ox::String path = "/usr/share/";
				ox::PathIterator it(path.c_str(), path.len());
				auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
				oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "usr") == 0, "PathIterator shows wrong next");
				oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "share") == 0, "PathIterator shows wrong next");
				return OxError(0);
			}
		},
		{
			"PathIterator::next3",
			[](std::string_view) {
				ox::String path = "/";
				ox::PathIterator it(path.c_str(), path.len());
				auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
				oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "\0") == 0, "PathIterator shows wrong next");
				return OxError(0);
			}
		},
		{
			"PathIterator::next4",
			[](std::string_view) {
				ox::String path = "usr/share/charset.gbag";
				ox::PathIterator it(path.c_str(), path.len());
				auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
				oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "usr") == 0, "PathIterator shows wrong next");
				oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "share") == 0, "PathIterator shows wrong next");
				oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "charset.gbag") == 0, "PathIterator shows wrong next");
				return OxError(0);
			}
		},
		{
			"PathIterator::next5",
			[](std::string_view) {
				ox::String path = "usr/share/";
				ox::PathIterator it(path.c_str(), path.len());
				auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
				oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "usr") == 0, "PathIterator shows wrong next");
				oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "share") == 0, "PathIterator shows wrong next");
				return OxError(0);
			}
		},
		{
			"PathIterator::dirPath",
			[] (std::string_view) {
				ox::String path = "/usr/share/charset.gbag";
				ox::PathIterator it(path.c_str(), path.len());
				auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
				oxAssert(it.dirPath(buff, path.len()) == 0 && ox_strcmp(buff, "/usr/share/") == 0, "PathIterator shows incorrect dir path");
				return OxError(0);
			}
		},
		{
			"PathIterator::fileName",
			[](std::string_view) {
				ox::String path = "/usr/share/charset.gbag";
				ox::PathIterator it(path.c_str(), path.len());
				auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
				oxAssert(it.fileName(buff, path.len()) == 0 && ox_strcmp(buff, "charset.gbag") == 0, "PathIterator shows incorrect file name");
				return OxError(0);
			}
		},
		{
			"PathIterator::hasNext",
			[](std::string_view) {
				const auto path = "/file1";
				ox::PathIterator it(path, ox_strlen(path));
				oxAssert(it.hasNext(), "PathIterator shows incorrect hasNext");
				oxAssert(!it.next().hasNext(), "PathIterator shows incorrect hasNext");
				return OxError(0);
			}
		},
		{
			"Ptr::subPtr",
			[](std::string_view) {
				constexpr auto buffLen = 5000;
				ox::ptrarith::Ptr<uint8_t, uint32_t> p(ox_alloca(buffLen), buffLen, 500, 500);
				oxAssert(p.valid(), "Ptr::subPtr: Ptr p is invalid.");

				auto subPtr = p.subPtr<uint64_t>(50);
				oxAssert(subPtr.valid(), "Ptr::subPtr: Ptr subPtr is invalid.");
				return OxError(0);
			}
		},
		{
			"NodeBuffer::insert",
			[](std::string_view) {
				constexpr auto buffLen = 5000;
				auto list = new (ox_alloca(buffLen)) ox::ptrarith::NodeBuffer<uint32_t, ox::FileStoreItem<uint32_t>>(buffLen);
				oxAssert(list->malloc(50).valid(), "NodeBuffer::insert: malloc 1 failed");
				oxAssert(list->malloc(50).valid(), "NodeBuffer::insert: malloc 2 failed");
				auto first = list->firstItem();
				oxAssert(first.valid(), "NodeBuffer::insert: Could not access first item");
				oxAssert(first->size() == 50, "NodeBuffer::insert: First item size invalid");
				return OxError(0);
			}
		},
		{
			"FileStore::readWrite",
			[](std::string_view) {
				constexpr auto buffLen = 5000;
				constexpr auto str1 = "Hello, World!";
				constexpr auto str1Len = ox_strlen(str1) + 1;
				constexpr auto str2 = "Hello, Moon!";
				constexpr auto str2Len = ox_strlen(str2) + 1;
				auto list = new (ox_alloca(buffLen)) ox::ptrarith::NodeBuffer<uint32_t, ox::FileStoreItem<uint32_t>>(buffLen);
				oxAssert(ox::FileStore32::format(list, buffLen), "FileStore::format failed.");
				ox::FileStore32 fileStore(list, buffLen);
				oxAssert(fileStore.write(4, const_cast<char*>(str1), str1Len, 1), "FileStore::write 1 failed.");
				oxAssert(fileStore.write(5, const_cast<char*>(str2), str2Len, 1), "FileStore::write 2 failed.");

				char str1Read[str1Len];
				size_t str1ReadSize = 0;
				oxAssert(fileStore.read(4, reinterpret_cast<void*>(str1Read), str1Len, &str1ReadSize), "FileStore::read 1 failed.");

				return OxError(0);
			}
		},
		{
			"Directory",
			[](std::string_view) {
				ox::Vector<uint8_t> fsBuff(5000);
				oxAssert(ox::FileStore32::format(fsBuff.data(), fsBuff.size()), "FS format failed");
				ox::FileStore32 fileStore(fsBuff.data(), fsBuff.size());
				ox::Directory32 dir(fileStore, 105);

				oxTrace("ox::fs::test::Directory") << "Init";
				oxAssert(dir.init(), "Init failed");

				oxTrace("ox::fs::test::Directory") << "write 1";
				oxAssert(dir.write("/file1", 1), "Directory write of file1 failed");

				oxTrace("ox::fs::test::Directory") << "find";
				oxAssert(dir.find("file1").error, "Could not find file1");
				oxAssert(dir.find("file1").value == 1, "Could not find file1");

				oxTrace("ox::fs::test::Directory") << "write 2";
				oxAssert(dir.write("/file3", 3), "Directory write of file3 failed");

				oxTrace("ox::fs::test::Directory") << "write 3";
				oxAssert(dir.write("/file2", 2), "Directory write of file2 failed");

				return OxError(0);
			}
		},
		{
			"FileSystem",
			[](std::string_view) {
				ox::Vector<uint8_t> fsBuff(5000);
				oxTrace("ox::fs::test::FileSystem") << "format";
				oxAssert(ox::FileSystem32::format(fsBuff.data(), fsBuff.size()), "FileSystem format failed");
				ox::FileSystem32 fs(ox::FileStore32(fsBuff.data(), fsBuff.size()));

				oxTrace("ox::fs::test::FileSystem") << "mkdir";
				oxAssert(fs.mkdir("/dir", true), "mkdir failed");
				oxAssert(fs.stat("/dir").error, "mkdir failed");
				oxAssert(fs.mkdir("/l1d1/l2d1/l3d1", true), "mkdir failed");
				oxAssert(fs.stat("/l1d1/l2d1/l3d1").error, "mkdir failed");
				oxAssert(fs.mkdir("/l1d1/l2d2", true), "mkdir failed");
				oxAssert(fs.stat("/l1d1/l2d2").error, "mkdir failed");

				return OxError(0);
			}
		},
	},
};

int main(int argc, const char **args) {
	int retval = -1;
	if (argc > 1) {
		std::string_view testName = args[1];
		std::string_view testArg = "";
		if (args[2]) {
			testArg = args[2];
		}
		if (tests.find(testName) != tests.end()) {
			retval = tests.at(testName)(testArg);
		}
	}
	return retval;
}
<|endoftext|>


<commit_before>#include "pic_utils.h"

#include <algorithm>
#include <assert.h>
#include <boost/filesystem.hpp>
#include <cuda_runtime_api.h>
#include <fstream>
#include <stdio.h>

#include "commandline_options.h"
#include "host_mem.h"
#include "simulation_state.h"

void checkForCudaError(const char *errorMsg)
{
   cudaError_t error = cudaGetLastError();
   if(error != cudaSuccess)
   {
      FILE *file;
      SimulationState &simState(SimulationState::getRef());
      fprintf(stderr,"ERROR on iteration %u: %s: %s\n",
         simState.iterationNum, errorMsg, cudaGetErrorString(error) );
      file = fopen(errorLogName.c_str(), "w");
      fprintf(file,"ERROR on iteration %u: %s\n", simState.iterationNum,
         cudaGetErrorString(error) );
      fclose(file);
      assert(error == cudaSuccess);
      exit(1);
   }
}

void checkForCudaErrorSync(const char *errorMsg)
{
   cudaThreadSynchronize();
   checkForCudaError(errorMsg);
}

void checkForCudaError(const char *errorMsg, cudaError_t error)
{
   if(error != cudaSuccess)
   {
      SimulationState &simState(SimulationState::getRef());
      fprintf(stderr,"ERROR on iteration %u: %s: %s\n", simState.iterationNum,
         errorMsg, cudaGetErrorString(error) );
      assert(error == cudaSuccess);
      exit(1);
   }
}

void errExit(const char *errorString)
{
   FILE *file;
   file = fopen(errorLogName.c_str(), "w");
   fprintf(stderr,"ERROR: %s\n", errorString);
   fprintf(file,"ERROR: %s\n", errorString);
   fclose(file);
   assert(false);
   exit(1);
}

void resizeDim3(dim3 &rhs, std::size_t x, std::size_t y, std::size_t z)
{
   rhs.x = static_cast<unsigned int>(x);
   rhs.y = static_cast<unsigned int>(y);
   rhs.z = static_cast<unsigned int>(z);
}

//*****************************************************************************
// Name: outinfo
// Purpose: Output info files that are used to periodically report
//          on the iteration number, simulation time, number of
//          electrons and the number of ions
// Parameters:
// ---------------------
// fname  - Filename to output
// idx_nm - Index to append to fname
// time   - TODO *** Find a better description ***
// need   - The number of electrons
// niid   - The number of ions
//*****************************************************************************
void outinfo(const std::string &fname,int idx_nm,float time,int need,int niid)
{
   char name[100];
   FILE *fp;
   sprintf(name,"%s/%s",outputPath.c_str(), fname.c_str(), idx_nm);
   if((fp=fopen(name,"a"))==NULL) {
      printf("Cannot open '%s' file for writing\n",name);
      exit(1);
   }
   fprintf(fp,"%d\t%f\t%d\t%d\n",idx_nm,time,need,niid);
   fclose(fp);
}

void createOutputDir(const char * dir)
{
   if(!boost::filesystem::exists(dir))
   {
      std::cout << "Creating " << dir << std::endl;
      boost::filesystem::create_directory(dir);
   }
}

bool fileExists(const std::string &fileName)
{
  if(boost::filesystem::exists(fileName))
  {
     return true;
  }
  else
  {
     return false;
  }
}

bool verifyParticle(const float part[], unsigned int nx1, unsigned int ny1)
{
   bool ret = true;
   if(part[0] < 0 || part[0] > nx1)
   {
      ret = false;
   }
   else if(part[1] < 0 || part[1] > ny1)
   {
      ret = false;
   }
   else if(fabs(part[2]) > 1000)
   {
      ret = false;
   }
   else if(fabs(part[3]) > 1000)
   {
      ret = false;
   }
   else if(fabs(part[4]) > 1000)
   {
      ret = false;
   }
   else if(part[0] != part[0])
   {
      ret = false;
   }
   else if(part[1] != part[1])
   {
      ret = false;
   }
   else if(part[2] != part[2])
   {
      ret = false;
   }
   else if(part[3] != part[3])
   {
      ret = false;
   }
   else if(part[4] != part[4])
   {
      ret = false;
   }
   else if(part[0] == 0 && part[1] == 0 &&
           part[2] == 0 && part[3] == 0)
   {
      ret = false;
   }

   return ret;
}

void loadPrevSimState(const std::string &loadDir,
                      DevMem<float2> &dev_eleHotLoc, DevMem<float3> &dev_eleHotVel,
                      DevMem<float2> &dev_eleColdLoc, DevMem<float3> &dev_eleColdVel,
                      DevMem<float2> &dev_ionHotLoc, DevMem<float3> &dev_ionHotVel,
                      DevMem<float2> &dev_ionColdLoc, DevMem<float3> &dev_ionColdVel,
                      unsigned int &numEleHot, unsigned int &numEleCold,
                      unsigned int &numIonHot, unsigned int &numIonCold)
{
   const unsigned int FPPF = 6; // Floats Per Particle File
   const unsigned int FPPM = 5; // Floats Per Particle Memory

   SimulationState &simState(SimulationState::getRef());
   CommandlineOptions &options(CommandlineOptions::getRef());

   const std::size_t strSize = 40;
   char infoName[strSize];
   char eleName[strSize];
   char ionName[strSize];

   // Generate file names
   sprintf(infoName, "info");
   boost::filesystem::path infoPath(loadDir + "/" + infoName);
   boost::filesystem::path elePath;
   boost::filesystem::path ionPath;

   if(!boost::filesystem::exists(infoPath))
   {
      std::cerr << "ERROR: " << infoPath.string() << " does not exist!" << std::endl;
      exit(1);
   }

   // Now I need to find the right files to load
   std::ifstream infoF(infoPath.string().c_str(), std::ios::binary);
   infoF.seekg(-1, std::ios_base::end);
   std::stringstream infoLine;
   bool foundFiles = false;
   unsigned int numEle;
   unsigned int numIon;
   unsigned int index;

   infoLine << getPrevLine(infoF);
   while(!foundFiles && infoLine.str() != "")
   {
      infoLine >> simState.iterationNum >> simState.simTime >> numEle >> numIon;
      index = simState.iterationNum;
      sprintf(eleName, "ele_%04d", index);
      sprintf(ionName, "ion_%04d", index);
      elePath = boost::filesystem::path(loadDir) / eleName;
      ionPath = boost::filesystem::path(loadDir) / ionName;

      if(boost::filesystem::exists(elePath) &&
         boost::filesystem::exists(ionPath))
      {
         foundFiles = true;
      }
      infoLine.clear();
      infoLine << getPrevLine(infoF);
   }

   if(infoLine.str() == "")
   {
      std::cerr << "ERROR: " << infoPath.string()
         << " is either empty or does not reference any ele or ion files that exist." << std::endl;
      exit(1);
   }

   std::cout << "Restating run from index " << index << std::endl;

   float hot;
   std::ifstream infoFile(infoPath.string().c_str());
   FILE *eleFile;
   FILE *ionFile;

   infoFile.close();
   simState.iterationNum *= D_LF;

   HostMem<float2> h_eleHotLoc(dev_eleHotLoc.size());
   HostMem<float3> h_eleHotVel(dev_eleHotVel.size());
   HostMem<float2> h_eleColdLoc(dev_eleColdLoc.size());
   HostMem<float3> h_eleColdVel(dev_eleColdVel.size());
   HostMem<float2> h_ionHotLoc(dev_ionHotLoc.size());
   HostMem<float3> h_ionHotVel(dev_ionHotVel.size());
   HostMem<float2> h_ionColdLoc(dev_ionColdLoc.size());
   HostMem<float3> h_ionColdVel(dev_ionColdVel.size());

   numEleHot = 0;
   numEleCold = 0;
   numIonHot = 0;
   numIonCold = 0;

   float2 tmpLoc;
   float3 tmpVel;

   eleFile = fopen(elePath.string().c_str(), "rb");
   fread(&numEle, sizeof(unsigned int), 1, eleFile);
   for(unsigned int i = 0; i < numEle; i++)
   {
      fread(&tmpLoc, sizeof(float2), 1, eleFile);
      fread(&tmpVel, sizeof(float3), 1, eleFile);
      fread(&hot, sizeof(float), 1, eleFile);
      if(hot > 0)
      {
         assert(numEleHot < h_eleHotLoc.size());
         h_eleHotLoc[numEleHot] = tmpLoc;
         h_eleHotVel[numEleHot] = tmpVel;
         numEleHot++;
      }
      else
      {
         assert(numEleCold < h_eleColdLoc.size());
         h_eleColdLoc[numEleCold] = tmpLoc;
         h_eleColdVel[numEleCold] = tmpVel;
         numEleCold++;
      }
   }
   fclose(eleFile);

   ionFile = fopen(ionPath.string().c_str(), "rb");
   fread(&numIon, sizeof(unsigned int), 1, ionFile);
   for(unsigned int i = 0; i < numIon; i++)
   {
      fread(&tmpLoc, sizeof(float2), 1, ionFile);
      fread(&tmpVel, sizeof(float3), 1, ionFile);
      fread(&hot, sizeof(float), 1, ionFile);
      if(hot > 0)
      {
         assert(numIonHot < h_ionHotLoc.size());
         h_ionHotLoc[numIonHot] = tmpLoc;
         h_ionHotVel[numIonHot] = tmpVel;
         numIonHot++;
      }
      else
      {
         assert(numIonCold < h_ionColdLoc.size());
         h_ionColdLoc[numIonCold] = tmpLoc;
         h_ionColdVel[numIonCold] = tmpVel;
         numIonCold++;
      }
   }
   fclose(ionFile);

   dev_eleHotLoc.copyArrayToDev(h_eleHotLoc);
   dev_eleHotVel.copyArrayToDev(h_eleHotVel);
   dev_eleColdLoc.copyArrayToDev(h_eleColdLoc);
   dev_eleColdVel.copyArrayToDev(h_eleColdVel);
   dev_ionHotLoc.copyArrayToDev(h_ionHotLoc);
   dev_ionHotVel.copyArrayToDev(h_ionHotVel);
   dev_ionColdLoc.copyArrayToDev(h_ionColdLoc);
   dev_ionColdVel.copyArrayToDev(h_ionColdVel);
}

void getLastLine(const std::string fileName, std::string &lastLine)
{
   char lastChar = 0;
   std::ifstream f(fileName.c_str());
   // Seek for the last character; for some reason -1 is always a newline
   f.seekg(-2, std::ios_base::end);

   lastLine = getPrevLine(f);

}

std::string getPrevLine(std::ifstream &f)
{
   std::string line;
   char lastChar = 0;

   // Loop until I'm done with the file or I've read the last non-emtpy line
   while(f && line == "")
   {
      // Check to see if I've found the start of a line
      lastChar = static_cast<char>(f.peek());
      if('\n' == lastChar || f.tellg() == static_cast<std::ifstream::streampos>(0))
      {
         std::istream::streampos pos = f.tellg();
         // If I'm back at the beginning of the file, lastChar won't be newline
         // In those cases, I don't want to skip the first character
         if('\n' == lastChar)
         {
            f.seekg(1, std::ios_base::cur);
         }

         std::getline(f, line);
         // Clear the EOF bit if its been set
         f.clear();
         // Reset the file cursor to its position before the getline
         f.seekg(pos);
      }
      // I haven't found the start of a non-emtpy line yet.
      // Read one more character back.
      f.seekg(-1, std::ios_base::cur);
   }

   return line;
}
<commit_msg>Fixed a bug which corrupted loaded particle information when restarting.<commit_after>#include "pic_utils.h"

#include <algorithm>
#include <assert.h>
#include <boost/filesystem.hpp>
#include <cuda_runtime_api.h>
#include <fstream>
#include <stdio.h>

#include "commandline_options.h"
#include "host_mem.h"
#include "simulation_state.h"

void checkForCudaError(const char *errorMsg)
{
   cudaError_t error = cudaGetLastError();
   if(error != cudaSuccess)
   {
      FILE *file;
      SimulationState &simState(SimulationState::getRef());
      fprintf(stderr,"ERROR on iteration %u: %s: %s\n",
         simState.iterationNum, errorMsg, cudaGetErrorString(error) );
      file = fopen(errorLogName.c_str(), "w");
      fprintf(file,"ERROR on iteration %u: %s\n", simState.iterationNum,
         cudaGetErrorString(error) );
      fclose(file);
      assert(error == cudaSuccess);
      exit(1);
   }
}

void checkForCudaErrorSync(const char *errorMsg)
{
   cudaThreadSynchronize();
   checkForCudaError(errorMsg);
}

void checkForCudaError(const char *errorMsg, cudaError_t error)
{
   if(error != cudaSuccess)
   {
      SimulationState &simState(SimulationState::getRef());
      fprintf(stderr,"ERROR on iteration %u: %s: %s\n", simState.iterationNum,
         errorMsg, cudaGetErrorString(error) );
      assert(error == cudaSuccess);
      exit(1);
   }
}

void errExit(const char *errorString)
{
   FILE *file;
   file = fopen(errorLogName.c_str(), "w");
   fprintf(stderr,"ERROR: %s\n", errorString);
   fprintf(file,"ERROR: %s\n", errorString);
   fclose(file);
   assert(false);
   exit(1);
}

void resizeDim3(dim3 &rhs, std::size_t x, std::size_t y, std::size_t z)
{
   rhs.x = static_cast<unsigned int>(x);
   rhs.y = static_cast<unsigned int>(y);
   rhs.z = static_cast<unsigned int>(z);
}

//*****************************************************************************
// Name: outinfo
// Purpose: Output info files that are used to periodically report
//          on the iteration number, simulation time, number of
//          electrons and the number of ions
// Parameters:
// ---------------------
// fname  - Filename to output
// idx_nm - Index to append to fname
// time   - TODO *** Find a better description ***
// need   - The number of electrons
// niid   - The number of ions
//*****************************************************************************
void outinfo(const std::string &fname,int idx_nm,float time,int need,int niid)
{
   char name[100];
   FILE *fp;
   sprintf(name,"%s/%s",outputPath.c_str(), fname.c_str(), idx_nm);
   if((fp=fopen(name,"a"))==NULL) {
      printf("Cannot open '%s' file for writing\n",name);
      exit(1);
   }
   fprintf(fp,"%d\t%f\t%d\t%d\n",idx_nm,time,need,niid);
   fclose(fp);
}

void createOutputDir(const char * dir)
{
   if(!boost::filesystem::exists(dir))
   {
      std::cout << "Creating " << dir << std::endl;
      boost::filesystem::create_directory(dir);
   }
}

bool fileExists(const std::string &fileName)
{
  if(boost::filesystem::exists(fileName))
  {
     return true;
  }
  else
  {
     return false;
  }
}

bool verifyParticle(const float part[], unsigned int nx1, unsigned int ny1)
{
   bool ret = true;
   if(part[0] < 0 || part[0] > nx1)
   {
      ret = false;
   }
   else if(part[1] < 0 || part[1] > ny1)
   {
      ret = false;
   }
   else if(fabs(part[2]) > 1000)
   {
      ret = false;
   }
   else if(fabs(part[3]) > 1000)
   {
      ret = false;
   }
   else if(fabs(part[4]) > 1000)
   {
      ret = false;
   }
   else if(part[0] != part[0])
   {
      ret = false;
   }
   else if(part[1] != part[1])
   {
      ret = false;
   }
   else if(part[2] != part[2])
   {
      ret = false;
   }
   else if(part[3] != part[3])
   {
      ret = false;
   }
   else if(part[4] != part[4])
   {
      ret = false;
   }
   else if(part[0] == 0 && part[1] == 0 &&
           part[2] == 0 && part[3] == 0)
   {
      ret = false;
   }

   return ret;
}

void loadPrevSimState(const std::string &loadDir,
                      DevMem<float2> &dev_eleHotLoc, DevMem<float3> &dev_eleHotVel,
                      DevMem<float2> &dev_eleColdLoc, DevMem<float3> &dev_eleColdVel,
                      DevMem<float2> &dev_ionHotLoc, DevMem<float3> &dev_ionHotVel,
                      DevMem<float2> &dev_ionColdLoc, DevMem<float3> &dev_ionColdVel,
                      unsigned int &numEleHot, unsigned int &numEleCold,
                      unsigned int &numIonHot, unsigned int &numIonCold)
{
   const unsigned int FPPF = 6; // Floats Per Particle File
   const unsigned int FPPM = 5; // Floats Per Particle Memory

   SimulationState &simState(SimulationState::getRef());
   CommandlineOptions &options(CommandlineOptions::getRef());

   const std::size_t strSize = 40;
   char infoName[strSize];
   char eleName[strSize];
   char ionName[strSize];

   // Generate file names
   sprintf(infoName, "info");
   boost::filesystem::path infoPath(loadDir + "/" + infoName);
   boost::filesystem::path elePath;
   boost::filesystem::path ionPath;

   if(!boost::filesystem::exists(infoPath))
   {
      std::cerr << "ERROR: " << infoPath.string() << " does not exist!" << std::endl;
      exit(1);
   }

   // Now I need to find the right files to load
   std::ifstream infoF(infoPath.string().c_str(), std::ios::binary);
   infoF.seekg(-1, std::ios_base::end);
   std::stringstream infoLine;
   bool foundFiles = false;
   unsigned int numEle;
   unsigned int numIon;
   unsigned int index;

   infoLine << getPrevLine(infoF);
   while(!foundFiles && infoLine.str() != "")
   {
      infoLine >> simState.iterationNum >> simState.simTime >> numEle >> numIon;
      index = simState.iterationNum;
      sprintf(eleName, "ele_%04d", index);
      sprintf(ionName, "ion_%04d", index);
      elePath = boost::filesystem::path(loadDir) / eleName;
      ionPath = boost::filesystem::path(loadDir) / ionName;

      if(boost::filesystem::exists(elePath) &&
         boost::filesystem::exists(ionPath))
      {
         foundFiles = true;
      }
      infoLine.clear();
      infoLine << getPrevLine(infoF);
   }

   if(infoLine.str() == "")
   {
      std::cerr << "ERROR: " << infoPath.string()
         << " is either empty or does not reference any ele or ion files that exist." << std::endl;
      exit(1);
   }

   std::cout << "Restating run from index " << index << std::endl;

   std::ifstream infoFile(infoPath.string().c_str());

   infoFile.close();
   simState.iterationNum *= D_LF;

   HostMem<float2> h_eleHotLoc(dev_eleHotLoc.size());
   HostMem<float3> h_eleHotVel(dev_eleHotVel.size());
   HostMem<float2> h_eleColdLoc(dev_eleColdLoc.size());
   HostMem<float3> h_eleColdVel(dev_eleColdVel.size());
   HostMem<float2> h_ionHotLoc(dev_ionHotLoc.size());
   HostMem<float3> h_ionHotVel(dev_ionHotVel.size());
   HostMem<float2> h_ionColdLoc(dev_ionColdLoc.size());
   HostMem<float3> h_ionColdVel(dev_ionColdVel.size());

   numEleHot = 0;
   numEleCold = 0;
   numIonHot = 0;
   numIonCold = 0;

   std::ifstream eleFile(elePath.string().c_str(), std::ios::binary);
   eleFile.read(reinterpret_cast<char*>(&numEle), sizeof(unsigned int));
   eleFile.read(reinterpret_cast<char*>(&numEleHot), sizeof(unsigned int));
   eleFile.read(reinterpret_cast<char*>(&numEleCold), sizeof(unsigned int));
   for(unsigned int i = 0; i < numEleHot; i++)
   {
      eleFile.read(reinterpret_cast<char*>(&h_eleHotLoc[i]), sizeof(float2));
      eleFile.read(reinterpret_cast<char*>(&h_eleHotVel[i]), sizeof(float3));
   }
   for(unsigned int i = 0; i < numEleCold; i++)
   {
      eleFile.read(reinterpret_cast<char*>(&h_eleColdLoc[i]), sizeof(float2));
      eleFile.read(reinterpret_cast<char*>(&h_eleColdVel[i]), sizeof(float3));
   }
   eleFile.close();

   std::ifstream ionFile(ionPath.string().c_str(), std::ios::binary);
   eleFile.read(reinterpret_cast<char*>(&numIon), sizeof(unsigned int));
   eleFile.read(reinterpret_cast<char*>(&numIonHot), sizeof(unsigned int));
   eleFile.read(reinterpret_cast<char*>(&numIonCold), sizeof(unsigned int));
   for(unsigned int i = 0; i < numIonHot; i++)
   {
      eleFile.read(reinterpret_cast<char*>(&h_ionHotLoc[i]), sizeof(float2));
      eleFile.read(reinterpret_cast<char*>(&h_ionHotVel[i]), sizeof(float3));
   }
   for(unsigned int i = 0; i < numIonCold; i++)
   {
      eleFile.read(reinterpret_cast<char*>(&h_ionColdLoc[i]), sizeof(float2));
      eleFile.read(reinterpret_cast<char*>(&h_ionColdVel[i]), sizeof(float3));
   }
   ionFile.close();

   dev_eleHotLoc.copyArrayToDev(h_eleHotLoc);
   dev_eleHotVel.copyArrayToDev(h_eleHotVel);
   dev_eleColdLoc.copyArrayToDev(h_eleColdLoc);
   dev_eleColdVel.copyArrayToDev(h_eleColdVel);
   dev_ionHotLoc.copyArrayToDev(h_ionHotLoc);
   dev_ionHotVel.copyArrayToDev(h_ionHotVel);
   dev_ionColdLoc.copyArrayToDev(h_ionColdLoc);
   dev_ionColdVel.copyArrayToDev(h_ionColdVel);
}

void getLastLine(const std::string fileName, std::string &lastLine)
{
   char lastChar = 0;
   std::ifstream f(fileName.c_str());
   // Seek for the last character; for some reason -1 is always a newline
   f.seekg(-2, std::ios_base::end);

   lastLine = getPrevLine(f);

}

std::string getPrevLine(std::ifstream &f)
{
   std::string line;
   char lastChar = 0;

   // Loop until I'm done with the file or I've read the last non-emtpy line
   while(f && line == "")
   {
      // Check to see if I've found the start of a line
      lastChar = static_cast<char>(f.peek());
      if('\n' == lastChar || f.tellg() == static_cast<std::ifstream::streampos>(0))
      {
         std::istream::streampos pos = f.tellg();
         // If I'm back at the beginning of the file, lastChar won't be newline
         // In those cases, I don't want to skip the first character
         if('\n' == lastChar)
         {
            f.seekg(1, std::ios_base::cur);
         }

         std::getline(f, line);
         // Clear the EOF bit if its been set
         f.clear();
         // Reset the file cursor to its position before the getline
         f.seekg(pos);
      }
      // I haven't found the start of a non-emtpy line yet.
      // Read one more character back.
      f.seekg(-1, std::ios_base::cur);
   }

   return line;
}
<|endoftext|>