<commit_before>#include "webcam.hpp"
#include <chrono>

using namespace cv;
using namespace std;

Mat ellipticKernel(int width, int height = -1) {
 if (height==-1) {
  return getStructuringElement(MORPH_ELLIPSE,Size(width,width), Point(width/2, width/2));
 } else {
  return getStructuringElement(MORPH_ELLIPSE,Size(width,height), Point(width/2, height/2));
 }
}

unsigned long long getMilliseconds() {
 return chrono::system_clock::now().time_since_epoch()/chrono::milliseconds(1);
}

void morphFast(Mat inout, int smallsize = 100, int factor = 25, int eq = 1, int diler = 0) {
 int width, height;
 width = inout.size().width;
 height = inout.size().height;
 Mat downsample;
 resize(inout, downsample, Size(smallsize,smallsize));
 Mat kernel = ellipticKernel(factor);
 if (diler) {
  erode(downsample, downsample, kernel);
 } else {
  dilate(downsample, downsample, kernel);
 }
 if (eq) {
  equalizeHist(downsample, downsample);
 }
 resize(downsample, inout, Size(width, height));
}

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

 int tracker1, tracker2, tracker3;
 namedWindow("s",1);
 createTrackbar("1","s",&tracker1,100);
 createTrackbar("2","s",&tracker2,100);
 createTrackbar("3","s",&tracker3,100);

 CvCapture* capture = 0;
 int width, height, fps;

 capture = cvCaptureFromCAM(0);

 if (!capture) {
  printf("No camera detected!");
  return -1;
 }

 unsigned long long times[100];
 int f = 0;
 for (int i=0; i<100; i++)
  times[i] = 0;

 ifstream configFile (".config");

 if (configFile.is_open()) {

  //probably want to support corrupted .config
  string line;
  getline(configFile, line);
  istringstream(line)>>width;
  getline(configFile, line);
  istringstream(line)>>height;
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, width);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, height);

  configFile.close();

 } else {

  initResolutions();

  for (int i=36; i<150; i++) {
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, resolutions[i].width);
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, resolutions[i].height);
  }

  width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
  height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);

  ofstream configFileOut(".config");
  configFileOut << width;
  configFileOut << "\n";
  configFileOut << height;
  configFileOut << "\n";
  configFileOut.close();
 }

 bool keepGoing = true;

// srand(890);//not interested in good randomness

 for (int i = 0; i < 30; i++) {
  // capture some frames so exposure correction takes place
  cvQueryFrame(capture);
 }

 Mat background = cvQueryFrame(capture);
 background = background.clone();
 blur(background, background, Size(50,50));

 Mat image;
 Mat channel[3];
 unsigned long long timenow = getMilliseconds();

 while (keepGoing) {
  image = cvQueryFrame(capture);
  times[0] += getMilliseconds() - timenow;
  timenow = getMilliseconds();
// preprocess by rotating according to OVR roll
//  imshow("webcam", image);

// let's make multiple masks where 0=not mouth, 1=uncertain

// then multiply them together and multiply that with image
// and run haar classifier on image

  Mat gray, blurred_img;
  cvtColor(image, gray, CV_RGB2GRAY);
  blur(image, blurred_img, Size(50,50));
  times[1] += getMilliseconds() - timenow;
  timenow = getMilliseconds();

// this mask filters out areas with too many edges
// removed for now; it didn't generalize well
/*
  Mat canny;
  Canny(gray, canny, 50, 50, 3);
  blur(canny, canny, Size(width/20,height/20));
  bitwise_not(canny, canny);
  threshold(canny, canny, 200, 1, THRESH_BINARY);
  blur(canny*255, canny, Size(width/10, height/10));
  threshold(canny, canny, 220, 1, THRESH_BINARY);
  imshow("canny mask", gray.mul(canny));
*/

// this mask filters out areas which have not changed much
// background needs to be updated when person is not in frame
// use OVR SDK to do this later
  Mat flow;
  absdiff(blurred_img, background, flow);
  cvtColor(flow, flow, CV_RGB2GRAY);
  morphFast(flow);
  threshold(flow, flow, 60, 1, THRESH_BINARY);
//  imshow("flow mask", gray.mul(flow));
  times[2] += getMilliseconds() - timenow;
  timenow = getMilliseconds();

// this mask gets anything kind of dark (DK2) and dilates
  Mat kindofdark;
  equalizeHist(gray, kindofdark);
  threshold(kindofdark, kindofdark, 100, 1, THRESH_BINARY_INV);
  morphFast(kindofdark, 100, 17, 0);
//  imshow("dark mask", gray.mul(kindofdark));
  times[3] += getMilliseconds() - timenow;
  timenow = getMilliseconds();

// this mask gets rid of anything far away from red stuff
// did not work well and was slow
/*
  Mat notlips;
  Mat channels[3];
  split(image, channels);
  channels[2].convertTo(notlips, CV_32FC1);
  divide(notlips, gray, notlips, 1, CV_32FC1);
  //equalistHist is horrible for a red background
  //equalizeHist(notlips, notlips);
  threshold(notlips, notlips, tracker3/30.0, 1, THRESH_BINARY);
  notlips.convertTo(notlips, CV_8UC1);
  imshow("lip mask", notlips*255);
  Mat otherMorph = notlips.clone();
  int tx = tracker1+1-(tracker1%2);
  if (tx<3) tx=1;
  if (tx>90) tx=91;
  morphFast(notlips, 100, tx, 0, 0);
  int ty = tracker2+1-(tracker2%2);
  if (ty<3) ty=1;
  if (ty>90) ty=91;
  morphFast(notlips, 100, ty, 0, 1);
  imshow("lips2", notlips.mul(gray));
  morphFast(otherMorph, 100, tx, 0, 1);
  morphFast(otherMorph, 100, tx, 0, 0);
  imshow("lips3", otherMorph.mul(gray));
  waitKey(1);
*/

  Mat mask = flow.mul(kindofdark);
// open the mask
  Mat smallMask0, smallMask1;
  resize(mask, smallMask0, Size(width/5,height/5));
  Mat smallKernel = ellipticKernel(69,79);
  erode(smallMask0, smallMask1, smallKernel);
  dilate(smallMask1, smallMask1, smallKernel);
  bitwise_and(smallMask0, smallMask1, smallMask1);
  resize(smallMask1, mask, Size(width, height));
//  imshow("morph mask", gray.mul(mask));
  times[4] += getMilliseconds() - timenow;
  timenow = getMilliseconds();

// update background with new morph mask
// average what we know is background with prior background
// dilate it first since we really want to be sure it's bg

/*
// actually dilation is slow and our current mask is already
// really nice :)
  Mat dilatedMask;
  dilate(smallMask1, dilatedMask, smallKernel);
  resize(dilatedMask, dilatedMask, Size(width, height));
  imshow("erosion", dilatedMask.mul(gray));
*/
//  imshow("background", background);

/*
  Moments lol = moments(gray, 1);
  circle(image, Point(lol.m10/lol.m00,lol.m01/lol.m00),20,Scalar(128),30);
  imshow("leimage", image);
*/

  CascadeClassifier mouth_cascade;
  mouth_cascade.load("Mouth.xml");
  vector<Rect> mouths;
  int scale = 3;
  Mat classifyThis;
  equalizeHist(gray, gray);//ew; watch out not to use this later
  resize(gray.mul(mask), classifyThis, Size(width/scale,height/scale));
//  bilateralFilter(gray, classifyThis, 15, 10, 1);
  mouth_cascade.detectMultiScale(classifyThis, mouths, 1.1, 0, CV_HAAR_SCALE_IMAGE);
  Mat rectImage(height, width, CV_8UC1, Scalar(0));
  for (size_t i=0; i<mouths.size(); i++) {
   Rect scaled(mouths[i].x*scale, mouths[i].y*scale, mouths[i].width*scale,mouths[i].height*scale);
   Mat newRect(height, width; CV_8UC1, Scalar(0));
   rectangle(newRect, scaled, Scalar(1), CV_FILLED);
   rectImage += newRect;
  }
  threshold(rectImage, rectImage, tracker1, 1, THRESH_BINARY);
  times[6] += getMilliseconds() - timenow;
  timenow = getMilliseconds();
  imshow("MOUTH", rectImage.mul(gray));

  bitwise_and(rectImage, mask, mask);

  Mat mask_;
  subtract(1, mask ,mask_);
  Mat mask3, mask3_;
  channel[0] = mask;
  channel[1] = mask;
  channel[2] = mask;
  merge(channel, 3, mask3);
  channel[0] = mask_;
  channel[1] = mask_;
  channel[2] = mask_;
  merge(channel, 3, mask3_);

  background = background.mul(mask3) +
   (background.mul(mask3_)/2 + blurred_img.mul(mask3_)/2);
  times[5] += getMilliseconds() - timenow;
  timenow = getMilliseconds();

  for (int i=0; i<7; i++) {
   printf("%llu , ", times[i]);
   times[i] = 0;
  }

  printf("\n");

  keepGoing = (waitKey(1)<0);

 }

 cvReleaseCapture(&capture);

 return 0;
}
<commit_msg>hacking<commit_after>#include "webcam.hpp"
#include <chrono>

using namespace cv;
using namespace std;

Mat ellipticKernel(int width, int height = -1) {
 if (height==-1) {
  return getStructuringElement(MORPH_ELLIPSE,Size(width,width), Point(width/2, width/2));
 } else {
  return getStructuringElement(MORPH_ELLIPSE,Size(width,height), Point(width/2, height/2));
 }
}

unsigned long long getMilliseconds() {
 return chrono::system_clock::now().time_since_epoch()/chrono::milliseconds(1);
}

void morphFast(Mat inout, int smallsize = 100, int factor = 25, int eq = 1, int diler = 0) {
 int width, height;
 width = inout.size().width;
 height = inout.size().height;
 Mat downsample;
 resize(inout, downsample, Size(smallsize,smallsize));
 Mat kernel = ellipticKernel(factor);
 if (diler) {
  erode(downsample, downsample, kernel);
 } else {
  dilate(downsample, downsample, kernel);
 }
 if (eq) {
  equalizeHist(downsample, downsample);
 }
 resize(downsample, inout, Size(width, height));
}

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

 int tracker1, tracker2, tracker3;
 namedWindow("s",1);
 createTrackbar("1","s",&tracker1,100);
 createTrackbar("2","s",&tracker2,100);
 createTrackbar("3","s",&tracker3,100);

 CvCapture* capture = 0;
 int width, height, fps;

 capture = cvCaptureFromCAM(0);

 if (!capture) {
  printf("No camera detected!");
  return -1;
 }

 unsigned long long times[100];
 int f = 0;
 for (int i=0; i<100; i++)
  times[i] = 0;

 ifstream configFile (".config");

 if (configFile.is_open()) {

  //probably want to support corrupted .config
  string line;
  getline(configFile, line);
  istringstream(line)>>width;
  getline(configFile, line);
  istringstream(line)>>height;
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, width);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, height);

  configFile.close();

 } else {

  initResolutions();

  for (int i=36; i<150; i++) {
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, resolutions[i].width);
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, resolutions[i].height);
  }

  width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
  height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);

  ofstream configFileOut(".config");
  configFileOut << width;
  configFileOut << "\n";
  configFileOut << height;
  configFileOut << "\n";
  configFileOut.close();
 }

 bool keepGoing = true;

// srand(890);//not interested in good randomness

 for (int i = 0; i < 30; i++) {
  // capture some frames so exposure correction takes place
  cvQueryFrame(capture);
 }

 Mat background = cvQueryFrame(capture);
 background = background.clone();
 blur(background, background, Size(50,50));

 Mat image;
 Mat channel[3];
 unsigned long long timenow = getMilliseconds();

 while (keepGoing) {
  image = cvQueryFrame(capture);
  times[0] += getMilliseconds() - timenow;
  timenow = getMilliseconds();
// preprocess by rotating according to OVR roll
//  imshow("webcam", image);

// let's make multiple masks where 0=not mouth, 1=uncertain

// then multiply them together and multiply that with image
// and run haar classifier on image

  Mat gray, blurred_img;
  cvtColor(image, gray, CV_RGB2GRAY);
  blur(image, blurred_img, Size(50,50));
  times[1] += getMilliseconds() - timenow;
  timenow = getMilliseconds();

// this mask filters out areas with too many edges
// removed for now; it didn't generalize well
/*
  Mat canny;
  Canny(gray, canny, 50, 50, 3);
  blur(canny, canny, Size(width/20,height/20));
  bitwise_not(canny, canny);
  threshold(canny, canny, 200, 1, THRESH_BINARY);
  blur(canny*255, canny, Size(width/10, height/10));
  threshold(canny, canny, 220, 1, THRESH_BINARY);
  imshow("canny mask", gray.mul(canny));
*/

// this mask filters out areas which have not changed much
// background needs to be updated when person is not in frame
// use OVR SDK to do this later
  Mat flow;
  absdiff(blurred_img, background, flow);
  cvtColor(flow, flow, CV_RGB2GRAY);
  morphFast(flow);
  threshold(flow, flow, 60, 1, THRESH_BINARY);
//  imshow("flow mask", gray.mul(flow));
  times[2] += getMilliseconds() - timenow;
  timenow = getMilliseconds();

// this mask gets anything kind of dark (DK2) and dilates
  Mat kindofdark;
  equalizeHist(gray, kindofdark);
  threshold(kindofdark, kindofdark, 100, 1, THRESH_BINARY_INV);
  morphFast(kindofdark, 100, 17, 0);
//  imshow("dark mask", gray.mul(kindofdark));
  times[3] += getMilliseconds() - timenow;
  timenow = getMilliseconds();

// this mask gets rid of anything far away from red stuff
// did not work well and was slow
/*
  Mat notlips;
  Mat channels[3];
  split(image, channels);
  channels[2].convertTo(notlips, CV_32FC1);
  divide(notlips, gray, notlips, 1, CV_32FC1);
  //equalistHist is horrible for a red background
  //equalizeHist(notlips, notlips);
  threshold(notlips, notlips, tracker3/30.0, 1, THRESH_BINARY);
  notlips.convertTo(notlips, CV_8UC1);
  imshow("lip mask", notlips*255);
  Mat otherMorph = notlips.clone();
  int tx = tracker1+1-(tracker1%2);
  if (tx<3) tx=1;
  if (tx>90) tx=91;
  morphFast(notlips, 100, tx, 0, 0);
  int ty = tracker2+1-(tracker2%2);
  if (ty<3) ty=1;
  if (ty>90) ty=91;
  morphFast(notlips, 100, ty, 0, 1);
  imshow("lips2", notlips.mul(gray));
  morphFast(otherMorph, 100, tx, 0, 1);
  morphFast(otherMorph, 100, tx, 0, 0);
  imshow("lips3", otherMorph.mul(gray));
  waitKey(1);
*/

  Mat mask = flow.mul(kindofdark);
// open the mask
  Mat smallMask0, smallMask1;
  resize(mask, smallMask0, Size(width/5,height/5));
  Mat smallKernel = ellipticKernel(69,79);
  erode(smallMask0, smallMask1, smallKernel);
  dilate(smallMask1, smallMask1, smallKernel);
  bitwise_and(smallMask0, smallMask1, smallMask1);
  resize(smallMask1, mask, Size(width, height));
//  imshow("morph mask", gray.mul(mask));
  times[4] += getMilliseconds() - timenow;
  timenow = getMilliseconds();

// update background with new morph mask
// average what we know is background with prior background
// dilate it first since we really want to be sure it's bg

/*
// actually dilation is slow and our current mask is already
// really nice :)
  Mat dilatedMask;
  dilate(smallMask1, dilatedMask, smallKernel);
  resize(dilatedMask, dilatedMask, Size(width, height));
  imshow("erosion", dilatedMask.mul(gray));
*/
//  imshow("background", background);

/*
  Moments lol = moments(gray, 1);
  circle(image, Point(lol.m10/lol.m00,lol.m01/lol.m00),20,Scalar(128),30);
  imshow("leimage", image);
*/

  CascadeClassifier mouth_cascade;
  mouth_cascade.load("Mouth.xml");
  vector<Rect> mouths;
  int scale = 3;
  Mat classifyThis;
  equalizeHist(gray, gray);//ew; watch out not to use this later
  resize(gray.mul(mask), classifyThis, Size(width/scale,height/scale));
//  bilateralFilter(gray, classifyThis, 15, 10, 1);
  mouth_cascade.detectMultiScale(classifyThis, mouths, 1.1, 0, CV_HAAR_SCALE_IMAGE);
  Mat rectImage(height, width, CV_8UC1, Scalar(0));
  for (size_t i=0; i<mouths.size(); i++) {
   Rect scaled(mouths[i].x*scale, mouths[i].y*scale, mouths[i].width*scale,mouths[i].height*scale);
   Mat newRect(height, width, CV_8UC1, Scalar(0));
   rectangle(newRect, scaled, Scalar(1), CV_FILLED);
   rectImage += newRect;
  }
  threshold(rectImage, rectImage, tracker1, 1, THRESH_BINARY);
  times[6] += getMilliseconds() - timenow;
  timenow = getMilliseconds();
  imshow("MOUTH", rectImage.mul(gray));

  bitwise_and(rectImage, mask, mask);

  Mat mask_;
  subtract(1, mask ,mask_);
  Mat mask3, mask3_;
  channel[0] = mask;
  channel[1] = mask;
  channel[2] = mask;
  merge(channel, 3, mask3);
  channel[0] = mask_;
  channel[1] = mask_;
  channel[2] = mask_;
  merge(channel, 3, mask3_);

  background = background.mul(mask3) +
   (background.mul(mask3_)/2 + blurred_img.mul(mask3_)/2);
  times[5] += getMilliseconds() - timenow;
  timenow = getMilliseconds();

  for (int i=0; i<7; i++) {
   printf("%llu , ", times[i]);
   times[i] = 0;
  }

  printf("\n");

  keepGoing = (waitKey(1)<0);

 }

 cvReleaseCapture(&capture);

 return 0;
}
<|endoftext|>


<commit_before>#include "lit.h"
#include "asm.h"
#include "lex.h"
#include "expr.h"
#include "parse.h"
#include "token.h"
#include "stdfunc.h"
#include "util.h"
#include "option.h"
#include "library.h"

MemoryList mem;
ctrl_t break_list, return_list;

// ---- for native code --- //

char *File_read(char *s, int len, FILE *fp) { fread(s, 1, len, fp); return s; }

void putNumber(int32_t n) {
	printf("%d", n);
}
void putString(int32_t *n) {
	printf("%s", (char *)n);
}
void putln() { printf("\n"); }

void ssleep(uint32_t t) {
#if defined(WIN32) || defined(WINDOWS)
	Sleep(t * CLOCKS_PER_SEC / 1000);
#else
	usleep(t * CLOCKS_PER_SEC / 1000);
#endif
}

void appendAddr(uint32_t addr) {
	mem_info mi = {
		.addr = addr,
		.isfree = false
	};
	mem.mem.push_back(mi);
}

void free_addr(uint32_t addr) {
	for(int i = 0; i < mem.mem.size(); i++) {
		if(mem.mem[i].addr == addr) {
			free((void *)mem.mem[i].addr);
			mem.mem[i].isfree = false;
		}
	}
}

void freeAddr() {
	if(mem.count() > 0) {
		for(size_t i = 0; i < mem.count(); i++) {
			if(mem.mem[i].isfree == 0) {
				free((void *)mem.mem[i].addr);
				mem.mem.pop_back();
			}
		}
	}
}

char *rea_concat(char *a, char *b) {
	a = (char *)realloc(a, strlen(a) + strlen(b) + 2);
	return strcat(a, b);
}

void *funcTable[] = {
	(void *) putNumber, // 0
	(void *) putString, // 4
	(void *) putln,			// 8
	(void *) malloc, 		// 12
	(void *) printf, 		// 16
	(void *) appendAddr,// 20
	(void *) ssleep, 		// 24
	(void *) fopen, 		// 28
	(void *) fprintf, 	// 32
	(void *) fclose,		// 36
	(void *) File_read,	// 40
	(void *) free_addr,	// 44
	(void *) freeAddr,	// 48
	(void *) fgets, 		// 52
	(void *) rea_concat // 56
};

// Lit class is from here

Lit::Lit(int ac, char **av)
	:lex(tok), parser(tok), argc(ac), argv(av) {
	tok.pos = 0; tok.size = 0xfff;
	return_list.addr_list = (uint32_t *)calloc(sizeof(uint32_t), 1);
	break_list.addr_list = (uint32_t *)calloc(sizeof(uint32_t), 1);
}

Lit::~Lit() {
	freeAddr();
}

int Lit::execute(char *source) {
	lex.lex(source);
	parser.parser();
	run();
	return 0;
}

int Lit::run() {
	printf("");
	return ((int (*)(int *, void**))ntv.code)(0, funcTable);
}

void Lit::interpret() {
	std::string line, all;

	while(std::getline(std::cin, line)) {
		all += line + " ; ";
		line.clear();
	}

	clock_t bgn = clock();
		execute((char *)all.c_str());
	clock_t end = clock();
#ifdef DEBUG
	printf("time: %.3lf\n", (double)(end - bgn) / CLOCKS_PER_SEC);
#endif
}

void Lit::run_from_file(char *source) {
	std::ifstream ifs_src(source);
	if(!ifs_src) ::error("LitSystemError: cannot open file '%s'", source);
	std::istreambuf_iterator<char> it(ifs_src);
	std::istreambuf_iterator<char> last;
	std::string src_all(it, last);

	execute((char *)src_all.c_str());
}

int Lit::start() {
	show_option();
	return 0;
}
<commit_msg>bug fix about string concat<commit_after>#include "lit.h"
#include "asm.h"
#include "lex.h"
#include "expr.h"
#include "parse.h"
#include "token.h"
#include "stdfunc.h"
#include "util.h"
#include "option.h"
#include "library.h"

MemoryList mem;
ctrl_t break_list, return_list;

// ---- for native code --- //

char *File_read(char *s, int len, FILE *fp) { fread(s, 1, len, fp); return s; }

void putNumber(int32_t n) {
	printf("%d", n);
}
void putString(int32_t *n) {
	printf("%s", (char *)n);
}
void putln() { printf("\n"); }

void ssleep(uint32_t t) {
#if defined(WIN32) || defined(WINDOWS)
	Sleep(t * CLOCKS_PER_SEC / 1000);
#else
	usleep(t * CLOCKS_PER_SEC / 1000);
#endif
}

void appendAddr(uint32_t addr) {
	mem_info mi = {
		.addr = addr,
		.isfree = false
	};
	mem.mem.push_back(mi);
}

void free_addr(uint32_t addr) {
	for(int i = 0; i < mem.mem.size(); i++) {
		if(mem.mem[i].addr == addr) {
			free((void *)mem.mem[i].addr);
			mem.mem[i].isfree = false;
		}
	}
}

void freeAddr() {
	if(mem.count() > 0) {
		for(size_t i = 0; i < mem.count(); i++) {
			if(mem.mem[i].isfree == 0) {
				free((void *)mem.mem[i].addr);
				mem.mem.pop_back();
			}
		}
	}
}

char *rea_concat(char *a, char *b) {
	char *t = (char *)malloc(strlen(a) + strlen(b) + 2);
	strcpy(t, a);
	return strcat(t, b);
}

void *funcTable[] = {
	(void *) putNumber, // 0
	(void *) putString, // 4
	(void *) putln,			// 8
	(void *) malloc, 		// 12
	(void *) printf, 		// 16
	(void *) appendAddr,// 20
	(void *) ssleep, 		// 24
	(void *) fopen, 		// 28
	(void *) fprintf, 	// 32
	(void *) fclose,		// 36
	(void *) File_read,	// 40
	(void *) free_addr,	// 44
	(void *) freeAddr,	// 48
	(void *) fgets, 		// 52
	(void *) rea_concat // 56
};

// Lit class is from here

Lit::Lit(int ac, char **av)
	:lex(tok), parser(tok), argc(ac), argv(av) {
	tok.pos = 0; tok.size = 0xfff;
	return_list.addr_list = (uint32_t *)calloc(sizeof(uint32_t), 1);
	break_list.addr_list = (uint32_t *)calloc(sizeof(uint32_t), 1);
}

Lit::~Lit() {
	freeAddr();
}

int Lit::execute(char *source) {
	lex.lex(source);
	parser.parser();
	run();
	return 0;
}

int Lit::run() {
	printf("");
	return ((int (*)(int *, void**))ntv.code)(0, funcTable);
}

void Lit::interpret() {
	std::string line, all;

	while(std::getline(std::cin, line)) {
		all += line + " ; ";
		line.clear();
	}

	clock_t bgn = clock();
		execute((char *)all.c_str());
	clock_t end = clock();
#ifdef DEBUG
	printf("time: %.3lf\n", (double)(end - bgn) / CLOCKS_PER_SEC);
#endif
}

void Lit::run_from_file(char *source) {
	std::ifstream ifs_src(source);
	if(!ifs_src) ::error("LitSystemError: cannot open file '%s'", source);
	std::istreambuf_iterator<char> it(ifs_src);
	std::istreambuf_iterator<char> last;
	std::string src_all(it, last);

	execute((char *)src_all.c_str());
}

int Lit::start() {
	show_option();
	return 0;
}
<|endoftext|>


<commit_before>#include "webcam.hpp"
#include <chrono>

using namespace cv;
using namespace std;

Mat ellipticKernel(int width, int height = -1) {
 if (height==-1) {
  return getStructuringElement(MORPH_ELLIPSE,Size(width,width), Point(width/2, width/2));
 } else {
  return getStructuringElement(MORPH_ELLIPSE,Size(width,height), Point(width/2, height/2));
 }
}

unsigned long long getMilliseconds() {
 return chrono::system_clock::now().time_since_epoch()/chrono::milliseconds(1);
}

void morphFast(Mat inout, int smallsize = 100, int factor = 25, int eq = 1, int diler = 0) {
 int width, height;
 width = inout.size().width;
 height = inout.size().height;
 Mat downsample;
 resize(inout, downsample, Size(smallsize,smallsize));
 Mat kernel = ellipticKernel(factor);
 if (diler) {
  erode(downsample, downsample, kernel);
 } else {
  dilate(downsample, downsample, kernel);
 }
 if (eq) {
  equalizeHist(downsample, downsample);
 }
 resize(downsample, inout, Size(width, height));
}

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

 int tracker1, tracker2, tracker3;
 namedWindow("s",1);
 createTrackbar("1","s",&tracker1,100);
 createTrackbar("2","s",&tracker2,100);
 createTrackbar("3","s",&tracker3,100);

 CvCapture* capture = 0;
 int width, height, fps;

 capture = cvCaptureFromCAM(0);

 if (!capture) {
  printf("No camera detected!");
  return -1;
 }

 unsigned long long times[100];
 int f = 0;
 for (int i=0; i<100; i++)
  times[i] = 0;

 ifstream configFile (".config");

 if (configFile.is_open()) {

  //probably want to support corrupted .config
  string line;
  getline(configFile, line);
  istringstream(line)>>width;
  getline(configFile, line);
  istringstream(line)>>height;
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, width);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, height);

  configFile.close();

 } else {

  initResolutions();

  for (int i=36; i<150; i++) {
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, resolutions[i].width);
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, resolutions[i].height);
  }

  width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
  height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);

  ofstream configFileOut(".config");
  configFileOut << width;
  configFileOut << "\n";
  configFileOut << height;
  configFileOut << "\n";
  configFileOut.close();
 }

 bool keepGoing = true;

// srand(890);//not interested in good randomness

 for (int i = 0; i < 30; i++) {
  // capture some frames so exposure correction takes place
  cvQueryFrame(capture);
 }

 Mat background = cvQueryFrame(capture);
 background = background.clone();
 blur(background, background, Size(50,50));

 Mat image;
 Mat channel[3];
 unsigned long long timenow = getMilliseconds();

 CascadeClassifier mouth_cascade;
 mouth_cascade.load("Mouth.xml");

 while (keepGoing) {
  image = cvQueryFrame(capture);
  times[0] = getMilliseconds() - timenow;
  timenow = getMilliseconds();

// preprocess by rotating according to OVR roll
//  imshow("webcam", image);

// let's make multiple masks where 0=not mouth, 1=uncertain

// then multiply them together and multiply that with image
// and run haar classifier on image

  Mat gray, blurred_img;
  cvtColor(image, gray, CV_RGB2GRAY);
  blur(image, blurred_img, Size(50,50));
  times[1] = getMilliseconds() - timenow;
  timenow = getMilliseconds();

// this mask filters out areas which have not changed much
// this is horrible with new background; redo it
  Mat flow(height, width, CV_8UC1, 1);
/*
  absdiff(blurred_img, background, flow);
  cvtColor(flow, flow, CV_RGB2GRAY);
  imshow("prethresh", flow);
  threshold(flow, flow, 5, 1, THRESH_BINARY);
  imshow("flow mask", gray.mul(flow));
  times[2] = getMilliseconds() - timenow;
  timenow = getMilliseconds();

*/

// this mask gets anything kind of dark (DK2) and dilates
  Mat kindofdark(height, width, CV_8UC1, 1);
  equalizeHist(gray, kindofdark);
  threshold(kindofdark, kindofdark, 100, 1, THRESH_BINARY_INV);
  morphFast(kindofdark, 100, 17, 0);
//  imshow("dark mask", gray.mul(kindofdark));
  times[3] = getMilliseconds() - timenow;
  timenow = getMilliseconds();

// combine mask with its opening
  Mat mask = flow.mul(kindofdark);
  Mat smallMask0, smallMask1;
  resize(mask, smallMask0, Size(width/5,height/5));
  Mat smallKernel = ellipticKernel(69,79);
  erode(smallMask0, smallMask1, smallKernel);
  dilate(smallMask1, smallMask1, smallKernel);
  bitwise_and(smallMask0, smallMask1, smallMask1);
  resize(smallMask1, mask, Size(width, height));
//  imshow("morph mask", gray.mul(mask));
  times[4] = getMilliseconds() - timenow;
  timenow = getMilliseconds();

// run haar classifier on nonflow parts of image
  vector<Rect> mouths;
  int scale = 3;
  Mat classifyThis;
  equalizeHist(gray, gray);
  resize(gray.mul(mask), classifyThis, Size(width/scale,height/scale));
  mouth_cascade.detectMultiScale(classifyThis, mouths, 1.1, 0, CV_HAAR_SCALE_IMAGE);
  Mat rectImage(height, width, CV_8UC1, Scalar(0));
  for (size_t i=0; i<mouths.size(); i++) {
   Rect scaled(mouths[i].x*scale, mouths[i].y*scale, mouths[i].width*scale,mouths[i].height*scale);
   Mat newRect(height, width, CV_8UC1, Scalar(0));
   rectangle(newRect, scaled, Scalar(1), CV_FILLED);
   rectImage += newRect;
  }
  double minVal, maxVal;//ignore minVal, it'll be 0
  minMaxLoc(rectImage, &minVal, &maxVal);
  Mat recThresh;
  threshold(rectImage, recThresh, maxVal*0.8, 1, THRESH_BINARY);
// what's the point of this v ?
//  bitwise_and(recThresh, mask, mask);
  times[5] = getMilliseconds() - timenow;
  timenow = getMilliseconds();
  imshow("mouth", recThresh.mul(gray));

/*
  Moments lol = moments(recThresh, 1);
  circle(image, Point(lol.m10/lol.m00,lol.m01/lol.m00),20,Scalar(128),30);
  imshow("leimage", image);
*/

// update background with new morph mask

// either this or no
//  mask = recThresh;

  Mat mask_;
  subtract(1, mask ,mask_);
  Mat mask3, mask3_;
  channel[0] = mask;
  channel[1] = mask;
  channel[2] = mask;
  merge(channel, 3, mask3);
  channel[0] = mask_;
  channel[1] = mask_;
  channel[2] = mask_;
  merge(channel, 3, mask3_);

  background = background.mul(mask3) +
   (background.mul(mask3_)/2 + blurred_img.mul(mask3_)/2);
  times[6] = getMilliseconds() - timenow;
  timenow = getMilliseconds();

//  imshow("bg", background);

  for (int i=0; i<7; i++) {
   printf("%llu , ", times[i]);
  }

  printf("\n");

  keepGoing = (waitKey(1)<0);

 }

 cvReleaseCapture(&capture);

 return 0;
}
<commit_msg>hacking<commit_after>#include "webcam.hpp"
#include <chrono>

using namespace cv;
using namespace std;

Mat ellipticKernel(int width, int height = -1) {
 if (height==-1) {
  return getStructuringElement(MORPH_ELLIPSE,Size(width,width), Point(width/2, width/2));
 } else {
  return getStructuringElement(MORPH_ELLIPSE,Size(width,height), Point(width/2, height/2));
 }
}

unsigned long long getMilliseconds() {
 return chrono::system_clock::now().time_since_epoch()/chrono::milliseconds(1);
}

void morphFast(Mat inout, int smallsize = 100, int factor = 25, int eq = 1, int diler = 0) {
 int width, height;
 width = inout.size().width;
 height = inout.size().height;
 Mat downsample;
 resize(inout, downsample, Size(smallsize,smallsize));
 Mat kernel = ellipticKernel(factor);
 if (diler) {
  erode(downsample, downsample, kernel);
 } else {
  dilate(downsample, downsample, kernel);
 }
 if (eq) {
  equalizeHist(downsample, downsample);
 }
 resize(downsample, inout, Size(width, height));
}

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

 int tracker1, tracker2, tracker3;
 namedWindow("s",1);
 createTrackbar("1","s",&tracker1,100);
 createTrackbar("2","s",&tracker2,100);
 createTrackbar("3","s",&tracker3,100);

 CvCapture* capture = 0;
 int width, height, fps;

 capture = cvCaptureFromCAM(0);

 if (!capture) {
  printf("No camera detected!");
  return -1;
 }

 unsigned long long times[100];
 int f = 0;
 for (int i=0; i<100; i++)
  times[i] = 0;

 ifstream configFile (".config");

 if (configFile.is_open()) {

  //probably want to support corrupted .config
  string line;
  getline(configFile, line);
  istringstream(line)>>width;
  getline(configFile, line);
  istringstream(line)>>height;
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, width);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, height);

  configFile.close();

 } else {

  initResolutions();

  for (int i=36; i<150; i++) {
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, resolutions[i].width);
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, resolutions[i].height);
  }

  width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
  height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);

  ofstream configFileOut(".config");
  configFileOut << width;
  configFileOut << "\n";
  configFileOut << height;
  configFileOut << "\n";
  configFileOut.close();
 }

 bool keepGoing = true;

// srand(890);//not interested in good randomness

 for (int i = 0; i < 30; i++) {
  // capture some frames so exposure correction takes place
  cvQueryFrame(capture);
 }

 Mat background = cvQueryFrame(capture);
 background = background.clone();
 blur(background, background, Size(50,50));

 Mat image;
 Mat channel[3];
 unsigned long long timenow = getMilliseconds();

 CascadeClassifier mouth_cascade;
 mouth_cascade.load("Mouth.xml");

 while (keepGoing) {
  image = cvQueryFrame(capture);
  times[0] = getMilliseconds() - timenow;
  timenow = getMilliseconds();

// preprocess by rotating according to OVR roll
//  imshow("webcam", image);

// let's make multiple masks where 0=not mouth, 1=uncertain

// then multiply them together and multiply that with image
// and run haar classifier on image

  Mat gray, blurred_img;
  cvtColor(image, gray, CV_RGB2GRAY);
  blur(image, blurred_img, Size(50,50));
  times[1] = getMilliseconds() - timenow;
  timenow = getMilliseconds();

// this mask filters out areas which have not changed much
// this is horrible with new background; redo it
  Mat flow(height, width, CV_8UC1, 1);

  absdiff(blurred_img, background, flow);
  cvtColor(flow, flow, CV_RGB2GRAY);
  imshow("prethresh", flow);
  threshold(flow, flow, tracker1, 1, THRESH_BINARY);
  imshow("flow mask", gray.mul(flow));
  times[2] = getMilliseconds() - timenow;
  timenow = getMilliseconds();
  flow = Mat(height, width, CV_8UC1, 1);

// this mask gets anything kind of dark (DK2) and dilates
  Mat kindofdark(height, width, CV_8UC1, 1);
  equalizeHist(gray, kindofdark);
  threshold(kindofdark, kindofdark, 100, 1, THRESH_BINARY_INV);
  morphFast(kindofdark, 100, 17, 0);
//  imshow("dark mask", gray.mul(kindofdark));
  times[3] = getMilliseconds() - timenow;
  timenow = getMilliseconds();

// combine mask with its opening
  Mat mask = flow.mul(kindofdark);
  Mat smallMask0, smallMask1;
  resize(mask, smallMask0, Size(width/5,height/5));
  Mat smallKernel = ellipticKernel(69,79);
  erode(smallMask0, smallMask1, smallKernel);
  dilate(smallMask1, smallMask1, smallKernel);
  bitwise_and(smallMask0, smallMask1, smallMask1);
  resize(smallMask1, mask, Size(width, height));
//  imshow("morph mask", gray.mul(mask));
  times[4] = getMilliseconds() - timenow;
  timenow = getMilliseconds();

// run haar classifier on nonflow parts of image
  vector<Rect> mouths;
  int scale = 3;
  Mat classifyThis;
  equalizeHist(gray, gray);
  resize(gray.mul(mask), classifyThis, Size(width/scale,height/scale));
  mouth_cascade.detectMultiScale(classifyThis, mouths, 1.1, 0, CV_HAAR_SCALE_IMAGE);
  Mat rectImage(height, width, CV_8UC1, Scalar(0));
  for (size_t i=0; i<mouths.size(); i++) {
   Rect scaled(mouths[i].x*scale, mouths[i].y*scale, mouths[i].width*scale,mouths[i].height*scale);
   Mat newRect(height, width, CV_8UC1, Scalar(0));
   rectangle(newRect, scaled, Scalar(1), CV_FILLED);
   rectImage += newRect;
  }
  double minVal, maxVal;//ignore minVal, it'll be 0
  minMaxLoc(rectImage, &minVal, &maxVal);
  Mat recThresh, recBinary;
  threshold(rectImage, recThresh, maxVal*0.8, 1, THRESH_BINARY);
// what's the point of this v ?
  threshold(rectImage, recBinary, 1, 1, THRESH_BINARY);
  bitwise_and(recBinary, mask, mask);
  times[5] = getMilliseconds() - timenow;
  timenow = getMilliseconds();
  imshow("mouth", recThresh.mul(gray));

/*
  Moments lol = moments(recThresh, 1);
  circle(image, Point(lol.m10/lol.m00,lol.m01/lol.m00),20,Scalar(128),30);
  imshow("leimage", image);
*/

// update background with new morph mask

  Mat mask_;
  subtract(1, mask ,mask_);
  Mat mask3, mask3_;
  channel[0] = mask;
  channel[1] = mask;
  channel[2] = mask;
  merge(channel, 3, mask3);
  channel[0] = mask_;
  channel[1] = mask_;
  channel[2] = mask_;
  merge(channel, 3, mask3_);

  background = background.mul(mask3) +
   (background.mul(mask3_)/2 + blurred_img.mul(mask3_)/2);
  times[6] = getMilliseconds() - timenow;
  timenow = getMilliseconds();

  imshow("bg", background);

  for (int i=0; i<7; i++) {
   printf("%llu , ", times[i]);
  }

  printf("\n");

  keepGoing = (waitKey(1)<0);

 }

 cvReleaseCapture(&capture);

 return 0;
}
<|endoftext|>


<commit_before>#include "webcam.hpp"

using namespace cv;
using namespace std;

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

 CvCapture* capture = 0;
 int width, height, fps;

 capture = cvCaptureFromCAM(0);

 if (!capture) {
  printf("No camera detected!");
  return -1;
 }

 ifstream configFile (".config");

 if (configFile.is_open()) {

  //probably want to support corrupted .config
  string line;
  getline(configFile, line);
  istringstream(line)>>width;
  getline(configFile, line);
  istringstream(line)>>height;
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, width);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, height);

  configFile.close();

 } else {

  initResolutions();

  for (int i=36; i<150; i++) {
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, resolutions[i].width);
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, resolutions[i].height);
  }

  width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
  height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);

  ofstream configFileOut(".config");
  configFileOut << width;
  configFileOut << "\n";
  configFileOut << height;
  configFileOut << "\n";
  configFileOut.close();
 }

 bool keepGoing = true;

// srand(890);//not interested in good randomness

 Mat image;
 Mat channel[3];

 while (keepGoing) {

  image = cvQueryFrame(capture);
  //imshow("webcam", image);

// thresholds on dark regions

  Mat gray, blurred_gray, threshold_gray;
  cvtColor(image, gray, CV_BGR2GRAY);
  blur(gray, blurred_gray, Size(width/10,height/20));
  equalizeHist(blurred_gray, blurred_gray);
  bitwise_not(blurred_gray, blurred_gray);
  threshold(blurred_gray, threshold_gray, 210, 1, THRESH_BINARY);
  imshow("threshold", threshold_gray);
  imshow("lol", blurred_gray);

  Mat mask = threshold_gray.mul(blurred_gray/2.0);
  imshow("mask", mask);

  Moments lol = moments(mask, 1);
  circle(image, Point(lol.m10/lol.m00,lol.m01/lol.m00),20,Scalar(128),30);
  imshow("leimage", image);
  keepGoing = (waitKey(25)<0);

 }

 cvReleaseCapture(&capture);

 return 0;
}
<commit_msg>hacking<commit_after>#include "webcam.hpp"

using namespace cv;
using namespace std;

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

 CvCapture* capture = 0;
 int width, height, fps;

 capture = cvCaptureFromCAM(0);

 if (!capture) {
  printf("No camera detected!");
  return -1;
 }

 ifstream configFile (".config");

 if (configFile.is_open()) {

  //probably want to support corrupted .config
  string line;
  getline(configFile, line);
  istringstream(line)>>width;
  getline(configFile, line);
  istringstream(line)>>height;
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, width);
  cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, height);

  configFile.close();

 } else {

  initResolutions();

  for (int i=36; i<150; i++) {
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, resolutions[i].width);
   cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, resolutions[i].height);
  }

  width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
  height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);

  ofstream configFileOut(".config");
  configFileOut << width;
  configFileOut << "\n";
  configFileOut << height;
  configFileOut << "\n";
  configFileOut.close();
 }

 bool keepGoing = true;

// srand(890);//not interested in good randomness

 Mat image;
 Mat channel[3];

 while (keepGoing) {

  image = cvQueryFrame(capture);
  //imshow("webcam", image);

// thresholds on dark regions

  Mat gray, blurred_gray, threshold_gray;
  cvtColor(image, gray, CV_BGR2GRAY);
  blur(gray, blurred_gray, Size(width/10,height/20));
  equalizeHist(blurred_gray, blurred_gray);
  bitwise_not(blurred_gray, blurred_gray);
  threshold(blurred_gray, threshold_gray, 210, 1, THRESH_BINARY);
  imshow("threshold", threshold_gray);

  Mat mask = threshold_gray.mul(gray);
  imshow("mask", mask);

  Moments lol = moments(mask, 1);
  circle(image, Point(lol.m10/lol.m00,lol.m01/lol.m00),20,Scalar(128),30);
  imshow("leimage", image);
  keepGoing = (waitKey(25)<0);

 }

 cvReleaseCapture(&capture);

 return 0;
}
<|endoftext|>


<commit_before>#ifndef __CONCURRENCY_FIFO_CHECKER_HPP__
#define __CONCURRENCY_FIFO_CHECKER_HPP__

#include <vector>

#include <boost/function.hpp>

#include "arch/arch.hpp"
#include "utils2.hpp"

// The memcached order_source_t and the backfill_receiver_t will want
// to be in distinct buckets.

// The master and slave never happen in the same process.  Then the
// memcache buckets have to be different.
const int SLAVE_ORDER_SOURCE_BUCKET = 0;
const int MASTER_ORDER_SOURCE_BUCKET = 0;
const int MEMCACHE_START_BUCKET = 1;

class order_token_t {
public:
    static const order_token_t ignore;

    // By default we construct a totally invalid order token, not
    // equal to ignore, that must be initialized.
    order_token_t() : bucket_(-2), value_(-2) { }

    order_token_t with_read_mode() {
        return order_token_t(bucket_, value_, read_mode_);
    }

private:
    explicit order_token_t(int bucket, int64_t x, bool read_mode)
        : bucket_(bucket), read_mode_(read_mode), value_(x) { }
    int bucket_;
    bool read_mode_;
    int64_t value_;

    friend class order_source_t;
    friend class order_sink_t;
    friend class plain_sink_t;
    friend class contiguous_order_sink_t;
};

class order_source_pigeoncoop_t {
public:
    order_source_pigeoncoop_t(int starting_bucket = 0)
        : least_unregistered_bucket_(starting_bucket) { }

    friend class order_source_t;
private:
    static void nop() { }

    void unregister_bucket(int bucket) {
        ASSERT_NO_CORO_WAITING;
        rassert(bucket < least_unregistered_bucket_);
        free_buckets_.push_back(bucket);
    }

    int register_for_bucket() {
        ASSERT_NO_CORO_WAITING;
        if (free_buckets_.empty()) {
            int ret = least_unregistered_bucket_;
            ++ least_unregistered_bucket_;
            return ret;
        } else {
            int ret = free_buckets_.back();
            rassert(ret < least_unregistered_bucket_);
            free_buckets_.pop_back();
            return ret;
        }
    }

    // The bucket we should use next, if free_buckets_ is empty.
    int least_unregistered_bucket_;

    // The buckets less than least_unregistered_bucket_.
    std::vector<int> free_buckets_;

    DISABLE_COPYING(order_source_pigeoncoop_t);
};

class order_source_t {
public:
    order_source_t(int bucket = 0, boost::function<void()> unregisterator = order_source_pigeoncoop_t::nop)
        : bucket_(bucket), counter_(0), unregister_(unregisterator) { }

    order_source_t(order_source_pigeoncoop_t *coop)
        : bucket_(coop->register_for_bucket()), counter_(0),
          unregister_(boost::bind(&order_source_pigeoncoop_t::unregister_bucket, coop, bucket_)) { }

    ~order_source_t() { unregister_(); }

    order_token_t check_in() { return order_token_t(bucket_, ++counter_, false); }

    order_token_t check_in_read_mode() { return order_token_t(bucket_, ++counter_, true); }

private:
    int bucket_;
    int64_t counter_;
    boost::function<void ()> unregister_;

    DISABLE_COPYING(order_source_t);
};

class order_sink_t {
public:
    order_sink_t() { }

    void check_out(order_token_t token) {
        if (token.bucket_ != order_token_t::ignore.bucket_) {
            rassert(token.bucket_ >= 0);
            if (token.bucket_ >= int(last_seens_.size())) {
                last_seens_.resize(token.bucket_ + 1, std::pair<int64_t, int64_t>(0, 0));
            }

            verify_token_value_and_update(token, &last_seens_[token.bucket_]);
        }
    }

private:

    friend class plain_sink_t;
    static void verify_token_value_and_update(order_token_t token, std::pair<int64_t, int64_t> *ls_pair) {
        // We tolerate equality in this comparison because it can
        // be used to ensure that multiple actions don't get
        // interrupted.  And resending the same action isn't
        // normally a problem.
        if (token.read_mode_) {
            rassert(token.value_ >= ls_pair->first, "token.value_ = %ld, last_seens_[token.bucket_].first = %ld, token.bucket_ = %d", token.value_, ls_pair->first, token.bucket_);
            ls_pair->second = std::max(ls_pair->second, token.value_);
        } else {
            rassert(token.value_ >= ls_pair->second, "token.value_ = %ld, last_seens_[token.bucket_].second = %ld, token.bucket_ = %d", token.value_, ls_pair->second, token.bucket_);
            ls_pair->first = ls_pair->second = token.value_;
        }
    }

    // .first = last seen write, .second = max(last seen read, last seen write)
    std::vector<std::pair<int64_t, int64_t> > last_seens_;

    DISABLE_COPYING(order_sink_t);
};

// An order sink with less overhead, for situations where there is
// only one source (like the top of a btree slice) and many sinks.
class plain_sink_t {
public:
    plain_sink_t() : ls_pair_(0, 0) { }

    void check_out(order_token_t token) {
        if (token.bucket_ != order_token_t::ignore.bucket_) {
            // TODO: do read/write mode.
            rassert(token.bucket_ >= 0);
            rassert(token.bucket_ == 0, "Only bucket 0 allowed, you made a programmer error");

            order_sink_t::verify_token_value_and_update(token, &ls_pair_);
        }
    }

private:
    std::pair<int64_t, int64_t> ls_pair_;

    DISABLE_COPYING(plain_sink_t);
};

#endif  // __CONCURRENCY_FIFO_CHECKER_HPP__
<commit_msg>Disable order_sink token checking temporarily (see #328)<commit_after>#ifndef __CONCURRENCY_FIFO_CHECKER_HPP__
#define __CONCURRENCY_FIFO_CHECKER_HPP__

#include <vector>

#include <boost/function.hpp>

#include "arch/arch.hpp"
#include "utils2.hpp"

// The memcached order_source_t and the backfill_receiver_t will want
// to be in distinct buckets.

// The master and slave never happen in the same process.  Then the
// memcache buckets have to be different.
const int SLAVE_ORDER_SOURCE_BUCKET = 0;
const int MASTER_ORDER_SOURCE_BUCKET = 0;
const int MEMCACHE_START_BUCKET = 1;

class order_token_t {
public:
    static const order_token_t ignore;

    // By default we construct a totally invalid order token, not
    // equal to ignore, that must be initialized.
    order_token_t() : bucket_(-2), value_(-2) { }

    order_token_t with_read_mode() {
        return order_token_t(bucket_, value_, read_mode_);
    }

private:
    explicit order_token_t(int bucket, int64_t x, bool read_mode)
        : bucket_(bucket), read_mode_(read_mode), value_(x) { }
    int bucket_;
    bool read_mode_;
    int64_t value_;

    friend class order_source_t;
    friend class order_sink_t;
    friend class plain_sink_t;
    friend class contiguous_order_sink_t;
};

class order_source_pigeoncoop_t {
public:
    order_source_pigeoncoop_t(int starting_bucket = 0)
        : least_unregistered_bucket_(starting_bucket) { }

    friend class order_source_t;
private:
    static void nop() { }

    void unregister_bucket(int bucket) {
        ASSERT_NO_CORO_WAITING;
        rassert(bucket < least_unregistered_bucket_);
        free_buckets_.push_back(bucket);
    }

    int register_for_bucket() {
        ASSERT_NO_CORO_WAITING;
        if (free_buckets_.empty()) {
            int ret = least_unregistered_bucket_;
            ++ least_unregistered_bucket_;
            return ret;
        } else {
            int ret = free_buckets_.back();
            rassert(ret < least_unregistered_bucket_);
            free_buckets_.pop_back();
            return ret;
        }
    }

    // The bucket we should use next, if free_buckets_ is empty.
    int least_unregistered_bucket_;

    // The buckets less than least_unregistered_bucket_.
    std::vector<int> free_buckets_;

    DISABLE_COPYING(order_source_pigeoncoop_t);
};

class order_source_t {
public:
    order_source_t(int bucket = 0, boost::function<void()> unregisterator = order_source_pigeoncoop_t::nop)
        : bucket_(bucket), counter_(0), unregister_(unregisterator) { }

    order_source_t(order_source_pigeoncoop_t *coop)
        : bucket_(coop->register_for_bucket()), counter_(0),
          unregister_(boost::bind(&order_source_pigeoncoop_t::unregister_bucket, coop, bucket_)) { }

    ~order_source_t() { unregister_(); }

    order_token_t check_in() { return order_token_t(bucket_, ++counter_, false); }

    order_token_t check_in_read_mode() { return order_token_t(bucket_, ++counter_, true); }

private:
    int bucket_;
    int64_t counter_;
    boost::function<void ()> unregister_;

    DISABLE_COPYING(order_source_t);
};

class order_sink_t {
public:
    order_sink_t() { }

    void check_out(order_token_t token) {
        if (token.bucket_ != order_token_t::ignore.bucket_) {
            rassert(token.bucket_ >= 0);
            if (token.bucket_ >= int(last_seens_.size())) {
                last_seens_.resize(token.bucket_ + 1, std::pair<int64_t, int64_t>(0, 0));
            }

            // TODO: Reenable! See issue #328
            //verify_token_value_and_update(token, &last_seens_[token.bucket_]);
        }
    }

private:

    friend class plain_sink_t;
    static void verify_token_value_and_update(order_token_t token, std::pair<int64_t, int64_t> *ls_pair) {
        // We tolerate equality in this comparison because it can
        // be used to ensure that multiple actions don't get
        // interrupted.  And resending the same action isn't
        // normally a problem.
        if (token.read_mode_) {
            rassert(token.value_ >= ls_pair->first, "token.value_ = %ld, last_seens_[token.bucket_].first = %ld, token.bucket_ = %d", token.value_, ls_pair->first, token.bucket_);
            ls_pair->second = std::max(ls_pair->second, token.value_);
        } else {
            rassert(token.value_ >= ls_pair->second, "token.value_ = %ld, last_seens_[token.bucket_].second = %ld, token.bucket_ = %d", token.value_, ls_pair->second, token.bucket_);
            ls_pair->first = ls_pair->second = token.value_;
        }
    }

    // .first = last seen write, .second = max(last seen read, last seen write)
    std::vector<std::pair<int64_t, int64_t> > last_seens_;

    DISABLE_COPYING(order_sink_t);
};

// An order sink with less overhead, for situations where there is
// only one source (like the top of a btree slice) and many sinks.
class plain_sink_t {
public:
    plain_sink_t() : ls_pair_(0, 0) { }

    void check_out(order_token_t token) {
        if (token.bucket_ != order_token_t::ignore.bucket_) {
            // TODO: do read/write mode.
            rassert(token.bucket_ >= 0);
            rassert(token.bucket_ == 0, "Only bucket 0 allowed, you made a programmer error");

            order_sink_t::verify_token_value_and_update(token, &ls_pair_);
        }
    }

private:
    std::pair<int64_t, int64_t> ls_pair_;

    DISABLE_COPYING(plain_sink_t);
};

#endif  // __CONCURRENCY_FIFO_CHECKER_HPP__
<|endoftext|>


<commit_before>#pragma once

#include <stdexcept>
#include <variant>
#include <string>
#include <string_view>
#include <vector>
#include <map>
#include <iostream>
#include <cassert>

#include "acmacs-base/debug.hh"
#include "acmacs-base/float.hh"
#include "acmacs-base/filesystem.hh"

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

namespace rjson
{
    namespace implementation { class NumberHandler; }

    class value;

    template <typename F> struct content_type;
    template <typename F> using rjson_type = typename content_type<std::decay_t<F>>::type;

    class string
    {
     public:
        inline string(std::string aData) : mData{aData} {}
        inline string(const char* aData) : mData{aData} {}
        inline std::string to_json() const { return std::string{"\""} + static_cast<std::string>(mData) + "\""; }
        inline operator std::string() const { return mData; }
        inline string& operator=(std::string aSrc) { mData = aSrc; return *this; }
        inline bool operator==(const std::string aToCompare) const { return mData == aToCompare; }
        inline bool operator==(const string& aToCompare) const { return mData == aToCompare.mData; }
        inline size_t size() const { return mData.size(); }
        inline bool empty() const { return mData.empty(); }
        inline bool operator<(const string& to_compare) const { return mData < to_compare.mData; }

     private:
        std::string mData;
    };

    class boolean
    {
     public:
        inline boolean(bool aValue) : mValue{aValue} {}
        inline std::string to_json() const { return mValue ? "true" : "false"; }
        inline operator bool() const { return mValue; }
        inline boolean& operator=(bool aSrc) { mValue = aSrc; return *this; }

     private:
        bool mValue;
    };

    class null
    {
     public:
        inline null() {}
        inline std::string to_json() const { return "null"; }
    };

    class number
    {
     public:
        inline number(double aSrc) : mValue{double_to_string(aSrc)} {}
        inline number& operator=(double aSrc) { mValue = double_to_string(aSrc); return *this; }
        inline std::string to_json() const { return mValue; } // { return double_to_string(mValue); }
        inline operator double() const { return std::stod(mValue); } // { return mValue; }

     private:
        inline number(std::string_view&& aData) : mValue{aData} {} // mValue{std::stod(static_cast<std::string>(aData))} {}

          // double mValue;
        std::string mValue;

        friend class implementation::NumberHandler;
    };

    class integer
    {
     public:
        inline integer(long aSrc) : mValue{std::to_string(aSrc)} {}
        inline integer& operator=(long aSrc) { mValue = std::to_string(aSrc); return *this; }
        inline std::string to_json() const { return mValue; } // { return std::to_string(mValue); }
        inline operator double() const { return std::stod(mValue); } // { return mValue; }
        inline operator long() const { return std::stol(mValue); } // { return mValue; }

     private:
        inline integer(std::string_view&& aData) : mValue{aData} {} // mValue{std::stol(static_cast<std::string>(aData))} {}

          // long mValue;
        std::string mValue;

        friend class implementation::NumberHandler;
    };

    class object
    {
     public:
        inline object() = default;
        inline object(std::initializer_list<value> key_values);

        std::string to_json() const;

        void insert(const string& aKey, value&& aValue);
        void insert(const string& aKey, const value& aValue);
        void insert(value&& aKey, value&& aValue);
        inline size_t size() const { return mContent.size(); }
        inline bool empty() const { return mContent.empty(); }

          // returns reference to the value at the passed key.
          // if key not found, inserts aDefault with the passed key and returns reference to the inserted
        value& get_ref(std::string aKey, value&& aDefault);
        const value& get_ref(std::string aKey, value&& aDefault) const;
        object& get_ref_to_object(std::string aKey);

        template <typename F> inline std::decay_t<F> get_field(std::string aFieldName, F&& aDefaultValue) const
            {
                return std::get<rjson_type<F>>(get_ref(aFieldName, rjson_type<F>{std::forward<F>(aDefaultValue)}));
            }

        void set_field(std::string aKey, value&& aValue);

     private:
        std::map<string, value> mContent;
          // std::vector<std::pair<string, value>> mContent;
    };

    class array
    {
     public:
        inline array() = default;
        inline array(array&&) = default;
        inline array(const array&) = default;
        inline array(std::initializer_list<value> args);
        inline array& operator=(array&&) = default;
        inline array& operator=(const array&) = default;

        std::string to_json() const;

        void insert(value&& aValue);
        void insert(const value& aValue);
        inline size_t size() const { return mContent.size(); }
        inline bool empty() const { return mContent.empty(); }
        inline value& operator[](size_t index) { return mContent[index]; }
        inline const value& operator[](size_t index) const { return mContent[index]; }

     private:
        std::vector<value> mContent;
    };

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

    template <> struct content_type<double> { using type = rjson::number; };
    template <> struct content_type<long> { using type = rjson::integer; };
    template <> struct content_type<int> { using type = rjson::integer; };
    template <> struct content_type<bool> { using type = rjson::boolean; };
    template <> struct content_type<std::string> { using type = rjson::string; };

    template <typename FValue> value to_value(const FValue& aValue);

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

    using value_base = std::variant<null, object, array, string, integer, number, boolean>; // null must be the first alternative, it is the default value;

    class value : public value_base
    {
     public:
        using value_base::operator=;
        using value_base::value_base;
        inline value(const value&) = default; // gcc7 wants this, otherwise it is deleted
        inline value& operator=(const value&) = default; // gcc7 wants this, otherwise it is deleted
          // inline ~value() { std::cerr << "DEBUG: ~value " << to_json() << DEBUG_LINE_FUNC << '\n'; }

          // returns reference to the value at the passed key.
          // if key not found, inserts aDefault with the passed key and returns reference to the inserted
          // if this is not an object, throws  std::bad_variant_access
        inline value& get_ref(std::string aKey, value&& aDefault)
            {
                try {
                    return std::get<object>(*this).get_ref(aKey, std::forward<value>(aDefault));
                }
                catch (std::bad_variant_access&) {
                    std::cerr << "ERROR: rjson::value::get_ref: not an object: valueless_by_exception:" << valueless_by_exception() << " index:" << index() << '\n'; // to_json() << '\n';
                    throw;
                }
            }

        inline object& get_ref_to_object(std::string aKey)
            {
                try {
                    return std::get<object>(*this).get_ref_to_object(aKey);
                }
                catch (std::bad_variant_access&) {
                    std::cerr << "ERROR: rjson::value::get_ref_to_object: not an object: " << to_json() << '\n'; // valueless_by_exception:" << valueless_by_exception() << " index:" << index() << '\n'; // to_json() << '\n';
                    throw;
                }
            }

        template <typename F> inline std::decay_t<F> get_field(std::string aFieldName, F&& aDefaultValue) const
            {
                try {
                    return std::get<object>(*this).get_field(aFieldName, std::forward<F>(aDefaultValue));
                }
                catch (std::bad_variant_access&) {
                    std::cerr << "ERROR: rjson::value::get_field: not an object: " << to_json() << '\n'; // to_json() << '\n';
                    throw;
                }
                // return std::get<rjson_type<F>>(get_ref(aFieldName, rjson_type<F>{std::forward<F>(aDefaultValue)}));
            }

        template <typename F> inline void set_field(std::string aFieldName, F&& aValue)
            {
                set_field(aFieldName, to_value(aValue));
                // try {
                //     std::get<object>(*this).set_field(aFieldName, to_value(aValue));
                // }
                // catch (std::bad_variant_access&) {
                //     std::cerr << "ERROR: rjson::value::set_field: not an object: " << to_json() << '\n';
                //     throw;
                // }
            }

        std::string to_json() const;

    }; // class value

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

    template <typename FValue> inline value to_value(const FValue& aValue)
    {
        return rjson_type<FValue>{aValue};
    }

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

    class Error : public std::exception
    {
     public:
        // inline Error(size_t aLine, size_t aColumn, std::string aMessage)
        //     : mMessage{std::to_string(aLine) + ":" + std::to_string(aColumn) + ": " + aMessage} //, mLine{aLine}, mColumn{aColumn}
        //     {}

        inline Error(size_t aLine, size_t aColumn, std::string&& aMessage)
            : mMessage{std::to_string(aLine) + ":" + std::to_string(aColumn) + ": " + std::move(aMessage)} //, mLine{aLine}, mColumn{aColumn}
            {}

        inline const char* what() const noexcept override { return mMessage.c_str(); }

     private:
        std::string mMessage;
          //size_t mLine, mColumn;

    }; // class Error

    value parse_string(std::string aJsonData);
    value parse_file(std::string aFilename);

} // namespace rjson

// ----------------------------------------------------------------------
// gcc-7 support
// ----------------------------------------------------------------------

#if __GNUC__ == 7
namespace std
{
      // gcc 7.2 wants those, if we derive from std::variant
    template<> struct variant_size<rjson::value> : variant_size<rjson::value_base> {};
    template<size_t _Np> struct variant_alternative<_Np, rjson::value> : variant_alternative<_Np, rjson::value_base> {};
}
#endif

// ----------------------------------------------------------------------
// inline
// ----------------------------------------------------------------------

namespace rjson
{
    inline void object::insert(const string& aKey, value&& aValue) { mContent.emplace(aKey, std::move(aValue)); }
    inline void object::insert(const string& aKey, const value& aValue) { mContent.emplace(aKey, aValue); }
    inline void object::insert(value&& aKey, value&& aValue) { insert(std::get<string>(std::forward<value>(aKey)), std::forward<value>(aValue)); }

    inline object::object(std::initializer_list<value> key_values)
    {
        if ((key_values.size() % 2) != 0)
            throw std::runtime_error("rjson::object::object(initializer_list): odd number of arguments");
        try {
            for (auto elt = std::begin(key_values); elt != std::end(key_values); ++elt) {
                const auto& key = std::get<string>(*elt);
                ++elt;
                insert(key, *elt);
            }
        }
        catch (std::bad_variant_access&) {
            std::cerr << "ERROR: rjson::object::object(initializer_list): invalid object field name type?\n";
            throw;
        }
    }

    inline value& object::get_ref(std::string aKey, value&& aDefault)
    {
        const auto [iter, inserted] = mContent.emplace(aKey, std::forward<value>(aDefault));
        return iter->second;

        // auto found = std::find_if(std::begin(mContent), std::end(mContent), [&aKey](const auto& entry) { return entry.first == aKey; });
        // if (found == std::end(mContent)) {
        //       // std::cerr << "DEBUG: object::get_ref: not found: " << aKey << ' ' << to_json() << " default:" << aDefault.to_json() << '\n';
        //       return mContent.emplace_back(aKey, std::forward<value>(aDefault)).second;
        // }
        // else {
        //     // std::cerr << "DEBUG: object::get_ref: found: " << aKey << ' ' << found->second.to_json() << '\n';
        //     return found->second;
        // }
    }

    inline const value& object::get_ref(std::string aKey, value&& aDefault) const { return const_cast<object*>(this)->get_ref(aKey, std::forward<value>(aDefault)); }

    inline object& object::get_ref_to_object(std::string aKey)
    {
        const auto existing = mContent.find(aKey);
        if (existing == mContent.end())
            return std::get<object>(get_ref(aKey, object{}));
        else
            return std::get<object>(existing->second);
    }

    inline void object::set_field(std::string aKey, value&& aValue)
    {
        mContent.insert_or_assign(aKey, std::forward<value>(aValue));

        // auto found = std::find_if(std::begin(mContent), std::end(mContent), [&aKey](const auto& entry) { return entry.first == aKey; });
        // if (found == std::end(mContent)) {
        //     mContent.emplace_back(std::move(aKey), std::forward<value>(aValue));
        // }
        // else {
        //     found->second = std::forward<value>(aValue);
        // }
    }

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

    inline void array::insert(value&& aValue) { mContent.push_back(std::move(aValue)); }
    inline void array::insert(const value& aValue) { mContent.push_back(aValue); }

    inline array::array(std::initializer_list<value> args)
    {
        for (const auto& arg: args)
            insert(arg);
    }

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

    template <> inline void value::set_field(std::string aFieldName, value&& aValue)
    {
        try {
            std::get<object>(*this).set_field(aFieldName, std::forward<value>(aValue));
        }
        catch (std::bad_variant_access&) {
            std::cerr << "ERROR: rjson::value::set_field: not an object: " << to_json() << '\n';
            throw;
        }
    }

    inline std::string value::to_json() const
    {
        return std::visit([](auto&& arg) -> std::string { return arg.to_json(); }, *this);
    }
}

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

inline std::ostream& operator<<(std::ostream& out, const rjson::value& aValue)
{
    return out << aValue.to_json();
}

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<commit_msg>rjson development<commit_after>#pragma once

#include <stdexcept>
#include <variant>
#include <string>
#include <string_view>
#include <vector>
#include <map>
#include <iostream>
#include <cassert>

#include "acmacs-base/debug.hh"
#include "acmacs-base/float.hh"
#include "acmacs-base/filesystem.hh"

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

namespace rjson
{
    namespace implementation { class NumberHandler; }

    class value;

    template <typename F> struct content_type;
    template <typename F> using rjson_type = typename content_type<std::decay_t<F>>::type;

    class string
    {
     public:
        inline string(std::string aData) : mData{aData} {}
        inline string(const char* aData) : mData{aData} {}
        inline std::string to_json() const { return std::string{"\""} + static_cast<std::string>(mData) + "\""; }
        inline operator std::string() const { return mData; }
        inline string& operator=(std::string aSrc) { mData = aSrc; return *this; }
        inline bool operator==(const std::string aToCompare) const { return mData == aToCompare; }
        inline bool operator==(const string& aToCompare) const { return mData == aToCompare.mData; }
        inline size_t size() const { return mData.size(); }
        inline bool empty() const { return mData.empty(); }
        inline bool operator<(const string& to_compare) const { return mData < to_compare.mData; }

     private:
        std::string mData;
    };

    class boolean
    {
     public:
        inline boolean(bool aValue) : mValue{aValue} {}
        inline std::string to_json() const { return mValue ? "true" : "false"; }
        inline operator bool() const { return mValue; }
        inline boolean& operator=(bool aSrc) { mValue = aSrc; return *this; }

     private:
        bool mValue;
    };

    class null
    {
     public:
        inline null() {}
        inline std::string to_json() const { return "null"; }
    };

    class number
    {
     public:
        inline number(double aSrc) : mValue{double_to_string(aSrc)} {}
        inline number& operator=(double aSrc) { mValue = double_to_string(aSrc); return *this; }
        inline std::string to_json() const { return mValue; } // { return double_to_string(mValue); }
        inline operator double() const { return std::stod(mValue); } // { return mValue; }

     private:
        inline number(std::string_view&& aData) : mValue{aData} {} // mValue{std::stod(static_cast<std::string>(aData))} {}

          // double mValue;
        std::string mValue;

        friend class implementation::NumberHandler;
    };

    class integer
    {
     public:
        inline integer(long aSrc) : mValue{std::to_string(aSrc)} {}
        inline integer& operator=(long aSrc) { mValue = std::to_string(aSrc); return *this; }
        inline std::string to_json() const { return mValue; } // { return std::to_string(mValue); }
        inline operator double() const { return std::stod(mValue); } // { return mValue; }
        inline operator long() const { return std::stol(mValue); } // { return mValue; }

     private:
        inline integer(std::string_view&& aData) : mValue{aData} {} // mValue{std::stol(static_cast<std::string>(aData))} {}

          // long mValue;
        std::string mValue;

        friend class implementation::NumberHandler;
    };

    class object
    {
     public:
        class field_not_found : public std::exception { public: using std::exception::exception; };

        inline object() = default;
        inline object(std::initializer_list<value> key_values);

        std::string to_json() const;

        void insert(const string& aKey, value&& aValue);
        void insert(const string& aKey, const value& aValue);
        void insert(value&& aKey, value&& aValue);
        inline size_t size() const { return mContent.size(); }
        inline bool empty() const { return mContent.empty(); }

          // returns reference to the value at the passed key.
          // if key not found, inserts aDefault with the passed key and returns reference to the inserted
        value& get_ref(std::string aKey, value&& aDefault);
        const value& get_ref(std::string aKey) const; // throws field_not_found
        const value& get_ref(std::string aKey, value&& aDefault) const;
        object& get_ref_to_object(std::string aKey);

        template <typename F> inline std::decay_t<F> get_field(std::string aFieldName, F&& aDefaultValue) const
            {
                return std::get<rjson_type<F>>(get_ref(aFieldName, rjson_type<F>{std::forward<F>(aDefaultValue)}));
            }

        template <typename F> inline std::decay_t<F> get_field(std::string aFieldName) const // throws field_not_found
            {
                return std::get<rjson_type<F>>(get_ref(aFieldName));
            }

        void set_field(std::string aKey, value&& aValue);

     private:
        std::map<string, value> mContent;
          // std::vector<std::pair<string, value>> mContent;
    };

    class array
    {
     public:
        inline array() = default;
        inline array(array&&) = default;
        inline array(const array&) = default;
        inline array(std::initializer_list<value> args);
        inline array& operator=(array&&) = default;
        inline array& operator=(const array&) = default;

        std::string to_json() const;

        void insert(value&& aValue);
        void insert(const value& aValue);
        inline size_t size() const { return mContent.size(); }
        inline bool empty() const { return mContent.empty(); }
        inline value& operator[](size_t index) { return mContent[index]; }
        inline const value& operator[](size_t index) const { return mContent[index]; }

     private:
        std::vector<value> mContent;
    };

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

    template <> struct content_type<double> { using type = rjson::number; };
    template <> struct content_type<long> { using type = rjson::integer; };
    template <> struct content_type<int> { using type = rjson::integer; };
    template <> struct content_type<bool> { using type = rjson::boolean; };
    template <> struct content_type<std::string> { using type = rjson::string; };

    template <typename FValue> value to_value(const FValue& aValue);

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

    using value_base = std::variant<null, object, array, string, integer, number, boolean>; // null must be the first alternative, it is the default value;

    class value : public value_base
    {
     public:
        using value_base::operator=;
        using value_base::value_base;
        inline value(const value&) = default; // gcc7 wants this, otherwise it is deleted
        inline value& operator=(const value&) = default; // gcc7 wants this, otherwise it is deleted
          // inline ~value() { std::cerr << "DEBUG: ~value " << to_json() << DEBUG_LINE_FUNC << '\n'; }

          // returns reference to the value at the passed key.
          // if key not found, inserts aDefault with the passed key and returns reference to the inserted
          // if this is not an object, throws  std::bad_variant_access
        inline value& get_ref(std::string aKey, value&& aDefault)
            {
                try {
                    return std::get<object>(*this).get_ref(aKey, std::forward<value>(aDefault));
                }
                catch (std::bad_variant_access&) {
                    std::cerr << "ERROR: rjson::value::get_ref: not an object: valueless_by_exception:" << valueless_by_exception() << " index:" << index() << '\n'; // to_json() << '\n';
                    throw;
                }
            }

        inline object& get_ref_to_object(std::string aKey)
            {
                try {
                    return std::get<object>(*this).get_ref_to_object(aKey);
                }
                catch (std::bad_variant_access&) {
                    std::cerr << "ERROR: rjson::value::get_ref_to_object: not an object: " << to_json() << '\n'; // valueless_by_exception:" << valueless_by_exception() << " index:" << index() << '\n'; // to_json() << '\n';
                    throw;
                }
            }

        template <typename F> inline std::decay_t<F> get_field(std::string aFieldName, F&& aDefaultValue) const
            {
                try {
                    return std::get<object>(*this).get_field(aFieldName, std::forward<F>(aDefaultValue));
                }
                catch (std::bad_variant_access&) {
                    std::cerr << "ERROR: rjson::value::get_field: not an object: " << to_json() << '\n'; // to_json() << '\n';
                    throw;
                }
                // return std::get<rjson_type<F>>(get_ref(aFieldName, rjson_type<F>{std::forward<F>(aDefaultValue)}));
            }

        template <typename F> inline void set_field(std::string aFieldName, F&& aValue)
            {
                set_field(aFieldName, to_value(aValue));
                // try {
                //     std::get<object>(*this).set_field(aFieldName, to_value(aValue));
                // }
                // catch (std::bad_variant_access&) {
                //     std::cerr << "ERROR: rjson::value::set_field: not an object: " << to_json() << '\n';
                //     throw;
                // }
            }

        std::string to_json() const;

    }; // class value

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

    template <typename FValue> inline value to_value(const FValue& aValue)
    {
        return rjson_type<FValue>{aValue};
    }

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

    class Error : public std::exception
    {
     public:
        // inline Error(size_t aLine, size_t aColumn, std::string aMessage)
        //     : mMessage{std::to_string(aLine) + ":" + std::to_string(aColumn) + ": " + aMessage} //, mLine{aLine}, mColumn{aColumn}
        //     {}

        inline Error(size_t aLine, size_t aColumn, std::string&& aMessage)
            : mMessage{std::to_string(aLine) + ":" + std::to_string(aColumn) + ": " + std::move(aMessage)} //, mLine{aLine}, mColumn{aColumn}
            {}

        inline const char* what() const noexcept override { return mMessage.c_str(); }

     private:
        std::string mMessage;
          //size_t mLine, mColumn;

    }; // class Error

    value parse_string(std::string aJsonData);
    value parse_file(std::string aFilename);

} // namespace rjson

// ----------------------------------------------------------------------
// gcc-7 support
// ----------------------------------------------------------------------

#if __GNUC__ == 7
namespace std
{
      // gcc 7.2 wants those, if we derive from std::variant
    template<> struct variant_size<rjson::value> : variant_size<rjson::value_base> {};
    template<size_t _Np> struct variant_alternative<_Np, rjson::value> : variant_alternative<_Np, rjson::value_base> {};
}
#endif

// ----------------------------------------------------------------------
// inline
// ----------------------------------------------------------------------

namespace rjson
{
    inline void object::insert(const string& aKey, value&& aValue) { mContent.emplace(aKey, std::move(aValue)); }
    inline void object::insert(const string& aKey, const value& aValue) { mContent.emplace(aKey, aValue); }
    inline void object::insert(value&& aKey, value&& aValue) { insert(std::get<string>(std::forward<value>(aKey)), std::forward<value>(aValue)); }

    inline object::object(std::initializer_list<value> key_values)
    {
        if ((key_values.size() % 2) != 0)
            throw std::runtime_error("rjson::object::object(initializer_list): odd number of arguments");
        try {
            for (auto elt = std::begin(key_values); elt != std::end(key_values); ++elt) {
                const auto& key = std::get<string>(*elt);
                ++elt;
                insert(key, *elt);
            }
        }
        catch (std::bad_variant_access&) {
            std::cerr << "ERROR: rjson::object::object(initializer_list): invalid object field name type?\n";
            throw;
        }
    }

    inline value& object::get_ref(std::string aKey, value&& aDefault)
    {
        const auto [iter, inserted] = mContent.emplace(aKey, std::forward<value>(aDefault));
        return iter->second;

        // auto found = std::find_if(std::begin(mContent), std::end(mContent), [&aKey](const auto& entry) { return entry.first == aKey; });
        // if (found == std::end(mContent)) {
        //       // std::cerr << "DEBUG: object::get_ref: not found: " << aKey << ' ' << to_json() << " default:" << aDefault.to_json() << '\n';
        //       return mContent.emplace_back(aKey, std::forward<value>(aDefault)).second;
        // }
        // else {
        //     // std::cerr << "DEBUG: object::get_ref: found: " << aKey << ' ' << found->second.to_json() << '\n';
        //     return found->second;
        // }
    }

    inline const value& object::get_ref(std::string aKey, value&& aDefault) const { return const_cast<object*>(this)->get_ref(aKey, std::forward<value>(aDefault)); }

    inline const value& object::get_ref(std::string aKey) const
    {
        const auto existing = mContent.find(aKey);
        if (existing == mContent.end())
            throw field_not_found{};
        return existing->second;
    }

    inline object& object::get_ref_to_object(std::string aKey)
    {
        const auto existing = mContent.find(aKey);
        if (existing == mContent.end())
            return std::get<object>(get_ref(aKey, object{}));
        else
            return std::get<object>(existing->second);
    }

    inline void object::set_field(std::string aKey, value&& aValue)
    {
        mContent.insert_or_assign(aKey, std::forward<value>(aValue));

        // auto found = std::find_if(std::begin(mContent), std::end(mContent), [&aKey](const auto& entry) { return entry.first == aKey; });
        // if (found == std::end(mContent)) {
        //     mContent.emplace_back(std::move(aKey), std::forward<value>(aValue));
        // }
        // else {
        //     found->second = std::forward<value>(aValue);
        // }
    }

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

    inline void array::insert(value&& aValue) { mContent.push_back(std::move(aValue)); }
    inline void array::insert(const value& aValue) { mContent.push_back(aValue); }

    inline array::array(std::initializer_list<value> args)
    {
        for (const auto& arg: args)
            insert(arg);
    }

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

    template <> inline void value::set_field(std::string aFieldName, value&& aValue)
    {
        try {
            std::get<object>(*this).set_field(aFieldName, std::forward<value>(aValue));
        }
        catch (std::bad_variant_access&) {
            std::cerr << "ERROR: rjson::value::set_field: not an object: " << to_json() << '\n';
            throw;
        }
    }

    inline std::string value::to_json() const
    {
        return std::visit([](auto&& arg) -> std::string { return arg.to_json(); }, *this);
    }
}

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

inline std::ostream& operator<<(std::ostream& out, const rjson::value& aValue)
{
    return out << aValue.to_json();
}

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<|endoftext|>


<commit_before>#include "condor_common.h"
#include "condor_sinful.h"

#include <stdio.h>

bool verbose = false;
#define REQUIRE( condition ) \
	if(! ( condition )) { \
		fprintf( stderr, "Failed requirement '%s' on line %d.\n", #condition, __LINE__ ); \
		return 1; \
	} else if( verbose ) { \
		fprintf( stdout, "Passed requirement '%s' on line %d.\n", #condition, __LINE__ ); \
	}

int main( int, char ** ) {
	Sinful s;
	Sinful t;

	//
	// Test, for 0, 1, 2, and 3 condor_sockaddrs: that the vector is not NULL,
	// that the vector has the correct number of elements, that the vector's
	// elements values are correct (and in the correct order); and that the
	// string form of the sinful is correct; and that the parser correctly
	// handles the sinful string (by repeating the vector tests); and that
	// the string->sinful->string loop also works (by repeating the string
	// test).  Then repeat the 0 test after clearing the Sinful of addrs.
	//
	// We then also test adding three condor_sockaddrs in a row, just in
	// case one-at-a-time testing somehow hides a problem; this also tests
	// that adding condor_sockaddrs after clearing the Sinful works.
	//

	std::vector< condor_sockaddr > * v = s.getAddrs();
	REQUIRE( v != NULL );
	REQUIRE( v->size() == 0 );
	delete v; v = NULL;

	char const * sinfulString = NULL;
	sinfulString = s.getSinful();
	REQUIRE( sinfulString == NULL );

	REQUIRE( ! s.hasAddrs() );

	condor_sockaddr sa;
	bool ok = sa.from_ip_and_port_string( "1.2.3.4:5" );
	REQUIRE( ok );
	s.addAddrToAddrs( sa );

	v = s.getAddrs();
	REQUIRE( v != NULL );
	REQUIRE( v->size() == 1 );
	REQUIRE( (*v)[0] == sa );
	delete v; v = NULL;

	sinfulString = s.getSinful();
	REQUIRE( sinfulString != NULL );
	REQUIRE( strcmp( sinfulString, "<?addrs=1.2.3.4:5>" ) == 0 );

	t = Sinful( sinfulString );
	v = t.getAddrs();
	REQUIRE( v != NULL );
	REQUIRE( v->size() == 1 );
	REQUIRE( (*v)[0] == sa );
	delete v; v = NULL;

	sinfulString = t.getSinful();
	REQUIRE( sinfulString != NULL );
	REQUIRE( strcmp( sinfulString, "<?addrs=1.2.3.4:5>" ) == 0 );

	REQUIRE( s.hasAddrs() );

	condor_sockaddr sa2;
	ok = sa2.from_ip_and_port_string( "5.6.7.8:9" );
	REQUIRE( ok );
	s.addAddrToAddrs( sa2 );

	v = s.getAddrs();
	REQUIRE( v != NULL );
	REQUIRE( v->size() == 2 );
	REQUIRE( (*v)[0] == sa );
	REQUIRE( (*v)[1] == sa2 );
	delete v; v = NULL;

	sinfulString = s.getSinful();
	REQUIRE( sinfulString != NULL );
	REQUIRE( strcmp( sinfulString, "<?addrs=1.2.3.4:5+5.6.7.8:9>" ) == 0 );

	t = Sinful( sinfulString );
	v = t.getAddrs();
	REQUIRE( v != NULL );
	REQUIRE( v->size() == 2 );
	REQUIRE( (*v)[0] == sa );
	REQUIRE( (*v)[1] == sa2 );
	delete v; v = NULL;

	sinfulString = t.getSinful();
	REQUIRE( sinfulString != NULL );
	REQUIRE( strcmp( sinfulString, "<?addrs=1.2.3.4:5+5.6.7.8:9>" ) == 0 );

	REQUIRE( s.hasAddrs() );

	condor_sockaddr sa3;
	ok = sa3.from_ip_and_port_string( "[1:3:5:7::a]:13" );
	REQUIRE( ok );
	s.addAddrToAddrs( sa3 );

	v = s.getAddrs();
	REQUIRE( v != NULL );
	REQUIRE( v->size() == 3 );
	REQUIRE( (*v)[0] == sa );
	REQUIRE( (*v)[1] == sa2 );
	REQUIRE( (*v)[2] == sa3 );
	delete v; v = NULL;

	sinfulString = s.getSinful();
	REQUIRE( sinfulString != NULL );
	REQUIRE( strcmp( sinfulString, "<?addrs=1.2.3.4:5+5.6.7.8:9+[1:3:5:7::a]:13>" ) == 0 );

	t = Sinful( sinfulString );
	v = t.getAddrs();
	REQUIRE( v != NULL );
	REQUIRE( v->size() == 3 );
	REQUIRE( (*v)[0] == sa );
	REQUIRE( (*v)[1] == sa2 );
	REQUIRE( (*v)[2] == sa3 );
	delete v; v = NULL;

	sinfulString = t.getSinful();
	REQUIRE( sinfulString != NULL );
	REQUIRE( strcmp( sinfulString, "<?addrs=1.2.3.4:5+5.6.7.8:9+[1:3:5:7::a]:13>" ) == 0 );

	REQUIRE( s.hasAddrs() );

	s.clearAddrs();
	v = s.getAddrs();
	REQUIRE( v != NULL );
	REQUIRE( v->size() == 0 );

	sinfulString = s.getSinful();
	REQUIRE( sinfulString != NULL );
	REQUIRE( strcmp( sinfulString, "<>" ) == 0 );

	t = Sinful( sinfulString );
	v = t.getAddrs();
	REQUIRE( v != NULL );
	REQUIRE( v->size() == 0 );

	sinfulString = t.getSinful();
	REQUIRE( sinfulString != NULL );
	REQUIRE( strcmp( sinfulString, "<>" ) == 0 );

	REQUIRE( ! s.hasAddrs() );

	s.addAddrToAddrs( sa );
	s.addAddrToAddrs( sa2 );
	s.addAddrToAddrs( sa3 );

	v = s.getAddrs();
	REQUIRE( v != NULL );
	REQUIRE( v->size() == 3 );
	REQUIRE( (*v)[0] == sa );
	REQUIRE( (*v)[1] == sa2 );
	REQUIRE( (*v)[2] == sa3 );
	delete v; v = NULL;

	sinfulString = s.getSinful();
	REQUIRE( sinfulString != NULL );
	REQUIRE( strcmp( sinfulString, "<?addrs=1.2.3.4:5+5.6.7.8:9+[1:3:5:7::a]:13>" ) == 0 );

	t = Sinful( sinfulString );
	v = t.getAddrs();
	REQUIRE( v != NULL );
	REQUIRE( v->size() == 3 );
	REQUIRE( (*v)[0] == sa );
	REQUIRE( (*v)[1] == sa2 );
	REQUIRE( (*v)[2] == sa3 );
	delete v; v = NULL;

	sinfulString = t.getSinful();
	REQUIRE( sinfulString != NULL );
	REQUIRE( strcmp( sinfulString, "<?addrs=1.2.3.4:5+5.6.7.8:9+[1:3:5:7::a]:13>" ) == 0 );

	REQUIRE( s.hasAddrs() );

	// In practice, all C++03 implementations are stable with respect
	// to insertion order; the  C++11 standard requires that they are.
	// This is the unit test for the former.
	std::multimap< int, condor_sockaddr > sortedByDesire;

	sortedByDesire.insert(std::make_pair( 0, sa ));
	sortedByDesire.insert(std::make_pair( 0, sa2 ));
	sortedByDesire.insert(std::make_pair( 0, sa3 ));
	int i = 0;
	std::multimap< int, condor_sockaddr >::const_iterator iter;
	for( iter = sortedByDesire.begin(); iter != sortedByDesire.end(); ++iter, ++i ) {
		switch( i ) {
			case 0:
				REQUIRE( (* iter).second == sa );
				break;
			case 1:
				REQUIRE( (* iter).second == sa2 );
				break;
			case 2:
				REQUIRE( (* iter).second == sa3 );
				break;
			default:
				REQUIRE( false );
				break;
		}
	}

	sortedByDesire.clear();
	REQUIRE( sortedByDesire.size() == 0 );
	sortedByDesire.insert(std::make_pair( 1, sa ));
	sortedByDesire.insert(std::make_pair( 0, sa2 ));
	sortedByDesire.insert(std::make_pair( 0, sa3 ));
	i = 0;
	for( iter = sortedByDesire.begin(); iter != sortedByDesire.end(); ++iter, ++i ) {
		switch( i ) {
			case 0:
				REQUIRE( (* iter).second == sa2 );
				break;
			case 1:
				REQUIRE( (* iter).second == sa3 );
				break;
			case 2:
				REQUIRE( (* iter).second == sa );
				break;
			default:
				REQUIRE( false );
				break;
		}
	}

	sortedByDesire.clear();
	REQUIRE( sortedByDesire.size() == 0 );
	sortedByDesire.insert(std::make_pair( 0, sa2 ));
	sortedByDesire.insert(std::make_pair( 1, sa ));
	sortedByDesire.insert(std::make_pair( 0, sa3 ));
	i = 0;
	for( iter = sortedByDesire.begin(); iter != sortedByDesire.end(); ++iter, ++i ) {
		switch( i ) {
			case 0:
				REQUIRE( (* iter).second == sa2 );
				break;
			case 1:
				REQUIRE( (* iter).second == sa3 );
				break;
			case 2:
				REQUIRE( (* iter).second == sa );
				break;
			default:
				REQUIRE( false );
				break;
		}
	}

	return 0;
}
<commit_msg>(#4934)  Unbreak the Sinful self-test for new (CCB-safe) addrs format.<commit_after>#include "condor_common.h"
#include "condor_sinful.h"

#include <stdio.h>

bool verbose = false;
#define REQUIRE( condition ) \
	if(! ( condition )) { \
		fprintf( stderr, "Failed requirement '%s' on line %d.\n", #condition, __LINE__ ); \
		return 1; \
	} else if( verbose ) { \
		fprintf( stdout, "Passed requirement '%s' on line %d.\n", #condition, __LINE__ ); \
	}

int main( int, char ** ) {
	Sinful s;
	Sinful t;

	//
	// Test, for 0, 1, 2, and 3 condor_sockaddrs: that the vector is not NULL,
	// that the vector has the correct number of elements, that the vector's
	// elements values are correct (and in the correct order); and that the
	// string form of the sinful is correct; and that the parser correctly
	// handles the sinful string (by repeating the vector tests); and that
	// the string->sinful->string loop also works (by repeating the string
	// test).  Then repeat the 0 test after clearing the Sinful of addrs.
	//
	// We then also test adding three condor_sockaddrs in a row, just in
	// case one-at-a-time testing somehow hides a problem; this also tests
	// that adding condor_sockaddrs after clearing the Sinful works.
	//

	std::vector< condor_sockaddr > * v = s.getAddrs();
	REQUIRE( v != NULL );
	REQUIRE( v->size() == 0 );
	delete v; v = NULL;

	char const * sinfulString = NULL;
	sinfulString = s.getSinful();
	REQUIRE( sinfulString == NULL );

	REQUIRE( ! s.hasAddrs() );

	condor_sockaddr sa;
	bool ok = sa.from_ip_and_port_string( "1.2.3.4:5" );
	REQUIRE( ok );
	s.addAddrToAddrs( sa );

	v = s.getAddrs();
	REQUIRE( v != NULL );
	REQUIRE( v->size() == 1 );
	REQUIRE( (*v)[0] == sa );
	delete v; v = NULL;

	sinfulString = s.getSinful();
	REQUIRE( sinfulString != NULL );
	REQUIRE( strcmp( sinfulString, "<?addrs=1.2.3.4-5>" ) == 0 );

	t = Sinful( sinfulString );
	v = t.getAddrs();
	REQUIRE( v != NULL );
	REQUIRE( v->size() == 1 );
	REQUIRE( (*v)[0] == sa );
	delete v; v = NULL;

	sinfulString = t.getSinful();
	REQUIRE( sinfulString != NULL );
	REQUIRE( strcmp( sinfulString, "<?addrs=1.2.3.4-5>" ) == 0 );

	REQUIRE( s.hasAddrs() );

	condor_sockaddr sa2;
	ok = sa2.from_ip_and_port_string( "5.6.7.8:9" );
	REQUIRE( ok );
	s.addAddrToAddrs( sa2 );

	v = s.getAddrs();
	REQUIRE( v != NULL );
	REQUIRE( v->size() == 2 );
	REQUIRE( (*v)[0] == sa );
	REQUIRE( (*v)[1] == sa2 );
	delete v; v = NULL;

	sinfulString = s.getSinful();
	REQUIRE( sinfulString != NULL );
	REQUIRE( strcmp( sinfulString, "<?addrs=1.2.3.4-5+5.6.7.8-9>" ) == 0 );

	t = Sinful( sinfulString );
	v = t.getAddrs();
	REQUIRE( v != NULL );
	REQUIRE( v->size() == 2 );
	REQUIRE( (*v)[0] == sa );
	REQUIRE( (*v)[1] == sa2 );
	delete v; v = NULL;

	sinfulString = t.getSinful();
	REQUIRE( sinfulString != NULL );
	REQUIRE( strcmp( sinfulString, "<?addrs=1.2.3.4-5+5.6.7.8-9>" ) == 0 );

	REQUIRE( s.hasAddrs() );

	condor_sockaddr sa3;
	ok = sa3.from_ip_and_port_string( "[1:3:5:7::a]:13" );
	REQUIRE( ok );
	s.addAddrToAddrs( sa3 );

	v = s.getAddrs();
	REQUIRE( v != NULL );
	REQUIRE( v->size() == 3 );
	REQUIRE( (*v)[0] == sa );
	REQUIRE( (*v)[1] == sa2 );
	REQUIRE( (*v)[2] == sa3 );
	delete v; v = NULL;

	sinfulString = s.getSinful();
	REQUIRE( sinfulString != NULL );
	REQUIRE( strcmp( sinfulString, "<?addrs=1.2.3.4-5+5.6.7.8-9+[1-3-5-7--a]-13>" ) == 0 );

	t = Sinful( sinfulString );
	v = t.getAddrs();
	REQUIRE( v != NULL );
	REQUIRE( v->size() == 3 );
	REQUIRE( (*v)[0] == sa );
	REQUIRE( (*v)[1] == sa2 );
	REQUIRE( (*v)[2] == sa3 );
	delete v; v = NULL;

	sinfulString = t.getSinful();
	REQUIRE( sinfulString != NULL );
	REQUIRE( strcmp( sinfulString, "<?addrs=1.2.3.4-5+5.6.7.8-9+[1-3-5-7--a]-13>" ) == 0 );

	REQUIRE( s.hasAddrs() );

	s.clearAddrs();
	v = s.getAddrs();
	REQUIRE( v != NULL );
	REQUIRE( v->size() == 0 );

	sinfulString = s.getSinful();
	REQUIRE( sinfulString != NULL );
	REQUIRE( strcmp( sinfulString, "<>" ) == 0 );

	t = Sinful( sinfulString );
	v = t.getAddrs();
	REQUIRE( v != NULL );
	REQUIRE( v->size() == 0 );

	sinfulString = t.getSinful();
	REQUIRE( sinfulString != NULL );
	REQUIRE( strcmp( sinfulString, "<>" ) == 0 );

	REQUIRE( ! s.hasAddrs() );

	s.addAddrToAddrs( sa );
	s.addAddrToAddrs( sa2 );
	s.addAddrToAddrs( sa3 );

	v = s.getAddrs();
	REQUIRE( v != NULL );
	REQUIRE( v->size() == 3 );
	REQUIRE( (*v)[0] == sa );
	REQUIRE( (*v)[1] == sa2 );
	REQUIRE( (*v)[2] == sa3 );
	delete v; v = NULL;

	sinfulString = s.getSinful();
	REQUIRE( sinfulString != NULL );
	REQUIRE( strcmp( sinfulString, "<?addrs=1.2.3.4-5+5.6.7.8-9+[1-3-5-7--a]-13>" ) == 0 );

	t = Sinful( sinfulString );
	v = t.getAddrs();
	REQUIRE( v != NULL );
	REQUIRE( v->size() == 3 );
	REQUIRE( (*v)[0] == sa );
	REQUIRE( (*v)[1] == sa2 );
	REQUIRE( (*v)[2] == sa3 );
	delete v; v = NULL;

	sinfulString = t.getSinful();
	REQUIRE( sinfulString != NULL );
	REQUIRE( strcmp( sinfulString, "<?addrs=1.2.3.4-5+5.6.7.8-9+[1-3-5-7--a]-13>" ) == 0 );

	REQUIRE( s.hasAddrs() );

	// In practice, all C++03 implementations are stable with respect
	// to insertion order; the  C++11 standard requires that they are.
	// This is the unit test for the former.
	std::multimap< int, condor_sockaddr > sortedByDesire;

	sortedByDesire.insert(std::make_pair( 0, sa ));
	sortedByDesire.insert(std::make_pair( 0, sa2 ));
	sortedByDesire.insert(std::make_pair( 0, sa3 ));
	int i = 0;
	std::multimap< int, condor_sockaddr >::const_iterator iter;
	for( iter = sortedByDesire.begin(); iter != sortedByDesire.end(); ++iter, ++i ) {
		switch( i ) {
			case 0:
				REQUIRE( (* iter).second == sa );
				break;
			case 1:
				REQUIRE( (* iter).second == sa2 );
				break;
			case 2:
				REQUIRE( (* iter).second == sa3 );
				break;
			default:
				REQUIRE( false );
				break;
		}
	}

	sortedByDesire.clear();
	REQUIRE( sortedByDesire.size() == 0 );
	sortedByDesire.insert(std::make_pair( 1, sa ));
	sortedByDesire.insert(std::make_pair( 0, sa2 ));
	sortedByDesire.insert(std::make_pair( 0, sa3 ));
	i = 0;
	for( iter = sortedByDesire.begin(); iter != sortedByDesire.end(); ++iter, ++i ) {
		switch( i ) {
			case 0:
				REQUIRE( (* iter).second == sa2 );
				break;
			case 1:
				REQUIRE( (* iter).second == sa3 );
				break;
			case 2:
				REQUIRE( (* iter).second == sa );
				break;
			default:
				REQUIRE( false );
				break;
		}
	}

	sortedByDesire.clear();
	REQUIRE( sortedByDesire.size() == 0 );
	sortedByDesire.insert(std::make_pair( 0, sa2 ));
	sortedByDesire.insert(std::make_pair( 1, sa ));
	sortedByDesire.insert(std::make_pair( 0, sa3 ));
	i = 0;
	for( iter = sortedByDesire.begin(); iter != sortedByDesire.end(); ++iter, ++i ) {
		switch( i ) {
			case 0:
				REQUIRE( (* iter).second == sa2 );
				break;
			case 1:
				REQUIRE( (* iter).second == sa3 );
				break;
			case 2:
				REQUIRE( (* iter).second == sa );
				break;
			default:
				REQUIRE( false );
				break;
		}
	}

	return 0;
}
<|endoftext|>